# EmuZWin built-in ZX Assembler
supported operators and directives.

(Ñ) by Vladimir Kladov, 2003-2006

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.

- A single line can contain a single several assembler statements, or a single directives, wrapping lines is not allowed for several special cases only( ENUM, FOR ). Also, a line can be empty or contain a comment only (starting with ';', or with '*' but for '*' - only if it is in the first column of the line).
- Any statement line of source text can have a label which is an identifier starting with a letter, or one of characters '@','_','!','~','#','%','$','!', '\', '[', ']' or OEM character with hex code C0-FF (so, Russian language identifiers are allowed) and (optionally) followed with any characters excluding ':', ';', and other symbols which can be interpreted as arithmetic or logical operation symbols.
- A label can be separated from its statement with ':', but this is optional (spaces are allowed). Therefore if a label is matching any reserved word, it must be separated with ':' from other characters in the line (this forces reusing reserved word as a label therefore). But instructions or directives without parameters (or directives which can have no parameters) anyway can not be used as labels (e.g., loop). It is allowed to have only one label in a line, without a statement.
- An operator, which has no label must be started with (at least one) space or tabulation. An operator which has no label can start from the left edge of the line therefore (it is not necessary to add spaces or tabulations at the beginning of the line). If a line contains several assembler statements or directives these can be separated from each other with ':' (but this is optional also and necessary only in some cases, to divide an expression in the last operand from the following statement).
- All labels are case-sensitive. (So Abc, abc and ABC are different names). But op-codes, directives, register names, conditional flags (Z, NZ, etc.) and hexadecimal digits are case insensitive.
- Numeric constants usually should be (but not always!) started with digits 0..9 (hexadecimal numbers can be recognized even started with hexadecimal digits A..F, if those are finished with one of hexadecimal base mark: H or h or .H or .h). Default base is decimal, but if at least one hexadecimal character 'a'..'f' occur, base 16 used for such constant. If numeric constant is terminated with 'h' (or 'H'), also base 16 used. Also, binary numbers in form e.g. 00001001.B with terminating '.B' or '.b' are allowed. And the same for octal numbers, with base suffix '.O' or '.o' (and for decimal .D and for hexadecimal .H numbers): e.g. 71.O means octal number equal to 39.H (=57.D=111001.B). Also hexadecimal numbers are allowed in form #xxxx (starting with '#' and containing hexadecimal digits) and in form $xxxx (but the last case only if correspondent option is turned on in the Assembler options). And, for binary numbers, format %xxxx can be allowed from the assembler options.
  If an identifier still not defined after the first pass, and it contains only hexadecimal digits, it is assumed to be hexadecimal number. (So, it is possible to write OUT FE to code instruction OUT (FE),A)
- String constants are quoted with single ( ' ) or double ( " ) quotation marks, and duplicated marks in a string are meaning a single such character to code characters ' and " it selves, use another quotation marks for a string. One- or two-character string can be used everywhere in place of number (note, that the second character in such string represents high byte of 16-bit word, so 'AB' = $4241).
- Expressions are allowed everywhere as immediate operands, offsets, jump labels, etc.
- Anywhere in the expression special function sizeof(structname) can be used as a usual constant (see STRUCT directive below).
- Special label '.' (single dot symbol) means "an address of the command itself" always. Special label '$' means "an address of the next instruction".
- Local labels are allowed starting from one of 6 characters '.', '_', '@', '!', '?', '\' (each can be allowed in Assembler options separately). Local labels are not checked for duplicating at all. To jump to nearest local label (or use it in an expression), just use its name. But if there two such labels are available, one above and another below the jump instruction, the last is used (first labels are searching forward). To specify a direction to go to, use local label name in form B[local] or F[local] (B - back, F - forward, lower case b[local] and f[local] also are allowed, and it is possible to use symbols '<' and '>' in place of 'B' and 'F', but only in GOTO, JP and JR instructions, but in such case only single label is allowed, not an expression).
- In expressions, following binary operations are allowed:
  + add
  - subtract
  * multiply
  / divide
  % reminder
  & and
  | or
  ^ xor
  < less (true=FFFF, false=0)
  <= less or equal
  > greater
  >= greater or equal
  <> or != or ~= not equal
  = equal
  << shift left
  >> shift right
- Parenthesis can be used to control calculation order in expressions as usual. If there are no parenthesis, operation priorities are used, from highest to lowest:
  << >>
  * / %
  + -
  & ^
  |
  < > <= >= = <>

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). Since in most cases the operator can be continued on the next line, only directives are noted which have some restrictions to this rule.

