Make Conditional Assembly compatible with other cross-assemblers
Hello asMSX team!
I am developing a routine that I would like to work with in the asMSX, Sjasm and tniASM cross-assemblers, but the peculiarities of defining constants and variables do not allow it, so I have gone to try to use conditional assembly.
While in Sjasm and tniASM they are compatible to a minimum, which allow the use of conditional assembly with this objective, in asMSX this is not fulfilled.
I would like to propose that this problem be discussed, thinking of facilitating the development of routines for common use without having to create and maintain several code files.
References:
- Sjasm 0.42 manual - Conditional assembly
- tniASM Guide Book:
2.6 Conditional Assembly
Sometimes it's useful to have a certain piece of code assemble only
when certain conditions are met. For instance when writing code for
multiple platforms at the same time (Z80 and R800 for example), or
for including/excluding debug code.
tniASM provides this functionality through the IF-construct. Its
basic form is:
IF {operand} [{...}] [ELSE [{...}]] ENDIF
Note that due to the multi-pass nature of tniASM, it's allowed to
use forward references in IF-constructs. They may also be used
accross source file boundaries. Ofcourse IF's can be nested with a
practically infinite depth.
2.6.1 IF {expression}
The expression is evaluated and is considered 'false' when zero,
while any non-zero result is considered 'true'.
loop: {...}
IF $-loop < 128
djnz loop
ELSE
dec b
jp nz,loop
ENDIF
2.6.2 IFDEF {label}
Check if a label was previously declared this pass.
R800: ; comment away for Z80 version
IFDEF R800 mulub a,b ELSE call mulub_a_b ENDIF
IFDEF R800 ELSE
mulub_a_b: {...}
ret
ENDIF
2.6.3 IFEXIST {string}
Check if a file exists. Look at the second example for a nice
trick, which works with any IF-instruction.
IFEXIST "test" {...} ENDIF ; do {...} if "test" exists
IFEXIST "test" ELSE {...} ENDIF ; do {...} if "test" does not exist
2.6.4 IFEXIST {label}
Similar to IFDEF, but checks if a label exists regardless of where
or when it is declared. You can use this to check if a label is
declared further on in the source code.
I have seen that the asMSX supports conditions written without parentheses (I have not seen it in the manual), so the compatibility problem is reduced.
If I have found a problem in the relational operator of equality.
In Sjasm they support both = and ==, while tniASM only supports = and asMSX supports ==.
A possible solution could be to add the equality operator = to asMSX.
It is worth highlighting, as a curiosity, in the not equal operator everyone supports !=, although in tniASM, it also supports <>.
References:
- Sjasm 0.42 manual - Expressions - Operators
- tniASM Guide Book:
2.4.1 Precedence Level 0 - Relational Operators
The relational operators are:
x = y equals
x <> y not equals
x >< y " "
x != y " "
x < y less than
x > y more than
x <= y less than or equals
x =< y " " " "
x >= y more than or equals
x => y " " " "
Unlike in the C-language, the relational operators use -1 for 'true'
and 0 for 'false' (in stead of 1 and 0). This way there's no need
for boolean versions of the AND, OR and XOR operators, since they
work in exactly the same way as the bitwise ones.
The relational operators allow for complex expressions such as:
x*(1+2*(x<0))
which gives the absolute value of 'x'.
I don't think it's a good idea to use a single = to compare, as it can lead to confusion.
@duhow I agree with you. I have continued to study this topic and I don't think it offers any improvement.
But I found a way, while listening to The Social Network soundtrack ;)
I share it here in case it would be useful for someone who has the same need.
If you add in the main code a Label that marks the name of the assembler (ASMSX, SJASM or TNIASM) and/or the runtime environment (MSXROM, MSXDOS or MSXBASIC), you can use IFDEF to add differences, although there is an exception: for Sjasm IFDEF doesn't work with Labels, it works with macros. For this case it would be necessary to add a 'DEFINE' plus the label.
Although all this at the moment will not work with asMSX until issue #90 is solved
For asMSX and tniASM:
;This label allows you to distinguish the assembler,
;when you need it when using conditional assembly
;Labels: ASMSX , SJASM or TNIASM
;Use it with the IFDEF statement
ASMSX:
;This label allows you to distinguish the runtime environment,
;when you need it when using conditional assembly
;Labels: MSXROM , MSXDOS or MSXBASIC
;Use it with the IFDEF statement
MSXROM:
For Sjasm:
;This label allows you to distinguish the assembler,
;when you need it when using conditional assembly
;Labels: ASMSX , SJASM or TNIASM
;Use it with the IFDEF statement
DEFINE SJASM
;This label allows you to distinguish the runtime environment,
;when you need it when using conditional assembly
;Labels: MSXROM , MSXDOS or MSXBASIC
;Use it with the IFDEF statement
DEFINE MSXROM
Example of a conditional assembler use case:
IFDEF MSXDOS
LD HL,$002D ;MSXID3=BIOS System constant (MSX version number)
LD A,[$FCC1] ;EXPTBL=main BIOS-ROM slot address
CALL $000C ;RDSLT=Reads the value of an address in another slot
EI ;RDSLT leaves interrupts disabled
ELSE
ld A,[$002D] ;MSXID3=BIOS System constant (MSX version number)
ENDIF
Having #108 to define ASMSX in program, you should be able to use it for specific actions to do in ASMSX.
Feel free to provide any feedback or additional commits there.
With #90 fixed, this should be already ok and we can close it.