Skip to content
This repository has been archived by the owner on Sep 10, 2022. It is now read-only.

informedcitizenry/z80DotNet

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

z80DotNet, A Simple .Net-Based Z80 Cross-Assembler

Version 1.15

Please Note: I have merged this project with its sister project, 6502.Net, and it will now no longer be maintained.

Introduction

The z80DotNet Macro Assembler is a simple cross-assembler targeting the Zilog Z80 and compatible CPU. It is written for .Net (Version 4.5.1) and supports all of the published (legal) instructions of the Z80 processor, as well as most of the unpublished (illegal) operations. Like the MOS 6502, the Z80 was a popular choice for video game system and microcomputer manufacturers in the 1970s and mid-1980s. For more information, see wiki entry or Z80 resource page to learn more about this microprocessor.

Overview

The z80DotNet assembler is simple to use. Invoke it from a command line with the assembly source and (optionally) the output filename in the parameters. A z80DotNet.exe myprg.asm command will output assembly listing in myprgm.asm to binary output. To specify output file name use the -o <file> or --output=<file> option, otherwise the default output filename will be a.out.

You can specify as many source files as assembly input as needed. For instance, z80DotNet.exe mylib.asm myprg.asm will assemble both the mylib.asm and myprgm.asm files sequentially to output. Be aware that if both files define the same symbol an assembler error will result.

General Features

Assembly Statements

All assembly statements are composed of ASCII or Unicode text. Statements are terminated by a carriage return:

        ld a,0                    

Multiple statements per line are allowed; they are separated by a colon (:) character:

        ld (hl),MESSAGE:call STDOUT    ; multiple statement line

Semi-colons denote the beginning of line comments, and remaining line text will not be processed by the assembler.

Numeric constants

Integral constants can be expressed as decimal, hexadecimal, and binary. Decimal numbers are written as is, while hex numbers are prefixed with a $ and binary numbers are prefixed with a %.

            65490 = 65490
            $ffd2 = 65490
%1111111111010010 = 65490

Negative numbers are assembled according to two's complement rules, with the highest bits set. Binary strings can alternatively be expressed as . for 0 and # for 1, which is helpful for laying out pixel data:

number1     .byte %...###..
            .byte %..####..
            .byte %.#####..
            .byte %...###..
            .byte %...###..
            .byte %...###..
            .byte %...###..
            .byte %.#######

Labels, Symbols and Variables

When writing assembly, hand-coding branches, addresses and constants can be time-consuming and lead to errors. Labels take care of this work for you! There is no restriction on name size, but all labels must begin with an underscore or letter, and can only contain underscores, letters, and digits, and they cannot be re-assigned:

            yellow   =   6

            ld  a,yellow     ; load yellow into acc.
            jr  nz,setborder ; now set the border color
            ...
setborder:  call $229b       ; poke border color with acc.

Trailing colons for labels are optional.

Once labels are defined they cannot be redinfed in other parts of code. This gets tricky as source grows, since one must choose a unique name for each label. There are a few ways to avoid this problem.

routine1    ld  a,(hl)
            jr  z,_done
            call stdout
            inc hl
            jr  routine1
_done       ret

routine2    ld  c,flag
            jr z,_done
            jp  dosomething
_done       ret

In the routine above, there are two labels called _done but the assembler will differentiate between them, since the second _done follows a different non-local label than the first. The first is to append the label with an underscore, making it a local label.

In addition to local labels, scope blocks can be used. All source inside a pair of .block and .endblock directives are considered local to that block, but can also be nested, making them much like namespaces.

A scope block looks like this:

            ...
endloop     ld  a,$ff    
            ret

myblock     .block
            call endloop    ; accumulator will be 0
            ...             ; since endloop is local to myblock
endloop     xor a
            ret
            .endblock

Labels inside named scopes can be referenced with dot notation:

speccy     .block

key_in      = $10a8
wait_key    = $15d4

            .endblock

            call speccy.key_in  ; call the subroutine whose label        
                                ; is defined in the speccy block

Any block not preceded by a label is an anonymous block. All symbols inside an anonymous block are only visible within the block, and are unavailable outside:

            .block
            call inc32
            ...
inc32       inc bc
            jr  z,done
            inc de
done        ret
            .endblock

            call inc32  ; will produce an assembler error

Anonymous labels allow one to do away with the need to think of unique label names altogether. There are two types of anonymous labels: forward and backward. Forward anonymous labels are declared with a +, while backward anonymous labels are declared using a -. They are forward or backward to the current assembly line and are referenced in the operand with one or more + or - symbols:

-           ld  a,(ix+$00)
            jr  nz,+            ; jump to first forward anonymous from here
            ld  a,' '
+           rst $10
            inc ix
            rlca
            jr  nc,-            ; jump to first backward anonymous from here
            add a,a
            jr  nc,+            ; jump to first forward anonymous from here
            and %01111111
            jr  ++              ; jump to second forward anonymous from here
+           ld  (ix+$10),a
            ret
+           ld  (ix+$20),a
            ret

As you can see, anonymous labels, though convenient, would hinder readability if used too liberally. They are best for small branch jumps, though can be used in the same was as labels:

-           .byte $01, $02, $03
            ld  a,(-)           ; put anonymous label reference inside paranetheses.

Another type of named symbol besides a label is a variable. Variables, like labels, are named references to values in operand expressions, but whose value can be changed as often as required. A variable is declared with the .let directive, followed by an assignment expression. Variables and labels cannot share the same symbol name.

            .let myvar = 34
            ld  a,myvar
            .let myvar = myvar + 1
            ld  b,myvar

Unlike labels, variables cannot be referenced in other expressions before they are declared, since variables are not preserved between passes.

            .let y = x  
            .let x = 3

In the above example, the assembler would error assuming x has never been declared before.

Comments

Adding comments to source promotes readability, particularly in assembly. Comments can be added to source code in one of two ways, as single-line trailing source code, or as a block. Single-line comments start with a semi-colon. Any text written after the semi-colon is ignored, unless it is being expressed as a string or constant character.

            xor a,a      ; 0 = color black
            call $2294   ; set border color to accumulator
            ld	a,';'    ; the first semi-colon is a char literal so will be assembled
            rst $10   

Block comments span multiple lines, enclosed in .comment and .endcomment directives. These are useful when you want to exclude unwanted code:

            .comment

            this will set the cpu on fire do not assemble!

            ld a,-1
            ld ($5231),a

            .endcomment

Non-code (data) assembly

In addition to z80 assembly, data can also be assembled. Expressions evaluate internally as 64-bit signed integers, but must fit to match the expected operand size; if the value given in the expression exceeds the data size, this will cause an illegal quantity error. The following pseudo-ops are available:

Directive Size
.byte One byte unsigned
.sbyte One byte signed
.addr Two byte address
.sint Two bytes signed
.word Two bytes unsigned
.lint Three bytes signed
.long Three bytes unsigned
.dint Four bytes signed
.dword Four bytes unsigned
.align Zero or more bytes
.fill One or more bytes

