EmuZWin built-in ZX Assembler
supported operators and directives.

(Ñ) by Vladimir Kladov, 2003

Starting from v2.2, it is possible to view entire list of all operators and directives, supported by the built-in ZX Assembler, directly in assembler window.

Source code should satisfy following rules to be compiled correctly.

Following directives and assembler statements are supported by the internal assembler. (Character '#' used to note that an operand could be of any numeric expression allowed).


ORG [{ RAMn | ROMn },] #target_address [, #dest_address ]
Defines target assembling address and target output destination address.
RAMn and ROMn is used to define RAM bank (n=0..7) or ROM bank (n=0..1).
If distinct dest_address is defined, compiled bytes are put to that address,
though a code itself is compiled for target_address.
 
label[:] EQU #expression
Defines constant label equal to given expression. label must be unique.
 
label[:] = #expression
Defines variable label equal to given expression. It is possible to 
redefine it with '=' directive any times in the code.
 
label1[:] ENUM [#expr1][,label2[=#expr2]]...
or
ENUM label1[=#expr1][,label2[=#expr2]]...
Creates a number of constants label1, label2, ... If expr2, expr3, etc.
are omitted, following constants are assigned to the previous ones incremented
by 1. If the expr1 is omitted, by default the value 0 is used. 
A list of labels can be continued on the next line of the source and
can occupy several lines (to continue the list, the line should be  finished
with comma). 
 
label[:] DEFINE any text to the end of line
Creates redefinition for the label. Anywhere in the text strings 'label',
'.label', 'label.' and '.label.' will be replaced with the text defined
(trimmed at the left side).
 
DEFB [[(#repeat_count1)]{#expr1|'string1'|?}][,[(#repeat_count2)][{#expr2|'string2'}]]...
a list of bytes. For a string, for each character a single byte is
generated always. So, DEFB 'abc',0 will be compiled to 4 bytes 
61h,62h,63h,0. If (repeat_count) is defined for a value or string it is
repeated repeat_count times (if 0 or less, it is not generated at all).
If the symbol '?' is used, correspondent memory is not initialized and
is skipping while generating code. If no value defined, value 0 is used
to initialize memory.
 
DEFW [[(#repeat_count1)]{#expr1}][,[(#repeat_count2)][{#expr2}]]...
a list of 16-bit words. Very similar to DEFB, but for each value 2 bytes
of memory are initialized (as usual, less significant byte if first - LSB).
 
DEFS[{ #expression | 'string' }] [, [{ #expression | 'string' }] ]...
a list of bytes. For a string, for each character a single byte is
generated always. The difference to DEFB is that the code for the last character 
of each string constant has the bit 7 set on. 
So, DEFS 'abc' will be compiled to 4 bytes 
61h,62h,E3h.
 
label[:] STRUCT
[label1[:]] {DEFB|DEFW|struct_name} [(#repeat_count)[?]]
...
[labelN[:]] {ESTRUCT|ENDSTRUCT}
Creates number of constants label.label1, label.label2, ... which can be later
used as usual constants in any expression. Also, special function sizeof(label)
become available in expressions for each structure defined.
 
FILE filepath
filepath is a path to a binary file to include it (can be enclosed into 
double quotations ("filepath"). Binary file can not exceed 65536 bytes and
it is included as is, byte by byte. Filepath can be also a
list of directories, in such case these are adding to a list of search paths
where the assembler searches for includes.
 
INCLUDE filepath
filepath is a path to a text file to include it as a part of source. filepath
can be enclosed into double quotations ("filepath"). Filepath can be also a
list of directories, in such case these are adding to a list of search paths
where the assembler searches for includes.
 
label[:] MACRO paramlist
  ...
[label2[:]] {ENDM|ENDMACRO|EMAC}
Defines a macro. paramlist can contain: - first, a list of fixed parameters
(must be passed in the same order); - second, parameters in form name=[default].
For named parameters, these can be passed while calling a macro in any order,
but always in form name=value. Named parameters having default value defined
can be omitted while calling a macro. Formal parameters can be any allowed
identifiers, values passed can be either expressions or strings in single
or double quotations (for case of double quotations, content in quotas is passed
without quotas). MACRO header and ENDM|ENADMACRO|EMAC directives must be the
single statements in the source line. Macro should be defined in the source
before any call to it.
 
label[:] PROC
  ...
[label2[:]] {ENDP|ENDPROC|EPROC}
Defines a procedure. Actually this is used to restrict visibility of labels
defined interior of PROC definition to the other part of source: all such
labels (including label2) become local and known only in the procedure itself.
Procedures can be nested, with no restrictions on nesting level.
 
DUP #expr
  ...
{EDUP|ENDDUP}
Duplicates all the statements defined between DUP and EDUP directives, #expr
times (but if #expr <= 0, all the statements are skipping and do not generate
any code occupying 0 bytes of code, and in such case all the directives there
also do not affect code though it can be checked for correctness).
 
FOR var=values
  ...
{EFOR|ENDFOR}
Duplicates all the statements defined between FOR and EFOR directives for
each listed value, assigning such value to a variable var on each step
like it were made using directive label DEFINE text. A list of values can
contain any expressions, double- or single-quoted strings (while assigning
string double-quoted, only string itself without quotations is assigned),
and also a range in form #from TO #to [STEP #step] is allowed here. FOR
statement must be the last in the line. A list of values can be continued
on the next lines (to continue the list, finish it with the comma at the end).
 
IF #expr [THEN]
  ...
[ELSEIF #expr1 [THEN]
  ...]...
[ELSE 
  ...]
{EIF|ENDIF}
Conditional compiling depending on results of #expr, #expr1, ... calculation.
If any #exprK is not 0, correspondent part of code is compiled and other
parts are skipping.
 
IFcond [THEN]
  ...
[ELSE 
  ...]
{EIF|ENDIF}
cond is one of Z80 conditions (Z,NZ,C,NC,PO,PE,P,M). This is a pseudo-statement 
rather then just a macro. It generates code to jump to ELSE (or EIF, if ELSE is
not defined) branch if cond is not satisfied, and if ELSE is defined, also a jump
is generated to EIF at the end of THEN branch. Short jumps are used if possible.
In case then BREAK or CONTINUE is only a statement in THEN branch, code is 
optimized to use a single jump instruction.
 
[label[:]] LOOP
  ...
{ELOOP|ELOOPB}
Generates a code for infinite loop (ELOOP case) or usual DJNZ (ELOOPB case).
If DJNZ can not be used (ELOOPB) because of long jump distance, almost equivalent
instructions are used: DEC B:JP NZ,loop (4 bytes long). Anywhere in the loop 
operators BREAK [label] or CONTINUE [label] can be used to leave or continue the loop. 
Using a label in BREAK and CONTINUE statements allows to make a jump outside from 
the nested LOOP.
 
BREAK [label]

See LOOP directive above.
 
CONTINUE [label]

See LOOP directive above.
 
GOTO [cond,][label]

This is an equivalent of JR/JP instruction but the compiler decides if to use
short jump or distance is too far (or condition is not suitable to use short
jump). The important restriction here is that any expression can not be used
as an operand, but only a label, local or global.
 
PUSH rp1[,rp2]...

Generates a sequence PUSH rp1:PUSH rp2:... for all the register pair names listed
(AF,BC,DE,HL,IX,IY are allowed as usual).
 
POP rp1[,rp2]...

Generates a sequence ...:POP rp2:POP rp1 (register pairs by default are popped in
the inverted order. Use POPNOINVERT and POPINVERT directives to control this order
for such POP directive.
 
POPNOINVERT

See POP directive above.
 
POPINVERT

See POP directive above.
 

Alphabetical list of instructions.
ADC HL, { BC | DE | HL | SP }
ADC IX, { BC | DE | IX | SP }
ADC IY, { BC | DE | IY | SP }
ADC [ A, ] { B | C | D | E | H | L | M | (HL) | A | 
             IXH | IXL | (IX±#offset ) | (IY±#offset) |
             #expression }
ADD HL, { BC | DE | HL | SP }
ADD IX, { BC | DE | IX | SP }
ADD IY, { BC | DE | IY | SP }
ADD [ A, ] { B | C | D | E | H | L | M | (HL) | A | 
             IXH | IXL | (IX±#offset ) | (IY±#offset) |
             #expression }
AND [ A, ] { B | C | D | E | H | L | M | (HL) | A | 
             IXH | IXL | (IX±#offset ) | (IY±#offset) |
             #expression }
BIT #number, { B | C | D | E | H | L | M | (HL) | A | 
             IXH | IXL | (IX±#offset ) | (IY±#offset) }
BIT #number, { (IX±#offset ) | (IY±#offset) },
             { B | C | D | E | H | L | A }
CALL [ { NZ | Z | NC | C | PO | PE | P | M }, ] #address
CCF
CP  [ A, ] { B | C | D | E | H | L | M | (HL) | A | 
             IXH | IXL | (IX±#offset ) | (IY±#offset) |
             #expression }
CPD
CPDR
CPI
CPIR
CPL
DAA
DI
DEC { B | C | D | E | H | L | M | (HL) | A | IXH | IXL | IYH | IYL |
      ( {IX|IY}±#offset ) } 
DI
DJNZ #address
EI
EX (SP), { HL | IX | IY }
EX AF, AF'
EX DE, { HL | IX | IY }
EXX
HALT
IM0 | IM1 | IM2 | IM #n
IN [ A, ] { (#port) | (C) }
IN { B | C | D | E | H | L | F | A }, (C)
INC { B | C | D | E | H | L | M | (HL) | A | IXH | IXL | IYH | IYL |
      ( {IX|IY}±#offset ) } 
IND
INDR
INI
INIR
JP [ { NZ | Z | NC | C | PO | PE | P | M }, ] #address
JR [ { NZ | Z | NC | C }, ] #address
LD A, { I | R | B | C | D | E | H | L | M | (HL ) | A | 
        #expression | IXH | IXL | IYH | IYL | 
       (IX±#offset) | (IY±#offset) | (BC) | (DE) | (#address) }
LD { B | C | D | E | H | L | M | (HL) }, 
   { B | C | D | E | H | L | M | A | #expression }
LD { B | C | D | E | IXH | IXL | A | (IX±#offset) },
   { B | C | D | E | IXH | IXL | A | #expression }
LD { B | C | D | E | IYH | IYL | A | (IY±#offset) },
   { B | C | D | E | IYH | IYL | A | #expression }
LD { B | C | D | E | IXH | IXL | A },
   { B | C | D | E | IXH | IXL | A | (IX±#offset) }
LD { B | C | D | E | IYH | IYL | A },
   { B | C | D | E | IYH | IYL | A | (IY±#offset) }
LD { I | R }, A
LD { BC | DE | HL | SP | IX | IY }, { #expression | ( #address ) }
LD ( #address ), { BC | DE | HL | SP | IX | IY }
LDD
LDDR
LDI
LDIR
NEG
NOP
OR  [ A, ] { B | C | D | E | H | L | M | (HL) | A | 
             IXH | IXL | (IX±#offset ) | (IY±#offset) |
             #expression }
OUT { (#port) | (C) } [, A ]
OUT (C), { B | C | D | E | H | L | F | A }
OUTD
OTDR
OUTI
OTIR
POP  { BC | DE | HL | AF | IX | IY }
PUSH { BC | DE | HL | AF | IX | IY }
RES #number, { B | C | D | E | H | L | M | (HL) | A | 
             IXH | IXL | (IX±#offset ) | (IY±#offset) }
RES #number, { (IX±#offset ) | (IY±#offset) },
             { B | C | D | E | H | L | A }
RET [ { NZ | Z | NC | C | PO | PE | P | M | N | I } ]
RETI
RETN
RL  { B | C | D | E | H | L | M | (HL) | A | 
    IXH | IXL | (IX±#offset ) | (IY±#offset) }
RLA
RLC { B | C | D | E | H | L | M | (HL) | A | 
    IXH | IXL | (IX±#offset ) | (IY±#offset) }
RLCA
RLD
RR  { B | C | D | E | H | L | M | (HL) | A | 
    IXH | IXL | (IX±#offset ) | (IY±#offset) }
RRA
RRC { B | C | D | E | H | L | M | (HL) | A | 
    IXH | IXL | (IX±#offset ) | (IY±#offset) }
RRCA
RRD
RST #expression ;
    (allowed following values: 
     0..7 and also 8, 16, 24, 32, 40, 48, 56 - decimal)
SBC HL, { BC | DE | HL | SP }
SBC [ A, ] { B | C | D | E | H | L | M | (HL) | A | 
             IXH | IXL | (IX±#offset ) | (IY±#offset) |
             #expression }
SCF
SET #number, { B | C | D | E | H | L | M | (HL) | A | 
             IXH | IXL | (IX±#offset ) | (IY±#offset) }
SET #number, { (IX±#offset ) | (IY±#offset) },
             { B | C | D | E | H | L | A }
SLA { B | C | D | E | H | L | M | (HL) | A | 
    IXH | IXL | (IX±#offset ) | (IY±#offset) }
SLA { (IX±#offset ) | (IY±#offset) },
    { B | C | D | E | H | L | A }
SLI { B | C | D | E | H | L | M | (HL) | A | 
    IXH | IXL | (IX±#offset ) | (IY±#offset) }
SLI { (IX±#offset ) | (IY±#offset) },
    { B | C | D | E | H | L | A }
SLL { B | C | D | E | H | L | M | (HL) | A | 
    IXH | IXL | (IX±#offset ) | (IY±#offset) }
SLL { (IX±#offset ) | (IY±#offset) },
    { B | C | D | E | H | L | A }
SRA { B | C | D | E | H | L | M | (HL) | A | 
    IXH | IXL | (IX±#offset ) | (IY±#offset) }
SRL { B | C | D | E | H | L | M | (HL) | A | 
    IXH | IXL | (IX±#offset ) | (IY±#offset) }
SRL { (IX±#offset ) | (IY±#offset) },
    { B | C | D | E | H | L | A }
SUB [ A, ] { B | C | D | E | H | L | M | (HL) | A | 
             IXH | IXL | (IX±#offset ) | (IY±#offset) |
             #expression }
XOR [ A, ] { B | C | D | E | H | L | M | (HL) | A | 
             IXH | IXL | (IX±#offset ) | (IY±#offset) |
             #expression }

Starting from version 2.3 Build 1.5:

Additional rules are added to allow assembling code obtained disassembling a block of memory using Disassemble feature. These are:

- all text following comma ( , ) in brackets is treated as a comment. E.g. LD HL, (0FFFEh,any text here).
- all text following comma in the last operand of the instruction also is treated as a comment. E.g. LD HL,0FFFEh,any text here.
- all numbers having hexadecimal digits are treated as hexadecimal numbers even if those have no leading zero but finishing 'H' char. E.g, FFFFH, 0FFFF, 0FFFFH are allowed, but not FFFF. And, if a label is defined FFFFH, it is overriding FFFFH hexadecimal. So, avoid using labels having only hexadecimal digits and trailing 'H' char.

A feature also added "Set PC" which allow to select from drop down menu (when clicked on a correspondent button on the toolbar in the Assembler window) an address to set to PC in the Debugger.

Left mouse click with Ctrl pressed on a name jumps to a correspondent label in the text (if any such found), adding current position to the history of jumps.

Speed of assembling code is enough fast now to use the Assembler more convenient. In Labels window, use right mouse click to popup a menu with additional options (if to list user and/or system labels e.g.)

Starting from version 2.3 Build 1.5:

- Binary numbers are allowed ( 00010111.B );
- Directive FILE added to include binary files.

New Extensions (version 2.7):

- Colorization of the source text provided.
- Bookmarks in source provided (Ctrl+Shift+n - set bookmark, Ctrl+n - go to bookmark, n - digit key on the keyboard). Bookmarks are saved with the text and restored when loaded.
- Adjusting font size for assembler provided (from Asm options dialog or Ctrl+'+', Ctrl+'-' in the memo).
- Indentations provided (ctrl+shift+I, ctrl+shift+U).
- Smart tabs provided in the editor.
- A lot of changes and improvements in the language itself:

C-- for Z80 embedded.

In C-- statements, all register names are reserved names of predefined variables:
byte A, A', F, F', B, B', C, C', D, D', E, E', H, H', L, L', I, R, IXL, IXH, IYL, IYH
int AF, AF', BC, BC', DE, DE', HL, HL', IX, IY, SP
Also, some accumulator flags are predefined symbols and can be used in some circumstances:
bit CF

Important: a single C-- operator should be written without any internal spaces (but spaces are allowed in the expression or in the parenthesis). C-- operators can be separated from each other or from assembler statements with spaces or symbol ':'. C-- statements as well as most of assembler ones should be written in a single line (division it on parts placed in several neighbor lines is not allowed).

If any register pair is used (and not only in the C-- statement but in any assembler instruction too), it can be auto-incremented or auto-decremented as usual in C, both prefixing or suffixing incrementing and decrementing are allowed. In all such cases the register is incremented or decremented by 1.

Assignment operator: dest=expression. In simple case when dest points to memory but expression is a registry, or otherwise, dest is a registry and expression represents another registry or memory location, and such movement can be compiled to a single direct LD instruction, this is compiled so. E.g.:

A=B LD A,B
A=(HL) LD A,(HL)
A=(IX+10) LD A,(IX+10)
(16384)=SP LD (16384), SP
(DE++)=(HL++) LDI

If an assignment can not be compiled into a direct LD instruction (e.g. moving data from memory to memory), then either register A used as a temporary data storage and is destroying without warning, or stack is used temporarily. E.g.:

(DE)=(BC) LD A,(BC):LD (DE),A
(17000)=(18000) LD A,(18000):LD (17000),A
BC'=BC PUSH BC:EXX:POP BC:EXX
(IX)=DE LD (IX),E:LD (IX+1),D
(HL)=BC LD (HL),C:INC HL:LD (HL),B:DEC HL
(HL++)=BC LD (HL),C:INC HL:LD (HL),B
SP=DE EX DE,HL:LD SP,HL:EX DE,HL
SP=HL' EXX:LD SP,HL:EXX
SP=IY LD SP,IY

Separate operators ++ and -- can be applied only in postfix form and either to a register or register pair or to memory location addressed using HL, IX, IY registers. E.g.:

A++ INC A
HL-- DEC HL
(++HL)-- INC HL:DEC (HL)
(IX+5)++ INC (IX+5)

Other possible operators:
= (assign)
& (and) | (or) ^ (xor)
+ (add) +CF+ (ADC)
- (subtract)  -CF- (SBC)
r<<CF (shift left, RLC) r<< RL r<<- (SLA)
r>>CF (shift right, RRC) r>> RR r>>- (SRA)
>< (swap, exchange instructions)
? (compare)

Possible usage:

A=A+5 ADD A,5
A+B ADD A,B
A-C-CF SBC A,C
&E AND A,E
|(HL) OR A,(HL)
A?(IX+100) CP A,(IX+100)

As you can see, A=A op opd2 can be always replaced with A op opd2 or even op opd2, but at least A' op opd2 must be used if alternative accumulator is used:

A'^E EX AF,AF':XOR A,E:EX AF,AF'

For case of register pairs  (16-bits arithmetics) only prefix Dest= can be omitted in the statement Dest=Dest op Src:

HL=HL+DE ADD HL,DE
HL+BC ADD HL, BC
IX+DE'+CF EXX:ADC IX, DE:EXX
IY+HL EX DE,HL:ADD IY,DE:EX DE,HL

Several samples of shift instructions:

A<< RLA
>>CF RRCA
B<<- SLA B
E'>>- EXX:SRA E:EXX
A'<<CF EX AF,AF':RLCA:EX AF,AF'

Several samples of swap instructions:

HL><DE EX DE,HL
(SP)><DE EX DE,HL:EX (SP),HL:EX DE,HL
IX><BC PUSH IX:PUSH BC:POP IX:POP BC
DE><HL' PUSH DE:EXX:PUSH HL:EXX:POP DE:EXX:POP HL:EXX
AF><AF' EX AF,AF'

 


Last update: 8-Aug-2004

http://bonanzas.rinet.ru mailto: bonanzas@online.sinor.ru