Skip to content

Latest commit

 

History

History
2716 lines (1710 loc) · 105 KB

LanguageReference.md

File metadata and controls

2716 lines (1710 loc) · 105 KB

Nestor80 assembler language reference

This documents details the source file format supported by Nestor80 and lists all the available assembler instructions (called "pseudo-operators" in the MACRO-80 manual), both the ones inherited from MACRO-80 and the ones newly introduced by Nestor80. It also explains some basic concepts about how Nestor80 works (e.g. passes, absolute vs relocatable assembly) and details the available advanced features (e.g. conditioanl assembly, macros, symbol scoping).

The Nestor80 package actually consists of three tools: Nestor80 (assembler), Linkstor80 (linker), and Libstor80 (library manager). The last two are only relevant when writing relocatable code. This document discusses the assembler only.

Nestor80 is almost fully compatible with MACRO-80. You may want to take a look also to the original MACRO-80 user manual for things that might be missing here or that are explained differently.

Document conventions

The following icons are used in this document:

🆕 A "new" icon is used when introducing a feature or instruction that is new in Nestor80 (it wasn't available in MACRO-80).

✨ A "sparks" icon is used when referring to a feature or instruction that was already available in MACRO-80 but has been enhanced or improved in a backwards-compatible way in Nestor80.

🚫 A "forbidden" icon is used to refer to a MACRO-80 feature or instruction that is not available or has changed in a backwards-incompatible way in Nestor80. Old source code intended for MACRO-80 and relying in such features or instructions will likely require changes before being suitable for assembly with Nestor80.

💡 A "lightbulb" icon is used when providing an useful suggestion or hint.

⚠ A "warning" icon is used when discussing a tricky, subtle or confusing subject; or in general to bring attention to an important concept.

Text in italics will be used the first time a new term or concept is introduced. Alternatively, when referring to a concept or term that is introduced in a later section, it will link to the section in which it is defined.

Nestor80 treats assembler instructions and CPU instructions in a case-insensitive way. In the examples in this document instructions are written in lower case, while symbols and macro names are written un upper case.

This documents refers to some (but not all) of the available Nestor80 command line arguments. To get the full reference of the existing arguments you can run Nestor80 with the --help argument, or you can look at the help text in the Nestor80 source code.

Basic concepts

Before detailing the assembler features and the assembler language reference a couple of concepts related to how the assembler works will be introduced.

Passes

Nestor80 is a two pass assembler. This means that the source code is processed twice: the first time the assembler determines how many bytes each source code line will use in the target program (the contents of the binary file resulting from processing the source code) and updates the current location counter (the pointer in Z80 memory where the code generated by each line will be loaded) accordingly, using this information to assign the appropriate values to labels. The second time, already with all the label values at hand, is when the code is actually assembled.

⚠ When the location counter overflows (its value goes beyond FFFFh) after an instruction that generates output (so not including ORG), it will go back to 0 and a warning will be generated.

Let's see a simple example:

org 100h
call PROGRAM
ret
PROGRAM:
;Some code here
ret

In pass 1 the assembler does the following:

  1. It sees a CALL PROGRAM instruction and although the value of PROGRAM is still unknown, one thing that is for sure is that the line will use three bytes of memory in the target program. Thus, the current location counter is updated to 103h.
  2. It sees a RET instruction and knows that it will use one byte, thus the location counter is updated to 104h.
  3. It sees the definition of the PROGRAM label and assigns it the value of the current location counter, 104h.
  4. It processes the rest of the code accordingly.

In pass 2 the assembler already knows the value of PROGRAM and thus processes the second line as if it was CALL 0104h, writing CDh 04h 01h to the target program.

A similar processing happens for other types of symbols that don't depend on the location counter but may be unknown when found in pass 1, e.g. constants:

call CHPUT
ret
CHPUT equ 00A2h

Usually the fact that the assembly process takes two passes is transparent for the developer, but the IF1 and IF2 instructions exist for advanced scenarios in which it's convenient to process different blocks of source code depending on the current pass. This is typically used to prevent the output of duplicated messages during the assembly process with .PRINT, .WARN or .ERROR.

Here's an advanced example from the source code of Nextor. The following macro will store the value of a given symbol, but if the symbol is undefined by the time the macro is expanded in pass 2, it will be specified as an external symbol reference (with the ## suffix); the DEFW 0 in pass 1 is needed to keep the location counter consistent in both passes:

defa macro ADDR
 if1
  defw  0
 else
  ifdef ADDR
   defw ADDR
  else
   defw ADDR##
  endif
 endif
endm

⚠ Unlike MACRO-80, Nestor80 will skip pass 2 if errors are found in pass 1 (but not if only warnings are found). Thus during the development process it's possible to find that some assembly errors seemingly "appear from nowhere" after some other errors were fixed (the former being errors found in pass 2 and the later being errors found in pass 1). A fatal error will terminate the assembly process immediately.

The location counter can be temporarily modified to account for code that will be executed at a different address, see .PHASE.

Absolute and relocatable code

Nestor80 can produce both absolute 🆕 and relocatable files.

  • An absolute file contains binary code "ready to use", intended to be loaded and executed at the fixed memory locations indicated by the ORG instructions found in code. Most assemblers produce only absolute files.

  • Relocatable files contain relocatable code, that is, "pre-assembled" code in which labels are flagged as being relative to the memory address where the target program will be loaded and symbols may be flagged as external, that is, defined in other relocatable file.

💡 Nestor80 can produce relocatable files in two formats: extended MACRO-80 compatible format, and SDCC compatible format. When the term "relocatable code" is used in this document it refers to a concept or capability that applies to both formats; when discussing a concept or capability that applies to one of the two formats only, "MACRO-80 relocatable" or "SDCC relocatable" will be used instead.

Relocatable files can't be executed, instead a linker (typically Linkstor80 for MACRO-80 relocatable files, or SDLD -often through SDCC itself- for SDCC relocatable files) must be used to convert it into an absolute file by providing the actual loading memory addresses for the target program. The linker is typically used to "glue together" two or more of these files (and linking public symbols with the corresponding external symbols).

It's possible to instruct Nestor80 to produce an absolute file, a MACRO-80 relocatable file or a SDCC relocatable file by using the --build-type command line argument, but by default Nestor80 will decide the appropriate type automatically. The decision is taken as follows:

  • If an ORG instruction is found in the source code before a CPU instruction, a label defined as public with ::, or any of the following instructions: ASEG, CSEG, DSEG, COMMON, DEFB, DEFW, DEFS, DC, DEFZ, PUBLIC, EXTRN, .REQUEST, then the build type will be absolute.
  • Otherwise, if an AREA instruction is found before any of the above, the build type will be SDCC relocatble.
  • Otherwise, the build type will be MACRO-80 relocatable.

Put it another way, if you want your code to be automatically detected as intended to be assembled as absolute, use an ORG instruction as the first "effective" source code line (so the first line except blanks, comments, macro definitions and constant definitions); if you want that automatic detection to choose the SDCC relocatable format, use an AREA instruction instead.

💡 If you want to know the exact source line in which Nestor80 selects the build type, run Nestor80 with a verbosity level of at least two (with the --verbosity argument).

⚠ If the build type is forced to absolute with --build-type but the code contains no ORG instructions, an implicit ORG 0 at the beginning of the code is assumed.

⚠ Pass the --link-80-compatibility argument to Nestor80 if you are building a MACRO-80 relocatable file and you plan to use the old LINK-80 tool instead of Linkstor80 for the linking process. This argument forces Nestor80 to generate relocatable files using the old MACRO-80/LINK-80 format instead of the new extended format. See "Relocatable file format" for details on the differences between both formats.

Some assembler instructions make sense only in the context of relocatable code, for example AREA, CSEG, DSEG, PUBLIC OR EXTRN; these instructions will do nothing, and the assembler will throw warnings, if they are found while assembling absolute code.

See "Writing relocatable code" for more details about how relocatable code programming works.

Absolute output strategies

When producing absolute output there are two strategies that Nestor80 can use:

  • Memory map: A 64K memory map is created and filled with the output bytes according to the ORG instructions found; then the output file is created by dumping the filled memory map between the minimum and the maximum memory addresses used, with a maximum of 64KBytes.

  • Direct output file write: Output is simply written sequentially to the output file, without a maximum for the written length. A side effect is that ORG instructions are treated as equivalent to .PHASE.

"Memory map" is the default strategy, the --direct-output-write argument can be used to instruct Nestor80 to use the "Direct output file write" strategy instead.

For example, given the following code:

org 100
db 1,2,3,4
org 110
db 5,6,7,8
org 102
db 9,10

Output when using "memory map" strategy: 1,2,9,10,0,0,0,0,0,0,5,6,7,8
Output when using "direct file write" strategy: 1,2,3,4,5,6,7,8,9,10

Source code format

Nestor80 converts source code files to absolute or relocatable files. A source code file is a text file in which each line is either blank, a comment, or a statement; lines are processed one by one. The maximum supported line length is 1034 characters ✨ and all the usual line ending conventions are supported (CR+LF characters, LF only, and CR only). ✨ Spaces and tabs are treated equivalently, and those found at the beginning and at the end of the line are removed before the line is processed.

A comment-only line starts with a semicolon character, ;, and has no effect in the assembly process. A statement has the following format:

[label:[:]] [operator] [arguments] [;comment]

Any number of spaces or tabs can be used to separate the statement components.

A label is a type of symbol that has the value of the location counter at the time it's defined (the value that the location counter has when the line is processed). A label definition must end with either : or ::; the later is used when assembling relocatable code to indicate that the label is public.

An operator is a word that can be either the mnemonic of a CPU instruction (e.g. LD) or an assembler instruction. An assembler instruction (called "pseudo-operator" in the MACRO-80 manual) is an instruction for the assembler itself, for example ORG instructs the assembler to change the value of the current location counter.

⚠ In this manual the word "instruction" alone will be used to refer to assembler instructions, as opposed to CPU instructions.

The comment, if present, runs until the end of the line and has no effect in the assembly process. Multiline comments are supported by using the .COMMENT instruction.

Nestor80 supports Z80, R800 🆕 and Z280 🆕 CPU instructions, being Z80 the default CPU; a .CPU R800 instruction can be used to enable support for R800 instructions, and likewise, .CPU Z280 enables support for Z280 instructions (see also "Z280 support"). The 8080 CPU is not supported by Nestor80. 🚫

The arguments depend on the operator. For CPU instructions they will typically be one or two comma-separated values, each being either a CPU register name or an expression, for example LD HL,BUFFER+1000h. There are operators with mandatory arguments, others with no arguments defined, and others with optional arguments.

Control characters other than tabs are stripped from the source lines before processing, however the form feed characters (\f, encoded as 0x0C in ASCII) are counted before these are significant when generating a listing file (they force a listing page change).

MACRO-80 assumes that the source code is encoded in ASCII, Nestor80 however supports source code supplied in any character encoding. ✨

MACRO-80 treats source code characters with the high bit set as line numbers generated by a text editor, this is not the case of Nestor80. 🚫

Symbols

A symbol is a named 8 or 16 bit value. When assembling relocatable code this value can belong to the absolute, code or data segment or to a COMMON block. Valid characters for symbols are letters (any unicode letter is allowed, not just ASCII letters ✨), digits, and these: $.?@_. The first character of a symbol can't be a digit.

Nestor80 treats symbols in a case-insensitive way, e.g. foo, FOO and Foo refer all to the same symbol.

There's in principle no limit for the length of a symbol ✨, but when assembling MACRO-80 relocatable code with the --link-80-compatibility argument the maximum length for external and public symbols will be 6 characters. This limitation is given by the format of the LINK-80 relocatable files. Nestor80 will issue a warning if it finds two or more external symbols that are different but share the first 6 characters (since these will get their names truncated and thus be actually the same symbol), and will throw an error if the same happens with public symbols.

When writing relocatable code, the following suffixes are allowed for symbols:

  • A symbol reference can have the ## suffix to indicate that it's an external symbol (a symbol that is defined in another relocatable file). This is equivalent to using the EXTRN instruction:
ld hl,FOO##

;Equivalent to:

extrn FOO
ld hl,FOO
  • A label can be defined with the :: suffix (instead of just :) to indicate that it's a public symbol (a symbol that can be accessed from another relocatable file). This is equivalent to using the PUBLIC instruction:
FOO::
  ;Some code

;Equivalent to:

public FOO
FOO:
  ;Some code

💡 If the --unknown-symbols-external argument is passed to Nestor80 then any symbol that is still unknown at the end of pass 2 will be implicitly considered an external symbol.

Named constants

A named constant (or just "constant") is a symbol that represents a numeric value and can be used in expressions. There are two types of constants: fixed and redefinible. The value of a fixed constant can't be altered, while the value of a redefinible constant can, by using a new constant definition instruction with the same constant name.

A fixed constant is defined using the following syntax: <name>[:] EQU <value expression>. The colon after the constant name is optional ✨ (in MACRO-80 the colon after the constant name isn't allowed). Example:

FOO equ 34
FOO: equ 30+4  ;Allowed since the value is the same

ld a,FOO+6     ;Equivalent to "ld a,40"

FOO equ 89     ;"Symbol already exists" error

A redefinible constant is (re)defined using the following syntax: <name>[:] DEFL <value expression>. As in the case of the fixed constants, the colon after the constant name is optional ✨. Example:

FOO defl 34
ld a,FOO      ;Equivalent to "ld a,34"

FOO: defl 89
ld a,FOO      ;Equivalent to "ld a,89"

FOO defl FOO+1   ;The constant itself can be part of the redefinition expression
ld a,FOO      ;Equivalent to "ld a,90"

For compatibility with MACRO-80 the ASET instruction is allowed as an alias for DEFL.

Note that EQU and DEFL can't be mixed for the same constant name:

FOO equ 1
FOO defl 2    ;"Symbol already exists" error
FOO defl 1
FOO equ 2     ;"Symbol already exists" error

⚠ You may think that the term "constant" isn't really appropriate for redefinible values. The term "variable", however, has been avoided on purpose to avoid confussion with how the word is normally used in the context of software development, as "value that can change at runtime"; a redefinible constant can have its value changed at assemble time, not at runtime.

⚠ (🚫?) The MACRO-80 manual mentions also the instruction SET as an additional alias for DEFL, but in practice it doesn't work as such: SET is only recognized as the Z80 instruction of the same name in MACRO-80. Nestor80 behaves as MACRO-80 behaves and not as the MACRO-80 documentation says, so you can't use SET to define constants.

Numeric constants

Numeric constants can be specified in any radix from 2 to 16. The default radix is 10 but this can be changed with the .RADIX instruction. When the radix is 11 or higher the letters A to F (case insensitive) are used to represents the digits after the 9.

In order to specify a number in a radix different from the default one the following notations can be used (prefixes and suffixes are case-insensitive):

Notation Radix
nnnnB Binary
nnnnI 🆕 Binary
nnnnD Decimal
nnnnM 🆕 Decimal
nnnnO Octal
nnnnQ Octal
nnnnH Hexadecimal
X'nnnn' Hexadecimal
0xnnnn 🆕 Hexadecimal
#nnnn 🆕 Hexadecimal (see note)

Note: The # character is interpreted as a hexadecimal number prefix by default, but if the --discard-hash-prefix argument is passed to Nestor80 then such characters will be ignored when used as number prefixes; so for example #1234 will be equivalent to 1234 in the default radix, and #1010I will be equivalent to the binary number 1010. This can be useful to assemble source code written for the SDAS assembler, which requires numeric constants to be prefixed with a # character.

⚠ The B and D suffixes are actually unusable when the default radix is 12 or higher and 14 or higher, respectively. Consider the following example:
.radix 16
defw 1010b,1234d

You might think that these are the binary number 1010 and the decimal number 1234, but that's not the case: these are actually the hexadecimal numbers 010B and 234D. This behavior is inherited from MACRO-80.

That's the reason why the new suffixes I (bInary) and M (deciMal) have been introduced in Nestor80.

💡 The # prefix for hexadecimal numbers has been introduced in Nestor80 for compatibility with other assemblers that use the same notation, but in general it's recommended to use the H suffix instead since # could cause confusion with the suffix for external symbols, ##.

A string can be used as equivalent to the numeric constant resulting from encoding it with the current character encoding, with the following rules:

  1. The current character encoding must produce at most two bytes for the string (an error will be thrown otherwise).
  2. A string that produces two bytes in the current character encoding is interpreted as a big-endian value in DEFB instructions, and as a low-endian value elsewhere.
  3. An empty string produces no output in a DEFB statement, and the value zero everywhere else.

The second rule exists for consistency with how DEFB converts strings into bytes in the general case (strings of any length).

The following example listing illustrates how strings are converted to bytes following these rules:

                         .strenc ASCII
  0000                   defb ''
  0000    41             defb 'A'
  0001    42 41          defw 'AB'
  0003    41 42          defb 'AB'
  0005    41 42 43 44    defb 'ABCD'
  0009    00 00          defw ''
  000B    3E 00          ld a,''
  000D    21 00 00       ld hl,''

Strings

Strings are sequences of arbitrary characters enclosed in single quotes, ', or double quotes, ". Strings are converted to bytes using the current character encoding 🆕 (MACRO-80 didn't have the concept of "character encodings" and simply outputted the string bytes as they were physically stored in the source file).

The current character encoding is the one specified in a --string-encoding argument when running Nestor80, and can also be changed in code with the .STRENC instruction. You can run Nestor80 with the --list-encodings argument to see a list of available encodings. The default encoding when none is specified is 7 bit ASCII.

Strings that produce two or less bytes once converted by the current encoding can be used anywhere a numeric value is expected, see "Numeric constants". Strings of any length can be used in the DEFB instruction, in this case characters are converted to bytes sequentially in the order in which they appear in the string.

Single-quoted strings don't accept escape character with the only exception of '', which allows escaping the single quote itself. Example:

DEFB 'This ain''t gonna escape much'

Double-quoted strings accept escape sequences by default using the \ character as the sequence initiator 🆕. The following escape sequences are allowed (values are in the ASCII encoding except where otherwise stated):

Sequence Name Value
\' Single quote 27h
\" Double quote 22h
\\ Backslash 5Ch
\0 Null 00h
\a Alert 07h
\b Backspace 08h
\f Form feed 0Ch
\n New line 0Ah
\r Carriage return 0Dh
\t Horizontal tab 09h
\v Vertical tab 0Bh
\x Arbitrary escape sequence (2 hex digits) Example: \x12 = 12h
\u Arbitrary escape sequence (4 hex digits) Example: \u0012 = 12h
Example: \uABCD = CDh, ABh (in UTF-16)

The support for escape sequences in double-quoted strings can be disabled by using the Nestor80 command line argument --no-string-escapes or the instruction .STRESC OFF in code. When escape sequences are disabled the double quote character itself can still be escaped by doubling it:

.stresc OFF
defb "The ""escaped"" string"

💡 It's recommended to disable escape sequences when compiling old code that contains strings, since in MACRO-80 the \ character was considered a regular character with no escaping meaning.

⚠ Note that when string escaping is enabled the only way to escape the double quote character is to use the \" sequence or the \x22 or \u0022 sequences; the special sequence "" is available only when escape sequences are disabled.

An empty string (e.g. DEFB '') produces no output.

Strings in messages for the assembler console

The messages to be printed during the assembly process with the .PRINT, .WARN, .ERROR and .FATAL instructions can optionally be enclosed in double quotes, ". When that's the case these messages support the same escape sequences that the strings used in expressions, once decoded these will be sent "as is" to the console; also "" can be used to represent an empty string. For example:

.print1 "Hello\nworld"
.print1 ""
.print1 "Printing \"nice\" messages"

This is what will get printed:

Hello
world

Printing "nice" messages

⚠ Escape sequences are always processed as such in messages enclosed in double quotes for .PRINT, .WARN, .ERROR and .FATAL instructions, even if escape sequences for regular strings are disabled with .STRESC OFF or by passing the --no-string-escapes argument to Nestor80.

Expressions

An expression is a combination of numeric constants, symbols and arithmetic operators that are ultimately evaluated to a numeric value. When assembling relocatable code, expressions that contain external symbol references aren't evaluated; instead, they are outputted to the target relocatable file "as is" so that the evaluation will happen at linking time once the values of all the involved external references have been resolved (see "Writing relocatable code").

If a 8 bit value is expected (e.g. DB <value> or LD A,<value>) the expression must evaluate to a 16 bit value whose high byte is either 0 or FFh (otherwise an overflow error will be thrown) and the effective value of the expression is the low byte. On the other hand, if a 16 bit value is expected (e.g. DW <value> or LD HL,<value>) any overflow beyond the lower 16 bits is ignored and the result is the value formed by the low order 16-bits (e.g. 123456h is interpreted as 3456h).

Nestor80 defines the following arithmetic operators:

Operator Meaning Precedence
NUL Rest of expression
is empty?
10
TYPE Argument type 9
LOW Low byte 8
HIGH High byte 8
* Multiplication 7
/ Integer division 7
MOD Remaining of
integer division
7
SHR Shift right 7
SHL Shift left 7
- (unary) Unary minus 6
+ Addition 5
- Substraction 5
EQ Equals 4
= 🆕 Equals 4
NE Not equals 4
NEQ 🆕 Not equals 4
LT Less than 4
LE Less than or equal 4
LTE 🆕 Less than or equal 4
GT Greater than 4
GE Greater than or equal 4
GTE 🆕 Greater than or equal 4
NOT Bitwise NOT
(one's complement)
3
AND Bitwise AND 2
OR Bitwise OR 1
XOR Bitwise XOR 1

When assembling code in the MACRO-80 relocatable format with the --link-80-compatibility argument only the following arithmetic operators can be used in expressions involving external references: NUL, TYPE, LOW, HIGH, MOD, NOT, *, /, +, - (including unary). This is a limitation given by the old relocatable file format. Trying to use one of the unsupported operators in such an expression will result in an assembly error.

When assembling code in the SDCC relocatable format only a small subset of the available arithmetic operators can be used in expressions involving external references or symbols in relocatable areas. See "SDCC relocatable file format support" for the details.

The NUL and TYPE operators are special:

  • NUL works as follows: if the remaining of the source code line after the operator (not including the comment, if present) has any characters other than spaces and tabs, it will evaluate to 0; otherwise it will evaluate to 0FFFFh. This is useful mainly in the context of macro expansions.

💡 The IFB and IFNB instructions can be used alternatively to the NUL operator in order to check for empty arguments in macros.

  • TYPE will evaluate to a fixed absolute value depending on the type of the argument passed to it:
Argument type Value
External symbol reference 0x80
Numeric constant or absolute symbol 0x20
Symbol defined in the code segment (MACRO-80 format)
or in a relocatable area (SDCC format)
0x21
Symbol defined in the data segment (MACRO-80 format only) 0x22
Symbol defined in a COMMON block (MACRO-80 format only) 0x23

For example TYPE FOO## evaluates to 0x80, and TYPE FOO evaluates to 0x21 if FOO is a label defined in the code segment. Of course, when assembling absolute code TYPE will evaluate everything to 0x20.

⚠🚫 The TYPE operator is intended to be used with plain symbols and will act weirdly with complex expressions. For example, TYPE (FOO##+1) will evaluate to A0h in MACRO-80 and throw an error in Nestor80.

The operator precedence determines how the expression is evaluated: subexpressions involving operators of higher precedence are computed first, and operators with the same precedence are applied in the order in which they appear in the expression. For example, the expression 2+3*4 evaluates to 14 because * has higher precedence than +. Parenthesis can be used to override the default operator precedence, for example (2+3)*4 evaluates to 20.

The comparison operators (GT, LT, GE, LE, EQ, NE and equivalents) evaluate to FFFFh if the comparison is true and to zero otherwise. ⚠ Also they treat the numbers as unsigned integers, this means that an expression like x lt 0 always evaluates as zero ("false") for any value of x. See IF for an example of how to test for negative values.

The HIGH and LOW operators evaluate to the high and low byte of a 16 bit value, respectively; for example HIGH 1234h is 12h and LOW 1234h is 34h. When applied to relocatable values, the entire 16 bit value is written to the generated relocatable file and the evaluation is performed at linking time; for example if FOO is a label defined as address 1234h in the code segment, and the linker is instructed to use address 8511h as the base for the code segment, then HIGH FOO will properly evaluate to 97h and LOW FOO to 45h in the target program.

Expression interpolation 🆕

The messages to be printed during the assembly process with the .PRINT, .WARN, .ERROR and .FATAL instructions support expression interpolation, that is, they can include expressions that will be evaluated and the result printed as part of the message.

To interpolate an expression in an instruction it must be enclosed in { and }, using the following format:

{expression[:radix[size]]}

where:

  • radix specifies the radix to use to print the expression value, and can be one of the following:
    • D or d for decimal.
    • B or b for binary.
    • X or H for hexadecimal with uppercase letters.
    • x or h for hexadecimal with lowercase letters.

The default radix used if none specified is 10, regardless of any radix set with the .RADIX instruction.

  • size is the minimum number of digits that will be printed. The printed value will be padded to the left with zeros if needed.

For example, the following line

.print 20+11 equals {20+11}, or {20+11:H}h, or {20+11:x4}h, or {20+11:b8}b.

will print

20+11 equals 31, or 1Fh, or 001fh, or 00011111b.

⚠ All the symbols included in interpolated expressions must be known when the instruction is processed (this implies that the expressions can't contain external symbol references), otherwise an error will be thrown and the messages will be printed with the "offending" expressions unevaluated. Usually you'll want to use .PRINT2 instead of .PRINT or .PRINT1 to ensure that.

Bare expressions

MACRO-80 allows bare expressions lines, these are lines that have no operand and contain just a list of comma-separated expressions; these lines are treated as DEFB instructions. For example the line 1,2,3,4 is equivalent to DEFB 1,2,3,4.

In Nestor80 bare expressions aren't supported by default 🚫, but they will be supported if the --allow-bare-expressions command line argument is used. You might need this to assemble old source code, but in general bare expressions shouldn't be used since they can cause confussion (for example if you intend to introduce a named macro expansion and mistype the macro name you'll get a confusing "symbol not found" error).

Symbol scoping

Nestor80 offers two mechanism for scoping symbols so that the same symbol names can be reused in different parts of the same source code: modules and relative labels.

Modules 🆕

A module is a set of consecutive source code lines grouped under a unique name. All symbols defined inside a module (and by default, also all the non-external referenced symbols) will be considered relative to the module name; this means that the effective symbol name will be module_name.symbol. Example:

MAIN_INIT:
  call GRAPHICS.init
  call SOUND.init
  ret

module GRAPHICS

init:
  ;Some unique init
initloop:
  ;Some repeated init
  djnz initloop
  ret

endmod

module SOUND

init:
  ;Some unique init
initloop:
  ;Some repeated init
  djnz initloop
  ret

endmod

The above code is equivalent to the following one that doesn't use modules:

MAIN_INIT:
  call GRAPHICS.init
  call SOUND.init
  ret

GRAPHICS.init:
  ;Some unique init
GRAPHICS.initloop:
  ;Some repeated init
  djnz GRAPHICS.initloop
  ret

SOUND.init:
  ;Some unique init
SOUND.initloop:
  ;Some repeated init
  djnz SOUND.initloop
  ret

In order to refer to a symbol defined outside the module there are two options:

  1. Prepend the symbol name with a colon, :
  2. Use the ROOT instruction to list the symbols that are to be considered as defined outside the module.

Example:

CHPUT equ 00A2h

MAIN_INIT:
  call GRAPHICS.init
  call SOUND.init
  ret

module GRAPHICS

init:
  ld a,'!'
  call :CHPUT
  ret

endmod

module SOUND

root CHPUT

init:
  ld a,'?'
  call CHPUT
  ret

endmod

Modules can be nested:

MAIN_INIT:
  call GRAPHICS.LOWRES.init
  ret

module GRAPHICS
module LOWRES

init:
  ;Do init
  ret

endmod
endmod

When a symbols starts with a dot, no extra dot will be added when concatenating the symbol name and the module name, so .symbol becomes module.symbol, not module..symbol:

MAIN_INIT:
  call GRAPHICS.init
  call GRAPHICS..reinit
  ret

module GRAPHICS

.init:
  ;Do init
  ret

..reinit:
  ;Do reinit
  ret

endmod

Relative labels 🆕

A relative label is a label that starts with a dot, ., and is found after a non-relative label; the former is considered to be relative to the later, that is, the effective label name for .relative is non_relative.relative:

.relab

print:
  ;Init
.loop:
  ;Stuff
  djnz .loop
  ret

update:
  ;Init
.loop:
  ;Stuff
  djnz .loop
  ret

The above code is equivalent to the following one that doesn't use relative labels:

print:
  ;Init
print.loop:
  ;Stuff
  djnz print.loop
  ret

update:
  ;Init
update.loop:
  ;Stuff
  djnz update.loop
  ret

⚠ Relative labels are disabled by default. To enable the feature the .RELAB instruction must be used; conversely, the .XRELAB instruction disables the feature.

Within expressions any symbol whose name starts with a dot will be considered a relative label if the feature is enabled and at least one non-relative label has been declared previously, this can lead to errors when referencing constants:

.relab

.STROUT equ 09h

FOO:
  ;Do stuff
  ret

ld a,.STROUT  ;Error: symbol "FOO.STROUT" not found

In order to reference a symbol whose name starts with a dot but is not a relative label there are two options:

  1. Prepend the symbol name with a colon, :
  2. Temporarily disable the relative labels with .XRELAB

Example:

.relab

.STROUT equ 09h
BDOS equ 0005h

print:
  ld c,:.STROUT
  call BDOS
  ret	

reprint:
  .xrelab
  ld c,.STROUT
  .relab
  call BDOS
  ret

The last non-relative symbol is forgotten (and thus symbols starting with a dot go back to being considered regular symbols) when:

  1. A module is entered (MODULE instruction) or exited (ENDMOD instruction).
  2. The feature is enabled with .RELAB or disabled with .XRELAB (even if it was already enabled or disabled).

Example:

.relab

.STROUT equ 09h

FOO:
  ;Do stuff
  ret

.relab

ld a,.STROUT  ;No error, really referencing ".STROUT" due to the second .relab

Conditional assembly

Conditional assembly is a mechanism that allows to conditionally process or skip the assembly of blocks of code based on certain conditions. A conditional assembly block has the following format:

<IF instruction> [<arguments>]
  <true condition block>
[ELSE
  <false condition block>]
ENDIF

where:

  • <IF instruction> is an assembler instruction that will evaluate to either true or false, depending on the assembly process state and/or the passed <arguments> (some instructions don't accept arguments).
  • <true condition block> is the block of instructions that will be assembled if the IF instruction evaluates to true.
  • <false condition block> is an optional block of instructions that will be assembled if the IF instruction evaluates to false.

Example:

ifcpu R800
muluw hl,bc
else
call MULUW_HL_BC
endif

Conditional assembly blocks can be nested, see IF for an example.

The following IF instructions are supported by Nestor80, see the reference of each instruction for the syntax details:

Instruction Argument(s) Evaluates to true if...
IF expression Expression evaluates to non-zero
IF1 Assembler is processing pass 1
IF2 Assembler is processing pass 2
IFABS 🆕 Build type is absolute
IFB text Text is blank (has zero length)
IFCPU 🆕 CPU name CPU name is the current target CPU
IFDEF symbol name Symbol is defined
IFDIF text1, text2 text1 and text2 are different
IFDIFI 🆕 text1, text2 text1 and text2 are different,
with case-insensitive comparison
IFF expression Expression evaluates to zero
IFIDN text1, text2 text1 and text2 are identical
IFIDNI 🆕 text1, text2 text1 and text2 are identical,
with case-insensitive comparison
IFNB text Text is non-blank (has non-zero length)
IFNCPU 🆕 CPU name CPU name is not the current target CPU
IFNDEF symbol name Symbol is not defined
IFREL 🆕 Build type is relative

Macros

Macros are a powerful mechanism for reusing blocks of code in different parts of the same source file, possibly with changes based on arguments.

A macro needs to first be defined, then expanded. A macro definition consists of an opening instruction (possibly containing arguments), the macro body lines, and a closing ENDM instruction. A macro expansion is an actual usage of the macro, where the macro body lines are modified and/or repeated according to the macro definition and the passed arguments.

There are two main types of macros:

  • Repeat macros: the macro expansion starts immediately after the macro definition finishes, and the macro body lines are repeated a number of times based on the concrete macro type and the supplied arguments.
  • Named macros: the macro definition includes an unique macro name. The macro expansion happens when the macro name appears in the source code as if it was an instruction, possibly with arguments as specified in the macro definition.

Repeat macro with count

The repeat macro with count is the simplest macro type: it just repeats the body lines the number of times that is passed as argument. The opening instruction is REPT.

Example:

rept 1,2,3
defb 1
defb 2
endm

The macro expansion would be:

defb 1
defb 2
defb 1
defb 2
defb 1
defb 2

Repeat macro with arguments

The repeat macro with arguments macro (named "indefinite repeat" in the MACRO-80 documentation) accepts a placeholder and a list of comma-separated arguments in the opening instruction (IRP), and generates one repetition per argument in which the placeholder is replaced by the argument.

Example:

irp x,<1,2,3>
defb x
endm

The macro expansion would be:

defb 1
defb 2
defb 3

The rules for the arguments are as follows:

  • Angle brackets around the arguments list are mandatory.
  • Arguments can be separated with commas or with spaces (spaces around the arguments are stripped off before being used in the expansion).
  • Two consecutive commas, ,,, generate a repetition with an empty string as the argument.
  • Nested angle brackets can be used inside the arguments list for arguments that contain commas and spaces, e.g. << >,<,>> defines two arguments, a space and a comma. The ! character can be used too to use reserved characters as arguments.

Repeat macro with characters

The repeat macro with characters macro (named "indefinite repeat characters" in the MACRO-80 documentation) accepts a placeholder and a sequence of characters in the opening instruction (IRPC), and generates one repetition per character in which the placeholder is replaced by the argument.

Example equivalent to the one given for "Repeat macro with arguments":

irpc x,123
defb x
endm

The arguments list can be optionally delimited with angle brackets. This is needed if the characters sequence contains spaces, e.g. IRPC x,<a b> has three arguments: a, a space, and b.

Repeat macro with string 🆕

The repeat macro with string macro uses the new IRPS opening instruction which accepts a placeholder and a string, and generates one repetition per character of the string in which the placeholder is replaced by the argument. This is a more flexible version of "Repeat macro with characters", since there are no restrictions for the printable characters that the string can contain and (to some extent) it accepts escape sequences. For example IRPS x,"\x41\x42\x43" would be equivalent to IRPC x,ABC.

⚠ Not all escape sequences are supported. For example \r will insert a literal line break at the point where the placeholder is encountered, and this will cause either errors or the line to not generate any output.

Named macros

To define a named macro the MACRO opening instruction is used with the following syntax: <name>[:] MACRO [<placeholder1>[,<placeholder2>[,...]]]. The macro is expanded once for each instance of <name> used in the code, and the placeholders from the macro definition found in the macro body lines are replaced with the actual arguments passed to the macro expansion. The colon following <name> in the macro definition is optional ✨ (in MACRO-80 this colon wasn't allowed).

Here's a simple example. Macro definition:

SUM: macro first,second
ld a,first
add a,second
endm

Macro usage:

SUM 1,2

Generated macro expansion:

ld a,1
add a,2

⚠ A new macro definition will replace one that already exists with the same name. This behavior is compatible with MACRO-80, but in Nestor80 it will emit a warning. Example:

FOO macro
defb 0
endm

FOO macro
defb 1
endm

FOO

This will expand to defb 1.

Rules for placeholder replacement

When placeholders are replaced with actual arguments in all macro types (except "Repeat macro with count" which doesn't support placeholders) the following rules apply (a placeholder named foo is assumed in the examples):

  • The placeholder search is case-insensitive: instances of FOO will be replaced too.
  • Placeholders are not replaced inside comments, e.g. no replacement will happen in the line db 0 ;foo.
  • Placeholders aren't replaced when they are surrounded by valid symbol characters, e.g. replacement will happen in foo+1 but not in foobar or in @foo.
  • To overcome the above limitation the & character can be used before and if needed also after the placeholder name, for example when the actual argument is X then bar&foo will be replaced with barX and the&foo&bar will be replaced with theXbar.
  • Placeholders aren't replaced inside strings by default, e.g. no replacement will happen in the line db "foo".
  • Again, to overcome the above limitation the & character can be used before and if needed also after the placeholdder, e.g. if the actual argument is FIZZ then db "&foo" will be replaced with db "FIZZ".

And specifically for named macros:

  • If less arguments are passed to the macro expansion than placeholders were defined in the macro definition, the missing arguments are considered to be empty. For example, if the macro definition is FOO: MACRO X,Y,Z and the macro is expanded as FOO 1,2, then X will get replaced with 1, Y will get replaced with 2, and Z will get replaced with an empty string.
  • If more arguments are passed to the macro expansion than placeholders were defined in the macro definition, the extra arguments will be ignored. For example, if the macro definition is FOO: MACRO X,Y,Z, the macro expansion FOO 1,2,3,4,5 will be equivalent to FOO 1,2,3.

💡 The IFB, IFNB, IFIDN, IFIDNI, IFDIF and IFDIFI instructions and the NUL operator are useful to check for empty arguments and for exact argument values.

Here's an example that illustrates all the replacement rules. Macro definition:

THEMACRO macro foo
;Let's do things with foo
foo: ;Replaced!
FOO: ;Replaced!
foobar: ;Mixed with symbol chars? No replacement
bar&foo: ;Replaced!
the&foo&bar: ;Replaced!
defb "Oh, the foo! Is this &foo or &foo&bar?"
endm

Macro usage: THEMACRO FIZZ

Macro expansion:

;Let's do things with foo
FIZZ: ;Replaced!
FIZZ: ;Replaced!
foobar: ;Mixed with symbol chars? No replacement
barFIZZ: ;Replaced!
theFIZZbar: ;Replaced!
defb "Oh, the foo! Is this FIZZ or FIZZbar?"

Other special characters

Additionally to '&' the following characters have a special meaning when used in the context of macro expansions:

  • ;;: when a comment inside a macro definition starts with a double semicolon it won't be included in the macro expansion in listings. Example:
THEMACRO macro
defb 1 ;This is a one
defb 2 ;;You won't see this
endm

The macro expansion is listed as:

       THEMACRO
+      defb 1 ;This is a one
+      defb 2 
       end
  • !: used in argument lists for macro expansions as an escape character: the character following it will be interpreted literally, even if it's a "reserved" character in the context of macro arguments such as a space or a comma. Example:
THEMACRO macro x,y,z
defb "&x"
defb "&y"
defb "&z"
endm

THEMACRO ! ,!,,!!

Generated macro expansion:

db " "
db ","
db "!"
  • %: placed in front of a macro argument it forces the argument to be interpreted as an expression and to be evaluated, the evaluated value is what gets actually passed as the argument for the macro expansion. Example:
FOO equ 4

THEMACRO macro x
defb x
endm

THEMACRO %FOO+30
THEMACRO FOO+30
end

Generated macro expansions:

defb 34
defb FOO+30

Local symbols

Regular symbols can't be declared inside macros, since the second time that the macro is expanded a "Symbol already defined" error would be thrown for each of these symbols. To solve this problem symbols can be declared as local to the macro with the LOCAL instruction.

LOCAL declares a list of symbols that will be declared inside the macro definition. When found inside the macro expansions these symbols will be replaced with a symbol with the format ..<number>, where the number is in hexadecimal format and increases by one (across all the macro expansions in the entire program) after each usage; so ..0000, ..0001 etc.

Example:

NEVEREND macro
local loop
loop: jp loop
endm

NEVEREND
NEVEREND
NEVEREND

The generated code will be equivalent to:

..0000: jp ..0000
..0001: jp ..0001
..0002: jp ..0002

Nesting macros

Macros can be nested according to the following rules:

  • Repeat macros can be nested inside other repeat macros and inside named macros.
  • 🚫 Named macros can not be nested inside other named macros (this is something that MACRO-80 allowed).

See "Additional macro examples" for examples of nested repeat macros.

Additional macro examples

Here are some additional macro definition and expansion examples, taken from the MACRO-80 manual.

X defl 0

rept 10
X defl X+1
defb X
endm
irp X,<1,2,3,4,5,6,7,8,9,10>
defb X
endm
irpc X,0123456789
defb X+1
endm
x defl 0
rept 2
  rept 5
    x defl x+1
    defb x
  endm
endm
FOO macro N
  X defl 0
  rept N
    X defl X+1
    defb X
  endm
endm

FOO 10

All of the above expand to code equivalent to defb 1,2,3,4,5,6,7,8,9,10.

MKLAB macro Y
ERR&Y: defb 'Error &Y',0
endm

MKERR macro X
LB defl 0
rept X
LB defl LB+1
MKLAB %LB
endm
endm

MKERR 3

The above expands to:

ERR2: defb 'Error 1',0
ERR2: defb 'Error 2',0
ERR3: defb 'Error 3',0

Listings

Nestor80 allows to generate a listing with information about the generated addresses and symbols, displayed together with the source code. A listing is generated if the --listing-file argument is supplied to Nestor80.

The listing is a text file that pretty much replicates the format of the listing files generated by MACRO-80, with a couple of additions. The listing file is composed of pages that follow one another, with each page having this format:

<form feed character><title> Nestor80 <version> PAGE <page>[-<subpage>]
<subtitle>

<listing line>
<listing line>
...

where:

  • <form feed character> is a \f character (0Ch in ASCII).
  • <version> is the version number of the Nestor80 program that generated the listing.
  • <title> is the last listing title that was set with a TITLE instruction, by default it's empty.
  • <subtitle> is the last listing title that was set with a SUBTTL instruction, by default it's empty.
  • <page> is the current main page number, which starts at 1.
  • <subpage> is the current subpage number, which starts at 0 (it's not printed when it's 0).
  • <listing line> is the source code line being listed, possibly augmented with flags and an address.

Page numbers are updated for each new page as follows:

  • The main page number is increased (and the subpage number goes back to 0) when a form feed (\f character, 0Ch in ASCII) is found in the source code, and when a MAINPAGE instruction is found.
  • The secondary page number is increased when a page has been completed, and also when the PAGE instruction is found.

The default page size is 50 lines, this value can be changed with the PAGE instruction.

The format of a listing line is:

[<address>] [<bytes>] [<flags>] <source line>

where:

  • <address> is the value of the location counter at the time of starting to process the source line. This is included in the listing line only for lines that generate output, have a label, or (for relocatable code) change the current segment.
  • <bytes> are the absolute bytes or the relocatable values that the assembler generates for the source line.
  • <flags> are special characters that indicate if the line is part of a macro expansion or an included file.
  • <source line> is the verbatim source line as it was found in the source file.

<address> is a four digit hexadecimal numbers that is possibly followed by a suffix:

  • No suffix: absolute address.
  • ': address in the code segment (MACRO-80 format)
    or in a relocatable area (SDCC format).
  • ": address in the data segment (MACRO-80 format only).
  • !: address in a COMMON block (MACRO-80 format only).
  • *: address that is calculated at linking time (e.g. external symbol references), always shown as zero.

By default the <bytes> area will only display four bytes, and any remaining bytes (e.g. for long DEFB or INCBIN instructions) will appear below in extra lines, without source line. The amount of bytes per line can be configured 🆕 with the Nestor80 argument --listing-bytes-per-line.

By default a total of up to 128 bytes will be displayed for one single instruction in the <bytes> area; if an instruction generates more bytes, the excess bytes will be left out of the listing and "..." will be added after the last printed byte. This limit can be configured 🆕 with the Nestor80 argument --listing-max-bytes-per-instruction.

The possible flags are:

  • + if the line is part of a macro expansion.
  • C if the line is part of file included from the main source file.
  • C<depth> 🆕 if the line is part of file included from another included file. <depth> indicates how many nested INCLUDE instructions have been executed.

Symbols list

After the last page of regular listing a list of local symbols, public symbols, external symbols, named macros and (when building SDCC relocatable files) area names is included as well. The main page "number" used for these lists is S.

By default four symbols will be listed in each listing line, and only the first 16 characters of each symbol will be printed (longer symbols will be truncated and will get a ... at the end). These values can be configured 🆕 with the Nestor80 arguments --listing-symbols-per-line and --listing-max-symbol-length, respectively.

By default all symbols, macro names and area names in the symbols list will keep their original casing 🆕, but Nestor80 can be instructed to convert them to uppercase (which is what MACRO-80 does when generating listings) with the --listing-uppercase-symbols argument.

Temporarily stopping the listing

The .XLIST instruction will temporarily suspend the listing, that is, source lines following the instruction will not be included in the listing until either the end of the source line is reached or a .LIST instruction (which re-enables the listing) is found.

Suppressing false conditional blocks in listings

By default conditional blocks that evaluate to false will be included in listings, but this is configurable. The following mechanisms are available:

  • The --no-listing-false-conditionals Nestor80 argument will set the initial state to "suppress false conditional blocks in the listing".
  • The .LFCOND instruction will insruct Nestor80 to include false conditional blocks in listings.
  • The .SFCOND instruction will insruct Nestor80 to suppress false conditional blocks from listings.
  • The .TFCOND instruction will insruct Nestor80 to toggle (invert) the inclusion or supression of false conditional blocks in listings, but based on the initial state or on the state set by the previous .TFCOND instruction; previous executions of .LFCOND and .SFCOND are not taken in account.

Suppressing macro expansions in listings

By default, when Nestor80 is listing a macro expansion it will only include the source lines that generate output (so it won't include comment-only lines or any lines that aren't CPU instructions or DEFB, DEFS etc lines). The following instructions are available to configure this behavior:

  • .LALL instructs Nestor80 to include all macro expansion lines in listings.
  • .SALL instructs Nestor80 to not include macro expansions at all in listings.
  • .XALL instructs Nestor80 to go back to the default behavior (list only macro expansion lines that generate output).

Additional Nestor80 arguments for listings

Additionally to the Nestor80 arguments already mentioned, the following ones are available to configure the listing generation process:

  • --listing-file-encoding: the character encoding that will be used to generate the listing file, default is UTF-8.
  • --no-listing-include-code: don't actually include the source code in the listing file (list only symbols and macros).
  • --no-listing-include-symbols: don't include symbols, macros or SDCC areas in the listing file.
  • --end-of-line: use the specified end of line character sequence (CRLF, CR or LF) instead of the system default sequence.

Assembler instructions reference

This section lists all the assembler instructions supported by Nestor80. Any instruction alias is listed together with the "canonical" instruction name.

® Additionally to the document-wide icons, an "R" symbol next to an instruction name means that the instruction is relevant only when writing relocatable code. If you only write code intended to be assembled as absolute you can skip the documentation for these instructions. See "Absolute and relocatable code" and "Writing relocatable code".

💡 Some of the instructions with ® can be used only when building MACRO-80 relocatable files or only when building SDCC relocatable files. This is specified in the description of each instruction.

Some instructions have aliases. In most cases these come inherited from MACRO-80, which in turn implemented them for compatibility with even older assemblers. Except where otherwise stated, the syntax for the aliases is exactly the same as the one for the "canonical" instruction.

Instruction arguments are specified using the standard notation <argument>. A few instructions require an argument to be passed surrounded by literal angle brackets, in these cases thes angle brackets are specified as "<" and ">", see for example IFB.

💡 If the --accept-dot-prefix argument is passed to Nestor80 then it's possible to write all the instructions listed here prefixed with a dot (.), except those that have a dot prefixing its name already. For example .ORG will be accepted as an alias for ORG. This may be useful when assembling code written for other assemblers.

.COMMENT

Syntax: .COMMENT <delimiter><text><delimiter>

Defines a block of comment text with support for multiple lines. The first character found after the instruction will be considered the delimiter, and all text found in the source code until the delimiter is found again will be considered a comment and not processed. Example:

.comment * Here we go!

This is a comment, anything until another asterisk is found is ignored.

*

ld a,34 ;Regular code again

The entire line where the closing delimiter is found will be considered as part of the comment and thus ignored:

.comment *

Blah blah

* This is still ignored!

ld a,34 ;Regular code again

.CPU 🆕

Syntax: .CPU <cpu name>

Changes the target CPU for the assembled code. The initial CPU is the Z80 by default, but this can be changed with the Nestor80 argument --default-cpu.

Currently the supported CPUs are Z80 (default), R800 and Z280. Setting the R800 as the target CPU simply enables the MULUB and MULUW instructions:

MULUB A,A
MULUB A,B
MULUB A,C
MULUB A,D
MULUB A,E
MULUB A,H
MULUB A,L
MULUW HL,BC
MULUW HL,DE
MULUW HL,HL
MULUW HL,SP

Setting the Z280 as the target CPU enables all the new Z280 instructions. There's a mechanism to disable the Z280 privileged instructions and the I/O instructions, this is useful when assembling code intended to run in the Z280 user mode. See "Z280 support".

The Z80 undocumented instructions are always supported.

.CREF 🚫

Syntax: .CREF

In MACRO-80 this instruction enabled the inclusion of cross-reference information when generating a listing file. Nestor80 doesn't implement cross-reference information generation and thus this instruction does nothing.

.DEPHASE

Syntax: .DEPHASE

Marks the end of a phased code block. See .PHASE.

.ERROR 🆕

Syntax: .ERROR ["]<text>["]

Emits an assembly error with the specified text. The text supports expression interpolation.

When one or more errors are emitted in pass 1, pass 2 will be skipped. See "Passes", "Strings in messages for the assembler console".

.FATAL 🆕

Syntax: .FATAL ["]<text>["]

Throws an fatal error with the specified text. The text supports expression interpolation.

A fatal error will terminate the assembly process immediately. See also "Strings in messages for the assembler console".

.LALL

Syntax: .LALL

Instructs Nestor80 to include the complete macro text for expanded macros in listings following the instruction. The default initial condition (also set by .XALL) is to include only the source lines that produce any output in the target file (assembler instructions and DEFB, DEFW etc). See .XALL, .SALL, "Macros", "Listings".

.LFCOND

Syntax: .LFCOND

Instructs Nestor80 to include conditional blocks that evaluate as false in listings for all the matching blocks following the instruction. This is the default initial condition unless a --no-listing-false-conditionals argument is supplied to Nestor80. See also .LFCOND, .TFCOND, "Conditional blocks", "Listings".

.LIST

Syntax: .LIST

Instructs Nestor80 to include all the source code text following the instruction. This is the default initial condition when Nestor80 is instructed to generate a listing file with the --listing-file argument. See also .XLIST, "Listings".

.PHASE

Syntax: .PHASE <address>

Starts a phased code block. A phased code block is a set of instructions that are intended to be run at a different memory address (indicated by the <address> argument) than the one dictated by the current location counter. .DEPHASE is used to mark the end of a phased code block.

For example, assume that you have the following code in ROM starting at address 4000h and you have RAM starting at address 8000h. Your ROM is banked, with the bank number selected via Z80 port 10h. This is the code that you could use to calculate the 1 byte checksum of a given bank, together with the addresses and output generated for reference:

8000                  RAM_BUFFER equ 8000h
                    
                      org 4000h
                    
4000    21 13 40      ld hl,CALCULATE_CHECKSUM
4003    11 00 80      ld de,8000h
4006    01 1A 00      ld bc,CALCULATE_CHECKSUM_END - CALCULATE_CHECKSUM
4009    ED B0         ldir
                    
400B    3E 01         ld a,1
400D    CD 00 80      call RAM_BUFFER
4010    C3 2D 40      jp MORE_CODE
                    
                    ;Calculate the 1-byte checksum of a ROM bank.
                    ;Input:  A = ROM bank number
                    ;Output: A = Checksum
4013                CALCULATE_CHECKSUM:
                      .phase RAM_BUFFER
                    
8000    D3 10         out (10h),a
8002    16 00         ld d,0
8004    21 00 40      ld hl,4000h
8007    01 00 40      ld bc,4000h
                    
800A                LOOP:
800A    7E            ld a,(hl)
800B    82            add a,d
800C    57            ld d,a
800D    23            inc hl
800E    0B            dec bc
800F    78            ld a,b
8010    B1            or c
8011    C2 0A 80      jp nz,LOOP
                    
8014    3E 00         ld a,0
8016    D3 10         out (10h),a  ;Assume the ROM bank number of the caller was 0
                    
8018    7A            ld a,d
8019    C9            ret
                    
                      .dephase
402D                CALCULATE_CHECKSUM_END:
                    
                      ;Location counter from before .PHASE is restored here,
                      ;appropriately updated by the size of the phased block
402D                MORE_CODE:
402D    3E 22         ld a,34

Although the starting address of a phased block will normally be an absolute address, using relocatable addresses is also allowed:

0000'                 dseg
                      org 1000h
1000"               FOO:
                  
1000"                 cseg
                  
0000'   3E 22         ld a,34
                  
                      .phase FOO
1000"   00 01 02      db 0,1,2
                      .dephase
                  
0005'   3E 59         ld a,89

🚫 There are two restrictions for phased blocks that weren't present in MACRO-80:

  1. The value of <address> must be known by the time the .PHASE statement is reached (it can't be an expression containing a symbol that is defined later in code).
  2. Segment/area change instructions (AREA, ASEG, CSEG, DSEG, COMMON) aren't allowed inside a phased block.

The second one is something that doesn't seem to be supported by MACRO-80 anyway: even though no errors are emitted, the location counter gets an incorrect value after a segment change instruction inside a phased block.

.PRINT 🆕

Syntax: .PRINT ["]<text>["]

Prints a text to the terminal where the assembler is running (unless the --silence-assembly-print argument was passed to Nestor80). The message supports expression interpolation.

The text will be printed in both pass 1 and pass 2. Normally you'll want to print the text only in one of the passes, so you should either wrap the .PRINT instruction in an IF1 or IF2 block, or use the .PRINT1 or .PRINT2 instruction instead. See "Passes", "Strings in messages for the assembler console".

.PRINT1 🆕

Syntax: .PRINT1 ["]<text>["]

Like .PRINT, but only prints the text in pass 1. See "Passes".

.PRINT2 🆕

Syntax: .PRINT1 ["]<text>["]

Like .PRINT, but only prints the text in pass 2. See "Passes".

.PRINTX

Syntax: .PRINTX <delimiter><text>[<delimiter>]

Prints a text to the terminal where the assembler is running (unless the --silence-assembly-print argument was passed to Nestor80). The first character of the text is considered a delimiter, and the text is printed until either the delimiter is found again or the end of the line is found (the delimiters themselves are printed too). For example .PRINTX /Foo prints /Foo, and .PRINTX /Foo/bar prints /Foo/.

This instruction is provided for compatibility with MACRO-80. New programs should use .PRINT, .PRINT1 or .PRINT2 instead, which don't need a delimiter and support expression interpolation and escape sequences in the text.

.RADIX

Syntax: .RADIX <value>

Changes the default radix for the numeric constants that don't have a radix suffix. <value> must evaluate to a number between 2 and 16, and the default radix for numeric constants in <value> is 10 regardless of the current default radix.

Example:

defb 12      ;12

.radix 16
defb 12      ;18

.radix 2
defb 1010    ;10

.RELAB 🆕

Syntax: .RELAB

Enables the relative labels feature. See also .XRELAB.

.REQUEST ®

Syntax: .REQUEST <filename>[,<filename>[,...]]

⚠ This instruction can be used only when buidling a MACRO-80 relocatable file.

Defines a list of files in which the linker will search for any globals that remain undefined during the linking process. Filenames can't contain an extension (.REL extension is assumed) nor any drive or directory specification; additionally, when using the --link-80-compatibility argument filenames must be up to 7 characters long and contain only ASCII letters.

.SALL

Syntax: .SALL

Instructs Nestor80 to not include macro expansions in listings following the instruction. The default initial condition (also set by .XALL) is to include only the source lines that produce any output in the target file (assembler instructions and DEFB, DEFW etc). See .XALL, .LALL, "Macros", "Listings".

.SFCOND

Syntax: .SFCOND

Instructs Nestor80 to not include conditional blocks that evaluate as false in listings for all the matching blocks following the instruction. See also .LFCOND, .TFCOND, "Conditional blocks", "Listings".

.STRENC 🆕

Syntax: .STRENC <encoding name>|<encoding page>|default

Sets the character encoding to be used to transform strings to sequences of bytes, typically for the DEFB instruction.

The encoding name or page must be one of the encodings supported by the system where Nestor80 is running. Running Nestor80 with the --list-encodings argument will show a list of the available encodings; each encoding has an unique name and an unique page number and either of the two can be used to identify the encoding. Encoding names are case-insensitive.

The default encoding is 7 bit ASCII unless a different encoding is specified by passing a --string-encoding argument to Nestor80. .STRENC default will revert to this default encoding.

💡 The encoding name ASCII is accepted as an alias for the default 7 bit ASCII encoding (whose "official" name is US-ASCII).

See also: "Strings".

.STRESC 🆕

Syntax: .STRESC ON|OFF

Turns on or off the support for escape sequences in strings delimited by double quotes, ". Escape sequences are enabled by default unless a --no-string-escapes argument is passed to Nestor80.

Turning off escape sequences may be needed when compiling old source code intended for MACRO-80 in which the backslash character \ is considered a regular character and not an escape sequence initiator. New programs should leave string escaping turned on and take advantage of the escape sequence support as needed.

See "Strings" for a list of the available escape sequences.

.TFCOND

Syntax: .TFCOND

Instructs Nestor80 to toggle the inclusion of conditional blocks that evaluate as false in listings, from on to off or the other way around, for all the matching blocks following the instruction.

The state that gets toggled is the one that was set by the previous instance of .TFCOND (any state change performed with .LFCOND or .SFCOND is ignored). The initial state is "on" unless a --no-listing-false-conditionals argument is passed to Nestor80.

See also .LFCOND, .SFCOND, "Conditional assembly", "Listings".

.WARN 🆕

Syntax: .WARN ["]<text>["]

Emits an assembly warning with the specified text. The text supports expression interpolation.

The warning will be emitted twice, once in pass 1 and once in pass2. If that's undesirable you can enclose the instruction in an IF1 or IF2 block. See "Passes", "Strings in messages for the assembler console".

.XALL

Syntax: .XALL

Instructs Nestor80 to include macro expansions in listings following the instruction, but only including the source lines that produce any output in the target file (assembler instructions and DEFB, DEFW etc); this is the default state for macro expansions in listings. See .SALL, .LALL, "Macros", "Listings".

.XCREF "🚫"

Syntax: .XCREF

In MACRO-80 this instruction disabled the inclusion of cross-reference information when generating a listing file (which had been enabled with .CREF). Nestor80 doesn't implement cross-reference information generation and thus this instruction is a no-op.

.XLIST

Syntax: .XLIST

Instructs Nestor80 to suppress the inclusion in listings of the source code text that follows the instruction, until either the end of the file (or an END instruction) is reached or a .LIST instruction is encountered. See also "Listings".

.XRELAB 🆕

Syntax: .XRELAB

Disables the relative labels feature. See also .RELAB.

.Z80

Syntax: .Z80

Sets the Z80 as the current target CPU. This instruction is provided for compatibility with MACRO-80, new programs should use .CPU Z80 instead.

AREA (.AREA) ®

Syntax: AREA <name> [({ABS|REL}[,{CON|OVR}])]

Aliases: .AREA

⚠ This instruction can be used only when buidling a SDCC relocatable file.

⚠ The syntax of this command is the same as the command of the same name in the SDAS assembler, however Nestor80 doesn't support paged areas and thus the PAG argument isn't available.

Switches to the code area with the specified name. Area names are case-insensitive.

There are two configurable parameters when defining an area (an area gets defined when it's switched to for the first time):

  • Absolute or relocatable. Code in an absolute area will be assembled at a fixed address, the final address for code in relocatable areas will be decided at linking time.
  • Concatenable or overlay. This defines what will the linker do when encountering multiple pieces of code defined in areas with the same name: if the area is defined as concatenable, then all the pieces will be concatenated together; if the area is defined as overlay, then each piece will be placed on top of the previous one.

Put it another way: when an already existing area is switched to, the location counter is set to the last used value for the area if it's concatenable, or reset to zero if it's overlay.

💡 Absolute areas are functionally equivalent to the ASEG area when building MACRO-80 relocatable files; relocatable concatenable areas are equivalent to the CSEG and DSEG areas (but you can define as many areas as you want); and relocatable overlay areas are equivalent to COMMON blocks.

The default value if no ABS/REL is specified is REL. For CON/OVR, the default is CON. So:

  area DATA           ;equivalent to: area DATA (REL,CON)
  area DATA (ABS)     ;equivalent to: area DATA (ABS,CON)
  area DATA (REL,OVR) ;when specifying OVR the initial ABS/REL is mandatory

⚠ An absolute area will always be effectively handled as overlay, even if defined as concatenable.

When switching again to an already defined area, either it must have no ABS/REL and CON/OVR specifiers (and thus it inherits the values from the definition), or it must have the same values used in the definition:

  area DATA (REL,OVR)
  area DATA            ;Ok, area is still (REL,OVR)
  area DATA (REL,OVR)  ;Ok, same definition
  area DATA (ABS,OVR)  ;Error!
  area DATA (REL,CON)  ;Error!
  area DATA (REL)      ;Error! (assumes CON in definition)

When the assembly process starts one single area exists, named _CODE and defined as (REL,CON). You can switch back to this area at any time, but you can't redefine it to be ABS or OVR.

See the ORG instruction for details about an important nuance regarding area names when using ORG statements.

See "SDCC relocatable file format support" for more details about building SDCC relocatable files.

ASEG ®

Syntax: ASEG

⚠ This instruction can be used only when buidling a MACRO-80 relocatable file.

Switches to the absolute segment and sets the location counter to the value it had the last time that segment was switched off with CSEG, DSEG or COMMON (or to zero, if it's the first time this instruction is used).

Example:

aseg
;Location counter here: absolute segment 0000h

org 100h
db 1,2,3,4
;Location counter here: absolute segment 0104h

cseg
db 10,20,30,40
dseg
db 50,60,70,80

ASEG
;Location counter here: absolute segment 0104h

COMMON ®

Syntax: COMMON /[<name>]/

⚠ This instruction can be used only when buidling a MACRO-80 relocatable file.

Switches to the COMMON block of the specified name and sets the location counter to zero (not to the last known location counter value for the block, this behavior is compatible with MACRO-80). The COMMON block name must be enclosed in two / characters (that aren't part of the name), is case-insensitive, and can be empty.

Example:

common /foo/
;Location counter here: COMMON FOO 0000h

org 100h
db 1,2,3,4
;Location counter here: COMMON FOO 0104h

common //
;Location counter here: COMMON (empty) 0000h

common /FOO/
;Location counter here: COMMON FOO 0000h

CONTM 🆕

Syntax: CONTM

This instruction is intended to be used inside macro definitions. In named macro expansions it's equivalent to .EXITM, in repeat macros it exits the current repetition immediately and then starts over at the next repetition (if there are more repetitions remaining), unlike .EXITM which discards any remaining repetition.

Example:

rept 3
db 1
db 2
contm
db 3
db 4
endm

;Generated code:

db 1
db 2
db 1
db 2
db 1
db 2

CSEG ®

Syntax: CSEG

⚠ This instruction can be used only when buidling a MACRO-80 relocatable file.

Switches to the code segment and sets the location counter to the value it had the last time that segment was switched off with CESG, DSEG or COMMON. The code segment is switched on with the location counter set to zero at the start of the source code processing.

Example:

;Location counter here: code segment 0000h

org 100h
db 1,2,3,4
;Location counter here: code segment 0104h

aseg
db 10,20,30,40
dseg
db 50,60,70,80

cseg
;Location counter here: code segment 0104h

DEFB (DB, DEFM)

Syntax: DEFB <expression or string>[,<expression or string>[,...]]

Aliases: DB, DEFM

Defines a sequence of or more raw bytes to be included in the output. Each item must be either an expression that can be evaluated to a byte, or a string; strings are converted to sequences of bytes using the current character encoding.

Example:

FOO equ 10h

.strenc ASCII
DEFB 0FF34h,FOO*2,"ABC\r\n"

;Sequence of bytes generated:
;34h,20h,41h,42h,43h,0Dh,0Ah

See also: "Expressions", "Strings".

DEFL (ASET)

Syntax: <name>[:] DEFL <value>

Aliases: ASET

Declares a redefinible constant with a given name. The constant can be used instead of the value in expressions, and can be redefined by using DEFL again with a different value. Example:

FOO: defl 30

defb FOO+4  ;Equivalent to 30+4

FOO: defl FOO+10 ;FOO equals 44 now

See "Named constants"

DEFS (DS)

Syntax: DEFS <size>[,<value>]

Aliases: DS

⚠ When buidling a SDCC relocatable file the <value> argument can't be used, and thus the syntax for this instruction is just DEFS <size>.

Defines a block of contiguous memory addresses of a given size, to be optionally filled with a repeated byte value.

Example with <value> specified:

defs 5,34

;Equivalent to:

defb 34,34,34,34,34

When <value> is not specified the output depends on the build type:

  • When the build type is absolute, DEFB <size> is equivalent to DEFB <size>,0.
  • When the build type is relocatable, by default DEFB <size> will generate an output equivalent to ORG $+<size>; that is, the location counter will be increased by the specified size and the block will be considered by the linker as a "memory gap" (how memory gaps are filled at linking time is undefined).
  • When the build type is MACRO-80 relocatable and a --initialize-defs argument is supplied to Nestor80, DEFB <size> is equivalent to DEFB <size>,0.

See "Absolute and relocatable code".

DEFW (DW)

Syntax: DEFW <expression or string>[,<expression or string>[,...]]

Aliases: DW

Defines a sequence of or more raw words (16 bit values) to be included in the output. Each item must be either an expression, or a string that gets converted to at most two bytes using the current character encoding. Expression values are stored in little endian format, and strings are stored as the second byte (of the output generated by the character encoding) first, then the first byte.

Example:

FOO equ 1200h

.strenc ASCII
defw 7,0ABCDh,FOO+34h,"A","BC"

;Sequence of bytes generated:
;07h,00h,CDh,ABh,34h,12h,41h,00h,43h,42h

See also: "Expressions", "Strings".

DEFZ (DZ) 🆕

Syntax: DEFZ <expression or string>[,<expression or string>[,...]]

Aliases: DZ

This instruction is equivalent to .DEFB, but appends the bytes that the current character encoding generates for the character \0 at the end of the generated sequence of bytes. This is useful to define zero-terminated strings without having to explicitly specify the zero character.

Example:

.strenc ASCII
defz "Hello"

;Equivalent to:

defb "Hello\0"

;...and (since ASCII converts \0 to a single 0 byte) to:

defb "Hello",0

DSEG ®

Syntax: DSEG

⚠ This instruction can be used only when buidling a MACRO-80 relocatable file.

Switches to the data segment and sets the location counter to the value it had the last time that segment was switched off with CSEG, ASEG or COMMON (or to zero, if it's the first time this instruction is used).

Example:

dseg
;Location counter here: data segment 0000h

org 100h
db 1,2,3,4
;Location counter here: data segment 0104h

cseg
db 10,20,30,40
aseg
db 50,60,70,80

dseg
;Location counter here: data segment 0104h

ELSE

Syntax: ELSE

Ends the true condition block of a conditional assembly block and starts the false condition block. See "Conditional assembly".

END

Syntax: END [<address>]

Ends the assembly process immediately, ignoring any source code remaining in the file.

The optional <address> argument is significant only when producing a MACRO-80 relocatable file, this address will be stored in the relocatable file as the program start address and it's up to the linker to use it during the linking process. When producing absolute files or SDCC relocatable files the argument will be ignored and a warning will be generated.

ENDIF

Syntax: ENDIF

Ends a conditional assembly block. See "Conditional assembly".

ENDM

Syntax: ENDM

Ends a macro definition, and for repeat macros it starts the macro expansion. See "Macros".

ENDMOD 🆕

Syntax: ENDMOD

Ends the current module. See "Modules".

ENDOUT 🆕

Syntax: ENDOUT

Instructs Nestor80 to stop generating output immediately while continuing to process the source code that follows the instruction (thus taking note of symbol definitions). This is useful as an alternative to constant definitions to define memory areas that don't need to be explicitly included in the output file.

Example:

org 100h

BUFFER_SIZE: equ 1024

ld hl,BUFFER
ld de,BUFFER+1
ld bc,BUFFER_SIZE-1
ld (hl),0
ldir

ld hl,1234h
ld (FLAGS),hl
ld a,89h
ld (FLAGS2),hl

ret

endout

org 8000h
BUFFER: ds BUFFER_SIZE
FLAGS: dw 0
FLAGS2:

Equivalent code without using ENDOUT:

org 100h

BUFFER_SIZE: equ 1024
BUFFER: equ 8000h
FLAGS: equ BUFFER+BUFFER_SIZE
FLAGS2: equ FLAGS+2

ld hl,BUFFER
ld de,BUFFER+1
ld bc,BUFFER_SIZE-1
ld (hl),0
ldir

ld hl,1234h
ld (FLAGS),hl
ld a,89h
ld (FLAGS2),hl

ret

EQU

Syntax: <name>[:] EQU <value>

Declares a fixed constant with a given name. The constant can be used instead of the value in expressions. Example:

FOO: equ 30

defb FOO+4  ;Equivalent to 30+4

A fixed constant can't be redefined: a second EQU with the same name and a different value will throw an error. Use DEFL if you want to declare a redefinible constant.

See "Named constants"

EXITM

Syntax: EXITM

This instruction is intended to be used inside macro definitions. It forces the macro expansion to terminate immediately, discarding any remaining repetition (unlike CONTM which starts over the next repetition, if any). See "Macros"

Example:

rept 3
db 1
db 2
exitm
db 3
db 4
endm

;Generated code:

db 1
db 2

EXTRN (EXT, EXTERNAL) ®

Syntax: EXTRN <symbol>[,<symbol>[,...]]

Aliases: EXT, EXTERNAL

Defines one or more symbol names as external, that is, they are supposed to be defined as public symbols by another relocatable program during the linking process. A symbol is also considered external if its name is followed by ## when it's referenced:

call FOO##

;Equivalent to:

extrn FOO
call FOO

Additionally, if the --unknown-symbols-external argument is passed to Nestor80 then any symbol that is still unknown at the end of pass 2 will be implicitly considered an external symbol.

See also PUBLIC.

IF (IFT, COND)

Syntax: IF <expression>

Aliases: IFT, COND

Starts a conditional assembly block in which the true condition is that <expression> evaluates to non-zero. The opposite instruction is IFF.

This instruction is typically used in macros and in combination with comparison operators. Example:

is_positive macro x

if (x) eq 0
  .print1 '&x' is zero
else
  if ((x) and 8000h) eq 8000h
    .print1 '&x' is negative
  else
    .print1 '&x' is positive
  endif
endif

endm

is_positive 1+1
is_positive 1-1
is_positive 1-2

This is what gets printed:

'1+1' is positive
'1-1' is zero
'1-2' is negative

⚠ You may be wondering why the previous example doesn't use if (x) gt 0 or if (x) lt 0 for the positive and negative cases. Nestor80 treats all numbers as unsigned integers, and thus if (x) lt 0 is never true. This behavior is compatible with MACRO-80.

See "Expressions", "Macros", "Conditional assembly".

IF1

Syntax: IF1

Starts a conditional assembly block in which the true condition is that the assembler is currently in pass 1. See "Passes", "Conditional assembly".

IF2

Syntax: IF2

Starts a conditional assembly block in which the true condition is that the assembler is currently in pass 2. See "Passes", "Conditional assembly".

IFABS 🆕

Syntax: IFABS

Starts a conditional assembly block in which the true condition is that the build type is absolute. The opposite instruction is IFREL. See "Absolute and relocatable code", "Conditional assembly".

⚠ If no build type is explicitly selected with the --build-type argument, before the build type is automatically selected both IFABS and IFREL will evaluate to false.

IFB

Syntax: IFB "<"<text>">"

Starts a conditional assembly block in which the true condition is that <text> is blank (has a zero length, including spaces). <text> must be surrounderd by angle brackets. The opposite instruction is IFNB.

IFB is typically used in macros in order to detect if a given argument is supplied. Example:

FOO macro x,y

ifb <x>
.error FOO: First argument is required!
endif

ifb <y>
.print FOO: No second argument passed.
else
.print FOO: Second argument passed: y
endif

endm

See "Conditional assembly", "Macros".

IFCPU 🆕

Syntax: IFCPU <cpu name>

Starts a conditional assembly block in which the true condition is that the current CPU is the one specified. The opposite instruction is IFNCPU. Example:

ifcpu R800
muluw hl,bc
else
call MULUW_HL_BC
endif

⚠ A non-existing CPU name passed as argument will evaluate to false and not throw any error.

IFDEF

Syntax: IFDEF <symbol>

Starts a conditional assembly block in which the true condition is that <symbol> is defined when the instruction is encountered. This may be useful in combination with the --define-symbols Nestor80 argument to externally alter how the code is assembled. The opposite instruction is IFNDEF.

⚠ Keep in mind that a symbol that gets defined in code is undefined before it's found in pass 1, but it's already defined when pass 2 starts:

.print2 Pass 2 started!

.print Before EQU...

ifdef foo
.print1 "Foo" is defined in pass 1
.print2 "Foo" is defined in pass 2
else
.print1 "Foo" is NOT defined in pass 1
.print2 "Foo" is NOT defined in pass 2

endif

foo equ 1

.print After EQU...

ifdef foo
.print1 "Foo" is defined in pass 1
.print2 "Foo" is defined in pass 2
else
.print1 "Foo" is NOT defined in pass 1
.print2 "Foo" is NOT defined in pass 2
endif

This is what gets printed:

Before EQU...
"Foo" is NOT defined in pass 1
After EQU...
"Foo" is defined in pass 1
Pass 2 started!
Before EQU...
"Foo" is defined in pass 2
After EQU...
"Foo" is defined in pass 2

See "Passes", "Conditional assembly".

IFDIF

Syntax: IFDIF "<"<text1>">","<"<text2>">"

This instruction is the opposite of IFIDN: the true condition is that <text1> is not identical to <text2>, including any spaces.

See "Conditional assembly".

IFDIFI 🆕

Syntax: IFDIFI "<"<text1>">","<"<text2>">"

This instruction is the opposite of IFIDNI: the true condition is that <text1> is not identical to <text2>, including any spaces, with the comparison being done in a case-insensitive way.

See "Conditional assembly".

IFF (IFE)

Syntax: IFF <expression>

Aliases: IFE

This instruction is the opposite of IF: the true condition is that <expression> evaluates to zero.

See "Conditional assembly".

IFIDN

Syntax: IFIDN "<"<text1>">","<"<text2>">"

Starts a conditional assembly block in which the true condition is that <text1> is identical to <text2>, including any spaces. The texts must be surrounderd by angle brackets. The opposite instruction is IFDIFF.

Example:

compare macro x,y

ifidn <x>,<y>
.print1 '&x' is identical to '&y'
else
.print1 '&x' is NOT identical to '&y'
endif

endm

compare foo,bar
compare foo,foo
compare foo,FOO

This is what gets printed:

'foo' is NOT identical to 'bar'
'foo' is identical to 'foo'
'foo' is NOT identical to 'FOO'

See "Conditional assembly".

IFIDNI 🆕

Syntax: IFIDNI "<"<text1>">","<"<text2>">"

This instruction is equivalent to IFIDN, except that the comparison of <text1> and <text2> is done in a case-insensitive way. The opposite instruction is IFDIFI.

Example:

compare macro x,y

ifidni <x>,<y>
.print1 '&x' is case-insensitive identical to '&y'
else
.print1 '&x' is NOT case-insensitive identical to '&y'
endif

endm

compare foo,bar
compare foo,foo
compare foo,FOO

This is what gets printed:

'foo' is NOT case-insensitive identical to 'bar'
'foo' is case-insensitive identical to 'foo'
'foo' is case-insensitive identical to 'FOO'

See "Conditional assembly".

IFNB

Syntax: IFNB "<"<text>">"

This instruction is the opposite of IFB: the true condition is that <text> is not blank (it has a non-zero length, including spaces).

See "Conditional assembly".

IFNCPU

Syntax: IFNCPU <cpu name>

This instruction is the opposite of IFCPU: the true condition is that the current CPU is not the specified one.

⚠ A non-existing CPU name passed as argument will evaluate to true and not throw any error.

See "Conditional assembly".

IFNDEF

Syntax: IFNDEF <symbol>

This instruction is the opposite of IFDEF: the true condition is that the symbol is not defined when the instruction is encountered.

See "Conditional assembly".

IFREL 🆕 ®

Syntax: IFREL <symbol>

This instruction is the opposite of IFABS: the true condition is that the build type is relocatable. See "Absolute and relocatable code", "Conditional assembly".

⚠ If no build type is explicitly selected with the --build-type argument, before the build type is automatically selected both IFABS and IFREL will evaluate to false.

INCBIN 🆕

Syntax: INCBIN <file path>

Allows to include the raw contents of an arbitrary file in the output, as if the file contents had been defined with DEFB. For example if you create an ABC.BIN file whose content is just the text ABC, and assuming it's saved with ASCII encoding, then INCBIN ABC.BIN is equivalent to DEFB 41h,42h,43h.

At most 64KBytes will be read from the file when assembling relocatable code and when assembling absolute code with the "memory map" strategy, and at most 1MByte when assembling absolute code with the "direct output file write" strategy. See "Absolute output strategies".

The rules for specifying file paths with spaces and double quotes and for resolving relative file paths are the same as for INCLUDE.

INCLUDE ($INCLUDE, MACLIB) ✨

Syntax: INCLUDE <file path>

Aliases: $INCLUDE, MACLIB

Starts assembling code read from the specified file. When the end of the file is reached, assembly continues from the line next to the INCLUDE instruction in the original source file.

The file include mechanism in Nestor80 implements two important enhancement compared to MACRO-80:

  1. <file path> accepts full and relative path specifications (with directory and drive -if supported by the operating system where Nestor80 is running- specifications), not just plain file names.
  2. Nested file inclusions (the included file can have in turn INCLUDE instructions) are supported up to 34 depth levels.

If <file path> contains spaces it must be enclosed in double quotes, ". If the file contains both spaces and double quotes, enclose the file name in " as described, then escape the double quotes that are part of the path by doubling them, "". Examples:

include file.asm
include "file with spaces.asm"
include FileWith"Quotes".asm
include "file with spaces and ""quotes"".asm"

When <file path> is a relative path the file is searched for by considering the path relative to the following locations, in the specified order:

  1. The current directory (in the terminal where Nestor80 was run).
  2. The directory of the source file where the INCLUDE instruction was found.
  3. Any extra directories passed to Nestor80 with --include-directory, in the order in which they were specified.

For example, if Nestor80 is run like this:

~/temp$ N80 projects/SuperGame/main.asm --include-directory ~/libs --include-directory ~/extra

...and main.asm contains this line:

INCLUDE data/graphics.asm

...then Nestor80 will search for graphics.asm using the following full paths, in that order:

  1. ~/temp/data/graphics.asm
  2. ~/projects/SuperGame/data/graphics.asm
  3. ~/libs/data/graphics.asm
  4. ~/extra/data/graphics.asm

💡 Always use the regular slash, /, as the directory separator in paths for INCLUDE. This character is widely recognized as the standard directory separator in all operating systems, and yes, it also works in Windows.

IRP

Syntax: IRP <placeholder>,"<"<argument>[,<argument>[,...]]">"

Starts a "repeat macro with arguments" macro, where the macro body is repeated for each of the passed arguments, replacing <placeholder> with the argument. The angle brackets around the arguments list are mandatory.

Example:

irp x,<1,2,3>
db x
endm

Equivalent code assembled:

db 1
db 2
db 3

See "Macros".

IRPC

Syntax: IRPC <placeholder>,["<"]<characters>[">"]

Starts an "indefinite repeat for characters" macro, where the macro body is repeated for each of the characters of the passed character sequence. The angle brackets around the arguments list are optional, but you'll need them if you want to add spaces in the list.

Example:

irpc x,123
db x
endm

irpc x,<A B>
db "&x"
endm

Equivalent code assembled:

db 1
db 2
db 3
db "A"
db " "
db "B"

See "Macros".

IRPS 🆕

Syntax: IRPC <placeholder>,<string>

Starts an "indefinite repeat for characters" macro, where the macro body is repeated for each of the characters of the passed string. The string has the same format as strings used in expressions, including the support or lack of it for escape sequences.

Example: IRPS x,"\x41\x42" will generate the same code as IRPC x,AB (provided that escape sequences in strings aren't disabled).

⚠ Not all escape sequences are supported. For example \r will insert a literal line break at the point where the placeholder is encountered, and this will cause either errors or the line to not generate any output.

See "Strings", "Macros".

LOCAL

Syntax: LOCAL <symbol>[,<symbol>[,...]]

Used in named macros to declare one or more symbols as local to the macro expansion. See "Local symbols", "Macros".

MAINPAGE 🆕

Syntax: MAINPAGE

Forces a main page change when generating a listing, equivalently to when a \f character (0Ch in ASCII) is found in the source code. See "Listings".

MODULE 🆕

Syntax: MODULE <name>

Starts a new module with the specified name. See "Modules".

NAME ®

Syntax: NAME('<program name>')

Specifies the program name, which will be set as such in the generated relocatable file. When using the --link-80-compatibility argument program names are limited to 6 characters in length and ASCII letters only.

If no program name is explicitly supplied, the program name is taken from the last TITLE instruction used. If neither NAME nor TITLE instructions are present in the code, the program name is taken from the source code file name.

This instruction has no effect when generating absolute code.

See "Writing relocatable code".

ORG

Syntax: ORG <address>

⚠ When buidling a SDCC relocatable file this instruction can only be used inside absolute areas.

Changes the current location counter, that is, the memory address in which the output is to be generated moving forward in the target program.

When assembling absolute code the ORG instruction found with the smallest address value is the "base" address of the file, and subsequent ORGs move the location counter accordingly inside the output file relative to this base, filling any gaps with zeros. For example:

org 20
db 1,2,3
org 15
db 4,5,6

The contents of the generated output file will be: 4,5,6,0,0,1,2,3.

If the --direct-output-write argument is passed to Nestor80 all the ORG statements will be treated as .PHASE statements, this means that ORGs will be taken in account to assign the appropriate values to labels, but not to decide the placement of the output in the output file: all the file contents will be generated sequentially. In the previous example, the generated file output with --direct-output-write would be simply 1,2,3,4,5,6. See "Absolute output strategies".

When building a MACRO-80 relocatable file any ORG statements found inside the absolute segment refer to absolute addresses, but addresses for ORG statements found in the code segment, the data segment or a COMMON block are relative to where these segments will end up being assembled in the final program. For example:

dseg
org 20h
FOO:

If the resulting relocatable file is linked with the data segment starting at address 100h, then the FOO label will refer to address 120h in the final binary file generated by the linker.

The above is true when linking one single relocatable file; when linking two or more it's a bit more complicated since ORG refer to the starting address of each segment in each program. See "Writing relocatable code" for the full details.

💡 The build type is by default selected automatically based on what instructions are found (or not found) before the first ORG instruction in the source code. See "Absolute and relocatable code".

💡 When building a SDCC relocatable file absolute areas are always defined as starting at address 0, and ORG instructions actually create a new area whose name is the one of the current area plus an increasing hexadecimal, lower-case suffix that begins at zero (there's one single suffix sequence that is shared by all area names) and has the specified address as the area staring address. These are otherwise regular absolute areas that can be switched to in code, but not redefined.

For example, the following code

  .area ONE_AREA (ABS)
  .org 0x100
  .org 0x200
  .area OTHER_AREA (ABS)
  .org 0x300
  .org 0x400
  .area ONE_AREA
  .org 0x500
  .org 0x600
  .area OTHER_AREA
  .org 0x700
  .org 0x800
  .area ONE_AREA
  .org 0x900
  .org 0xA00
  .area OTHER_AREA
  .org 0xB00
  .org 0xC00

will generate the following sequence of areas:

ONE_AREA at 0
ONE_AREA0 at 0x100
ONE_AREA1 at 0x200
OTHER_AREA at 0
OTHER_AREA2 at 0x300
OTHER_AREA3 at 0x400
ONE_AREA4 at 0x500
ONE_AREA5 at 0x600
OTHER_AREA6 at 0x700
OTHER_AREA7 at 0x800
ONE_AREA8 at 0x900
ONE_AREA9 at 0xA00
OTHER_AREAa at 0xB00
OTHER_AREAb at 0xC00

PAGE (SUBPAGE 🆕, $EJECT)

Syntax: PAGE [<new page size>]

Aliases: SUBPAGE, $EJECT

Forces a subpage change when generating a listing. Additionally, if <new page size> is supplied this value becomes the new listing page size in text lines. The default page size is 50, the minimum is 10, and there's no maximum ✨ (the maximum was 255 in MACRO-80).

The SUBPAGE alias is introduced in Nestor80 because the word "PAGE" doesn't clearly convey the fact that what is changing is the _sub_page number. It's recommended to combine it with the new MAINPAGE instruction if both main page changes and sub page changes are required for listings.

See "Listings".

PUBLIC (ENTRY, GLOBAL) ®

Syntax: PUBLIC <symbol>[,<symbol>[,...]]

Aliases: ENTRY, GLOBAL

Defines one or more symbol names as public, that is, they will be exposed to other relocatable programs (that can reference them as external) during the linking process. A label is also considered public if its name is followed by :: when it's declared; for declaring other symbols (e.g. constants) as public the only option is to use the PUBLIC instruction.

Example:

FOO::

;Equivalent to:

public FOO
FOO:

See also EXTRN.

REPT

Syntax: REPT <count>

Starts a "repeat with count" macro. All the lines inside the macro body will be repeated <count> times.

Example:

rept 3
defb 1
defb 2
endm

Equivalent code assembled:

defb 1
defb 2
defb 1
defb 2
defb 1
defb 2

See "Macros".

ROOT 🆕

Syntax: ROOT <symbol>[,<symbol>[,...]]

This instruction must appear inside a module. It's used to declare one or more symbols that will be considered as a "root" symbol, that is, not relative to the module; thus when these symbols are referenced they won't be prepended with the module name before being evaluated. Another option to achieve the same effect is to prepend the symbol names with a colon, :, when they are referenced. See "Modules".

SUBTTL ($TITLE)

Syntax: SUBTTL <text>

Aliases: $TITLE

Sets the subtitle to be used in the heading of each page of a listing (as the second line of text, right after the title). There's no limit for the length of <text> ✨ (in MACRO-80 the text gets truncated to the first 60 characters). See TITLE, "Listings".

Note: the syntax for the $TITLE alias is $TITLE('<text>').

TITLE

Syntax: TITLE <text>

Sets the title to be used in the heading of each page of a listing, as the very first line of text (together with the Nestor80 version number).

The argument given to TITLE will also be used, after being truncated to 6 characters, as the program name when generating a relocatable file, unless an explicit program name is supplied with NAME. If neither a program name nor a listing title are present in the source code, the program name will be composed from the source code file name.

See SUBTTL, "Listings".