Multi-byte directives assemble in little-endian order (the least significant byte first), which conforms to the z80 architecture. Data is comma-separated, and each value can be a constant or expression:

sprite      .byte %......##,%########,%##......
jump        .word sub1, sub2, sub3, sub4

For .fill and .align, the assembler accepts either one or two arguments. The first is the quantity, while the second is the value. If the second is not given then it is assumed to be uninitialized data (see below). For .fill, quantity is number of bytes, for .align it is the number of bytes by which the program counter can be divided with no remainder:

unused      .fill 256,0 ; Assemble 256 bytes with the value 0

atpage      .align 256  ; The program counter is guaranteed to be at a page boundary

Sometimes it is desirable to direct the assembler to make a label reference an address, but without outputting bytes at that address. For instance, program variables. Use the ? symbol instead of an expression:

highscore   .dword ?    ; set the symbol highscore to the program counter,
                        ; but do not output any bytes

Note that if uninitialized data is defined, but thereafter initialized data is defined, the output will fill bytes to the program counter from the occurrence of the uninitialized symbol:

highscore   .dword ?    ; uninitialized highscore variables
            xor a,a     ; The output is now 6 bytes in size

Use the .typedef directive to redefine a type name. This is useful for cross- and backward-compatibility with other assemblers. Each type can have more than one definition.

            .typedef    .byte,   db
            .typedef    .byte,   defb    ; multiple okay
            .typedef    .string, asc

Only pseudo operations can have their types redefined. For mnemonics or other assembler directives consider using macros instead.

Text processing and encoding

Psuedo Ops

In addition to integral values, z80DotNet can assemble Unicode text. Text strings are enclosed in double quotes, character literals in single quotes.

Strings can be assembled in a few different ways, according to the needs of the programmer.

Directive Meaning
.string A standard string literal
.cstring A C-style null-terminated string
.lsstring A string with output bytes left-shifted and the low bit set on its final byte
.nstring A string with the negative (high) bit set on its final byte
.pstring A Pascal-style string, its size in the first byte

Since .pstring strings use a single byte to denote size, no string can be greater than 255 bytes. Since .nstring and .lsstring make use of the high and low bits, bytes must not be greater in value than 127, nor less than 0.

String Format function

The special function format() function allows you to convert non-string data to string data using a .Net format string:

stdout      = $ffd2
stdstring   .string format("The stdout routine is at ${0:X4}", stdout)
            ;; will assemble to:
            ;; "The stdout routine is at $FFD2

Many traditional assemblers allow programmers to use their character and value string pseudo-ops interchangeably, e.g. .byte "HELLO" and .asc "HELLO". Note that z80DotNet treats character strings differently for the .byte and other value-based commands. For these pseudo-ops string characters are compacted, while the pseudo-op length is enforced:

            .byte "H"       ; okay
            .dword "HELLO"  ; also okay, .dword can accomodate 4 ASCII bytes
            .byte 'H','I'   ; still ok--two different literals
            .byte "HELLO"   ; will error out

Generally, it is best to use the string commands for processing character string literals, and the value commands for multibyte values.

Encodings

Assembly source text is processed as UTF-8, and by default strings and character literals are encoded as such. You can change how text output with the .encoding and .map directives. Use .encoding to select an encoding. The encoding name follows the same rules as labels.

The default encoding is none.

Text encodings are modified using the .map and .unmap directives. After selecting an encoding, you can map a Unicode character to a custom output code as follows:

            ;; select encoding
            .encoding myencoding

            ;; map A to output 0
            .map "A", 0

            .string "ABC"
            ;; > 00 42 43

            ;; char literals are also affected
            ld  a,'A'    ;; 3e 00

            ;; emoji will assemble too!
            .string "😁"    ;; f0 9f 98 81

The output can be one to four bytes. Entire character sets can also be mapped, with the re-mapped code treated as the first in the output range. The start and endpoints in the character set to be re-mapped can either be expressed as a two-character string literal or as expressions.

            ;; output lower-case chars as uppercase
            .map "az", "A"

            ;; output digits as actual integral values
            .map "0","9", 0

            ;; alternatively:
            .map 48, 48+9, 0

            ;; escape sequences are acceptable too:
            .map "\u21d4", $9f

Caution: Operand expressions containing a character literal mapped to a custom code will evaluate the character literal accordingly. This may produce unexpected results:

            .map 'A', 'a'

            .map 'a', 'A' ;; this is now the same as .map 'a', 'a'

Instead express character literals as one-character strings in double-quotes, which will evaluate to UTF-8 code units.

A further note about encodings and source files. As mentioned, source files are read and processed as UTF-8. While it is true that the .Net StreamReader class can auto-detect other encodings, this cannot be guaranteed (for instance if the BOM is lacking in a UTF-16-encoded source). If the source does not assemble as expected, consider converting it to UTF-8 or at least ASCII. This article offers a good overview on the issues concerning text encodings.

Escape sequences

Most .Net escape sequences will also output, including Unicode.

            .string "He said, \"How are you?\""
            .byte '\t', '\''

Here are a few recognized escape sequences:

Escape Sequence ASCII/Unicode Representation
\n Newline
\r Carriage return
\t Tab
\" Double quotation mark
\unnnn Unicode U+nnnn

File inclusions

Other files can be included in final assembly, either as z80DotNet-compatible source or as raw binary. Source files are included using the .include and .binclude directives. This is useful for libraries or other organized source you would not want to include in your main source file. The operand is the file name (and path) enclosed in quotes. .include simply inserts the source at the directive.

            ;; inside "../lib/library.s"

            .macro  inc16 reg16
            inc (\reg16)
            jr nz +
            inc \reg16
            inc (\reg16)
+           .endmacro
            ...

This file called "library.s" inside the path ../lib contains a macro definition called inc16 (See the section below for more information about macros).

            .include "../lib/library.s"

            .inc16 $c000    ; 16-bit increment value at $033c and $033d

If the included library file also contained its own symbols, caution would be required to ensure no symbol clashes. An alternative to .include is .binclude, which resolves this problem by enclosing the included source in its own scoped block.

lib         .binclude "../lib/library.s"    ; all symbols in "library.s"
                                            ; are in the "lib" scope

            call lib.memcopy

If no label is prefixed to the .binclude directive then the block is anonymous and labels are not visible to your code.

External files containing raw binary that will be needed to be included in your final output, such as graphics data, can be assembled using the .binary directive.

            * = $1000

            .binary "../rsrc/gfx.bin"

You can also control how the binary will be included by specifying the offset (number of bytes from the start) and size to include.

            * = $1000

charA:
            .binary "../rsrc/charset.bin",0,64
charB:
            .binary "../rsrc/charset.bin",64,64
