# CPUSim64 Directives

The CPUSim64 has two types of directives: Preprocessor directives and Assembler directives.

Preprocessor directives are instructions to the preprocessor. They tell the preprocessor how to modify your source `.asm` source file. The output of the preprocessor is pure CPUSim64 assembler code.

Assembler directives are instructions to the Assembler. They consist mainly of directives to allocate scopes or data.

Normally the `assemble.sh`, `run.sh` and `debug.sh` scripts will run the preprocessor before passing the output on to the assembler. Sometimes it is helpful to see how the preprocessor modified your code when there are errors. You can run just the preprocessor by using the `preprocess.sh` script. It will create a `.pp.asm` file that contains the output of just the preprocessor.

## Preprocessor Directives

Preprocessor directives always start with a pound sign (`#`). They are written by themselves on a line. Some directives have a begin and and end directive that must be used in pairs.

Directive | Operands | Description
--- | --- | ---
#include | <systemfile.def> "localfile.asm" | Includes the contents of a system file or a file in the current directory.
#define | IDENT literal | Defines the substitution symbol IDENT as a synonym for the literal value.
#undef | IDENT | Undefines the substitution symbol IDENT.
#def_func #end_func | FUNC_IDENT(params) none | Defines a stack-based function. Params are a comma-separated list of formal argument identifiers.
#call | FUNC_IDENT(args) | Calls a stack-based function. The args are a comma separated list of values that will be passed on the stack matching the formal parameters defined for the function.
#def_macro #end_macro | MACRO_IDENT(params) none | Defines a substitution macro. Params are a comma-separated list of placeholder names. Inside the body of the macro, parameters are represented using the special placeholder symbol `${param}`, where param is the name of the parameter to substitute.
#macro | MACRO_IDENT(args) | Instantiates a substitution of the macro. The args are a comma separated list of symbols that will be substituted into the macro matching the formal parameters defined for the macro.
#global | label: .dc? ... | Defines global read/write variables in the __DATA__ section of the program. Accessing the variables is done with `load`/`store` instructions.
#svar | ident_list | Defines stack variables for the function. The ident_list is a comma-separated list of variable names to be created. Must be the first directive following the beginning of a `#def_func` directive. Accessing the variables is done with `load`/`store` instructions.
#var | ident_list | Defines integer register variables for the function. The ident_list is a comma-separated list of variable names to be created. Must follow the `#svar` directive if present. Accessing the variables is done with the `move` instruction.
#fvar | ident_list | Defines floating point register variables for the function. The ident_list is a comma-separated list of variable names to be created. Must follow the `#var` directive if present. Accessing the variables is done with the `move` instruction.
#return | op | Moves the operand into register r0 and then returns. Causes all `#svar`, `#var` and `#fvar` variables to be deallocated.
#freturn | op | Moves the operand into register f0 and then returns. Causes all `#svar`, `#var` and `#fvar` variables to be deallocated.
#if #else_if #else #end_if | IDENT cmpOp IDENT/literal IDENT cmpOp IDENT/literal none none | Causes conditional inclusion of code lines. IDENT must be a symbol defined by a `#define` directive. The valid comparison operaters are `==`, `!=`, `<=`, `=>`, `<`, and `>`. If just an IDENT is supplied instead of an expression, the "truthiness" of the identifier is evaluated. O is false, everything else is true.
#ifdef #else #end_if | IDENT none none | Causes conditional inclusion of code lines. IDENT must be a symbol defined by a `#define` directive. If the identifier is defined (doesn't matter what it is defined as) then the code will be included. If the identifier is not defined the optional else block code will be included.
#ifndef #else #end_if | IDENT none none | Causes conditional inclusion of code lines. IDENT must be a symbol defined by a `#define` directive. If the identifier is not defined then the code will be included. If the identifier is defined (doesn't matter what it is defined as) the optional else block code will be included.
#for #end_for | inital IDENT cmpOp IDENT/literal increment none | Generates assembler code for a `for` loop. The initial value is specified by initial. The loop variable is identified by IDENT. The valid comparison operaters are `==`, `!=`, `<=`, `=>`, `<`, and `>`. The final value, increment, is the amount to add to the loop variable each loop.
#while #end_while | IDENT cmpOp IDENT/literal none | Generates assembler code for a `while` loop. The loop variable is identified by IDENT. The valid comparison operaters are `==`, `!=`, `<=`, `=>`, `<`, and `>`. The loop condition is evaluated at the beginning of the loop.
#do_while #end_do_while | none IDENT cmpOp IDENT/literal | Generates assembler code for a `do/while` loop. The loop variable is identified by IDENT. The valid comparison operaters are `==`, `!=`, `<=`, `=>`, `<`, and `>`. The loop condition is evaluated at the end of the loop.
#break | none | Breaks out of the innermost loop.
#continue | none | Continues to the next iteration of the innermost loop.
#if_cond #else_if_cond #else_cond #end_cond | IDENT cmpOp IDENT/literal IDENT cmpOp IDENT/literalnonenone | Generates assembler code for an `if/else` construct.
#if_cond_sr #else_cond #end_cond | z|nz|n|p|nn|np|pe|po|o|nononenone | Generates assembler code for an `if/else` construct based on the conditions in the status register (SR)
#sync #end_sync | IDENT | Acquires a lock on the mutex IDENT and releases it at the end of the block. Need to declare the mutex with `#macro DEFINE_MUTEX(IDENT)` and initialize it with `#call initializeMutex(IDENT)` Include `threadlib.asm` to get access to these macros/functions.

## Assembler Directives

Directive | Operands | Description
--- | --- | ---
.org | literal | Sets the location in memory for the next instruction.
.line | «filename», linenum | Resets the source filename and line number
.line_begin .line_end | «filename», linenum none | Resets the source filename and line number for the enclosed statements.
.block_begin .block_end | IDENT none | Creates a new scope for line labels. Label names beginning with a dollar sign (`$`) will be relative to the enclosing scope.
.dci | int_literal | Stores the specified integer in the next word of the assembled code.
.dcf | float_literal | Stores the specified floating point value in the next word of the assembled code.
.dca | count | Causes count + 1 words to be allocated at this point in the code. Contents are undefined. The first word will contain the count.
.dcb | byte_list | Causes the bytes specified by the comma separated byte_list to be allocated at this point in the code. Bytes will be packed 8 to a word (big-endian). The first word will contain the count.
.dcs | string_literal | Causes the string specified to be allocated at this point in the code. String is encoded in UTF-8 and will be packed 8 to a word (big-endian). The first word will contain the UTF-8 byte count.
.dcw | int_list float_list char_list | Causes the words specified by the comma separated list to be allocated at this point in the code. Initializers are placed one per word. The first word will contain the count.

Literals can be a decimal integer, hexadecimal integer, floating point literal, character literal or string literal.

#### Examples

- Decimal Integer: `326`, `-123`
- Hexadecimal Integer: `0x1a2b`, `-0X1234`
- Floating Point: `3.`, `-0.123`, `3.1415e10`, `4.567E-2`
- Character Literal: `'A'`, `'4'`, `'\t'`, `'\u00ab'`
- String Literal: `"Héllø, World!"`, `"C-style escapes \t \n"`, `"Unicode escapes \u00ab \u1234, \u134F"`

Unicode escapes are UTF-16 values. They must be exactly four hexadecimal digits.