Assembly Syntax Overview
Assembly code is a line oriented language, similar to languages like BASIC, FORTRAN, COBOL and many scripting languages. Each assembly code line divides into 4 major components:
Labels always start in the first column. Labels give a name to an address or a value. The assembler resolves labels into numbers when it assembles the program. There are two sorts of labels:
- Global labels. These start with one of these characters—
a-zA-Z!&_^~.—followed by zero or more of these:
0-9a-zA-Z!&_^~.Examples: "FOO", "abc", "_a1", ".blah".
- Local labels. These start with two @ signs, such as "@@loop". These labels are local to a PROC section. See the PROC directive below.
Other properties of labels:
- Labels must have distinct names from instruction mnemonics, directives and operators (defined below).
- Labels optionally may be followed by a colon or by white space. That is, both "foo" and "foo:" are allowed.
Labels are optional in most cases. Some directives, such as PROC, EQU and SET require a label.
Instructions and Directives
The next field is the instruction/directive field. Instructions and directives are always preceded by at least one white-space character, or a label with a colon. The CP1610 page lists all of the instructions.
Many instructions have two operands. In CP1610 assembly code, the last operand is generally the "destination" of the result, and the operands before it are "sources." For example:
ADDR R0, R1 ; Compute "R0 + R1" and put the result in "R1".
A couple instructions, like JSR don't quite fit that model:
JSR R5, foo ; Jump to "foo", and put return address in "R5."
ROMW: Sets the current "ROM width." In most cases, you can use "ROMW 16", which is also the default. Set this once per program.
ORG: Sets the current "origin," that is, the address that the assembler is currently assembling at.
INCLUDE: Copies in an outside file into the current assembly. Makes it easy to factor a large program into many files.
PROC / ENDP: These define sections of code. They are useful primarily for defining a scope for local variables. Must be used with a label.
DECLE: Outputs one or more words of data to the ROM. Can be followed by comma separated expressions and strings.
STRINGis a synonym.
BIDECLE: Similar to DECLE, except it writes words as pairs of bytes. For each word, it writes the lower byte first and the upper byte second. It's most useful with data read using SDBD.
EQU: Sets a label to a value, and therefore must be used with a label. Often useful for giving meaningful names to memory locations and other constants. Values set by EQU cannot be changed.
SET: Similar to EQU, except that the value assigned to the label can be changed later. This can be useful with the REPEAT directive to compute complicated expressions.
REPEAT / ENDR: Repeats a block of code multiple times. The repeated code is merely replayed for the assembler as if you had cut and pasted it the specified number of times. Useful for unrolling loops or computing complicated expressions at assembly time.
IF / ELSE / ENDI: Conditional assembly directives. Useful for guarding pieces of code from being assembled, or otherwise controlling the assembly process based on the values of some labels.
The example at the end shows each of these in use.
Using PROC / ENDP
PROC sections bear special mention. PROC is short for "procedure." The PROC directive indicates the start of a "local" name space. Local labels, those starting with "@@", become local to that section. Within that section, those labels may be referred to by their "@@" name.
Local labels also get a corresponding global name. The assembler strips off the @@, and prepends the PROC's name and a period. This makes it easy to refer to a PROC's local labels, and a handy way of grouping sets of names.
;; Loop 42 times and return FOO PROC MVII #42, R0 @@loop: DECR R0 BNEQ @@loop JR R5 ENDP ;; Loop 57 times and return BAR PROC MVII #57, R0 B FOO.loop ; Reuse FOO's loop. ENDP
In this example, the branch in FOO refers the local label "@@loop" by its local name. The branch in BAR refers to the same label by its global name, "FOO.loop".
Comments are optional, but recommended. Comments start with a semicolon '
;', and end at the end of the line. Comments can start anywhere on a line, including the first column.
Expressions are mathematical statements consisting of one or more numbers or labels, connected by various operators. Most expressions evaluate down to a single value. One special case is the "string expression", which expands to a list of words. String expressions are only valid in a limited number of contexts.
The assembler accepts numbers in four basic formats:
|Decimal||12345||Uses digits 0 - 9. Must not start with 0 unless the value is exactly 0.|
|Octal||0377||Uses digits 0 - 7. Always starts with a leading 0.|
|Hexadecimal||$5A3C||Uses digits 0 - 9, A - F. Case insensitive. Starts with $.|
|Binary||%01011010||Uses digits 0, 1. Starts with %.|
Strings are quoted expressions. They may be used directly with DECLE, BIDECLE, STRING and BYTE directives, or as an argument to the ASC() and STRLEN() operators. Characters within strings may be escaped using the backslash \. See the as1600 documentation for more details.
When used with DECLE, BIDECLE, STRING and BYTE directives, strings may be intermixed with other expressions, separated by commas. A common use for this is to terminate strings with a NUL (0) character.
DECLE "Hello World!", 0 STRING "Hello World!", 0 ; synonymous with previous line
The following table lists some common operators that appear in expressions. This list is not exhaustive. Please refer to the as1600 documentation for a complete list.
|AND||Bitwise logical AND|
|OR||Bitwise logical OR|
|XOR||Bitwise logical XOR|
|>||GT||Greater Than (signed)|
|>=||GE||Greater Than or Equal (signed)|
|<||LT||Less Than (signed)|
|<=||LE||Less Than or Equal (signed)|
|ASC("string",index)||Returns ASCII code of indexed character|
|STRLEN("string")||Returns the length of a string|
|DEFINED||Returns 1 if symbol is defined at this point (first pass)|
Expressions are computed at assembly time, which makes them a powerful method for computing complex values that will be fixed at run-time. This means that the values for all labels that appear in the expression must be known at assembly time. Expressions may include forward references, meaning references to labels whose values are not yet known. This is usually ok, since the assembler makes a second pass to finish computing these expressions. Certain directives, such as IF, EQU and REPEAT, need to know the exact value of the expression when the directive is reached the first time, though. The assembler will inform you if you use an expression whose value can't be computed when it needs it.
; This code has legal forward references. The assembler will accept these: TABLE DECLE (FOO AND $7F8) SHR 3, ((FOO AND $FC00) SHR 11) OR ((FOO AND $3) SHL 5) DECLE (BAR AND $7F8) SHR 3, ((BAR AND $FC00) SHR 11) OR ((BAR AND $3) SHL 5) FOO PROC ; ... more code here ENDP BAR PROC ; ... more code here ENDP
; This code, however, does not have legal forward references. ; The assembler will give an error for each EQU directive: CST1 EQU (FOO AND $7F8) SHR 3, ((FOO AND $FC00) SHR 11) OR ((FOO AND $3) SHL 5) CST2 EQU (FOO AND $7F8) SHR 3, ((FOO AND $FC00) SHR 11) OR ((FOO AND $3) SHL 5) FOO PROC ; ... more code here ENDP BAR PROC ; ... more code here ENDP
Also, the assembler will issue a warning if you have a forward reference to an EQU or SET directive. It's usually safe to ignore the warnings for EQU directives, but not for SET directives if the label's value gets SET more than once. The following examples trigger warnings:
; This triggers a warning that's probably safe to ignore, but still worth fixing. DECLE FOO, BAR, BAZ ; ... more code here FOO EQU 42 BAR EQU 17 BAZ EQU 23
; This also triggers a warning, and may not do what the programmer intended DECLE FOO ; ... more code here FOO SET 42 ;\ FOO SET 17 ; |- Which of these gets used in the DECLE above? FOO SET 23 ;/
Expressions are computed with 32-bit precision. This makes it easy to do extended precision work. If you try to use a 32-bit value as an operand to an instruction or one of the data directives (e.g. DECLE), though, the assembler will complain that the value is out of range. The assembler allows 32-bit values in the range $FFFF8000 (-32768) to $0000FFFF (+65535) to silently truncate to 16 bits—that is, they will truncate without an error.
MAGIC EQU $4A5A6A7A ; Set up magic 32-bit constant DECLE MAGIC ; Causes an error DECLE MAGIC AND $FFFF ; Valid DECLE MAGIC SHR 16 ; Also valid MVII #MAGIC, R0 ; Causes an error MVII #MAGIC AND $FFFF, R0 ; Valid MVII #MAGIC SHR 16, R0 ; Also valid NUM1 EQU $FFFF8000 ; -32768 as a 32-bit number NUM2 EQU $00008000 ; +32768 (unsigned) as a 32-bit number MVII #NUM1, R0 ; sets R0 to $8000 MVII #NUM2, R0 ; also sets R0 to $8000
(Note: Older versions of as1600 will give an error on any values outside the range of $00000000 - $0000FFFF. Upgrade to the latest as1600 to fix this.)
The following (largely nonsensical) example shows many of the above basic features in use.
ROMW 16 ; Set ROM width to 16-bit ORG $5000 ; Begin assembling code at location $5000 ROW EQU 10 ; Row to display copyright on COL EQU 1 ; Column to begin displaying copyright in ;------------------------------------------------------------------------------ ; EXEC-friendly ROM header. ;------------------------------------------------------------------------------ ROMHDR: BIDECLE ZERO ; MOB picture base (points to NULL list) BIDECLE ZERO ; Process table (points to NULL list) BIDECLE MAIN ; Program start address BIDECLE ZERO ; Bkgnd picture base (points to NULL list) BIDECLE ONES ; GRAM pictures (points to NULL list) BIDECLE TITLE ; Cartridge title/date DECLE $03C0 ; Flags: No ECS title, run code after title, ; ... no clicks ZERO: DECLE $0000 ; Screen border control DECLE $0000 ; 0 = color stack, 1 = f/b mode ONES: DECLE 1, 1, 1, 1, 1 ; Color stack initialization ;------------------------------------------------------------------------------ TITLE DECLE 107, "Hello World!", 0 MAIN PROC ; Start a PROC/ENDP section EIS ; Enable interrupts CALL PRINT.FLS DECLE 7 ; 7 is the color number for "white" DECLE $200 + ROW*20 + COL ; Expression, including labels DECLE " Copyright 2007 ", 0 ; The following piece of code is disabled IF 0 MVII #1234, R0 ENDI ; Copy 8 words from $120 to $128 quickly MVII #$120, R4 MVII #$128, R5 REPEAT 8 MVI@ R4, R0 MVO@ R0, R5 ENDR ; Spin forever: @@loop B @@loop ; Branches to local "@@loop" label, aka "MAIN.loop" ENDP ; Close a PROC/ENDP section INCLUDE "print.asm"