charC:
            .binary "../rsrc/charset.bin",128,64
            ...

            * = $c000

            ;; copy charA glyph graphics to $4000

            ld hl,charA
            ld de,$4000
            ld bc,64
            ldir

Mathematical and Conditional Expressions

All non-string operands are treated as math or conditional expressions. Compound expressions are nested in paranetheses. There are several available operators for both binary and unary expressions. The order of operation generally follows that the .Net languages for matching operators, with the byte extractors taking highest precedence.

Binary Operations

Operator Meaning
+ Add
- Subtract
* Multiply
/ Divide
% Modulo (remainder)
** Raise to the power of
& Bitwise AND
| Bitwise OR
^ Bitwise XOR
<< Bitwise left shift
>> Bitwise right shift
< Less than
<= Less than or equal to
== Equal to
!= Not equal to
>= Greater than or equal to
> Greater than
&& Logical AND
|| Logical OR
            .addr   HIGHSCORE + 3 * 2 ; the third address from HIGHSCORE
            .byte   * > $f000         ; if program counter > $f000, assemble as 1
                                      ; else 0

            ;; bounds check START_ADDR                          
            .assert START_ADDR >= MIN && START_ADDR <= MAX

Unary Operations

Operator Meaning
~ Bitwise complementary
< Least significant byte
> Most significant (second) byte
^ Bank (third) byte
! Logical NOT

            ld  h, #>routine    ; routine MSB
            ld  l, #<routine    ; routine LSB
            jp  (hl)                        

Math functions

Several built-in math functions that can also be called as part of the expressions.

            ld  a,sqrt(25)

See the section below on functions for a full list of available functions.

Math constants

The math constants π and e are defined as MATH_PI and MATH_E, respectively, and can be referenced in expressions as follows:

            .dword sin(MATH_PI/3) * 10  ; > 08
            .dword pow(MATH_E,2)        ; > 07

Not that no labels or variables can share these two names as they are reserved.

Addressing model

By default, programs start at address 0, but you can change this by setting the program counter before the first assembled byte. While many Z80 assemblers used $ to denote the program counter, z80DotNet uses the * symbol. The assignment can be either a constant or expression:

            * = ZP + 1000       ; program counter now 1000 bytes offset from
                                    ; the value of the constant ZP

(Be aware of the pesky trap of trying to square the program counter using the ** operator, i.e. ***. This produces unexpected results. Instead consider the pow() function as described in the section on math functions below.)

As assembly continues, the program counter advances automatically. You can manually move the program counter forward, but keep in mind doing so will create a gap that will be filled if any bytes are added to the assembly from that point forward. For instance:

            * = $1000

            xor a
            call $1234

            * = $1fff

            rst $38

Will output 4096 bytes, with 4091 zeros.

To move the program counter forward for the purposes having the symbols use an address space that code will be relocated to later, you can use the .relocate directive:

            * = $0200

            newlocation = $a000

            ld  hl,torelocate
            ld  de,newlocation
            ld  bc,torelocate_end - torelocate
            ldir
            ....

torelocate:                                 
            .relocate newlocation   ; no gap created

            call relocatedsub    ; now in the "newlocation" address space
            ...
relocatedsub    
            xor a
            ...

To reset the program counter back to its regular position use the .endrelocate directive:

            call relocatedsub
            ...
            jp  finish
torelocate:
            relocate newlocation

            ...

            .endrelocate
torelocate_end
            ;; done with movable code, do final cleanup
finish      ret

Macros and segments

One of the more powerful features of the z80DotNet cross assembler is the ability to re-use code segments in multiple places in your source. You define a macro or segment once, and then can invoke it multiple times later in your source; the assembler simply expands the definition where it is invoked as if it is part of the source. Macros have the additional benefit of allowing you to pass parameters, so that the final outputted code can be easily modified for different contexts, behaving much like a function call in a high level language. For instance, one of the more common operations in z80DotNet assembly is to do a 16-bit increment. You could use a macro for this purpose like this:

inc16       .macro  register
            inc (\register)
            jr  nz,+
            inc \register
            inc (\register)
+           .endmacro

The macro is called inc16 and takes a parameter called register. The code inside the macro consumes the parameters with a backslash \ followed by the parameter name. The parameter is a textual substitution; whatever you pass will be expanded at the reference point. Note the anonymous forward symbol at the branch instruction will be local to the block, as would any symbols inside the macro definition when expanded. To invoke a macro simply reference the name with a . in front:

myvariable .word ?
            ld  hl,myvariable
            .inc16  hl  ; do a 16-bit increment of myvariable

This macro expands to:

            inc (hl)
            jr  nz,+
            inc hl
            inc (hl)
+           ...

Parameter insertions also work in string literals, but the parameter formatting is more like a .Net string format with a @ symbol in front:

hello       .macro name
            .string "Hello, @{name}."
            .endmacro

Parameters can be referenced by number in this way:

today       .macro
            .string "Today is @{1}"
            .endmacro

        ;; Expansion of ".today Tuesday""
            .string "Today is Tuesday"

Segments are conceptually identical to macros, except they do not accept parameters and are usually used as larger segments of relocatable code. Segments are defined between .segment/.endsegment blocks with the segment name after each closure directive, then are declared into the source using the .dsegment directive, followed by the segment name. Unlike macros, segments can be declared before they are defined.

            .segment RAM

var1        .word ?
var2        .word ?
            ...
            .endsegment RAM

            .segment code
            di
            xor a
            ld  (IRQ_ENABLE),a
            ld  hl,RAM_START
            ld  bc,RAM_SIZE
            rst $08
            ...
            .endsegment code

Then you would assemble defined segments as follows:

            * = $0000
            .dsegment code
            .errorif * > $3fff, ".code segment outside of ROM space!"
            * = $4000
            .dsegment RAM

You can also define segments within other segment definitions. Note that doing this does not make them "nested." The above example would be re-written as:

            .segment program
            .segment bss
var1        .word ?
var2        .word ?
txtbuffer   .fill 256
            .endsegment bss
            .segment code
            xor a
            ...
            .segment hivars
variables   .byte ?
            ...
            .endsegment hivars
            .endsegment code
            .endsegment program

            * = $0000
            .dsegment code
            * = $4000
            .dsegment bss
            * = $d000
            .dsegment hivars

Flow Control

In cases where you want to control the flow of assembly, either based on certain conditions (environmental or target architecture) or in certain iterations, z80DotNet provides certain directives to handle this.

Conditional Assembly

Conditional assembly is available using the .if and related directive. Conditions can be nested, but expressions will be evaluated on first pass only. In cases where you want to control the flow of assembly based on certain conditions (environmental or target architecture), z80DotNet provides certain directives to handle this. Conditions can be nested, but expressions will be evaluated on first pass only.

            .ifdef ZXSPECTRUM
                call setcolor
            .else
                nop
                nop
                nop
            .endif

            .if * > $7fff   ; is program counter $8000 or more
                .end        ; terminate assembly
            .endif          ; end