ORG | ENTRYPOINT | EQU | x=y | .=y, $=y | ENUM | DEFINE | DEFB | DEFM | DEFW | DEFS
DEFG | DEFD | ENCODE | CTEXT | FILE | INCLUDE | MACRO | ERROR | DISPLAY | PROC | DUP
FOR | IF | IFcond | LOOP | BREAK | CONTINUE | GOTO | PUSH | POP | POPNOINVERT | POPINVERT
END |  |  |  |  |  |  |  |  |  |

    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.
    All the labels and variables used in the expression must be known on the
    first pass ofthe compiling process (i.e. forward references are not allowed,
    except you turned Strong Address Control option in the assembler off).
    ENTRYPOINT #expr
    Defines entry point to set PC automatically when code compiled OK.
    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. Variables can
    be used in any expressions as usual for labels.
    Note: after each compilation pass, such variables still save the last
    assigned value. This can be used for some calculations on the second
    or the third pass, when the code is generated finally.
    . = #expression
    or
    $ = #expression
    Special form of assignment, using current compiling address as a left
    part of the assignment. In result, following code will be compiling
    from the address specified by the expression. All the labels and
    variables used in the expression must be known on the first pass of
    the compiling process (i.e. forward references are not allowed as like
    as for ORG, except you turned Strong Address Control option in the
    assembler off). The main difference to ORG directive is that this address
    will not be put into a list of labels to switch PC address.
    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.
    label[:] DEFINE any text to the end of line
    About usage of macro parameters, identifiers defined with DEFINE or variable of
    the FOR preprocessor loop see below.
    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. If ENCODE directive have defined encoding, all characters
    are encoded before put it into memory. By default, 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 skip while generating code.
    DEFM[{ #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, DEFM 'abc' will be compiled to 4 bytes
    61h,62h,E3h.
    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 #repeat_count [, { #expression | 'string' | "string" } ]...

    a list of bytes like for DEFB but entire list of values generated
    #repeat_count times. The same as DUP #repeat_count DEFB list EDUP
    If only #repeat_count present without values, 0 is compiled
    #repeat_count times.
    DEFG ssssssss [ ssssssss ]...

    Special (new) directive to define binary bytes. s = '.' to represent 0,
    any other character to represent 1. Spaces used to separate bytes up to
    the end of the line. But numbers are treated as bytes (though those should
    be separated with spaces only). If the following line starts from '.', 'x'
    or 'X' it is supposed that DEFG allocates several lines, and bytes are
    placed into memory by columns. This directive can be useful to "draw" fonts
    in the source code directly, e.g.:

    DEFG ........ .X......
    DEFG .XXXXX.. .X......
    DEFG ......X. .XXXXX..
    DEFG ..XXXXX. .X....X.
    DEFG .X....X. .X....X.
    DEFG ..XXXX.X .XXXXX..
    DEFG ........ ........
    (this is a compiled to 0,40h,7Ch,40h,etc.)
    or:
    DEFG ........ .X......
         .XXXXX.. .X......
         ......X. .XXXXX..
         ..XXXXX. .X....X.
         .X....X. .X....X.
         ..XXXX.X .XXXXX..
         ........ ........
    (in this case bytes are: 0,7Ch,2,3Eh,42h,3Dh,0,40h,etc. i.e. bytes
    are placed by columns).
    DEFD xxxxxx [[,] xxxxxx ]...

    Directive to define packed hexadecimal. E.g. DEFD 1234567890 is the same
    as DEFB 12h,34h,56h,78h,90h. If an item an the list is not started with
    hexadecimal digit it is evaluated as usual expression. If comma not used,
    the directive ends when the next item is not started from hexadecimal
    digit.
    ENCODE #from1,#to1[,#from,#to]...

    Special directive to encode characters in strings into a desired encoding
    (e.g. Russian or other national characters in many cases it is better to
    encode using values below 80h or remapping most of them to looking similar
    Latin letters). Encoding given by the directive ENCODE is working until it
    is not remapped with the next ENCODE directive. #fromN and #toN can be any
    expressions treated as byte values.
    CTEXT text
    text
    ...
    text
    ENDTEXT

    Special directive to encode text in compact form. Trailing characters
    in each line are stored with bit 7 set. Final mark ENDTEXT must be
    starting at the first column in the line.
    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. label1 is set to value 0, and following
    labels depending on size of previos fields defined. Also, special function sizeof(label)
    become available in expressions for each structure defined. It is also possible
    to use label1, label2 etc. as standalone names.
    Note: due to the algorithm used, it is possible to code any instructions or
    directives in the structure, but this affects only the offset of the following
    labeled fields, and do not generate any bytes in memory.
    FILE filepath[,start[,length]]
    filepath is a path to a binary file to put it into memory (can be enclosed into
    double quotations ("filepath"). Binary file (or length specified) can not exceed
    65536 bytes and it is put 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. Macro definition can be located anywhere in the source
    even below places where it is used, and visible always even located in a
    non-processed conditional branch. Do not intersect macro level with other
    preprocessing directive levels. (E.g. mmm MACRO ... IF expr ENDM EIF - is not
    correct!)
    Any labels defined in the MACRO should be local (otherwise problems possible
    using the macro more then once).
    About usage of macro parameters, identifiers defined with DEFINE or variable of
    the FOR preprocessor loop see below.
    ERROR [#severity],'text'[,#passes]
    or
    ERROR [#severity],"text"[,#passes]

    Generates a user-defined error. Can be used e.g. in macro to indicate incorrect
    parameters passed. severity: 0 - warning (message is displayed but does not affect
    compiling; 1 - usual error (code will not be generated more, but the compiler do
    not stop immediately); 2 or higher - fatal error, compiler is stopped immediately
    displaying a text. If #passes not defined, message is displayed on all compiler
    passes. Otherwise passes is expressed and used as a mask: bit 0 set if to show
    at pass 1, bit 1 - at pass 2, and bit2 - at pass3. So, if passes = 2, message
    is displayed only at pass 1, if pass = 6 - at pass 2 and 3.
    DISPLAY 'text'[,#expr[,#passes]]
    or
    DISPLAY "text"[,#expr[,#passes]]
    or
    DISPLAY #expr[,#passes]
    or
    DISPLAY "text",#expr[,"text"[,#expr]]...[,#passes]

    Displays a text with #expr value (is present) concatenated (in decimal and hex).
    Like for ERROR, #passes (if present) defines a mask of flags indicating for the
    compiler on which passes to display a text. It is possible to define several
    pairs of text and value to display in a line.
    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).
    About usage of macro parameters, identifiers defined with DEFINE or variable of
    the FOR preprocessor loop see below.
    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.
    LONGIFcond [THEN]
      ...
    [LONGELSE
      ...]
    {EIF|ENDIF}
    The same as IFcond but always long jumps are used (JP). LONGELSE can be used
    with IFcond and LONGIFcond with usual ELSE, and what is used (ELSE or LONGELSE
    takes an effect only for jump at the end of the "THEN" branch to the end of
    the "ELSE" branch.
    [label[:]] WHILE
      ...
    {EWHILE|EWHILEB|EWHILENZ|EWHILEZ|EWHILENC|EWHILEC|EWHILEPO|EWHILEPE|EWHILEP|EWHILEM}
    (in earlier versions it was named LOOP...ELOOP|ELOOPB, if you want you can declare
    LOOP DEFINE WHILE
    ELOOP DEFINE EWHILE
    ELOOPB DEFINE EWHILEB - to provide working of the old code)
    Generates a code for infinite loop (EWHILE case), usual DJNZ (ELOOPB case) or for
    conditional loop (EWHILEcond).
    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 WHILE directive above.
    CONTINUE [label]

    See WHILE 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]...
    or
    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]...
    or
    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.
    END

    Finishes code. Any code below this directive will not be compiled.

Usage of macro parameters (in macro itself), names defined with DEFINE directive or of the variable of the FOR preprocessor loop.

Anywhere in visibility area such identifier is replaced with a (string) value assigned to it, i.e. it is substituted for each line with its value (even in a quoted string). Visibility area depends on substituting identifier: for macro parameter it is visible in the macro body when the macro is called, for FOR variable it is visible until EFOR / ENDFOR and for name defined with DEFINE directive - from the definition to the end of the source.
To allow concatenating the vale with other characters use .name or name. or .name. - while substituting name with its value, neighbor dots will be removed. To code '.' itself use to dots like name..xxxx.
To allow extracting only a part of value, use following form: "name"[ nnn ] or "name"[ nnn, LLL ] where nnn and LLL are decimal positive numbers. nnn=1 means the first character, LLL can be used to define length of substring extracted (if > 1). Important: character '[' must be the following closing '"' without spaces in between.
It is also possible to use such values in comparison operations anywhere in the expression in form: "name1" op "name2" or "name1" op string (where op can be one of comparison operation =, <>, <, <=, >, >=). E.g. IF "RP" = DE THEN ...

    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:

- Support for ':' to separate several assembler instructions in a line. Symbol ':' still can be used to separate label from other operators in the line (label must be the first and single in the line and should not match to any opcode mnemonics or other reserved word).
- Therefore, symbol ':' can be omitted at all except an expression should be separated from the following C-- operator (see below). But in most cases even such separation not necessary, and several assembler instructions and C-- operators can be simply written in a single line just separated with spaces.
- It is possible now to start a label not only from the left edge of a line, but predict it with some spaces and tabulations (but in such case the label must be either separated with symbol ':' or must not match any reserved word or name of macro - see below).
- It is possible now to start writing opcodes and directives from the left edge of a line (these are distinguishing from labels because labels should not match opcodes unless these are trailing with ':').
- DEFB and DEFW support now repeat counters in parenthesizes, and symbol '?' can be used to avoid memory initializing while compiling code, eg. DEFW (12)0 : DEFB (5)? : DEFB 1,2,?,?,?,(7)'abc'
- DEFS 'string1' [,string2]... (each string is compiled byte by byte, but the last character has bit 7 set). Numeric expressions also allowed and act exactly as for directive DEFB.
- PROC / ENDP creates a "procedure", i.e. a block of scope, all labels and other names defined in which are visible only in the procedure itself and not visible from the other code. (ENPROC or EPROC can be used also in place of ENDP)
- PUSH rp1,rp2, ... is equal to PUSH rp1 : PUSH rp2 : ...
- POP rp1,rp2,... is equal to POP ... : POP rp2 : POP rp1 (inverted order, but this can be changed using directives POPINVERT / POPNOINVERT
- Directive
  name DEFINE any text; do not place comments here!
  to allow any replacements even for opcode mnemonics or directives. Note, that defines are not recursive. To allow concatenating names with definitions, leading or trailing dots are eliminated while substituting (e.g.: if AAA DEFINE BBB then CCC.AAA.CCC become CCCBBBCCC after substituting but not CCC.BBB.CCC. So, if a dot actually necessary, it must be doubled: CCC..AAA.CCC become CCC.BBBCCC after the replacement).
- Directive INCLUDE "filename" added.
- Directive name MACRO paramlist / ENDM added.
- New preprocessing directives added
  - DUP expression / :E[ND]DUP
  - FOR param=valuelist / ENDFOR
  - IF expression [THEN] ... [:ELSEIF expression [THEN] ...]... [:ELSE ...] :E[ND]IF
  - ENUM const1=expr1[,const2[=expr2]]... or const1[:] ENUM expr1[,const2[=expr2]]...
  - variable=expression (same as EQU but variable can be reassigned so many times as this is necessary).
- New pseudo-instructions added:
  - IFcond [THEN] ... [:ELSE...] :E[ND]IF where cond can be C, NC, Z, NZ, P, M, PO, PE - as usual for JP instructions.
  - LOOP ... :ELOOP and LOOP ... ELOOPB.
  - BREAK [label] and CONTINUE [label] - to break or continue labeled loop statement.
- Structure definitions added: name STRUCT [data definitions]... E[ND]STRUCT
- Function Sizeof(name) supported for structure names and can be used as usual constant number.
- C - - for Z80 support added. See details about C-- below.

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