home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The C Users' Group Library 1994 August
/
wc-cdrom-cusersgrouplibrary-1994-08.iso
/
vol_300
/
348_01
/
z80a.man
< prev
next >
Wrap
Text File
|
1991-05-02
|
52KB
|
1,723 lines
Z80 Cross Assembler
Portable Version
This program lets you use your computer to assemble code for
the Intel Z80 family of microprocessors. The program is
written in portable C. All assembler features are supported
except relocation, linkage, and macros.
Z80 Cross-Assembler (Portable)
Version 0.0
Copyright (c) 1988 Michael G. Panas
1. Introduction
This assembler was developed to cross-assemble the Z80
assembly language mnemonics and pseudo opcodes defined by an
assembler already running on a mini-computer. As such the
mnemonics may look very strange, since they are not standard
Zilog Z80 mnemonics but, extensions to the 8080 language.
Many enhancements to the original mini-computer version have
been made.
This package assembles the dialect of Z80 source code
defined in Appendix I into Z80 object code. It will run
under DOS 2.x and up and also several UNIX machines (see
appendix II - portability).
2. How to Use the Cross-Assembler
This program requires one input file (your Z80 source code)
and zero to two output files (the listing and the object).
The input file MUST be specified, or the assembler will bomb
on a fatal error. The listing and object files are
optional. If no listing file is specified, no listing is
generated, and if no object file is specified, no object is
generated. If the object file is specified, the object is
written to this file in "Intel hexadecimal" format.
The command line for the cross-assembler looks like this:
z80a source_file { -l list_file } { -o object_file }
where the { } indicates that the specified item is optional.
Page 1
Some examples are in order:
z80a testz80.asm source: testz80.asm
listing: none
object: none
z80a testz80.asm -l testz80.prn source: testz80.asm
listing: testz80.prn
object: none
z80a testz80.asm -o testz80.hex source: testz80.asm
listing: none
object: testz80.hex
z80a testz80.asm -l testz80.prn -o testz80.hex
source: testz80.asm
listing: testz80.prn
object: testz80.hex
The order in which the source, listing, and object files are
specified does not matter. Note that no default file name
extensions are supplied by the assembler as this gives rise
to portability problems.
3. Format of Cross-Assembler Source Lines
The source file that the cross-assembler processes into a
listing and an object is an ASCII text file that you can
prepare with whatever editor you have at hand. The most-
significant (parity) bit of each character is cleared as the
character is read from disk by the cross-assembler, so
editors that set this bit (such as WordStar's document mode)
should not bother this program. All printing characters,
the ASCII TAB character (09H), and newline character(s) are
processed by the assembler. All other characters are passed
through to the listing file, but are otherwise ignored.
The source file is divided into lines by newline
character(s). The internal buffers of the cross-assembler
will accommodate lines of up to 255 characters which should
be more than ample for almost any job. If you must use
longer lines, change the constant MAXLINE in file z80a.h and
recompile the cross-assembler. Otherwise, you will overflow
the buffers, and the program will mysteriously crash.
Each source line is made up of three fields: the label
field, the opcode field, and the argument field. The label
field is optional, but if it is present, it must begin in
column 1. The opcode field is optional, but if it is
present, it must not begin in column 1. If both a label and
Page 2
an opcode are present, one or more spaces and/or TAB
characters must separate the two. If the opcode requires
arguments, they are placed in the argument field which is
separated from the opcode field by one or more spaces and/or
TAB characters. Multiple arguments are separated by
semicolons. Finally, an optional comment can be added to
the end of the line. This comment can begin with an
optional asterisk which signals the assembler to pass the
rest of the line to the listing and otherwise ignore it.
The assembler ignores any text after the argument field, for
this reason arguments must not contain any spaces. Thus,
the source line looks like this:
{label}{ opcode{ arguments}}{{*}commentary}
where the { } indicates that the specified item is optional.
Some examples are in order:
column 1
|
v
GRONK JP NC; LOOP This line has everything.
INC C This line has no label.
BEEP This line has no opcode.
* This line has no label and no opcode.
* The previous line has nothing at all.
END This line has no argument.
3.1 Labels
A label is any sequence of alphabetic or numeric characters
starting with an alphabetic. The legal alphabetics are:
! $ % & , . : ? [ ] ^ _ ` { | } ~ A-Z a-z
The numeric characters are the digits 0-9. Note that "A" is
not the same as "a" in a label. This is an enhancement from
the mini-computer version which accepted only upper case
labels. This can explain mysterious U (undefined label)
errors occurring when a label appears to be defined.
A label is permitted on any line except a line where the
opcode is LIST, ULIST, NCODE, CODE, TTL, PAG, PAGT, SKP,
TYP, IF, ELS, or ENF. The label is assigned the value of
the assembly program counter before any of the rest of the
line is processed except when the opcode is EQU, ORG, or
SET.
Page 3
Labels can have the same name as opcodes, but they cannot
have the same name as operators or registers. The reserved
(operator and register) names are:
* A AF AND B BC
C D DE EQ GE GT
H HIGH HL IX IY L
LE LT LOW M MOD NC
NE NOT NZ OR P PE
PO SHL SHR SP XOR Z
Labels may be pin-addressed by the use of an "@" as a prefix
to the label. Pin-address labels are referenced in the code
by the opposite side of the bytes than they normally would.
For example this DC strings' label points to the right hand
address of the string[B:
LABEL DC "this is a normal string"
If you then generate a pin-addressed version of the same
string the label refers to the left hand address of the
string:
@LABEL DC "this is a normal string"
It is neccessary to include pin-addressing in this assembler
to remain compatable with existing source files written with
the mini-computer version. The sense of byte addresses when
referenced without pin-addressing is reversed from what one
would expect in many pseudo ops such as DC and DAC.
If a label is used in an expression before it is assigned a
value, the label is said to be "forward-referenced." For
example:
L1 EQU L2+1 L2 is forward-referenced here.
L2
L3 EQU L2+1 L2 is not forward-referenced here.
Note no space between operands or operators is allowed.
3.2 Numeric Constants
Numeric constants can be formed in two ways; the mini-
computer version, or by the Intel convention. The Intel
convention was not part of the original mini-computer
language, but has been added as an enhancement.
The original standard used only decimal or hexadecimal
numbers in the style of Motorola. Decimal numbers are
formed by using the digits 0-9. Hexadecimal numbers are
Page 4
formed by using a dollar sign ($) followed by one or more
hexadecimal digits (0-9, A-F). The hex digits a-f are
converted to upper case by the assembler. Also added as an
enhancement was the (%) Motorola style prefix for binary
numbers. In this case only 0 and 1 are allowed as digits.
A numeric constant formed according to the Intel convention
starts with a numeric character (0-9), continues with zero
or more digits (0-9, A-F), and ends with an optional base
designator. The base designators are H for hexadecimal,
none or D for decimal, O or Q for octal, and B for binary.
The hex digits a-f are converted to upper case by the
assembler. Note that an Intel style numeric constant cannot
begin with A-F as it would be indistinguishable from a
label.
Thus, all of the following evaluate to 255 (decimal):
$ff %11111111 0ffH 255 255D 377O 377Q 11111111B
3.3 String Constants
A string constant is zero or more characters enclosed in
either single quotes (' ') or double quotes (" "). Single
quotes only match single quotes, and double quotes only
match double quotes, so if you want to put a single quote in
a string, you can do it like this: "'". In all contexts
except the DB statement, the first character or two of the
string constant are all that are used. The rest is ignored.
Noting that the ASCII codes for "A" and "B" are 041H and
042H, respectively, will explain the following examples:
"" and '' evaluate to 0000H
"A" and 'A' evaluate to 0041H
"AB" evaluates to 4142H
Note that the null string "" is legal and evaluates to
0000H.
Several escape sequences are also valid in strings:
Character HEX Gen Function
&N 00 Null
&B 08 Backspace
&T 09 Tab
&V 0B Vertical Tab
&I 0D Carridge Return
&& 26 A single &
&F FF -
&$XX XX Embedded Hex data
Page 5
3.4 Expressions
An expression is made up of labels, numeric constants, and
string constants glued together with arithmetic operators,
logical operators, and parentheses in the usual way that
algebraic expressions are made. Operators have the
following fairly natural order of precedence:
Highest anything in parentheses
unary +, unary -
*, /, MOD, SHL, SHR
binary +, binary -
LT, LE, EQ, GE, GT, NE
NOT
AND
OR, XOR
Lowest HIGH, LOW
A few notes about the various operators are in order:
1) The remainder operator MOD yields the remainder from
dividing its left operand by its right operand.
2) The shifting operators SHL and SHR shift their left
operand to the left or right the number of bits
specified by their right operand. Since the
exponentiation operator (**) is not supported the
SHL operator can be used in most cases to replace
it.
3) The relational operators LT, LE, EQ, GE, GT, and NE
can also be written as <, <= or =<, =, >= or =>, and
<> or ><, respectively. They evaluate to 0FFFFH if
the statement is true, 0 otherwise.
4) The logical opeators NOT, AND, OR, and XOR do
bitwise operations on their operand(s).
5) HIGH and LOW extract the high or low byte, of an
expression.
6) The special symbol * can be used in place of a label
or constant to represent the value of the program
counter before any of the current line has been
processed.
Here are some examples of legal expressions:
All arithmetic is unsigned with overflow from the 16-bit
word ignored. Thus:
Page 6
2+3*4 evaluates to 14
(2+3)*4 evaluates to 20
NOT 11110000B XOR 00001010B evaluates to 00000101B
HIGH 1234H SHL 1 evaluates to 0024H
001Q EQ 0 evaluates to 0
001Q = 2 SHR 1 evaluates to 0FFFFH
32768 * 2 evaluates to 0
4. Machine Opcodes
The opcodes of the Z80 processor that are supported by this
assembler are listed with thier syntax and Zilog equivalents
in Appendix I.
5. Pseudo Opcodes
Unlike Z80 opcodes, pseudo opcodes (pseudo-ops) do not
represent machine instructions. They are, rather,
directives to the assembler. These directives require
various numbers and types of arguments. They will be listed
individually below.
5.1 Pseudo-ops -- DC and DATA
The DC and DATA pseudo-ops allow arbitrary bytes to be
spliced into the object code. Its argument is a chain of
zero or more expressions that evaluate to -128 through 255
separated by semicolons. If a semicolon occurs with no
preceding expression, a 00H byte is spliced into the object
code. The sequence of bytes 0FEH, 0FFH, 00H, 01H, 02H could
be spliced into the code with the following statement:
DC -2;-1;;1;2
A special case exists here. If a string constant is entered
with no arithmetic done on it, then the entire string is
spliced into the code stream. Thus, the sequence of bytes
002H, 043H, 041H, 054H, 044H could be spliced into the code
with the following statement:
DC 1+1;"CAT";"C"+1
The label associated with a DC statement will point to the
right-most byte of the entire definition. This can be
changed to the left most byte by pin-addressing the label.
Thus the label in the next statement points to the fifth
byte (the null):
Page 7
MESS DC "Mess";$00
5.2 Pseudo-ops -- DA
The DA pseudo-op is used to reserve a block of storage for
program variables, or whatever. This storage is not
initialized in any way, so its value at run time will
usually be random. The argument expression (which may
contain no forward references) is added to the assembly
program counter. The following statement would reserve 10
bytes of storage called "STORAGE":
STORAGE DS 10
The label points to the right-most byte and may be changed
to left by pin-addressing the label:
@STORAGE DS 10
5.3 Pseudo-ops -- DAC
The DAC pseudo-op allows 16-bit words to be spliced into the
object code. Its argument is a chain of zero or more
expressions separated by semicolons. If a semicolon occurs
with no preceding expression, a word of 0000H is spliced
into the code. The word is placed into memory low byte in
low address, high byte in high address as per standard Intel
order. The sequence of bytes 0FEH, 0FFH, 00H, 00H, 01H, 02H
could be spliced into the code with the following statement:
DW 0FFFEH;;0201H
The label if present points to the right-most byte and may
be changed to left by pin-addressing the label.
5.4 Pseudo-ops -- CSECT
Used in the mini-computer version to enter a control section
into the object code. In this assembler it is a nop provided
for compatability only.
5.5 Pseudo-ops -- NCODE
Turns off object code generation in the output file. NCODE
allows RAM areas to be defined without the generation of any
code. The listing is still enabled unless turned off by a
SKP.
Page 8
5.6 Pseudo-ops -- CODE
Enables object code generation if previously disabled by
NCODE.
5.7 Pseudo-ops -- END
The END pseudo-op tells the assembler that the source
program is over. Any further lines of the source file are
ignored and not passed on to the listing. If an argument is
added to the END statement, the value of the argument will
be placed in the execution address slot in the Intel hex
object file. The execution address defaults to the program
counter value at the point where the END was encountered.
Thus, to specify that the program starts at label START, the
END statement would be:
END START
If end-of-file is encountered on the source file before an
END statement is reached, the assembler will add an END
statement to the listing and flag it with a * (missing
statement) error.
5.8 Pseudo-ops -- EQU
The EQU pseudo-op is used to assign a specific value to a
label, thus the label on this line is REQUIRED. Once the
value is assigned, it cannot be reassigned by writing the
label in column 1, by another EQU statement by a REG
statement, or by a SET statement. Thus, for example, the
following statement assigns the value 2 to the label TWO:
TWO EQU 1 + 1
The expression in the argument field must contain no forward
references.
5.9 Pseudo-ops -- IF, ELS, ENF
These three pseudo-ops allow the assembler to choose whether
or not to assemble certain blocks of code based on the
result of an expression. Code that is not assembled is
passed through to the listing but otherwise ignored by the
assembler. The IF pseudo-op signals the beginning of a
conditionally assembled block. It requires one argument
that may contain no forward references. If the value of the
argument is non-zero, the block is assembled. Otherwise,
the block is ignored. The ENF pseudo-op signals the end of
the conditionally assembled block. For example:
Page 9
IF EXPRESSION ;This whole thing generates
DB 01H, 02H, 03H ; no code whatsoever if
ENF ; EXPRESSION is zero.
The ELS pseudo-op allows the assembly of either one of two
blocks, but not both. The following two sequences are
equivalent:
IF EXPRESSION
... some stuff ...
ELS
... some more stuff ...
ENF
TEMP_LAB SET EXPRESSION
IF TEMP_LAB NE 0
... some stuff ...
ENF
IF TEMP_LAB EQ 0
... some more stuff ...
ENF
The pseudo-ops in this group do NOT permit labels to exist
on the same line as the status of the label (ignored or not)
would be ambiguous.
All IF statements (even those in ignored conditionally
assembled blocks) must have corresponding ENF statements and
all ELS and ENF statements must have a corresponding IF
statement.
IF blocks can be nested up to 16 levels deep before the
assembler dies of a fatal error. This should be adequate
for any conceivable job, but if you need more, change the
constant IFDEPTH in file z80a.H and recompile the assembler.
5.10 Pseudo-ops -- USE
The USE pseudo-op is used to splice the contents of another
file into the current file at assembly time. The name of
the file to be USEd is specified as a normal string
constant, so the following line would splice the contents of
file "const.def" into the source code stream:
USE "const.def"
USE files may, in turn, USE other files until four files are
open simultaneously. This limit should be enough for any
conceivable job, but if you need more, change the constant
FILES in file z80a.H and recompile the assembler.
Page 10
5.11 Pseudo-ops -- ORG and RLC
The ORG pseudo-op is used to set the assembly program
counter to a particular value. The expression that defines
this value may contain no forward references. The default
initial value of the assembly program counter is 0000H. The
following statement would change the assembly program
counter to 0F000H:
ORG 0F000H
If a label is present on the same line as an ORG statement,
it is assigned the new value of the assembly program
counter.
The RLC pseudo-op was used to relocate a block of code to
run in a different address than it was loaded. It is
provided here as an ORG statement since relocation is not
supported.
5.12 Pseudo-ops -- URLC
Nop provided for compatability.
5.13 Pseudo-ops -- PAG
The PAG pseudo-op always causes an immediate page ejection
in the listing by inserting a form feed ('\f') character
before the next line. If an argument is specified, the
argument expression specifies the number of lines per page
in the listing. Legal values for the expression are any
number except 1 and 2. A value of 0 turns the listing
pagination off. Thus, the following statement cause a page
ejection and would divide the listing into 60-line pages:
PAGE 60
Note arguments to PAG are an enhancement from the mini-
computer version.
5.14 Pseudo-ops -- SKP
Causes subsequent lines to not be printed on the listing
until a TYP statment is encountered. SKP/TYP blocks may be
nested.
Page 11
5.15 Pseudo-ops -- TYP
List output is resumed.
5.16 Pseudo-ops -- LIST and ULIST
Nops provided for compatability. Originally altered assembly
listing format.
5.17 Pseudo-ops -- SET
The SET pseudo-op functions like the EQU pseudo-op except
that the SET statement can reassign the value of a label
that has already been assigned by another SET statement.
Like the EQU statement, the argument expression may contain
no forward references. A label defined by a SET statement
cannot be redefined by writing it in column 1 or with an EQU
statement. The following series of statements would set the
value of label "COUNT" to 1, 2, then 3:
COUNT SET 1
COUNT SET 2
COUNT SET 3
5.18 Pseudo-ops -- TTL
The TTL pseudo-op sets the running title for the listing.
The argument field is required and must be a string
constant, though the null string ("") is legal. This title
is printed after every page ejection in the listing,
therefore, if page ejections have not been forced by the PAG
pseudo-op, the title will never be printed. The following
statement would print the title "Random Bug Generator -- Ver
3.14159" at the top of every page of the listing:
TTL "Random Bug Generator -- Ver 3.14159"
Subsequent title lines are used as subtitles.
5.19 Pseudo-ops -- PAGT
Set the subtitle line to "string". This line is printed on
the line following the TTL line on the listing after every
page ejection. May be changed many times.
PAGT "string"
Page 12
6. Assembly Errors
When a source line contains an illegal construct, the line
is flagged in the listing with a single-letter code
describing the error. The meaning of each code is listed
below. In addition, a count of the number of lines with
errors is kept and printed on the C "stderr" device (by
default, the console) after the END statement is processed.
If more than one error occurs in a given line, only the
first is reported. For example, the illegal label "=$#*'("
would generate the following listing line:
L 0000 FF 00 00 =$#*'( LDI16 DE,1000H
6.1 Error * -- Illegal or Missing Statement
This error occurs when either:
1) the assembler reaches the end of the source file
without seeing an END statement, or
2) an END statement is encountered in a USE file.
If you are "sure" that the END statement is present when the
assembler thinks that it is missing, it probably is in the
ignored section of an IF block. If the END statement is
missing, supply it. If the END statement is in a USE file,
delete it.
6.2 Error ( -- Parenthesis Imbalance
For every left parenthesis, there must be a right
parenthesis. Count them.
6.3 Error `` -- Missing Quotation Mark
Strings have to begin and end with either " or '. Remember
that " only matches " while ' only matches '.
6.4 Error D -- Illegal Digit
This error occurs if a digit greater than or equal to the
base of a numeric constant is found. For example, a 2 in a
binary number would cause a D error. Especially, watch for
8 or 9 in an octal number.
Page 13
6.5 Error E -- Illegal Expression
This error occurs because of:
1) a missing expression where one is required
2) a unary operator used as a binary operator or vice-
versa
3) a missing binary operator
4) a SHL or SHR count that is not 0 thru 15
6.6 Error I -- IF-ENF Imbalance
For every IF there must be a corresponding ENF. If this
error occurs on an ELS or ENF statement, the corresponding
IF is missing. If this error occurs on an END statement,
one or more ENF statements are missing.
6.7 Error L -- Illegal Label
This error occurs because of:
1) a non-alphabetic in column 1
2) a reserved word used as a label
3) a missing label on an EQU, or SET statement
4) a label on an IF, ELS, or ENF statement
6.8 Error M -- Multiply Defined Label
This error occurs because of:
1) a label defined in column 1 or with the EQU
statement being redefined
2) a label defined by a SET statement being redefined
either in column 1 or with the EQU statement
3) the value of the label changing between assembly
passes
6.9 Error O -- Illegal Opcode
The opcode field of a source line may contain only a valid
machine opcode, a valid pseudo-op, or nothing at all.
Anything else causes this error.
Page 14
6.10 Error P -- Phasing Error
This error occurs because of:
1) a forward reference in a EQU, ORG, or SET statement
2) a label disappearing between assembly passes
6.11 Error S -- Illegal Syntax
This error means that an argument field is scrambled. Sort
the mess out and reassemble. In particular, look for use of
registers that don't apply to a particular opcode, missing
commas, and the like.
6.12 Error T -- Too Many Arguments
This error occurs if there are more items (expressions,
register designators, etc.) in the argument field than the
opcode or pseudo-op requires. The assembler ignores the
extra items but issues this error in case something is
really mangled.
6.13 Error U -- Undefined Label
This error occurs if a label is referenced in an expression
but not defined anywhere in the source program. If you are
"sure" you have defined the label, note that upper and lower
case letters in labels are different. Defining "LABEL" does
not define "Label."
6.14 Error V -- Illegal Value
This error occurs because:
1) an 8 bit immediate value is not -128 thru 255, or
2) a DC argument is not -128 thru 255, or
3) a USE argument refers to a file that does not exist.
7. Warning Messages
Some errors that occur during the parsing of the cross-
assembler command line are non-fatal. The cross-assembler
flags these with a message on the C "stdout" device (by
default, the console) beginning with the word "Warning."
The messages are listed below:
Page 15
7.1