Caution: Be careful not to use the .end directive inside a conditional block, otherwise the .endif closure will never be reached, and the assembler will report an error.

Basic Repetitions

On occasions where certain instructions will be repeatedly assembled, it is convenient to repeat their output in a loop. For instance, if you want to pad a series of nop instructions. The .repeat directive does just that.

            ;; will assemble $ea ten times
            .repeat 10
            nop
            .endrepeat

These repetitions can also be nested, as shown below.

            ;; print each letter of the alphabet 3 times
            * = $1000

            ld  a,'A'
            .repeat 26
                .repeat 3
                    rst $10
                .endrepeat
                inc a
            .endrepeat
            .repeat 3
               rst $10
            .endrepeat
            ret

Loop Assembly

Repetitions can also be handled in for/next loops, where source can be emitted repeatedly until a condition is met. The added advantage is the variable itself can be referenced inside the loop.

            xor a,a
            .for i = $0400, i < $0800, i = i + 1
                ld (i),a
            .next

A minimum two operands are required: The initial expression and the condition expression. A third iteration expression is option. The iteration expression can be blank, however.

            .let a = 0;
            .let n = 1;
            .for , n < 10
                .if a == 3
                    .let n = n + 1;
                .else
                    .let n = n + 5;
                .endif
                .echo format("{0}",n);
            .next

            .comment

            Outputs:

            6
            11

            .endcomment

If required, loops can be broken out of using the .break directive

            .for i = 0, i < 256, i = i + 1
                .if * >= $1000
                    .break          ; make sure assembly does not go past $1000
                .endif
                ld a,'A'
                rst $10
            .next

All expressions, including the condition, are only evaluated on the first pass.

Caution: Changing the value of the iteration variable inside the loop can cause the application to hang. z80DotNet does not restrict re-assigning the iteration variable inside its own or nested loops.

Reference

Instruction set

z80DotNet supports all legal and (virtual all) illegal instruction types, including the so-called IXCB instructions (e.g. set 0,(ix+$00),b). Please consult the official Z80 User Manual for more information on general Z80 programming.

Pseudo-Ops

Following is the detail of each of the z80DotNet pseudo operations, or psuedo-ops. A pseudo-op is similar to a mnemonic in that it tells the assembler to output some number of bytes, but different in that it is not part of the CPU's instruction set. For each pseudo-op description is its name, any aliases, a definition, arguments, and examples of usage. Optional arguments are in square brackets ([ and ]).

Note that every argument, unless specified, is a legal mathematical expression, and can include symbols such as labels (anonymous and named) and the program counter. Anonymous labels should be referenced in parantheses, otherwise the expression engine might misinterpret them. If the expression evaluates to a value greater than the maximum value allowed by the pseudo-op, the assembler will issue an illegal quantity error.

Data/text insertions

