UZ80 is a cross-platform Z80 assembler that aims to be both small and fast while still providing valuable services such as macro instructions and conditional assembly. Internally, it departs from full two-pass methods and relies instead on assembling as much code as possible during the first pass and writing down the lines making references to still unseen symbols; these lines will be assembled when all symbols are known.
Software and documentation are provided "as is" with no warranty.
How to use
UZ80 relies on the standard C library, it doesn't need other libraries to run. Its command line syntax is as follows:
-q : quiet mode, no messages other than fatal errors are shown;
-v : verbose mode, all messages are shown; -vv shows even more information, such as label and macro dumps;
-Dlabel=value : defines a symbol named "label" whose value is "value";
-Dlabel : shortcut for "-Dlabel=1";
-D : shortcut for "-DDEBUG=1";
-Ipath : defines the INCLUDE path;
source : the source file; must be followed by a target file;
target : the target file; must follow a source file.
Indenting is important: labels must begin on the first character of each line and instructions start later in the line even when there are no labels. Instructions are either those belonging to the Z80, or the following pseudo instructions:
org EXPRESSION : sets the assembly origin point at EXPRESSION;
align EXPRESSION : aligns the current assembly point to the next address that is a multiplo of EXPRESSION;
defb EXPRESSION... : defines a data block as a series of bytes separated with commas; strings within quotes can be used, too;
defw EXPRESSION... : like "defb", but with 16-bit words and without strings;
defd EXPRESSION... : like "defw", but with 32-bit double words;
defs EXPRESSION[,EXPRESSION] : fills with zeroes (or with the byte set by the second EXPRESSION) the amount of bytes set by the first EXPRESSION;
LABEL equ EXPRESSION / LABEL = EXPRESSION : creates a new symbol named LABEL optionally featuring up to nine parameters.
if EXPRESSION : assembles the next lines if EXPRESSION is nonzero (conditional assembly); "else" can follow, "endif" must follow;
else : assembles the next lines if the current conditional assembly is zero; must follow "if", "endif" must follow;
endif : ends the current conditional assembly; can follow "else", must follow "if";
incbin "FILENAME" : includes the contents of a binary file named FILENAME within the current assembly;
include "FILENAME" : includes the contents of another source file named FILENAME within the current assembly;
LABEL macro [PARAM1[,PARAM2 ...] : defines a macro instruction named LABEL featuring the optional parameters PARAM1, PARAM2...
endm : ends the definition of the current macro;
end : stops assembling the current source file.
Expressions are similar to those used in C and in other assemblers: integers (either decimal formatted as 1234 or 1234d, hexadecimal as #1234, $1234, 1234h or 0x1234, octal as 1234o or binary as %10110111 or 10110111b) and symbols (case-insensitive; "$" stands for the current address) can endure addition ('+'), substraction ('-'), multiplication ('*'), division ('/'), modulo ('%'), logical NOT ('!'), bitwise NOT ('~'), bitwise AND ('&'), bitwise OR ('|'), bitwise XOR ('^'), left shift ('<<'), right shift ('>>') and several types of comparison ('<', '<=', '='/'==', '<>'/'!=', '>=', '>'); operation precedence follows common rules such as additions and substractions taking place after multiplications and divisions, but before comparisons, unless parentheses are used to prioritise some operations over others. Notice that "equ" and "macro" must include labels and thus need to begin on the first character of the line. An example of a macro with parameters is as follows:
Using it with "memcpy buffer,string,10" generates the following code:
The special symbols "\1", "\2", "\3"... stand for the first, second, third... parameters in the macro; the special symbol "\0" stands for the number of parameters. Local labels within a macro can be defined by appending the special symbol "\?" to the label name: "labelname\?".
Originally undocumented instructions such as SLL r, IN (C) and OUT (C) and parameters such as the high and low halves of IX and IY (XH, XL, YH and YL respectively) are supported, as well as several synonyms:
DEFM : DEFB
DB : DEFB
DW : DEFW
DD : DEFD
DS : DEFS
IXH/HX/HIX : XH
IXL/LX/LIX : XL
IYH/HY/HIY : YH
IYL/LY/LIY : YL
SHL : SLA
SHR : SRL
JP/CALL V/NV/S/NS,ADDR : JP/CALL PO/PE/M/P,ADDR
PUSH REG1,REG2,REG3... : PUSH REG1 + PUSH REG2 + PUSH REG3 ...
POP REG1,REG2,REG3... : ... POP REG3 + POP REG2 + POP REG1
NOP NUMBER : NOP repeated NUMBER times
Macros and the pseudoinstructions "if" and "include" can be recursively nested; however, too many levels of nesting will cause a fatal error. Exit codes are either 0 (success) or 1 (fatal error); fatal errors will display a short message stating the type and location of each error.
20191010-1925 -- minor patch adding two optional parameters to INCBIN to define the file offset and length.
20191003-2020 -- minor patch adding the pseudo instruction INCBIN, identical in syntax to INCLUDE, but taking the specified file as binary data rather than as source code.
20190928-1055 -- ninth public release. Added command line parameter -Ipath to define an optional INCLUDE path; fixed bugs in the handling of expressions within brackets and commas within quotes, and in INCLUDE with very long command line paths; made a couple of errors slightly more explicit. Code cleanup: source is 50k, binary is 32k.
20190731-2140 -- UZ80 is now GPL. Upgraded GCC to 5.1.0.
20190210-1150 -- minor source cleanup setting apart PSEUDO and OPCODE; RST accepts 0-7 as well as 0-56, in the same fashion JP (HL/IX/IY) could also be written JP HL/IX/IY; changed IN 0,(C) and OUT (C),0 into IN (C) and OUT (C) because whether the byte sent by OUT is 0 or 255 depends on the Z80 CMOS/NMOS type.
20181130-2030 -- minor patch fixing a bug where HY was a synonym of XH rather than YH, adding further synonyms HIX, HIY, LIX and LIY for XH, YH, XL and YL respectively, and restoring optional AS80 compatibility with command line parameter "-$" to emulate the bugs "IX-1-1" = "IX-0" (rather than "IX-2") and "lbl db $-lbl,$-lbl,$-lbl" = "lbl db 0,0,0" (rather than "lbl db 0,1,2").
20181104-1105 -- minor patch fixing a bug that raised errors in lines that had more than one parameter whereby the first one included a symbol not yet defined, but the second one didn't, and 256 symbols had already been defined.
20181025-1445 -- minor patch accepting the lines "label=expression", "label= expression" and "label =expression" as valid synonyms of "label = expression" rather than handling them as a very long label or rejecting them as improper labels or opcodes.
20180910-1020 -- minor patch fixing a bug in DEFB ("a"+1 was rejected despite the equivalent 1+"a" being valid and accepted) and making command line options case-insensitive.
20180822-1850 -- minor patch fixing several inconsistencies such as using more than one "-D" parameter, displaying the output size of a binary, "-vv" becoming obsolete because "-v" shows everything or symbols with invalid parameters not triggering an error. Parameters can be chained together: "-vzoBLAH" stands for "-v -z -oBLAH". Source file can be "-" (standard input) and can be pipelined. Added optional second field to DEFS to define the padding value, zero by default. Extended and documented special macro symbols "\0", "\1"-"\9" and "\?".
20180808-0946 -- eighth public release. Added "[" and "]" as indirect addressing symbols: LD A,[HL] is equivalent to LD A,(HL). Bugfixes: added dummy instructions "list" and "nolist" to ease compatibility; command line parameter "-vv" returns the right exit code rather than always 1, and "-oX" without source doesn't crash any longer; source line "label:opcode" defines the label and assembles the opcode rather than handling it as a very long label without any opcodes.
20180528-2020 -- minor patch fixing illegal command ADD IX/IY,HL being accepted instead of ADD IX,IX/ADD IY,IY.
20180510-1255 -- minor patch fixing a bug in source paths with folders.
20180506-1230 -- minor patch fixing a bug in hexadecimal suffixes (1234h) and adding octal and decimal suffixes (1234o and 1234d).
20180426-1030 -- sixth public release. Added synonyms LD BC/DE/HL,BC/DE/HL for LD C/E/L,C/E/L+LD B/D/H,B/D/H. Fixed illegal commands LD XL,L/H/(IX) and similar being accepted. INCLUDE swaps '/' and '\' if required.
20180417-1920 -- fifth public release. Ditched the last remainder of AS80 compatibility: the symbol "$" means the current target address rather than the current line's target; "defb nextline-$,nextline-$,nextline-$" followed by "nextline:" is now equivalent to "db 3,2,1" rather than "db 3,3,3". CHIPNSFX has been modified accordingly. Fixed error messages of missing symbols in label definition expressions.
20180414-1140 -- minor patch. Removed synonyms OTD and OTI. Code cleanup: source is 48k, binary is 32k.
20180408-1440 -- fourth public release. Buffers are now dynamically allocated and reallocated, "out of memory" should happen only when no more memory can be allocated. Several fixes in error handling: word overflow no longer names itself as "byte out of range"; error messages during final calculations are shown only once; opcodes relying on small constants (BIT, IM and RST) perform consistent range checks.
20180326-1155 -- third public release. Added synonyms SUB/AND/XOR/OR/CP A,PARAM for SUB/AND/XOR/OR/CP PARAM. Improper escape sequences raise fatal errors. The Win32 binary is no longer packed with UPX.
20180322-1930 -- second public release. Added instructions OUTD and OUTI (synonyms of OTD and OTI) and fixed inconsistencies when using a macro with fewer parameters than defined: BB4CPC and DUCKOUT compile.
20180321-2040 -- first public release. Succesfully assembles FROGALOT, HIREHARE, BASKETCS and the CHIPNSFX player demo.