Assembler Syntax

The WinAPE assembler is designed to be compatible with Maxam 1.5 with some extensions to the standard Maxam assembler.

The supports all Z80 Instructions, a number of Assembler Directives for functionality other than pure Z80 code, and the ability to use Labels and Comments. Each line of code can contain multiple instructions separated by the colon character (:), although generally most people use one line per instruction for readability.

Code Origin

All assembler code needs to be given a starting point in memory. Without defining the origin for the code, WinAPE will assume that the code starts at address #0000, and the code will most likely overwrite the lower region of memory used for restart instructions and interrupts. The assembler directive used to set the origin of code is org, and is usually one of the first lines in an assembly language program. For example:

org #4000

The above line tells the assembler to start producing code from memory address #4000. All instructions and directives which produce code output starting at the given address, and the current assembler code address can be used in expressions by using the $ symbol.


A label is used to define a symbol at the current assembly address. This can be useful for naming looping points, subroutines or variables. Labels must start with either an underscore character or an alphabetic character, and can only contain letters, numbers or underscore. A label definition can be a single word which is not a reserved word (Z80 or directive) either in a line on its own or immediately preceding another Z80 instruction or directive. Labels can also be preceded by a dot (.), which is not included as part of the symbol itself, and can also allow reserved words to be used as labels. For example:

org #4000

def:ghi ld a,b
.jkl ld c,d:mno
pqr: ld b,a
jp pqr

The above code will define ABC, def and ghi all as having the current address #4000. Code will be generated for the instruction ld a,b which is one byte, so the next label .jkl will create a symbol named jkl which will have the value #4001. Code will be generated for the instruction ld c,d which is also one byte, so the next two labels mno and pqr will have the value #4002. Code will be generated for the instruction ld b,a which is another single byte so the final label _stu will be given the value #4003. The jp pqr instruction uses the value of pqr to assemble a Z80 jump instruction with the address of the symbol.

The actual output from the assembler shows these values in the listing as below:

000001  0000  (4000)        org #4000
000002  4000                ABC
000003  4000                def
000003  4000  78            ghi ld a,b
000004  4001  4A            .jkl ld c,d
000004  4002                mno
000005  4002                pqr
000005  4002  47             ld b,a
000006  4003                _stu
000007  4003  C3 02 40      jp pqr

The columns shown are the line number in the current file, the current assembly address, generated code (or expression value) and the final column is the actual partial line of code since the last line or colon character.

Assigning Values to Symbols

By default symbols defined by labels are given the current code address as their value. It is possible to assign different values to symbols using the equ directive. For example:

.int_vector equ #38

free_space  equ end_addr + 20

.print      equ 6 * 3 + jump_table

The code above assigns the value of #38 to the symbol int_vector, the second line assigns the value of end_addr + 20 to the symbol free_space, and the third line assigns the value 6 * 3 + jump_table to the symbol print. Note that the assembler does not currently (as per Maxam) support operator precedence, so the expression is evaluated left-to-right, and jump_table + 6 * 3 would be produce a totally different result. For example:

x equ 3

y equ 2 * 4 + x

z equ x + 2 * 4

The code above assigns the value 3 to x, then the value for y is evaluated as 2 * 4 = 8 then 8 + x = 11 so the result will be a value of 11.
The final value for z is also evaluated left-to-right as x + 2 = 5, then 5 * 4 = 20 so the final value for z will be 20.

The LET directive

By default, symbols can only be defined to have one value in any assembler program. Symbols are not the same as BASIC variables, and it is very rare that their values need to be changed.

The let directive allows a symbol to be redefined to have different values in different parts of an assembler program. As a general rule you should never use let in your programs except in special circumstances.

Including other source files

The WinAPE assembler allows mutiple files to be assembled at once by including other source files using the read or incbin directives.

read allows the inclusion of another assembler source file. This may contain symbol definitions, macro definitions and source code in any combination, just as the main source file. Files included with read may also be nested, and the included file has access to all symbols within the parent source files in the same way as code within the main source file.

incbin allows the inclusion of binary data in the assembler output. This may be any arbitrary binary data generated from any source, such as graphics data, sound data or code generated by another compiler.

Files included with read or incbin are searched for beginning with the directory of the current file, then all other directories specified in the Library Path.