Files
snark13 c71e249a4e Add full compiler toolchain, libc, examples and reference docs
First substantive commit: the entire Sprinter C compiler tree on top of
the bare README+gitignore initial commit.

What's in here:
  bin/sprinter-cc        — driver script invoking SDCC + linker + mkexe
  libc/                  — Sprinter-specific libc layer over ESTEX/BIOS
                           (conio, gfx, io, mem, stdio + headers)
  runtime/               — crt0 variants (default/small/banked/minimal)
                           + heap + bank trampolines
  toolchain/             — mkexe (SprintEXE packer, C + tests)
  examples/              — 30 demo programs (gfx, file I/O, env, time, …)
  lib/Makefile           — builds the libc archive (sprinter.lib)
  docs/                  — converted Sprinter manuals + asm reference samples
  third_party/           — solid-c reference compiler dump + sdcc setup script
  release_docs/          — packaging / release notes

gitignore overhaul:
  • Drop dangerous blanket patterns: *.asm (would hide docs/samples/*.asm)
    and *.exe (case-insensitive match was hiding third_party/solid-c/*.EXE
    on macOS APFS).  Replaced with examples/*/*.{asm,exe,…} and lib/*.lib.
  • Restore tracking of toolchain/mkexe/tests/{one,big}.bin — those are
    INPUT fixtures, not build outputs.
  • Collapse the duplicated SDCC/C/Sdcc sections into one section per
    concern (build outputs / vendored / OS-junk).
  • Add .sprinter-cc-*/, build/ (catches lib/build/ too), .claude/.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-03 16:13:21 +03:00

1732 lines
57 KiB
Plaintext

MACRO-80 Assembler
2.1 Running MACRO-80
2.2 Command Format
2.2.1 Devices
2.2.2 Switches
2.3 Format of MACRO-80 Source Files
2.3.1 Statements
2.3.2 Symbols
2.3.3 Numeric Constants
2.3.4 Strings
2.4 Expression Evaluation
2.4.1 Arithmetic and Logical Operators
2.4.2 Modes
2.4.3 Externals
2.5 Opcodes as Operands
2.6 Pseudo Operations
2.6.1 ASEG
2.6.2 COMMON
2.6.3 CSEG
2.6.4 DB - Define Byte
2.6.5 DC - Define Character
2.6.6 DS - Define Space
2.6.7 DSEG
2.6.8 DW - Define Word
2.6.9 END
2.6.10 ENTRY/PUBLIC
2.6.11 EQU
2.6.12 EXT/EXTRN
2.6.13 INCLUDE
2.6.14 NAME
2.6.15 ORG - Define Origin
2.6.16 PAGE
2.6.17 ASET
2.6.18 SUBTTL
2.6.19 TITLE
2.6.20 .COMMENT
2.6.21 .PRINTX
2.6.22 .RADIX
2.6.23 .Z80
2.6.24 .8080
2.6.25 .REQUEST
2.6.26 Conditional Pseudo Operations
2.6.26.1 ELSE
2.6.26.2 ENDIF
2.6.27 Listing Control Pseudo Operations
2.6.28 Relocation Pseudo Operations
2.6.28.1 ORG Pseudo-op
2.6.29.2 LINK-80
2.6.29 Relocation Before Loading
2.7 Macros and Block Pseudo Operations
2.7.1 Terms
2.7.2 REPT-ENDM
2.7.3 IRP-ENDM
2.7.4 IRPC-ENDM
2.7.5 MACRO
2.7.6 ENDM
2.7.7 EXITM
2.7.8 LOCAL
2.7.9 Special Macro Operators and Forms
2.8 Using z80 Pseudo-ops
2.9 Sample Assembly
2.10 MACRO-80 Errors
2.11 Compatability with Other Assemblers
2.12 Format of Listings
2.12.1 Symbol Table Listing
CHAPTER 2
MACRO-80 ASSEMBLER
2.1 RUNNING MACRO-80
The command to run MACRO-80 is
M80
MACRO-80 returns the prompt "*", indicating it is ready to accept
commands.
NOTE
If you are using the TEKDOS
operating system, see Appendix
A for proper command formats.
2.2 COMMAND FORMAT
A command to MACRO-80 consists of a string of filenames with optional
switches. All filenames should follow the operating system's
conventions for filenames and extensions. The default extensions
supplied by Microsoft software are as follows:
File CP/M ISIS-II
Relocatable object file REL REL
Listing file PRN LST
MACRO-80 source file MAC MAC
FORTRAN source file FOR FOR
COBOL source file COB COB
Absolute file COM
2.2.1 Devices
Any field in the MACRO-80 command string can also specify a device
name. The default device name with the CP/M operating system is the
currently logged disk. The default device name with the ISIS-II
operating system is disk drive 0. The command format is:
dev:objfile,dev:lstfile=dev:source file
The device names are as follows:
Device CP/M ISIS-II
Disk drives A:, B:, C:,... :F0:, :F1:, :F2:, ...
Line printer LST: LST:
Teletype or CRT TTY: TTY:
High speed reader HSR
Examples:
*,TTY:=TEST Assemble the source file TEST.MAC
and list the program on the
console. No object code is
generated. Useful for error check.
*SMALL,TTY:=B:TEST Assemble TEST.MAC (found
on disk drive B), place
the object file in SMALL.REL
and list the program on the console.
2.2.2 Switches
A switch is a letter that is appended to the command string, preceded
by a slash. It specifies an optional task to be performed during
assembly. More than one switch can be used, but each must be preceded
by a slash. (With the TEKDOS operating system, switches are preceded by
commas or spaces. See Appendix A.) All switches are optional. The
available switches are:
Switch Action
O Octal lising
H Hexadecimal listing (default)
R Force generation of an object file
L Force generation of a lising file
C Force generation of a cross reference file
Z Assemble Z80 opcodes (default for Z80 operating systems)
I Assemble 8080 opcodes (default for 8080 operating systems)
P Each /P allocates an extra 256 bytes of stack space for use
during assembly. Use /P if stack overflow occurs during
assembly. Otherwise, not needed.
M Initialize Block Data Areas. If the programmer wants the
area that is defined by the DS (Define Space) pseudo-op
initialized to zeros, then the programmer should use the /M
switch in the command line. Otherwise, the space is not
guaranteed to contain zeros. That is, DS does not
automattically initialize the space to zeros.
X Usually used to suppress the listing of false conditionals.
The following paragraph describes the /X switch more
completely but in very technical terms.
The presence or absence of /X in the command line sets the
initial current mode and the initial value of the default
for listing or suppressing lines in false conditional
blocks. /X sets the current mode and initial value of
default to not-to-list. No /X sets current mode and initial
value of default to list. Current mode determines whether
false conditionals will be listed or suppressed. The
initial value of the default is used with the .TFCOND
pseudo-op so that .TFCOND is independent of .SFCOND and
.LFCOND. If the program contains .SFCOND or .LFCOND, /X has
no effect after .SFCOND or .LFCOND is encountered until a
.TFCOND is encountered in the file. So /X has an effect
only when used with a file that contains no conditional
listing psuedo-ops or when used with .TFCOND.
Examples:
*=TEST/L Assemble TEST.MAC, places the object file in TEST.REL
and a listing file in TEST.PRN. (With ISIS-II, the
listing file is TEST.LST.)
*=TEST/L/O Same as above, but listing file addresses will be in
octal.
*LAST=TEST/C Assemble TEST.MAC, place the object file in LAST.REL
and cross reference file in TEST.CRF. (See Chapter 3.)
2.3 FORMAT OF MACRO-80 SOURCE FILES
Input source lines of up to 132 characters in length are acceptable.
MACRO-80 preserves lower case letters in quoted strings and comments.
All symbols, opcodes and pseudo-opcodes typed in lower case will be
converted to upper case.
If the source file includes line numbers from an editor, each byte of
th eline number must have the high bit on. Line numbers from
Microsoft's EDIT-80 are acceptable.
2.3.1 Statements
Source files input to MACRO-80 consist of statements of the form:
[label:[:]] [operator] [arguments] [;comment]
With the exception of the ISIS assembler $ controls (see Section 2.11),
it is nog necessary that statements begin in column 1. Multiple blanks
or tabs may be used to improve readability.
If a label is present, it is the first item in the statement and is
immediately followed by a colon. If it is followed by two colons, it is
declared as PUBLIC (seen ENTRY/PUBLIC, Section 2.6.10). For example:
FOO:: RET
is equivalent to
PUBLIC FOO
FOO: RET
The next item after the label, or the first item on the line if no
label is present, is an operator. An operator may be an 8080 mnemonic,
pseudo-op, macro call or expression. The evaluation is as follows:
1. Macro call
2. Mnemonic/Pseudo operation
3. Expression
Instead of flagging an expression as an error, the assembler treats it
as if it were a DB statement (see Section 2.6.4).
The arguments following the operator will, of course, vary in form
according to the operator.
A comment always begins with a semicolon and ends with a carriage
return. A comment may be a line by itself or it may be appended to a
line that contains a statement. Extended comments can be entered using
the .COMMENT pseudo operation (see Section 2.6.20).
2.3.2 Symbols
MACRO-80 symbols may be of any length, however, only the first six
characters are significant. The following characters are legal in a
symbol:
A-Z 0-9 $ . ? @
With Microsoft's 8080/Z80/8086 assemblers, the underline character is
also legal in a symbol. A symbol may not start with a digit. When a
symbol is read, lower case is translated into upper case. If a symbol
reference is followed by ## it is declared external (see also the
EXT/EXTRN pseudo-op, Section 2.6.12).
2.3.3 Numeric Constants
The default base for numeric constants is decimal. This may be changed
by the .RADIX pseudo-op (see Section 2.6.22). Any base from 2 (binary)
to 16 (hexadecimal) may be selected. When the base is greater than 10,
A-F are the digits following 9. If the first digit of a number is not
numeric the number must be preceeded by a zero.
Numbers are 16-bit unsigned quantities. A number is always evaluated in
the current radix unless one of the following special notations is
used:
nnnnB Binary
nnnnD Decimal
nnnnO Octal
nnnnQ Octal
nnnnH Hexadecimal
X'nnnn' Hexadecimal
Overflow of a number beyond two bytes is ignored and the result is the
low order 16-bits.
A character constant is a string comprised of zero, one or two ASCII
characters, delimited by quotation marks, and used in a non-simple
expression. For example, in the statement
DB 'A' + 1
'A' is a character constant. But the statement
DB 'A'
uses 'A' as a string because it is in a simple expression. The rules
for character constant delimiters are the same as for strings.
A character constant comprised of one character has as its value the
ASCII value of that character. That is, the high order byte of the
value is zero, and the low order byte is the ASCII value of the
character. For example, the value of the constant 'A' is 41H.
A character constant comprised of two characters has as its value the
ASCII value of the first character in the high order byte and the ASCII
value of the second character in the low order byte. For example, the
value of the character constant 'AB' is 41H*256+42H
2.3.4 Strings
A string is comprised of zero or more characters delimited by quotation
marks. Either single or double quotes may be used as string delimiters.
The delimiter quotes may be used as characters if they appear twice for
every character occurrence desired. For example, the statement
DB "I am ""great"" today"
stores the string
I am "great" today
If there are zero characters between the delimiters, the string is a
null string.
2.4 EXPRESSION EVALUATION
2.4.1 Arithmetic And Logical Operators
The following operators are allowed in expressions. The operators are
listed in order of precedence.
NUL
LOW, HIGH
*, /, MOD, SHR, SHL
Unary Minus
+, -
EQ, NE, LT, LE, GT, GE
NOT
AND
OR, XOR
Parantheses are used to change the order of precedence. During
evaluation of an expression, as soon as a new operator is encountered
that has precedence less than or equal to the last operator
encountered, all operations up to the new operator are performed. That
is, subexpressions involving operators of higher precedence are
computed first.
All operators except +, -, *, / must be separated from their operands
by at least one space.
The byte isolation operators (HIGH, LOW) isolate the high or low order
8 bits of an Absolute 16-bit value. If a relocatable value is supplied
as an operand, HIGH and LOW will treat it as if it were relative to
location zero.
2.4.2 Modes
All symbols used as operands in expressions are in one of the following
modes: Absolute, Data Relative, Program (Code) Relative or COMMON. (See
Section 2.6 for the ASEG, CSEG, DSEG and COMMON pseudo-ops.) Symbols
assembled under the ASEG, CSEG (default), or DSEG pseudo-ops are in
Absolute, Code Relative or Data Relative mode respectively.
The number of COMMON modes in a program is determined by the number of
COMMON blocks that have been named with the COMMON pseudo-op. Two
COMMON symbols are not in the same mode unless they are in the same
COMMON block. In any operation other than addition or subtraction, the
mode of both operands must be Absolute.
If the operation is addition, the following rules apply:
1 At least one of the operands must be Absolute.
2 Absolute + <mode> = <mode>
If the operation is subtraction, the following rules apply:
1 <mode> - Absolute = <mode>
1 <mode> - <mode> = Absolute
where the two <mode>s are the same.
Each intermediate step in the evaluation of an expression must conform
to the above rules for modes, or an error will be generated. For
example, if FOO, BAZ and ZAZ are three Program Relative symbols, the
expression
FOO + (BAZ -ZAZ)
if legal because the first step (BAZ - ZAZ) generates an Absolute value
that is then added to the Program Relative value, FOO.
2.4.3 Externals
Aside from its classification by mode, a symbol is either External or
not External. (See EXT/EXTRN, Section 2.6.12.) An External value must
be assembled into a two-byte field. (Singe-byte Externals are not
supported.) The following rules apply to the use of Externals in
expressions:
1. Externals are legal only in addition and subtraction.
2. If an External symbol is used in an expression, the result of
the expression is always External.
3. When the operation is addition, either operand (but not both)
may be External.
4. When the operation is subtraction, only the first operand may
be External.
2.5 OPCODES AS OPERANDS
8080 opcodes are valid one-byte operands. Note that only the first byte
is a valid operand. For example:
MVI A,(JMP)
ADI (CPI)
MVI B,(RNZ)
CPI (INX H)
ACI (LXI B)
MVI C,MOV A,B
Errors will be generated if more than one byte is included in the
operand -- such as (CPI 5), LXI B,LABEL1 or (JMP LABEL2).
Opcodes used as one-byte operands need not be enclosed in parentheses.
NOTE
Opcodes are not valid operands
in Z80 mode.
2.6 PSEUDO OPERATIONS
2.6.1 ASEG
ASEG
ASEG sets the location counter to an absolute segment of memory. The
location of the absolute counter will be that of the last ASEG (default
is 0), unless an ORG is done after the ASEG to change the location. The
effect of ASEG is also achieved by using the code segment (CSEG) pseudo
operation and the /P switch in LINK-80. See also section 2.6.28
2.6.2 COMMON
COMMON /<block name>/
COMMON sets the location counter to the selected common block in
memory. The location is always the beginning of the area so that
compatibility with the FORTRAN COMMON statement is maintained. If
<block name> is omitted or consists of spaces, it is considered to be
blank common. See also Section 2.6.28.
2.6.3 CSEG
CSEG
CSEG sets the location counter to the code relative segment of memory.
The location will be that of the last CSEG (default is 0), unless an
ORG is done after the CSEG to change the location. CSEG is the default
condition of the assembler (the INTEL assembler defaults to ASEG). See
also Section 2.6.28.
2.6.4 DB - Define Byte
DB <exp>[,<exp>...]
DB <string>[<string>...]
The arguments to DB are either expressions or strings. DB stores the
values of the expressions or the characters of the strings in
successive memory locations beginning with the current location
counter.
Expressions must evaluate to one byte. (if the high byte of the result
is 0 or 255, no error is given; otherwise, an A error results.)
Strings of three or more characters may not be used in expressions
(i.e., they must be immediately followed by a comma or the end of the
line). The characters in a string are stored in the order of
appearance, each as a one-byte value with the high order bit set to
zero.
Example:
0000' 41 42 DB 'AB'
0002' 42 DB 'AB' AND 0FFH
0003' 41 42 43 DB 'ABC'
2.6.5 DC - Define Character
DC <string>
DC stores the characters in <string> in successive memory locations
beginning with the current location counter. As with DB, characters are
stored in order of appearance, each as a one-byte value with the high
order bit set to zero. However, DC stores the last character of the
string with the high order bit set to one. An error will result if the
argument to DC is a null string.
2.6.6 DS - Define Space
DS <exp>
DS reserves an area of memory. The value of <exp> gives the number of
bytes to be allocated. All names used in <exp> must be previously
defined (i.e., all names known at that point on pass 1). Otherwise, a V
error is generated during pass 1 and a U error may be generated during
pass 2. If a U error is nog generated during pass 2, a phase error will
probably be generated because the DS generated no code on pass 1.
2.6.7 DSEG
DSEG
DSEG sets the location counter to the Data Relative segment of memory.
The location of the data relative counter wil be that of the last DSEG
(default is 0), unless an ORG is done after the DSEG to change the
location. See also Section 2.6.28.
2.6.8 DW - Define Word
DW <exp>[,<exp>...]
DW stores the values of the expressions in successive memory locations
beginning with the current location counter. Expressions are evaluated
as 2-byte (word) values.
2.6.9 END
END [<exp>]
The END statement specifies the end of the program. If <exp> is
present, it is the start address of the program. If <exp> is not
present, then no start address is passed to LINK-80 for that program.
NOTE
If an assembly language program
is the main program, a start
address (label) must be
specified. If not, LINK-80 will
issue a "no start address"
error. If the program is a
subroutine to a FORTRAN program
(for example), the start
address is nog required because
FORTRAN has supplied one.
2.6.10 ENTRY/PUBLIC
ENTRY <name>[,<name>...]
or
PUBLIC <name>[,<name>...]
ENTRY or PUBLIC declares each name in the list as internal and
therefore available for use by this program and other programs to be
loaded concurrently. All of the names in the list must be defined in
the current program or a U error results. An M error is generated if
the name is an external name or common-blockname.
2.6.11 EQU
<name> EQU <exp>
EQU assigns the value of <exp> to <name>. If <exp> is external, an
error is generated. If <name> already has a value other than <exp>, an
M error is generated.
2.6.12 EXT/EXTRN
EXT <name>[,<name>...]
or
EXTRN <name>[,<name>...]
EXT or EXTRN declares that the name(s) in the list are external (i.e.,
defined in a different program). If any item in the list references a
name that is defined in the current program, an M error results. A
reference to a name where the name is followed immediately by two pound
signs (e.g., NAME##) also declares the name as external.
2.6.13 INCLUDE
INCLUDE <filename>
The INCLUDE pseudo-op applies only to CP/M versions of MACRO-80. The
pseudo-ops INCLUDE, $INCLUDE and MACLIB are synonymous.
The INCLUDE pseudo-op assembles source statements from an alternate
source file into the current source file. Use of INCLUDE eliminates the
need to repeat an often-used sequence of statements in the current
source file.
<filename> is any valid specification, as determined by the operating
system. Defaults for filename extensions and device names are the same
as those in a MACRO-80 command line.
The INCLUDE file is opened and assembled into the current source file
immediately following the INCLUDE statement. When end-of-file is
reached, assembly resumes with the statement following INCLUDE.
On a MACRO-80 listing, a plus sign is printed between the assembled
code and the source line on each line assembled from an INCLUDE file.
(See Section 2.12.)
Nested INCLUDEs are not allowed. If encountered, they will result in an
objectionable syntax error 'O'.
The file specified in the operand field must exist. If the file is not
found, the error 'V' (value error) is given, and the INCLUDE is
ignored.
2.6.14 NAME
NAME ('modname')
NAME defines a name for the module. Only the first six characters are
significant in a module name. A module name may also be defined with
the TITLE pseudo-op. In the absence of both the NAME and TITLE
pseudo-ops, the module name is created from the source file name.
2.6.15 ORG - Define Origin
ORG <exp>
The location counter is set to the value of <exp> and the assembler
assigns code starting with that value. All names used in <exp> must be
known on pass 1, and the value must either be absolute or in the same
area as the location counter.
2.6.16 PAGE
PAGE [<exp>]
PAGE causes the assembler to start a new output page. The value of
<exp>, if included, becomes the new page size (measured in lines per
page) and must be in the range 10 to 255. The default page size is 50
lines per page. The assembler puts a form feed character in the listing
file at the end of a page.
2.6.17 ASET
<name> ASET <exp>
ASET is the same as EQU, except no error is generated if <name> is
already defined.
2.6.18 SUBTTL
SUBTTL <text>
SUBTTL specifies a subtitle to be listed on the line after the title
(see TITLE, Section 2.6.19) on each page heading. <text> is truncated
after 60 characters. Any number of SUBTTLs may be given in a program.
2.6.19 TITLE
TITLE <text>
TITLE specifies a title to be listed on the first line of each page. If
more than one TITLE is given, a Q error results. The first six
characters of the title are used as the module name unless a NAME
pseudo operation is used. If neither a NAME or TITLE pseudo-op is used,
the module name is created from the source filename.
2.6.20 .COMMENT
.COMMENT <delim><text><delim>
The first non-blank character encountered after .COMMENT is the
delimiter. The following <text> comprises a comment block which
continues until the next occurence of <delimiter> is encountered. For
example, using an asterisk as the delimiter, the format of the comment
block would be:
.COMMENT *
any amount of text entered
here as the comment block
.
.
. *
;return to normal mode
2.6.21 .PRINTX
.PRINTX <delim><text><delim>
The first non-blank character encountered after .PRINTX is the
delimiter. The following text is listed on the terminal during assembly
until another occurence of the delimiter is encountered. .PRINTX is
useful for displaying progress through a long assembly or for
displaying the value of conditional assembly switches. For example:
IF CPM
.PRINTX /CPM version/
ENDIF
NOTE
.PRINTX will output on both
passes. If only one printout
is desired, use the IF1 or
IF2 pseudo-op. For example:
IF2
IF CPM
.PRINTX /CPM version/
ENDIF
ENDIF
will only print if CPM is
true and M80 is in pass 2.
2.6.22 .RADIX
.RADIX <exp>
The default base (or radix) for all constants is decimal. The .RADIX
statement allows the default radix to be changed to any base in the
range of 2 to 16. For example:
MOVI BX,0FFH
.RADIX 16
MOVI BC,0FF
The two MOVIs in the example are indentical. The <exp> in a .RADIX
statement is always in decimal radix, regardless of the current radix.
2.6.23 .Z80
.Z80 enables the assembler to accept Z80 opcodes. This is the default
condition when the assembler is running on a Z80 operating system. Z80
mode may also be set by appending the Z switch to the MACRO-80 command
string -- see Section 2.2.2.
2.6.24 .8080
.8080 enables the assembler to accept 8080 opcodes. This is the default
condition when the assembler is running on an 8080 operating system.
8080 mode may also be set by appending the I switch to the MACRO-80
command string -- see Section 2.2.2.
2.6.25 REQUEST
.REQUEST <filename>[,<filename>...]
.REQUEST sends a request to the LINK-80 loader to search the filenames
in the list for undefined globals. The filenames in the list should be
in the form of legal symbols. They should not include filename
extensions or disk specifications. LINK-80 supplies a default extension
and assumes the default disk drive.
2.6.26 Conditional Pseudo Operations
The conditional pseudo operations are:
IF/IFT <exp> True if <exp> is no 0.
IFE/IFF <exp> True if <exp> is 0.
IF1 True if pass 1.
IF2 True if pass 2.
IFDEF <symbol> True if <symbol> is defined or has been
declared External.
IFNDEF <symbol> True if <symbol> is undefined or not
declared External.
IFB <arg> True if <arg> is blank. The angle
brackets around <arg> are required.
IFNB <arg> True if <arg> is not blank. Used for
testing when dummy parameters are
supplied. The angle brackets around <arg>
are required.
IFIDN <arg1>,<arg2> True if the string <arg1> is IDeNtical to
the string <arg2>.
The angle brackets around <arg1> and
<arg2> are required.
IFDIF <arg1>,<arg2> True if the string <arg1> is DIFferent
from the string <arg2>.
The angle brackets around <arg1> and
<arg2> are required.
All conditionals use the following format:
IFxx [argument]
.
.
.
[ELSE
.
.
. ]
ENDIF
Conditionals may be nested to any level. Any argument to a conditional
must be known on pass 1 to avoid V errors and incorrect evaluation. For
IF, IFT, IFF, and IFE the expression must involve values which were
previously defined and the expression must be absolute. If the name is
defined after an IFDEF or IFNDEF, pass 1 considers the name to be
undefined, but it will be defined on pass 2.
2.6.26.1 ELSE - Each conditional pseudo operation may optionally be
used with the ELSE pseudo operation which allows alternate code to be
generated when the opposite condition exists. Only one ELSE if
permitted for a given IF, and an ELSE is always bound to the most
recent, open IF. A conditional with more than one ELSE or an ELSE
without a conditional will cause a C error.
2.6.26.2 ENDIF - Each IF must have a matching ENDIF to terminate the
conditional. Otherwise, an 'Unterminated conditional' message is
generated at the end of each pass. An ENDIF without a matching IF
causes a C error.
2.6.27 Listing Control Pseudo Operations
Output to the listing file can be controlled by two pseudo-ops:
.LIST and .XLIST
If a listing is nog being made, these pseudo-ops have no effect. .LIST
is the default condition. When a .XLIST is encountered, source and
object code fill not be listed until a .LIST is encountered.
The output of false conditional blocks is controlled by three
pseudo-ops: .SFCOND, .LFCOND, and .TFCOND.
These pseudo-ops give the programmer control over four cases.
1. Normally list false conditionals.
For this case, the programmer simply allows the default mode
to control the listing. The default mode is list false
conditionals. If the programmer decides to suppress false
conditionals, the /X switch can be issued in the command line
instead of editing the source file.
2. Normally surpress false conditionals.
For this case, the programmer issues the .TFCOND pseudo-op in
the program file. .TFCOND reverses (toggles) the default,
causing false conditionals to be suppressed. If the programmer
decides to list false conditionals, the /X switch can be
issued in the command line instead of editing the source file.
3. Always suppress/list false conditionals.
For this case, the programmer has decided for most false
conditionals whether to list or suppress, but for some false
conditionals the programmer has not yet decided. For the false
conditionals decided about, use .SFCOND or .LFCOND. For those
not yet decided, use .TFCOND. .TFCOND sets the current and
default settings to the opposite of the default. Initially,
the default is set by giving /X or no /X in the command line.
Two subcases exist:
1. The programmer wants some false conditionals not to list
unless /X is given. The programmer uses the .SFCOND and
.LFCOND pseudo-ops to control which areas always suppress
or list false conditionals. To selectively suppress some
false conditionals, the programmer issues .TFCOND at the
beginning of the conditional block and again at the end of
the conditional block. (NOTE: The second .TFCOND should be
issued so that the default setting will be the same as the
initial setting. Leaving the default equal to the initial
setting makes it easier to keep track of the default mode
if there are many such areas.) If the conditional block
evaluates as false, the lines will be suppressed. In this
subcase, issuing the /X switch in the command line causes
the conditional block affected by .TFCOND to list even if
it evaluates as false.
2. The programmer want some false conditionals to list unless
/X is given. Two consecutive .TFCONDs places the
conditional listing setting in initial state which is
determined by the presence or absence of the /X switch in
the command line (the first .TFCOND sets the default to
not initial; the second to initial). The selected
conditional block then responds to the /X switch: if a /X
switch is issued in the command line, the conditional
block is suppressed if false; if no /X switch is issued in
the command line, the conditional block is listed even if
false.
The three conditional listing pseudo-ops are summarized below.
PSEUDO-OP DEFINITION
.SFCOND Suppresses the listing of conditional blocks that
evaluate as false.
.LFCOND Restores the listing of conditional blocks that
evaluate as false.
.TFCOND Toggles the current setting which controls the listing
false conditionals. .TFCOND sets the current and
default setting to not default. If a /X switch is given
in the MACRO-80 run command line for a file which
contains .TFCOND, /X reverses the effect of .TFCOND.
The following chart illustrates the effects of the three pseudo-ops
when encountered under /X and under no /X.
PSEUDO-OP NO /X /X
(none) ON OFF
. . .
. . .
. . .
.SFCOND OFF OFF
. . .
. . .
. . .
.LFCOND ON ON
. . .
. . .
. . .
.TFCOND OFF ON
. . .
. . .
. . .
.TFCOND ON OFF
. . .
. . .
. . .
.SFCOND OFF OFF
. . .
. . .
. . .
.TFCOND OFF ON
.TFCOND ON OFF
. . .
. . .
. . .
.TFCOND OFF ON
The output of cross reference information is controlled by .CREF and
.XCREF. If the cross reference facility (see Chapter 3) has not been
invoked, .CREF and .XCREF have no effect. The default condition is
.CREF. When a .XCREF is encountered, no cross reference information is
output until .CREF is encountered.
The output of MACRO/REPT/IRP/IRPC expansions is controlled by three
pseudo-ops: .LALL, .SALL and .XALL. .LALL lists the complete macro text
for all expansions. .SALL suppresses listing of all text and object
code produced by macros. .XALL is the default condition; a source line
is listed only if it generates object code.
2.6.28 Relocation Pseudo Operations
The ability to create relocatable modules is one of the major features
of Microsoft assemblers. Relocatable modules offer the advantages of
easier coding and faster testing, debugging and modifying. In addition,
it is possible to specify segments of assembled code that will later be
loaded into RAM (the Data Relative segment) and ROM/PROM (the Code
Relative segment). The pseudo operations that select relocatable areas
are CSEG and DSEG. The ASEG pseudo-op is used to generate
non-relocatable (absolute) code. The COMMON pseudo-op creates a common
data area for every COMMON block that is named in the program.
The default mode for the assembler is Code Relative. That is, assembly
begins with a CSEG automatically executed and the location counter in
the Code Relative mode, pointing to location 0 in the Code Relative
segment of memory. All subsequent instructions will be assembled into
the Code Relative segment of memory until a ASEG or DSEG or COMMON
pseudo-op is executed. For example, the first DSEG encountered sets the
location counter to location zero in the Data Relative segment of
memory. The following code is assembled in the Data Relative segment of
memory. If a subsequent CSEG is encountered, the location counter will
return to the next free location in the Code Relative segment and so
on.
The ASEG, DSEG, CSEG pseudo-ops never have operands. If you wish to
alter the current value of the location counter, use the ORG pseudo-op.
2.6.28.1 ORG Pseudo-op - At any time, the value of the location
counter may be changed by use of the ORG pseudo-op. The form of the ORG
statement is:
ORG <exp>
where the value of <exp> will be the new value of the location counter
in the current mode. All names used in <exp> must be known on pass 1
and the value of <exp> must be either Absolute or in the current mode
of the location counter. For example, the statements
DSEG
ORG 50
set the Data Relative counter to 50, relative to the start of the Data
Relative segment of memory.
2.6.28.2 LINK-80 - The LINK-80 linking loader (see Chapter 4 of this
manual) combines the segments and creates each relocatable module in
memory when the program is loaded. The origins of the relocatable
segments are not fixed until the program is loaded and the origins are
assigned by LINK-80. The command to LINK-80 may contain user-specified
origins through the use of the /P (for Code Relative) and /D (for Data
and COMMON segments) switches.
For example, a program that begins with the statements
ASEG
ORG 800H
and is assembled entirely in Absolute mode will always load beginning
at 800 unless the ORG statement is changed in the source file. However,
the same program, assembled in Code Relative mode with no ORG
statement, may be loaded at any specified address by appending the
/P:<address> switch to the LINK-80 command string.
2.6.29 Relocation Before Loading
Two pseudo-ops, .PHASE and .DEPHASE, allow code to be located in one
area, but executed only at a different, specified area.
For example:
0000' .PHASE 100H
0100 E8 0003 FOO: CALL BAZ
0103 E9 FF01 JMP ZOO
0106 C3 BAZ: RET
.DEPHASE
0007' E9 FFFB ZOO: JMP 5
All labels within a .PHASE block are defined as the absolute value from
the origin of the phase area. The code, however, is loaded in the
current area (i.e., from 0' in this example). The code within the block
can later be moved to 100H and executed.
2.7 MACROS AND BLOCK PSEUDO OPERATIONS
The macro facilites provided by MACRO-80 include three repeat pseudo
operations: reapeat (REPT), indefinite repeat (IRP), and indefinite
repeat character (IRPC). A macro definition operation (MACRO) is also
provided. Each of these four macro operations is terminated by the ENDM
pseudo operation.
2.7.1 Terms
For the purposes of discussion of macros and block operations, the
following terms will be used:
1. <dummy> is used to represent a dummy parameter. All dummy
paramters are legal symbols that appear in the body of a
macro expansion.
2. <dummylist> is a list of <dummy>s separated by commas.
3. <arglist> is a list of arguments separated by commas.
<arglist> must be delimited by angle brackets. Two angle
brackets with no intervening characters (<>) or two commas
with no intervening characters enter a null argument in the
list. Otherwise an argument is a character or series of
characters terminated by a comma or >. With angle brackets
that are nested inside an <arglist>, one level of brackets is
removed each time the bracketed argument is used in an
<arglist>. (See example, Section 2.7.5.) A quoted string is
an acceptable argument and is passed as such. Unless enclosed
in brackets or a quoted string, leading and trailing spaces
are deleted from arguments.
4. <paramlist> is used to represent a list of actual parameters
separated by commas. No delimiters are required (the list is
terminated by the end of line or a comment), but the rules
for entering null parameters and nesting brackets are the
same as described for <arglist>. (See example, Section
2.7.5.)
2.7.2 REPT-ENDM
REPT <exp>
.
.
.
ENDM
The block of statements between REPT and ENDM is repeated <exp> times.
<exp> is evaluated as a 16-bit unsigned number. If <exp> contains any
external or undefined terms, an error is generated. Example:
ASET 0
REPT 10 ;generates DB 1 - DB 10
ASET X+1
DB X
ENDM
2.7.3 IRP-ENDM
IRP <dummy>,<arglist>
.
.
.
ENDM
The <arglist> must be enclosed in angle brackets. The number of
arguments in the <arglist> determines the number of times the block of
statements is repeated. Each repetition substitutes the next item in
the <arglist> for every occurrence of <dummy> in the block. If the
<arglist> is null (i.e., <>), the block is processed once with each
occurence of <dummy> removed. For example:
IRP X,<1,2,3,4,5,6,7,8,9,10>
DB X
ENDM
gernerates the same bytes as the REPT example.
2.7.4 IRPC-ENDM
IRPC <dummy>,string (or <string>)
.
.
.
ENDM
IRPC is similar to IRP but the arglist is replaced by a string of text
and the angle brackets around the string are optional. The statements
in the block are repeated once for each character in the string. Each
repetition substitutes the next character in the string for every
occurrence of <dummy> in the block. For example:
IRPC X,0123456789
DB X+1
ENDM
generates the same code as the two previous examples.
2.7.5 MACRO
Often it is convenient to be able to generate a given sequence of
statements from various places in a program, even though different
parameters may be required each time the sequence is used. This
capability is provided by the MACRO statement.
The form is
<name> MACRO <dummylist>
.
.
.
ENDM
where <name> conforms to the rules for forming symbols. <name> is the
name that will be used to invoke the macro. The <dummy>s in <dummylist>
are the parameters that will be changed (replaced) each time the MACRO
is invoked. The statements before the ENDM comprise the body of the
macro. During assembly, the macro is expanded every time it is invoked
but, unlike REPT/IRP/IRPC, the macro is not expanded when it is
encountered.
The form of a macro call is
<name> <paramlist>
where <name> is the name supplied in the MACRO definition, and the
parameters in <paramlist> will replace the <dummy>s in the MACRO
<dummylist> on a one-to-one basis. The number of items in <dummylist>
and <paramlist> is limited only by the length of a line. The number of
parameters used when the macro is called need not be the same as the
number of <dummy>s in <dummylist>. If there are more parameters than
<dummy>s, the extras are ignored. If there are fewer, the extra
<dummy>s will be made null. The assembled code will contain the macro
expansion code after each macro call.
NOTE
A dummy parameter in a MACRO/REPT/IRP/IRPC
is always recognized exclusively as a dummy
parameter. Register names such as A and B
will be changed in the expansion if they
were used as dummy parameters.
Here is an example of a MACRO definition that defines a macro called
FOO:
FOO MACRO X
Y ASET 0
REPT X
Y ASET Y+1
DB Y
ENDM
ENDM
This macro generates the same code as the previous three examples when
the call
FOO 10
is executed.
Another example, which generates the same code, illustrates the removal
of one level of brackets when an argument is used as an arglist:
FOO MACRO X
IRP Y,<X>
DB Y
ENDM
ENDM
When the call
FOO <1,2,3,4,5,6,7,8,9,10>
is made, the macro expansion looks like this:
IRP Y,<1,2,3,4,5,6,7,8,9,10>
DB Y
ENDM
2.7.6 ENDM
Every REPT, IRP, IRPC and MACRO pseudo-op must be terminated with the
ENDM pseudo-op. Otherwise the 'Unterminated REPT/IRP/IRPC/MACRO'
message is generated at the end of each pass. An unmatched ENDM causes
an O error.
2.7.7 EXITM
The EXITM pseudo-op is used to terminate a REPT/IRP/IRPC or MACRO call.
When an EXITM is executed, the expansion is exited immediately and any
remaining expansion or repetition is not generated. If the block
containing the EXITM is nested within another block, the outer level
continues to be expanded.
2.7.8 LOCAL
LOCAL <dummylist>
The LOCAL pseudo-op is allowed only inside a MACRO definition. When
LOCAL is executed, the assembler creates a unique symbol for each
<dummy> in <dummylist> and substitutes that symbol for each occurence
of the <dummy> in the expansion. These unique symbols are usually used
to define a label within a macro, thus eliminating multiply-defined
labels on successive expansions of the macro. The symbols created by
the assembler range from ..0001 to ..FFFF. Users will therefore want to
avoid the term ..nnnn for their own symbols. If LOCAL statements are
used, they must be the first statements in the macro definition.
2.7.9 Special Macro Operators And Forms
& The ampersand is used in a macro expansion to concatenate text
or symbols. A dummy parameter that is in a quoted string will
not be substituted in the expansion unless it is immediately
preceded by &. To form a symbol from text and a dummy, put &
between them. For example:
ERRGEN MACRO X
ERROR&X:PUSH BX
MOVI BX,'&X'
JMP ERROR
ENDM
In this example, the call ERRGEN A will generate:
ERRORA: PUSH BX
MOVI BX,'A'
JMP ERROR
;; In a block operation, a comment preceded by two
semicolons is not saved as part of the expansion (i.e.,
it will not appear on the listing even under .LALL). A
comment preceded by one semicolon, however, will be
preserved and appear in the expansion.
! When an exclamation point is used in an argument, the
next character is entered literally (i.e., !; and <;>
are equivalent).
NUL NULL is an operator that returns true if its argument (a
parameter) is null. The remainder of a line after NUL is
considered to be the argument to NUL. The conditional
IF NUL argument
is false if, during the expansion, the first character
of the argument is anything other than a semicolon or
carriage return. It is recommended that testing for null
parameters be done using the IFB and IFNB conditionals.
% The percent sign is used only in a macro argument. %
converts the expression that follows it (usually a
symbol) to a number in the current radix. During macro
expansion, the number derived from converting the
expression is substituted for the dummy. Using the %
special operator allows a macro call by value. (Usually,
a macro call is a call by reference with the text of the
macro argument substituting exactly for the dummy.)
The expression following the % must conform to the same
rules as the DS (Define Space) pseudo-op. A valid
expression returning a non-relocatable constant is
required.
EXAMPLE: Normally, LB, the argument to MAKLAB, would be
substituted for Y, the argument to MACRO, as a string.
The % causes LB to be converted to a non-relocatable
constant which is then substituted for Y. Without the %
special operator, the result of assembly would be 'Error
LB' rather than 'Error 1', etc.
MAKLAB MACRO Y
ERR&Y: DB 'Error &Y',0
ENDM
MAKERR MACRO X
LB ASET 0
REPT X
LB ASET LB+1
MAKLAB %LB
ENDM
ENDM
When called by MAKERR 3, the assembler will generate:
ERR1: DB 'Error 1',0
ERR2: DB 'Error 2',0
ERR3: DB 'Error 3',0
TYPE The TYPE operator returns a byte that describes two
characteristics of its argument: 1) the mode, and 2)
whether it is External or not. The argument to TYPE may
be any expression (string, numeric, logical). If the
expression is invalid, TYPE returns zero.
The byte that is returned is configured as follows:
The lower two bits are the mode. If the lower two bits
are:
0 the mode is Absolute
1 the mode is Program Relative
2 the mode is Data Relative
3 the mode is Common Relative
The high bit (80H) is the External bit. If the high bit
is on, the expression contains an External. If the high
bit is off, the expression is local (not External).
The Defined bit is 20H. This bit is on if the expression
is locally defined, and it is off if the expression is
undefined or external. If neither bit is on, the
expression is invalid.
TYPE is usually used inside macros, where an argument
type may need to be tested to make a decision regarding
program flow. For example:
FOO MACRO X
LOCAL Z
Z ASET TYPE X
IF Z...
2.8 USING Z80 PSEUDO-OPS
When using the MACRO-80 assembler, the following Z80 pseudo-ops are
valid. The function of each pseudo-op is equivalent to that of its
counterpart.
Z80 pseudo-op Equivalent pseudo-op
COND IFT
ENDC ENDIF
*EJECT PAGE
DEFB DB
DEFS DS
DEFW DW
DEFM DB
DEFL ASET
GLOBAL PUBLIC
EXTERNAL EXTRN
The formats, where different, conform to the previous format. That is,
DEFB and DEFW are permitted a list of arguments (as are DB and DW), and
DEFM is permitted a string or numeric argument (as is DB).
2.9 SAMPLE ASSEMBLY
A>M80
*EXMPL1,TTY:=EXMPL1
MAC80 3.2 PAGE 1
00100 ;CSL3(P1,P2)
00200 ;SHIFT P1 LEFT CIRCULARY 3 BITS
00300 ;RETURN RESULT IN P2
00400 ENTRY CSL3
00450 ;GET VALUE OF FIRST PARAMETER
00500 CSL3:
0000' 7E 00600 MOV A,M
0001' 23 00700 INX H
0002' 66 00800 MOV H,M
0003' 6F 00900 MOV L,A
01000 ;SHIFT COUNT
0004' 06 03 01100 MVI B,3
0006' AF 01200 LOOP: XRA A
01300 ;SHIFT LEFT
0007' 29 01400 DAD H
01500 ;ROTATE IN CY BIT
0008' 17 01600 RAL
0009' 85 01700 ADD L
000A' 6F 01800 MOV L,A
01900 ;DECREMENT COUNT
000B' 05 02000 DCR B
02100 ;ONE MORE TIME
000C' C2 0006' 02200 JNZ LOOP
000F' EB 02300 XCHG
02400 ;SAVE RESULT IN SECOND PARAMETER
0010' 71 02500 MOV M,E
0011' 23 02600 INX H
0012' 72 02700 MOV M,D
0013' C9 02800 RET
02900 END
MAC80 3.2 PAGE S
CSL3 0000I' LOOP 0006'
No Fatal error(s)
2.10 MACRO-80 ERRORS
MACRO-80 errors are indicated by a one-character flag in column one of
the listing file. If a listing file is not being printed on the
terminal, each erroneous line is also printed or displayed on the
terminal. Below is a list of the MACRO-80 Error Codes:
A Argument error
Argument to pseudo-op is not in correct format or is out of
range (.PAGE 1; .RADIX 1; PUBLIC 1; JMPS TOOFAR).
C Conditional nesting error
ELSE without IF, ENDIF without IF, two ELSEs on one IF.
D Double Defined symbol
Reference to a symbol which is multiply defined.
E External error
Use of an external illigal in context (e.g., FOO SET NAME##;
MOVI AX,2-NAME##).
M Multiply Defined symbol
Definition of a symbol which is multiply defined.
N Number error
Error in a number, usually a bad digit (e.g., 8Q).
O Bad opcode or objectionable syntax
ENDM, LOCAL outside a block; ASET, EQU or MACRO without a
name; bad syntax in an opcode; or bad syntax in an expression
(mismatched parenthesis, quotes, consecutive operators,
etc.).
P Phase error
Value of a Label or EQU name is different on pass 2.
Q Questionable
Usually means a line is not terminated properly. This is a
warning error (e.g. MOV AX,BX,).
R Relocation
Illigal use of relocation in expression, such as abs-rel.
Data, code and COMMON areas are relocatable.
U Undefined symbol
A symbol referenced in an expression is not defined. (For
certain pseudo-ops, a V error is printed on pass 1 and a U on
pass 2.)
V Value error
On pass 1 a pseudo-op which must have its value known on pass
1 (e.g., .RADIX, .PAGE, DS, IF, IFE, etc.), has a value which
is undefined. If the symbol is defined later in the program,
a U error will not appear on the pass 2 listing.
Error Messages:
'No END statement encountered on input file'
No END statement; either it is missing or it is not parsed
due to being in a false conditional, unterminated
IRP/IRPC/REPT block or terminated macro.
'Unterminated conditional'
At least one conditional is unterminated at the end of the
file.
'Unterminated REPT/IRP/IRPC/MACRO'
At least one block is unterminated.
[xx] [No] Fatal error(s) [,xx warnings]
The number of fatal errors and warnings. The message is
listed on the CRT and in the list file.
2.11 COMPATIBILITY WITH OTHER ASSEMBLERS
The $EJECT and $TITLE controls are provided for compatability with
INTEL's ISIS assembler. The dollar sign must appear in column 1 only if
spaces or tabs separate the dollar sign from the control word. The
control
$EJECT
is the same as the MACRO-80 PAGE pseudo-op.
The control
$TITLE('text')
is the same as the MACRO-80 SUBTTL <text> pseudo-op.
The INTEL operands PAGE and INPAGE generate Q errors when used with the
MACRO-80 CSEG or DSEG pseudo-ops. These errors are warnings: the
assembler ignores the operands.
When MACRO-80 is entered, the default for the origin is Code Relative
0.
With the INTEL ISIS assembler, the default is Absolute 0.
With MACRO-80, the dollar sign ($) is a defined constant that indicates
the value of the location counter at the start of the statement. Other
assemblers may use a decimal point or an asterisk. Other constants are
defined by MACRO-80 to have the following values:
A-7 B-0 C-1 D-2 E-3
H-4 L-5 M-6 SP-6 PSW-6
2.12 FORMAT OF LISTINGS
On each page of a MACRO-80 listing, the first two lines have the form:
[TITLE text] M80 3.3 PAGE x[-y]
[SUBTTL text]
where:
1. TITLE text is the text supplied with the TITLE pseudo-op, if
one was given in the source program.
2. x is the major page number, which is incremented only when a
form feed is encountered in the source file. (When using
Microsoft's EDIT-80 text editor, a form feed is inserted
whenever a page mark is done.) When the symbol table is being
printed, x = S.
3. y is the minor page number, which is incremented whenever the
.PAGE pseudo-op is encountered in the source file, or
whenever the current page size has been filled.
4. SUBTTL text is the text supplied with the SUBTTL pseudo-op,
if one was given in the source program.
Next, a blank line is printed, followed by the first line of output.
A line of output on a MACRO-80 listing has the following form:
[crf#] [error] loc#m |xx | xxxx|... source
If cross reference information is being output, the first item on the
line is the cross reference number, followed by a tab.
A one-letter error code followed by a space appears next on the line,
if the line contains an error. If there is no error, a space is
printed. If there is no cross reference number, the error code column
is the first column on the listing.
The value of the location counter appears next on the line. It is a
4-digit hexadecimal number or 6-digit octal numer, depending on whether
the /O or /H switch was given in the MACRO-80 command string.
The character at the end of the location counter value is the mode
indicator. It will be one of the following symbols:
' Code Relative
" Data Relative
! COMMON Relative
<space> Absolute
* External
Next, three spaces are printed followed by the assembled code. One-byte
values are followed by a space. Two-byte values are followed by a mode
indicator. Two-byte values are printed in the opposite order the are
stored in, i.e., the high order byte is printed first. Externals are
either the offset or the value of the pointer to the next External in
the chain.
If a line of output on a MACRO-80 listing is from an INCLUDE file, the
character 'C' is printed after the assembled code on that line. If a
line of output is part of a text expansion (MACRO, REPT, IRP, IRPC) a
plus sign '+' is printed after the assembled code on that line.
The remainder of the line contains the line of source code, as it was
input.
Example:
0C49 3A A912' C+ LDA LCOUNT
'C+' indicates this line is from an INCLUDE file and part of a macro
expansion.
2.12.1 Symbol Table Listing
In the symbol table listing, all the macro names in the program are
listed alphabetically, followed by all the symbols in the program,
listed alphabetically. After each symbol, a tab is printed, followed by
the value of the symbol. If the symbol is Public, an I is printed
immediately after the value. The next character printed will be one of
the following:
U Undefined symbol.
C COMMON block name. (The "value" of the COMMON block is
its length (number of bytes) in hexadecimal or octal.)
* External symbol.
'space' Absolute value.
' Program Relative value.
" Data Relative value.
! COMMON Relative value.