Name.addr
Alias.word
DefinitionInsert an unsigned 16-bit value or values between 0 and 65535 into the assembly. Multiple arguments can be passed as needed. If ? is passed then the data is uninitialized.
Argumentsaddress[, address2[, ...]
Example
            * = $1000
mysub       ld  a,13                ; output newline
            rst $10
            ret
            .addr mysub             ; >1006 00 10
Name.align
AliasNone
DefinitionSet the program counter to a value divisible by the argument. If a second argument is specified, the expressed bytes will be outputted until the point the program counter reaches its new value, otherwise is treated as uninitialized memory.
Argumentsamount[, fillvalue]
Example
            * = $1023
            .align $10,$ff ; >1023 ff ff ff ff ff ff ff ff
                         ; >102b ff ff ff ff ff
            .byte $23      ; >1030 23
Name.binary
AliasNone
DefinitionInsert a file as binary data into the assembly. Optional offset and file size arguments can be passed for greater flexibility.
Argumentsfilename[, offset[, size]
Example
            .binary     "mybin.bin"          ; include all of 'mybin.bin'
            .binary     "routines.bin",19    ; skip program header 'routines.bin'
            .binary     "subroutines.prg",19,1000
                      ;; skip header, take only
                      ;; 1000 bytes thereafter.
Name.byte
AliasNone
DefinitionInsert an unsigned byte-sized value or values between 0 and 255 into the assembly. Multiple arguments can be passed as needed. If ? is passed then the data is uninitialized.
Argumentsvalue[, value[, ...]
Example
            * = $0400
            .byte $39, $38, $37, $36, $35, $34, $33, $32, $31
            ;; >0400 39 38 37 36 35 34 33 32
            ;; >0408 31
Name.cstring
AliasNone
DefinitionInsert a C-style null-terminated string into the assembly. Multiple arguments can be passed, with a null only inserted at the end of the argument list. If ? is passed then the data is an uninitialized byte. Enclosed text is assembled as string-literal while expressions are assembled to the minimum number of bytes required for storage, in little-endian byte order.
Argumentsvalue[, value[, ...]
Example
            * = 1000
            .cstring "hello, world!"    ; >1000 68 65 6c 6c 6f 2c 20 77
                                        ; >1008 6f 72 6c 64 21 00
            .cstring $cd,$2000          ; >1019 cd 00 20
Name.dint
AliasNone
DefinitionInsert a signed 32-bit value or values between −2147483648 and 2147483647 into the assembly, little-endian Multiple arguments can be passed as needed. If ? is passed then the data is uninitialized.
Argumentsvalue[, value[, ...]
Example
            * = $4000
            .dint   18000000      ; >4000 80 a8 12 01
Name.dword
AliasNone
DefinitionInsert a signed 32-bit value or values between 0 and 4294967295 into the assembly, little-endian. Multiple arguments can be passed as needed. If ? is passed then the data is uninitialized.
Argumentsvalue[, value[, ...]
Example
            * = $f000
            .dword  $deadfeed     ; >f000 ed fe ad de
Name.fill
AliasNone
DefinitionFill the assembly by the specified amount. Similar to align, that if only one argument is passed then space is merely reserved. Otherwise the optional second argument indicates the assembly should be filled with bytes making up the expression, in little-endian byte order.
Argumentsamount[, fillvalue]
Example
            .fill   23  ; reserve 23 bytes
            * = $1000
            .fill 11,$ffd2 ; >1000 d2 ff d2 ff d2 ff d2 ff
                           ; >1008 d2 ff d2
Name.lint
AliasNone
DefinitionInsert a signed 24-bit value or values between -8388608 and 8388607 into the assembly, little-endian. Multiple arguments can be passed as needed. If ? is passed then the data is uninitialized.
Argumentsvalue[, value[, ...]
Example
            * = $3100
            .lint   -80000    ; >3100 80 c7 fe
Name.long
AliasNone
DefinitionInsert a signed 24-bit value or values between 0 and 16777215 into the assembly, little-endian. Multiple arguments can be passed as needed. If ? is passed then the data is uninitialized.
Argumentsvalue[, value[, ...]
Example
            * = $8100
            .long   $ffdd22   ; >8100 22 dd ff
Name.lsstring
AliasNone
DefinitionInsert a string into the assembly, each byte shifted to the left, with the lowest bit set on the last byte. See example of how this format can be used. If the highest bit in each value is set, the assembler will error. Multiple arguments can be passed, with a null only inserted at the end of the argument list. If ? is passed then the data is an uninitialized byte. Enclosed text is assembled as string-literal while expressions are assembled to the minimum number of bytes required for storage, in little-endian byte order.
Argumentsvalue[, value[, ...]
Example
            and a               ; clear carry
            ld  de,screenbuf
            ld  hl,message
-           ld  a,(hl)          ; next char
            rrca                ; shift right
            ld  (de),a          ; save in buffer
            jr  c,done          ; carry set on shift? done
            inc hl              ; else next char
            inc de              ; and buff
            jr  -               ; get next
done        ret
message     .lsstring "HELLO"   
Name.nstring
AliasNone
DefinitionInsert a string into the assembly, the negative (highest) bit set on the last byte. See example of how this format can be used. If the highest bit on the last byte is already set, the assembler will error. Multiple arguments can be passed, with a null only inserted at the end of the argument list. If ? is passed then the data is an uninitialized byte. Enclosed text is assembled as string-literal while expressions are assembled to the minimum number of bytes required for storage, in little-endian byte order.
Argumentsvalue[, value[, ...]
Example
            ld  hl,message
            ld  de,screenbuf
-           ld  a,(hl)
            ld  b,a             ; copy to b to test high bit
            and a,%01111111     ; turn off high bit...
            ld  (de),a          ; and print
            rlc b               ; high bit into carry flag
            jr  c,done          ; if set we printed last char
            inc hl              ; else increment pointers
            inc de
            jr -                ; get next
done        ret
message     .nstring "hello"    
Name.pstring
AliasNone
DefinitionInsert a Pascal-style string into the assembly, the first byte indicating the full string size. Note this size includes all arguments in the expression. If the size is greater than 255, the assembler will error. If ? is passed then the data is an uninitialized byte. Enclosed text is assembled as string-literal while expressions are assembled to the minimum number of bytes required for storage, in little-endian byte order.
Argumentsvalue[, value[, ...]
Example
            * = $4000
            .pstring $23,$24,$25,$26,1024 ; >4000 06 23 24 25 26 00 04
            .pstring "hello"              ; >4007 05 68 65 6c 6c 6f
Name.sbyte
AliasNone
DefinitionInsert an unsigned byte-sized value or values between -128 and 127 into the assembly. Multiple arguments can be passed as needed. If ? is passed then the data is uninitialized.
Argumentsvalue[, value[, ...]
Example
            * = $0400
            .sbyte 127, -3  ; >0400 7f fd
Name.sint
AliasNone
DefinitionInsert a signed 16-bit value or values between -32768 and 32767 into the assembly, little-endian. Multiple arguments can be passed as needed. If ? is passed then the data is uninitialized.
Argumentsvalue[, value[, ...]
Example
            * = $1000
            .sint -16384        ; >1006 00 c0
Name.string
AliasNone
DefinitionInsert a string into the assembly. Multiple arguments can be passed. If ? is passed then the data is an uninitialized byte. Enclosed text is assembled as string-literal while expressions are assembled to the minimum number of bytes required for storage, in little-endian byte order.
Argumentsvalue[, value[, ...]
Example
            * = 1000
            .string "hello, world!"   ; >1000 68 65 6c 6c 6f 2c 20 77
                                      ; >1008 6f 72 6c 64 21

Assembler directives

Name.assert
AliasNone
DefinitionAsserts the truth of a given expression. If the assertion fails, an error is logged. A custom error can be optionally be specified.
Argumentscondition[, error]
Example
            * = $0800
            nop
            .assert 5 == 6              ; standard assertion error thrown
            .assert * < $0801, "Uh oh!" ; custom error output
Name.binclude
AliasNone
DefinitionInclude a source file and enclose the expanded source into a scoped block. The specified file is z80DotNet-compatible source. If no name is given in front of the directive then all symbols inside the included source will be inaccessible.
Argumentsfilename
Example
soundlib    .binclude "sound.s"
            call soundlib.play  ; Invoke the
                                ; play subroutine
                                ; inside the
                                ; sound.s source
            ;; whereas...
            .binclude "sound.s"
            call play           ; will not assemble!
Name.block/.endblock
AliasNone
DefinitionDefine a scoped block for symbols. Useful for preventing label definition clashes. Blocks can be nested as needed. Unnamed blocks are considered anonymous and all symbols defined within them are inaccessible outside the block. Otherwise symbols inside blocks can be accessed with dot-notation.
ArgumentsNone
Example
rom         .block
            stdin  = $10a8
            stdout = $15ef
            .endblock
            ...
stdout      ld  a,(hl)       
            call rom.stdout     ; this is a different
                                ; stdout!
done        ret                 ; this is not the done
                                ; below!                
            .block
            jr z,done           ; the done below!
            nop
            nop
done        ret                 
            .endblock
Name.break
AliasNone
DefinitionBreak out of the current for-next loop.
ArgumentsNone
Example
            .for n = 0, n < 1000, n = n + 1
                .if * > $7fff   ; unless address >= $8000
                    .break     
                .endif
                nop             ; do 1000 nops
            .next
Name.comment/.endcomment
AliasNone
DefinitionSet a multi-line comment block.
ArgumentsNone
Example
            .comment
            My code pre-amble
            .endcomment
Name.dsegment
AliasNone
DefinitionDeclare a segment to be used in code. The segment declaration can precede its definition in the .segment/.endsegment block.
ArgumentsSegment name
Example
      .dsegment code    ; > 06 0f
      .segment code
            ld  b,$0f
      .endsegment
Name.echo
AliasNone
DefinitionSend a message to the console output. Note if the assembler is in quiet mode, no output will be given.
Argumentsmessage
Example
            .echo "hi there!"
            ;; console will output "hi there!"
Name.encoding
AliasNone
DefinitionSelect the text encoding for assembly output. The default is none, which is not affected by .map and .unmap directives.
Argumentsencoding
Example
            .encoding petscii
            .string "hello"       ; >> 45 48 4c 4c 4f
Name.end
AliasNone
DefinitionTerminate the assembly.
ArgumentsNone
Example
            call $15ef
            jr  z,done          ; oops!
            ret
            .end                ; stop everything
done        ...                 ; assembly will never
                                ; reach here!
Name.eor
AliasNone
DefinitionXOR output with 8-bit value. Quick and dirty obfuscation trick.
Argumentsxormask
Example
            .eor $ff
            .byte 0,1,2,3       ; > ff fe fd fc
Name.equ
Alias=
DefinitionAssign the label, anonymous symbol, or program counter to the expression. Note that there is an implied version of this directive, such that if the directive and expression are ommitted altogether, the label or symbol is set to the program counter.
Argumentsvalue
Example
stdin       .equ $10a8
stdout      =   $15ef
            * .equ $5000
-           =   255
start       ; same as start .equ *
            xor a
Name.error
AliasNone
DefinitionPrints a custom error to the console. The error is treated like any assembler error and will cause failure of assembly.
Argumentserror
Example .error "We haven't fixed this yet!"
Name.errorif
AliasNone
DefinitionPrints a custom error to the console if the condition is met. Useful for sanity checks and assertions. The error is treated like any assembler error and will cause failure of assembly. The condition is any logical expression.
Argumentscondition, error
Example
            * = $5000
            nop
            .errorif * > $5001, "Uh oh!" ; if program counter
                                         ; is greater than 20481,
                                         ; raise a custom error
Name.[el]if[[n]def]/.endif
AliasNone
DefinitionAll source inside condition blocks are assembled if evaluated to true on the first pass. Conditional expressions follow C-style conventions. The following directives are available:
  • .if <expression> - Assemble if the expression is true
  • .ifdef <symbol> - Assemble if the symbol is defined
  • .ifndef <symbol> - Assemble if the symbol is not defined
  • .elif <expression> - Assemble if expression is true and previous conditions are false
  • .elifdef <symbol> - Assemble if symbol is defined and previous conditions are false
  • .elifndef <symbol> - Assemble if symbol is not defined and previous conditions are false
  • .else - Assemble if previous conditions are false
  • .endif - End of condition block
Argumentscondition
Example
            * = $0400
            cycles = 4
            .if cycles == 4
                nop
            .elif cycles == 16
                nop
                nop
            .endif
            ;; will result as:
            ;;
            ;; nop
Name.for/.next
AliasNone
DefinitionRepeat until codition is met. The iteration variable can be used in source like any other variable. Multiple iteration expressions can be specified. This operation is only performed on first pass.
Arguments[init_expression], condition[, iteration_expression[, ...]
Example
            .let x = 0
            .for pages = $100, pages < $800, pages = pages + $100, x = x + 1
                ld a,x
                ld (pages),a
            .next
Name.include
AliasNone
DefinitionInclude a source file into the assembly. The specified file is z80DotNet-compatible source.
Argumentsfilename
Example
            .include "mylib.s"
            ;; mylib is now part of source
Name.let
AliasNone
DefinitionDeclares and assigns or re-assigns a variable to the given expression. Labels cannot be redefined as variables, and vice versa.
Argumentsexpression
Example
            .let myvar =    $c000
            call myvar
            .let myvar =    myvar-$1000
            ld a,(myvar)
Name.macro/.endmacro
AliasNone
DefinitionDefine a macro that when invoked will expand into source. Must be named. Optional arguments are treated as parameters to pass as text substitutions in the macro source where referenced, with a leading either a backslash \ or as @{param} from within a string, either by name or by number in the parameter list. Parameters can be given default values to make them optional upon invocation. Macros are invoked with a leading .. All symbols in the macro definition are local, so macros can be re-used with no symbol clashes.
Argumentsparameter[, parameter[, ...]
Example
inc16       .macro
            inc (\1)
            jr  nz,+
            inc \1
            inc (\1)
+       .endmacro
            .inc16 hl
            ;; expands to =>
            inc (hl)
            jr  nz,+
            inc hl
            inc (hl)
+         
print       .macro  value = 13, printsub = $15ef
            ld  a,\value    ; or ld a,\1
            call \printsub  ; or call \2
            ret
            .endmacro
            .print
            ;; expands to =>
            ;; ld   a,$0d
            ;; call $15ef
            ;; ret
            .print 'E',$0010
            ;; expands to =>
            ;; ld   a,$45
            ;; call $0010
            ;; ret
Name.map
AliasNone
DefinitionMaps a character or range of characters to custom binary output in the selected encoding. Note: none is not affected by .map and .unmap directives. It is recommended to represent individual char literals as strings.
Argumentsstart[, end]/
"<start><end>",code
Example
            .encoding myencoding
            .map "A", "a"
            .map "π", $5e
            .byte 'A', 'π' ;; >> 61 5e
            .map "09", $00
            .string "2017" ;; >> 02 00 01 07
Name.relocate/.endrelocate
Alias.pseudopc/.realpc
DefinitionSets the logical program counter to the specified address with the offset of the assembled output not changing. Useful for programs that relocate parts of themselves to different memory spaces.
Argumentsaddress
Example
            * = $5000
relocated   =   $6000            
start       ld  hl,highcode
            ld  de,relocated
-           ld  bc,highcode_end-highcode
            ldir
            jp  relocated
highcode    
            .relocate relocated
            ld  hl,message
printloop   ld  a,(hl)
            and a,a
            jr  z,done
            call $15ef
            inc hl
            jr  printloop
done        ret
message     .cstring "HELLO, HIGH CODE!"
            .endrelocate
highcode_end
            ;; outputs the following:
            .comment
            >5000 21 0e 50  ; start       ld  hl,highcode
            >5003 11 00 60  ;             ld  de,relocated
            >5006 01 20 00  ; -           ld  bc,highcode_end-highcode
            >5009 ed b0     ;             ldir
            >500b c3 00 60  ;             jp  relocated
            >500e 21 0e 60  ;             ld  hl,message
            >5011 7e        ; printloop   ld  a,(hl)
            >5012 a7        ;             and a,a
            >5013 28 06     ;             jr  z,done
            >5015 cd ef 15  ;             call $15ef
            >5018 23        ;             inc hl
            >5019 18 f6     ;             jr  printloop
            >501b c9        ; done        ret
            ;; message
            >501c 48 45 4c 4c 4f 2c 20 48    
            >5024 49 47 48 20 43 4f 44 45
            >502c 21 00
            .endcomment
Name.repeat/.endrepeat
AliasNone
DefinitionRepeat the specified source the specified number of times. Can be nested, but must be terminated with an .endrepeat. This operation is only performed on first pass.
Argumentsrepeatvalue
Example
            * = $5000
            xor a
            .repeat 3
            inc a
            .endrepeat
            ret
            ;; will assemble as:
            ;;
            ;; xor  a
            ;; inc  a
            ;; inc  a
            ;; inc  a
            ;; ret
Name.segment/.endsegment
AliasNone
DefinitionDefines a block of code as a segment, to be declared into source with the .dsegment directive. Segments are similar to macros but take no parameters and symbols are not local. Useful for building a large mix of source code and data without needing to relocate code manually. Segments can be defined within other segment block definitions, but are not considered "nested." Segment closures require the segment name after the directive.
Argumentssegmentname
Example
            .segment bss
var1        .word ?
var2        .word ?
txtbuf      .fill 256
            .endsegment bss
            .segment highvar
variables   .dword ?, ?, ?, ?
            .endsegment highvar
            .segment code
            .segment data
glyph             ;12345678
            .byte %....####
            .byte %..#####.
            .byte %.#####..
            .byte %#####...
            .byte %#####...
            .byte %.#####..
            .byte %..#####.
            .byte %....####
            .endsegment data
            di
            call init
            .endsegment code
            * = $8000
            .dsegment bss
            * = $9000
            .dsegment highvar
            * = $5000
            .dsegment code
            * = $6000
            .dsegment data
Name.target
AliasNone
DefinitionSet the target architecture for the assembly output. See the --arch option in the command-line notes below for the available architectures.
Argumentsarchitecture
Example
            .target "zx"
            ;; the output binary will have an ZX Spectrum header
            ...
Name.typedef
AliasNone
DefinitionDefine an existing Pseudo-Op to a user-defined type. The type name adheres to the same rules as labels and variables and cannot be an existing symbol or instruction.
Argumentstype, typename
Example
            .typedef   .byte, defb
            * = $c000
            defb 0,1,2,3 ; >c000 00 01 02 03
Name.unmap
AliasNone
DefinitionUnmaps a custom code for a character or range of characters in the selected encoding and reverts to UTF-8. Note: none is not affected by .map and .unmap directives. It is recommended to represent individual char literals as strings.
Argumentsstart[, end]/
"<start><end>"
Example
            .encoding myencoding
            .unmap "A"
            .unmap "π"        ;; revert to UTF-8 encoding
            .byte 'A', 'π'    ;; >> 41 cf 80
            .unmap "09"
            .string "2017"    ;; >> 32 30 31 37
Name.warn
AliasNone
DefinitionPrints a custom warning to the console. The warning is treated like any assembler warning, and if warnings are treated as errors it will cause failure of assembly.
Argumentswarning
Example .warn "We haven't fixed this yet!"
Name.warnif
AliasNone
DefinitionPrints a custom warning to the console if the condition is met. The warning is treated like any assembler warning, and if warnings are treated as errors it will cause failure of assembly The condition is any logical expression.
Argumentscondition, warning
Example
            * = $5000
            nop
            .warnif   * > $5001, "Check bound"
            ;; if program counter
            ;; is greater than 20481,
            ;; raise a custom warning

Appendix

Built-In functions

Nameabs
DefinitionThe absolute (positive sign) value of the expression.
Argumentsvalue
Example.word abs(-2234) ; > ba 08
Nameacos
DefinitionThe arc cosine of the expression.
Argumentsvalue
Example.byte acos(1.0) ; > 00
Nameatan
DefinitionThe arc tangent of the expression.
Argumentsvalue
Example.byte atan(0.0) ; > 00
Namecbrt
DefinitionThe cubed root of the expression.
Argumentsvalue
Example.long cbrt(2048383) ; > 7f 00 00
Nameceil
DefinitionRound up expression.
Argumentsvalue
Example.byte ceil(1.1) ; > 02
Namecos
DefinitionThe cosine of the expression.
Argumentsvalue
Example.byte cos(0.0) ; > 01
Namecosh
DefinitionThe hyperbolic cosine of the expression.
Argumentsvalue
Example.byte cosh(0.0) ; > 01
Namedeg
DefinitionDegrees from radians.
Argumentsradian
Example.byte deg(1.0) ; > 39
Nameexp
DefinitionExponential of e.
Argumentspower
Example.dint exp(16.0) ; > 5e 97 87 00
Namefloor
DefinitionRound down expression.
Argumentsvalue
Example.char floor(-4.8) ; > fb
Nameformat
DefinitionConverts objects to a string in the format specified. The format string must adhere to Microsoft .Net standards. Please see the documentation on standard .Net format strings for more information.
Argumentsvalue
Example.echo format("Program counter is ${0:x4}", *)
Namefrac
DefinitionThe fractional part.
Argumentsvalue
Example.byte frac(5.18)*100 ; > 12
Namehypot
DefinitionPolar distance.
Argumentspole1, pole2
Example.byte hypot(4.0, 3.0) ; > 05
Nameln
DefinitionNatural logarithm.
Argumentsvalue
Example.byte ln(2048.0) ; > 07
Namelog10
DefinitionCommon logarithm.
Argumentsvalue
Example.byte log($7fffff) ; > 06
Namepow
DefinitionExponentiation.
Argumentsbase, power
Example.lint pow(2,16) ; > 00 00 01
Namerad
DefinitionRadians from degrees.
Argumentsdegree
Example.word rad(79999.9) ; > 74 05
Namerandom
DefinitionGenerate a random number within the specified range of numbers. Both arguments can be negative or positive, but the second argument must be greater than the first, and the difference between them can be no greater than the maximum value of a signed 32-bit integer. This is a .Net limitation.
Argumentsrange1, range2
Example
 .word random(251,255)   ; generate a random # between
                         ; 251 and 255.
Nameround
DefinitionRound number.
Argumentsvalue, places
Example.byte round(18.21, 0) ; > 12
Namesgn
DefinitionThe sign of the expression, returned as -1 for negative, 1 for positive, and 0 for no sign.
Argumentsvalue
Example
 .char sgn(-8.0), sgn(14.0), sgn(0)
 ;; > ff 01 00
Namesin
DefinitionThe sine of the expression.
Argumentsvalue
Example.char sin(1003.9) * 14 ; > f2
Namesinh
DefinitionThe hyperbolic sine of the expression.
Argumentsvalue
Example.byte sinh(0.0) ; > f2
Namesqrt
DefinitionThe square root of the expression.
Argumentsvalue
Example.byte sqrt(65536) - 1 ; > ff
Namestr
DefinitionThe expression as a text string. Only available for use with the string pseudo-ops.
Argumentsvalue
Example.string str($c000) ; > 34 39 31 35 32
Nametan
DefinitionThe tangent the expression.
Argumentsvalue
Example.byte tan(444.0)*5.0 ; > 08
Nametanh
DefinitionThe hyperbolic tangent the expression.
Argumentsvalue
Example.byte tanh(0.0) ; > 00

Command-line options

z80DotNet accepts several arguments, requiring at least one. If no option flag precedes the argument, it is considered an input file. Multiple input files can be assembled. If no output file is specified, source is assembled to a.out within the current working directory. Below are the available option flags and their parameters. Mono users note for the examples you must put mono in front of the executable.

Option-o
Alias--output
DefinitionOutput the assembly to the specified output file. A valid output filename is a required parameter.
Parameterfilename
Example
z80DotNet.exe myasm.asm -o myoutput
z80DotNet.exe myasm.asm -output=myoutput
Option--arch
AliasNone
DefinitionSpecify the target architecture of the binary output. If architecture not specified, output defaults to flat. The options:
  • flat - Flat binary with no header
  • zx - ZX Spectrum TAP header
  • amsdos - Amstrad CPC DOS header
  • asmtap - Amstrad CPC Tape header
  • msx - MSX header
Parameterarchitecture
Example
z80DotNet.exe myproggie.asm -b --arch=zx myproggie.prg
Option-b
Alias--big-endian
DefinitionAssemble multi-byte values in big-endian order (highest order magnitude first).
ParameterNone
Example
z80DotNet.exe myasm.asm -b -o bigend.bin
Option-C
Alias--case-sensitive
DefinitionSet the assembly mode to case-sensitive. All tokens, including assembly mnemonics, directives, and symbols, are treated as case-sensitive. By default, z80DotNet is not case-sensitive.
ParameterNone
Example
z80DotNet.exe mycsasm.asm -C
z80DotNet.exe mycsasm.asm --case-sensitive
Option-D
Alias--define
DefinitionAssign a global label a value. Note that within the source the label cannot be redefined again. The value can be any expression z80DotNet can evaluate at assembly time. If no value is given the default value is 1.
Parameter<label>=<value>
Example
z80DotNet.exe -D label=$e000 myasm.asm -o myoutput
Option-h
Alias-?, --help
DefinitionPrint all command-line options to console output.
ParameterNone
Example
z80DotNet.exe -h
z80DotNet.exe --help
Option-q
Alias--quiet
DefinitionAssemble in quiet mode, with no messages sent to console output, including errors and warnings.
ParameterNone
Example
z80DotNet.exe -q myasm.asm
z80DotNet.exe --quiet myasm.asm
Option-w
Alias--no-warn
DefinitionSuppress the display of all warnings.
ParameterNone
Example
z80DotNet.exe -w myasm.asm
z80DotNet.exe --no-warn myasm.asm
Option--werror
AliasNone
DefinitionTreat all warnings as errors.
ParameterNone
Example
z80DotNet.exe --werror myasm.asm
Option-l
Alias--labels
DefinitionDump all label definitions to listing.
Parameterfilename
Example
z80DotNet.exe myasm.asm -l labels.asm
z80DotNet.exe myasm.asm --labels=labels.asm
Option-L
Alias--list
DefinitionOutput the assembly listing to the specified file.
Parameterfilename
Example
z80DotNet.exe myasm.asm -L listing.asm
z80DotNet.exe myasm.asm --list=listing.asm
Option-a
Alias--no-assembly
DefinitionSuppress assembled bytes from assembly listing.
ParameterNone
Example
z80DotNet.exe myasm.asm -a -L mylist.asm
z80DotNet.exe myasm.asm --no-assembly --list=mylist.asm
Option-d
Alias--no-disassembly
DefinitionSuppress disassembly from assembly listing.
ParameterNone
Example
z80DotNet.exe myasm.asm -d -L mylist.asm
z80DotNet.exe myasm.asm --no-disassembly --list=mylist.asm
Option-s
Alias--no-source
DefinitionDo not list original source in the assembly listing.
ParameterNone
Example
z80DotNet.exe myasm.asm -s -L mylist.asm
z80DotNet.exe myasm.asm --no-source --list=mylist.asm
Option--verbose-asm
AliasNone
DefinitionMake the assembly listing verbose. If the verbose option is set then all non-assembled lines are included, such as blocks and comment blocks.
ParameterNone
Example
z80DotNet.exe myasm.asm --verbose-asm -L myverboselist.asm
Option-V
Alias--version
DefinitionPrint the current version of z80DotNet to console output.
ParameterNone
Example
z80DotNet.exe -V
z80DotNet.exe --version

Error messages

Addressing mode is not supported for instruction - The instruction does not support the addressing mode of the operand expression.

Assertion failed - An assertion failed due to the condition evaluating as false.

Attempted to divide by zero. - The expression attempted a division by zero.

Cannot redefine type to <type> because it is already a type - The type definition is already a type.

Cannot resolve anonymous label - The assembler cannot find the reference to the anonymous label.

Closure does not close a block - A block closure is present but no block opening.

Closure does not close a macro - A macro closure is present but no macro definition.

Closure does not close a segment - A segment closure is present but no segment definition.

Could not process binary file - The binary file could not be opened or processed.

Default parameter assignment error - The parameter in the macro definition could not be a default value.

Directive takes no arguments - An argument is present for a pseudo-op or directive that takes no arguments.

Duplicate paramater name found - The macro definition contains one or more parameters that have already been defined.

Encoding is not a name or option - The encoding selected is not a valid name.

error: invalid option - An invalid option was passed to the command-line.

error: option requires a value - An option was passed in the command-line that expected an argument that was not supplied.

<Feature> is depricated - The instruction or feature is depricated (this is a warning by default).

Filename not specified - A directive expected a filename that was not provided.

Format is invalid. - The format string passed to format() is not valid

General syntax error - A general syntax error.

Illegal quantity - The expression value is larger than the allowable size.

Invalid constant assignment - The constant could not be assigned to the expression.

Invalid parameter reference - The macro reference does not reference a defined parameter.

Invalid parameter(s) - The parameters defined for the macro are not valid.

Invalid Program Counter assignment - An attempt was made to set the program counter to an invalid value.

Label is not the leftmost character - The label is not the leftmost character in the line (this is a warning by default).

Macro expects a value for parameter; no default value defined - The macro expects a parameter that was not supplied.

Macro or segment is being called recursively - A macro or segment is being invoked in its own definition.

Macro parameter not specified - The macro expected a parameter that was not specified.

Macro parameter reference must be a letter or digit - The macro parameter was in an invalid format.

Missing closure for block - A block does not have a closure.

Missing closure for macro - The macro does not have a closure.

Missing closure for segment - A segment does not have a closure.

Parameter name invalid - The parameter for the macro definition has an invalid name.

Program Counter overflow - The program counter overflowed passed the allowable limit.

Pstring size too large - The P-String size is more than the maximum 255 bytes.

Quote string not enclosed - The quote string was not enclosed.

Redefinition of label - A label is redefined or being re-assigned to a new value, which is not allowed.

Redefinition of macro - An attempt was made to redefine a macro.

<Symbol> is not a valid symbol name - The label or variable has one or more invalid characters.

Symbol not found - The expression referenced a symbol that was not defined.

Index (zero based) must be greater than or equal to zero and less than the size of the argument list. - A format item in the format string passed to format() does not match the parameter.

Too few arguments for directive - The assembler directive expected more arguments than were provided.

Too many arguments for directive - More arguments were provided to the directive than expected.

Too many characters in character literal - The character literal has too many characters.

Type is unknown or not redefinable - An attempt was made to define an unknown or non-definable type.

Type name is a reserved symbol name - A type definition failed because the definition is a reserved name.

Unable to find binary file - A directive was given to include a binary file, but the binary file was not found, either due to filesystem error or file not found.

Unable to open source file - A source file could not be opened, either due to filesystem error or file not found.

Unknown architecture specified - An invalid or unknown parameter was supplied to the --arch option in the command-line.

Unknown instruction or incorrect parameters for instruction - An directive or instruction was encountered that was unknown, or the operand provided is incorrect.

Unknown or invalid expression - There was an error evaluating the expression.