APM Cross-Assembler for Z80

Preamble

EUCSD Zilog Z-80 Assembler - User Notes

Introduction

This assembler is a very basic low-level program development tool. There are no macros, and only one data byte or data word or machine instruction is generated per statement. Provided that no use is made of the Z-80's advanced instructions, this assembler may also be used to generate code for Intel 8080 and 8085 processors.

The syntax is as nearly as possible identical to that specified in the Zilog Z80-CPU technical manual.

Statements usually appear one to a line, but several may appear to a line (separated by semicolons), provided that (due to crude implementation) no more than 4 bytes of code are generated on any one line. N.B. no Z-80 instruction exceeds 4 bytes in length.

A comment, which starts with a '/', may appear either on a line by itself, or to the right of any other statement. Comments occupy the entire rest of the line, i.e. a semicolon does not terminate a comment.

Names obey the same rules as in HAL, i.e. a name is an arbitrary collection of letters and digits, starting with a letter, and containing no other characters, such as spaces. Although a name may be longer than 6 characters, only the first 6 are used to identify the name uniquely.

Numbers are assumed to be in decimal. Other bases may be used by prefixing the number by the base and '_', as in IMP-77, e.g. 8_23, 16_3FF. Constructs such as 8_16_2A, though silly, are quite legal if you know how to use them (this example means 38). Numbers may be signed with '-'(minus) or '\'(not). Quoted characters are enclosed in single quotes (as in IMP), e.g. 'A', and generate 8-bit constants. The special form of a quoted quote is ''' (not ''''). Double quotes are used to generate 16-bit constants, e.g. "AB", which is equivalent to 'A'<<8+'B'.

Operands

These fall into the following categories:

8-bit constant
16-bit constant
8-bit register     <A,B,C,D,E,H,L>
16-bit register    <AF,BC,DE,HL,IX,IY,SP>
index register     <IX,IY>
special register   <I,R>
the top-of-stack   <(SP)>
memory operand     <(constant),(16-bit register),(16-bit register + constant)>
IO-reference       <(C) or (constant)>

Whether a memory operand or a constant operand refers to an 8-bit or a 16-bit quantity depends on the context in which it is used.

Assembly-time expressions, which must evaluate to a constant or an operand, are worked out strictly left-to-right with no operator precedence. Parentheses may not be used to force any different order of evaluation. Operators available are +, -, &, !(or), \(xor), <<, and >>.

Special operands are ".", "$", and "*", all of which mean the same thing, namely the location counter at the beginning of the current instruction. Use whichever one you prefer. E.g. "DJNZ ." means "decrement B until it is zero", a useful delay instruction.

Statement types. A statement is either an instruction (with two, one, or no operands), a data statement, a name definition, or a directive (possibly with parameters).

A data statement consists simply of a constant (number, name, or expression). Normally this constant is dumped as one byte, but if it cannot thus be expressed, it is dumped as two, least significant byte first. Most zero-operand instructions are in fact just constants used as data statements. A small constant may be forced to occupy two bytes by prefixing it with the pseudo-instruction "W".

A name definition is either a label or an explicit definition. As expected, a label takes the form "name:", and may occur in front of any (possibly null) statement. An explicit definition takes the form "name=expression" (which in HAL would be preceeded by "$DEF"), e.g. BIT4=1<<4; POINTER=HL; ITEM=(POINTER)

Directives

These are illustrated here with sample parameters.

LISTON             turn listing on
LISTOFF            turn listing off
END                Must occur as the last statement in the file
LOC 16_400         Set location counter
W                  Force word data-statement (see above)
BLOCK 13           Reserve  a  block  of  storage  13  bytes  long.   This
                   directive has a padding side  effect,  and  so  usually
                   takes the form
BLOCK 16_66-.      which  means  "pad  to location 16_66".   The value 255
                   (16_FF) is  used  as  padding  data,  unless  specified
                   otherwise, as in
BLOCK .+8&7-.,nop which pads with NOPs up to the next 8-byte boundary.

Instructions

These take the form of Zilog-compatible mnemonics, possibly followed by one or two operands. They are listed here.

LD dest,source     'Load'  or  'move'.   Used  both  for  8-bit and 16-bit
                   quantities.   Note especially: Using (SP) as an operand
                   has a side-effect, so LD HL,(SP) is the same as POP HL.
                   Certain operands cannot be moved in one instruction, so
                   e.g. LD BC,HL must be written as LD B,H; LD C,L.
ADD dest,source    Addition (8 or 16 bit).  Destinations are restricted to
                   A,  HL,  IX,  and IY.   Similarly ADC and SBC, but with
                   destinations A and HL only.
INC dest           Both 8-bit and 16-bit.  Similarly DEC.
SUB source         Subtract (destination is A by implication).   Similarly
                   AND, XOR, OR, CP.
EX op1,op2         The possibilities are:
                   EX (SP),<HL,IX,IY>  Note: (SP) must come first
                   EX DE,HL            Note: DE must come first
                   EX AF,AF            Not EX AF,AF'
EXX                Swop register sets <BC,DE,HL>
PUSH <AF,BC,DE,HL,IX,IY>
POP  <AF,BC,DE,HL,IX,IY>
RST label          Restart (special kind of CALL)
IN reg,dev         Input instruction (dev is either (constant) or (C)).
OUT dev,reg        Output instruction (dev as above).
RLC dest           Rotate left circularly.   Also RRC, RLA, RRA, SLA, SRA,
                   SRL.    Rotate,   shift,   left,   right,   circularly,
                   logically, arithmetically.
BIT bit,dest       Bit test.  Also SET, RES.
CALL cond,label    Conditional call
JP cond,label      Conditional absolute jump
JR cond,label      Conditional  relative  jump.    Note  that  the  second
                   parameter is a label and not a displacement.  Also note
                   that the 8080/8085 does not have relative jumps.
RET cond           Conditional return
CALL label         Unconditional call
JP label           Unconditional absolute jump
JR label           Unconditional relative jump
RET                Unconditional return.
DJNZ label         Special Decrement B and jump if zero (Z80 only)

Miscellaneous instructions

LDI,LDD,LDIR,LDDR,      block move
CPI,CPD,CPIR,CPDR,      block compare
INI,IND,INIR,INDR,      block input
OUTI,OUTD,OTIR,OTDR,    block output
RETI,RETN,EI,DI,        interrupt control
IM0,IM1,IM2,            ditto
DAA,                    decimal adjust
CPL,NEG,                complement, negate A
CCF,SCF,                complement, set carry flag
NOP,HALT,DJNZ,          misc
RLCA,RRCA,RLA,RRA       8080-compatible rotates
RLD,RRD                 BCD digit digit rotates

Condition codes for calls, jumps, and returns

NZ   non-zero
Z    zero
NC   no carry
CY   carry (not C, since C is a register)
PO   parity odd
PE   parity even
P    sign positive
N    sign negative

Error flags

F  Statement syntactically unacceptable
U  Undefined name
I  Improper operand type
V  Overflow - more than 4 bytes generated on a line
T  Truncation - relative jump label out of range
P  Phase error - usually caused by forward reference in non-W
     data statement
*  Name-dictionary full

Deviations from Zilog's syntax spec

1) The jump qualifier for the condition carry is CY, not C; this is because the name would otherwise conflict with that of the C-register.

2) The destination for relative jumps is specified as a label, not as an absolute displacement. So use JR CY,LABEL rather than JR CY,LABEL-$. Implementations A) Legos _z80 <source>/<object>,<listing> Object and listing file names, if omitted, default to $obj and $list. Your "LIB" should be any one of ASSEM, MICROS, or EPROM. B) Vax $ z80 <file>
The source is taken from <file>.Z80, the object goes into <file>.OBJ,
and the listing will be put into <file>.LIS. Both source and listing are in normal VMS format, while the object is in IMP binary format. The symbol Z80 is defined by the public LOGIN file as "@SI1:[MICROS]Z80ASS".

In both VAX and LEGOS implementations the object file will be 1024n characters long, suitable for feeding into the EPROM blowing program.

Coda

Document dated 11/09/79 revised 15/11/79 RWT.

assem:z80.doc printed on 14/03/89 at 17.12

Rainer Thonnes