-
Notifications
You must be signed in to change notification settings - Fork 0
Assembly
Labels just define absolute memory addresses that can then be used as constants throughout the code.
A label is defined by writing the label name followed by a colon (:) at the beginning of a line. For example:
start:
; code hereLabels can be used in place of immediate values in instructions. For example:
JMP start ; Jump to the address defined by the label 'start'Labels must be unique within a program. Duplicate labels will error.
Labels can however be local and are scoped to the nearest global label. Local labels start with a dot (.). For example:
main:
.loop:
; code here
JMP .loop ; Jump to the local label '.loop'Local labels cannot be duplicated within the same global label scope, but can be reused in different global label scopes. Labels can be defined before or after they are used in the code. The assembler will resolve the addresses during assembly.
Commands are supported, all text after a semicolon (;) on a line is considered a comment and ignored by the assembler. For example:
MOV R1, R2 ; This is a comment
; This entire line is a commentData directives are used to directly insert data instead of encoding an instruction. The following data directives will directly define data in memory:
-
D8(Define Byte): Defines one or more bytes (8 bits each). -
D16(Define Short): Defines one or more shorts (16 bits each). -
D32(Define Word): Defines one or more words (32 bits each). -
DSTR(Define String): Defines bytes from a string literal, not null-terminated by default. -
RES8(Reserve Byte): Places a certain number of 0x00 bytes in the file. -
RES16(Reserve Short): Places a certain number of 0x0000 shorts in the file. -
RES32(Reserve Word): Places a certain number of 0x00000000 words in the file.
For examples:
mydata:
D8 0x12, 0x34, 0x56 ; Defines three bytes
D16 0x1234, 0x5678 ; Defines two shorts
D32 0x12345678, 0x9ABCDEF0 ; Defines two words
DSTR "Hello, World!\n\0" ; Defines bytes for the string (including null terminator and newline)
RES8 4 ; Same as D8 0, 0, 0, 0
RES16 4 ; Same as D16 0, 0, 0, 0
RES32 3 ; Same as D32 0, 0, 0| Register | Use |
|---|---|
| r0 | return value |
| r1 | first argument |
| r2 | second argument |
| r3 | third argument |
| stack | the rest of the arguments |
r0-3 inc is clobbered (Caller preserved)
rest is not clobbered (Callee preserved)
To specify that you want to access memory, wrap the address source in []. For example:
MOV R1, [R2] ; Load the value from the memory address in R2 into R1
MOV [0x1000], R3 ; Store the value in R3 into memory address 0x1000Any constant, label, or number literal may be used where numbers go. For example:
JMP 0x00
JMP main
JMP variablenameare all valid, as long as those labels/constants exist.
You may define constants using
#const VAR_NAME, valueThe value of the constant can also be any numerical input, including a label.
As well as using a mix of these types, you may also combine them in mathematical expressions, that will be evaluated at compile time. The order in which you define constants is also meaningless, you may use them before they are defined. For example:
#const A, 5
#const B, A*7 + 1
#const C, B-main
main:
JMP A+C/BAlthough this would likely cause a runtime error this is completely valid syntax. And all these values will be evaluated just fine. But be careful, circular dependencies will cause errors.
You may define small code snippets called macros which can be used like an instruction would and get expanded at assemble time.
#macro debug, 1
push r1
mov r1, $1
int 0x90
pop r1
#endmacroHere is an example of a debug macro which preserves r1 and debug prints the number passed through. To use it you would simply write:
debug SOMENUMBERordebug r1.
The , 1 specifies how many arguments the macro has. Each
argument is referenced as $NUM where NUM is the number of
the argument starting from 1 (first arg is $1). These arguments
are textually replaced at assemble time, so you can have whatever
you like in them.
Example macro that prints 3 numbers:
#define A, 7+8
#macro print_three, 3
mov r1, $1
int 0x90
mov r1, $2
int 0x90
mov r1, $3
int 0x90
#endmacro
main:
mov r4, 0xFF
print_three A, main - 3, r4