# DSA Assembly Language Reference

## Overview

This document is the comprehensive reference for writing DSA assembly programs. It covers assembly syntax, pseudo-instructions, directives, the module system, calling conventions, and provides complete examples.

**Related Documents:**
- For hardware instruction details and encoding: See *DSA ISA Specification*
- For build system and toolchain: See project documentation

## Assembly Syntax

### General Rules

- **Case Insensitive:** Mnemonics can be uppercase or lowercase (`mov` = `MOV`)
- **Comments:** Use `//` for line comments or `/* */` for block comments
- **Labels:** Identifier followed by colon (e.g., `main:`, `loop:`)
- **Whitespace:** Flexible spacing between operands
- **Numbers:** 
  - Decimal: `100`, `255`
  - Hexadecimal: `0x10`, `0xFFFF`
  - Binary: `0b1010` (if supported by assembler)

### Operand Order Convention

DSA assembly uses **GAS-style syntax** (source → destination):

```asm
mov rg0, rg1        ; Copy rg0 TO rg1 (destination is last)
add rg0, rg1, rg2   ; rg2 = rg0 + rg1 (destination is last)
```

For load/store with immediates:
```asm
lli 0x1234, rg0     ; Load immediate 0x1234 INTO rg0
ldw rg0, rg1, 8     ; Load from (rg0+8) INTO rg1
stw rg0, rg1, 8     ; Store rg0 TO address (rg1+8)
```

## Registers

| Register(s) | Type | Description | Usage Notes |
|-------------|------|-------------|-------------|
| **rg0-rgf** | General | 16 general-purpose registers | Use for variables, temporaries |
| **acc** | Special | Accumulator | ⚠️ **VOLATILE** - Used as scratch by pseudo-instructions |
| **spr** | Special | Stack pointer | Points to current top of stack |
| **bpr** | Special | Base pointer | Used for stack frames |
| **ret** | Special | Return address | Holds function return addresses |
| **zero** | Read-only | Always zero | Reads return 0, writes discarded |
| **pcx** | Read-only | Program counter | Cannot be written directly |
| **idr** | Privileged | Interrupt descriptor table | Kernel mode only |
| **mmr** | Privileged | Memory map register | Kernel mode only |
| **noreg** | Placeholder | No register | Used in encoding, triggers fault if accessed |

**Alternative Names:**
- **noreg** can also be referenced as **null** in assembly

**Register Conventions:**
- **acc**: Volatile scratch register used by pseudo-instructions - **never preserved across pseudo-ops**
- **rg0-rge**: Available for general use; calling convention defines preservation rules
- **rgf**: General purpose register, available for use

**⚠️ CRITICAL:** The `acc` register is used internally by label-based memory operations and other pseudo-instructions. Do not assume its value is preserved across any pseudo-instruction!

## Hardware Instructions

This section shows assembly syntax. For encoding details, see the ISA Specification.

### Data Movement

```asm
mov src_reg, dest_reg       ; Copy value from src_reg to dest_reg
movs src_reg, dest_reg      ; Copy with sign extension
```

**Examples:**
```asm
mov rg0, rg1                ; rg1 = rg0
movs acc, rg2               ; rg2 = sign_extend(acc)
```

### Memory Load Instructions

```asm
ldb base_reg, dest_reg [, offset]      ; Load byte (zero-extend)
ldbs base_reg, dest_reg [, offset]     ; Load byte (sign-extend)
ldh base_reg, dest_reg [, offset]      ; Load halfword (zero-extend)
ldhs base_reg, dest_reg [, offset]     ; Load halfword (sign-extend)
ldw base_reg, dest_reg [, offset]      ; Load word
```

**Offset:** Optional signed 16-bit offset (defaults to 0)

**Examples:**
```asm
ldb rg0, rg1                ; Load byte from address in rg0
ldw rg0, rg1, 8             ; Load word from (rg0 + 8)
ldhs rg2, rg3, -4           ; Load signed halfword from (rg2 - 4)
```

**Alignment Requirements:**
- `ldb/ldbs`: No alignment required
- `ldh/ldhs`: Must be 2-byte aligned
- `ldw`: Must be 4-byte aligned

### Memory Store Instructions

```asm
stb src_reg, base_reg [, offset]       ; Store byte
sth src_reg, base_reg [, offset]       ; Store halfword
stw src_reg, base_reg [, offset]       ; Store word
```

**Examples:**
```asm
stb rg0, rg1                ; Store byte to address in rg1
stw rg0, rg1, 12            ; Store word to (rg1 + 12)
sth acc, spr, -2            ; Store halfword to (spr - 2)
```

**Alignment Requirements:** Same as loads

### Immediate Load Instructions

```asm
lli immediate, dest_reg     ; Load lower 16 bits (CLEARS upper 16!)
lui immediate, dest_reg     ; Load upper 16 bits (preserves lower 16)
```

**⚠️ CRITICAL:** `lli` clears the upper 16 bits! Always use `lli` before `lui`.

**Loading 32-bit Constants:**
```asm
lli 0x1234, rg0             ; rg0 = 0x00001234
lui 0xABCD, rg0             ; rg0 = 0xABCD1234
```

**Note:** The assembler may process the immediate value for `lui` - specify the upper 16 bits directly (e.g., `lui 0xABCD, rg0` to set upper bits to 0xABCD).

**Loading Addresses:** See `lwi` pseudo-instruction

### Jump and Branch Instructions

```asm
jmp offset, base_reg        ; Unconditional jump to (base_reg + offset)
jeq offset, base_reg        ; Jump if equal
jne offset, base_reg        ; Jump if not equal
jgt offset, base_reg        ; Jump if greater than
jge offset, base_reg        ; Jump if greater or equal
jlt offset, base_reg        ; Jump if less than
jle offset, base_reg        ; Jump if less or equal
```

**Target Address Calculation:**
```
target = base_reg + sign_extend(offset)
```

**Jump Modes:**
```asm
; Absolute jump (using zero register)
jmp label, zero             ; Jump to label address

; Register-based jump  
jmp 0, ret                  ; Jump to address in ret register
jmp 4, ret                  ; Jump to (ret + 4)

; PC-relative (if assembler supports label resolution)
jeq loop_start, zero        ; Jump to loop_start if equal flag set
```

**Conditional Jumps:** Based on flags set by `cmp` instruction

**Examples:**
```asm
jmp start, zero             ; Absolute jump to 'start'
jmp 4, ret                  ; Jump to (ret + 4)
jeq end, zero               ; Jump to 'end' if equal flag set
jgt loop, zero              ; Jump to 'loop' if greater than flag set
```

### Comparison

```asm
cmp reg1, reg2              ; Compare reg1 with reg2, set flags
```

**Flags Set:**
- Equal: `reg1 == reg2`
- GreaterThan: `reg1 > reg2` (signed comparison)
- LessThan: `reg1 < reg2` (signed comparison)
- GreaterThanOrEqual: `reg1 >= reg2`
- LessThanOrEqual: `reg1 <= reg2`

**Example:**
```asm
cmp rg0, zero               ; Compare rg0 with 0
jeq is_zero, zero           ; Branch if rg0 == 0
jgt is_positive, zero       ; Branch if rg0 > 0
jlt is_negative, zero       ; Branch if rg0 < 0
```

### Arithmetic Instructions

```asm
add src1, src2, dest        ; dest = src1 + src2
sub src1, src2, dest        ; dest = src1 - src2
iadd src, immediate, dest   ; dest = src + immediate (DEST REQUIRED!)
isub src, immediate, dest   ; dest = src - immediate (DEST REQUIRED!)
inc reg                     ; reg = reg + 1
dec reg                     ; reg = reg - 1
```

**Examples:**
```asm
add rg0, rg1, rg2           ; rg2 = rg0 + rg1
sub rg0, rg1, rg2           ; rg2 = rg0 - rg1
iadd rg0, 10, rg0           ; rg0 = rg0 + 10 (in-place)
iadd rg0, 10, rg1           ; rg1 = rg0 + 10 (separate dest)
isub rg1, 5, rg2            ; rg2 = rg1 - 5
inc spr                     ; spr = spr + 1
dec spr                     ; spr = spr - 1
```

**⚠️ Note:** For `iadd`/`isub`, the destination register is **required** (not optional). For in-place operations, specify the source register as both source and destination.

### Bitwise Logical Operations

```asm
and src1, src2, dest        ; dest = src1 & src2
or src1, src2, dest         ; dest = src1 | src2
xor src1, src2, dest        ; dest = src1 ^ src2
not src, dest               ; dest = ~src
nand src1, src2, dest       ; dest = ~(src1 & src2)
nor src1, src2, dest        ; dest = ~(src1 | src2)
xnor src1, src2, dest       ; dest = ~(src1 ^ src2)
```

**Examples:**
```asm
and rg0, rg1, rg2           ; rg2 = rg0 & rg1
or rg0, rg1, rg2            ; rg2 = rg0 | rg1
not rg0, rg1                ; rg1 = ~rg0
xor rg0, rg0, rg0           ; rg0 = 0 (XOR register with itself)
```

### Shift Operations

```asm
shl reg, shift_amount       ; Shift left by amount (0-31)
shr reg, shift_amount       ; Shift right by amount (0-31)
```

**Shift Amount:**
- **Literal:** `shl rg0, 2` - shift by constant 2
- **Register:** `shl rg0, rg1` - shift by value in rg1 (low 5 bits)

**⚠️ Note:** Current assembler may only support literal shift amounts. Check your assembler documentation for register shift support.

**Examples:**
```asm
shl rg0, 2                  ; rg0 = rg0 << 2
shr rg1, 3                  ; rg1 = rg1 >> 3
; shl rg0, rg1              ; May not be supported by assembler
```

**Note:** Shift right is logical (zero-fill), not arithmetic

### System and Control Instructions

```asm
hlt                         ; Halt processor
nop                         ; No operation
int interrupt_code          ; Trigger interrupt (8-bit code)
irt                         ; Return from interrupt
```

**Examples:**
```asm
hlt                         ; Stop execution
nop                         ; Do nothing (timing/alignment)
int 0x21                    ; Trigger interrupt 0x21
irt                         ; Return from interrupt handler
```

## Pseudo-Instructions

Pseudo-instructions are assembly-level constructs that expand into one or more hardware instructions.

**⚠️ IMPORTANT:** Many pseudo-instructions use the `acc` register as a scratch register. The value in `acc` is **not preserved** across these operations!

### Data Definition Directives

```asm
db label: value1 [, value2, ...]    ; Define bytes
dh label: value1 [, value2, ...]    ; Define halfwords (16-bit)
dw label: value1 [, value2, ...]    ; Define words (32-bit)
```

**Examples:**
```asm
db message: "Hello, World!", 0       ; String with null terminator
db bytes: 0x01, 0x02, 0x03          ; Array of bytes
dh numbers: 1000, 2000, 3000        ; Array of halfwords
dw stack_base: 0x10000              ; Single word value
dw table: 0, 0, 0, 0                ; Array of 4 words
```

**String Encoding:** Strings are automatically null-terminated and encoded as byte sequences with escape sequences:
- `\n` = newline (0x0A)
- `\t` = tab (0x09)
- `\r` = carriage return (0x0D)
- `\\` = backslash
- `\"` = double quote
- `\0` = null (0x00)

**⚠️ Endianness Note:** Numeric values in data directives are stored in **big-endian** format by the assembler, unlike the little-endian used for instructions.

### Memory Reservation Directives

```asm
resb label: size            ; Reserve 'size' bytes
resh label: size            ; Reserve 'size' halfwords
resw label: size            ; Reserve 'size' words
```

**Examples:**
```asm
resb buffer: 256            ; Reserve 256 bytes
resh array: 100             ; Reserve 100 halfwords (200 bytes)
resw heap: 1024             ; Reserve 1024 words (4096 bytes)
```

**Note:** Reserved memory is uninitialized (contents undefined).

### Stack Operations

```asm
push reg                    ; Push register onto stack
pop reg                     ; Pop stack into register
```

**⚠️ CRITICAL - Stack Direction:** The DSA stack grows **DOWNWARD** (toward lower memory addresses).

**Expansion:**
```asm
; push rg0 expands to:
subi spr, 4, spr            ; spr = spr - 4 (allocate space, stack grows down)
stw rg0, spr, 0             ; Store rg0 to [spr]

; pop rg0 expands to:
ldw spr, rg0, 0             ; Load [spr] into rg0
addi spr, 4, spr            ; spr = spr + 4 (deallocate space)
```

**Examples:**
```asm
push rg0                    ; Save rg0 on stack
push rg1                    ; Save rg1 on stack
; ... do work ...
pop rg1                     ; Restore rg1
pop rg0                     ; Restore rg0
```

**Stack Diagram:**
```
Higher Memory Addresses
    ↑
    │  (old data)
    ├─────────────┤
    │   rg0 value │  ← After first push
    ├─────────────┤  ← SPR after first push
    │   rg1 value │  ← After second push
    ├─────────────┤  ← SPR after second push (stack grew down)
    ↓
Lower Memory Addresses
```

### Push/Pop Multiple Registers

```asm
pusha count                 ; Push first 'count' general registers (rg0-rgN)
popa count                  ; Pop first 'count' general registers
```

**Examples:**
```asm
pusha 4                     ; Push rg0, rg1, rg2, rg3
; ... do work ...
popa 4                      ; Pop rg3, rg2, rg1, rg0
```

**Expansion:**
```asm
; pusha 3 expands to:
subi spr, 12, spr           ; Allocate space for 3 words
stw rg0, spr, 0             ; Store rg0
stw rg1, spr, 4             ; Store rg1  
stw rg2, spr, 8             ; Store rg2

; popa 3 expands to:
ldw spr, rg0, 0             ; Load rg0
ldw spr, rg1, 4             ; Load rg1
ldw spr, rg2, 8             ; Load rg2
addi spr, 12, spr           ; Deallocate space
```

**Note:** Registers are pushed/popped in order (rg0, rg1, rg2, ...).

### Load Address Pseudo-Instruction

```asm
lwi label, dest_reg         ; Load address of label into register
```

**Expansion:**
```asm
; lwi message, rg0 expands to:
lli message, rg0            ; Load lower 16 bits of address
lui message, rg0            ; Load upper 16 bits of address
```

**Example:**
```asm
db message: "Hello!", 0
    
lwi message, rg0            ; rg0 = address of message
ldb rg0, rg1, 0             ; rg1 = first byte of message ('H')
```

### Memory Access with Labels

Load and store instructions can use labels directly:

```asm
ldb label, dest_reg [, offset]
ldh label, dest_reg [, offset]
ldw label, dest_reg [, offset]
stb src_reg, label [, offset]
sth src_reg, label [, offset]
stw src_reg, label [, offset]
```

**⚠️ CRITICAL:** These pseudo-instructions use `acc` as a scratch register! The value in `acc` will be overwritten.

**Expansion:**
```asm
; ldw buffer, rg2 expands to:
lli buffer, acc             ; Load lower 16 bits of buffer address into acc
lui buffer, acc             ; Load upper 16 bits of buffer address into acc
ldw acc, rg2, 0             ; Load word from address in acc into rg2

; stw rg1, current expands to:
lli current, acc            ; Load lower 16 bits of current address into acc
lui current, acc            ; Load upper 16 bits of current address into acc
stw rg1, acc, 0             ; Store word from rg1 to address in acc
```

**Examples:**
```asm
dw counter: 0

ldw counter, rg0            ; Load value of counter (clobbers acc!)
addi rg0, 1, rg0            ; Increment
stw rg0, counter            ; Store back (clobbers acc!)
```

**⚠️ Warning Example - ACC Clobbering:**
```asm
lli 100, acc                ; acc = 100
ldw data, rg0               ; ACC IS NOW OVERWRITTEN!
; acc now contains garbage (address calculation temp)
; The value 100 is LOST!
```

# DSA Assembly Language Reference - Part 2

## Function Call Pseudo-Instructions

```asm
call namespace::function    ; Call function from included module
return                      ; Return from function
```

**⚠️ CRITICAL:** The calling mechanism uses the **STACK** to store return addresses, not just the `ret` register!

**CALL Expansion:**
```asm
; call print::print expands to:
subi spr, 4, spr            ; Decrement stack pointer (allocate space)
stw pcx, spr, 0             ; Store return address (PCX) on stack
jmp function_addr, zero     ; Jump to function address
```

**RETURN Expansion:**
```asm
; return expands to:
ldw spr, ret, 0             ; Load return address from stack into ret
addi spr, 4, spr            ; Increment stack pointer (deallocate)
jmp 4, ret                  ; Jump to (ret + 4)
```

**Note on RETURN +4 Offset:** The implementation adds 4 to the return address. This may be to account for instruction sizing or pipeline considerations. Consult CPU documentation if modifying.

### Module System

```asm
include namespace "path/to/file.dsa"
```

**Example:**
```asm
include print "lib/print.dsa"
include math "lib/math.dsa"

; Can now call:
call print::print
call math::multiply
```

**Namespace Resolution:**
- Functions in included modules are accessible via `namespace::label`
- Namespace is the identifier before the filename
- Labels in included files are prefixed with the namespace

## Calling Convention

DSA uses a stack-based calling convention with downward-growing stack.

### Stack Frame Layout

**⚠️ CRITICAL:** Stack grows DOWNWARD (toward lower addresses)!

```
Higher Memory Addresses ↑
                        │
    ┌─────────────┐
    │   Caller's  │
    │   Frame     │
    └─────────────┘
    │   Arg N     │  ← Caller pushed (highest address argument)
    │   ...       │
    │   Arg 2     │  
    │   Arg 1     │  
    │   Arg 0     │  ← First argument (lowest address argument)
    ├─────────────┤  
    │   Ret Addr  │  ← Return address (pushed by CALL)
    ├─────────────┤
    │   Old BPR   │  ← Saved base pointer (pushed by callee)
    ├─────────────┤  ← BPR (current base), SPR (current top)
    │   Locals    │  ← Local variables (if any)
    │     ...     │
    └─────────────┘  ← SPR grows downward
                        │
Lower Memory Addresses  ↓
```

**Frame Pointer Offsets** (from BPR):
```
bpr + 0   = Old BPR (saved by function prologue)
bpr + 4   = Return address (pushed by CALL)
bpr + 8   = Argument 0 (first argument)
bpr + 12  = Argument 1
bpr + 16  = Argument 2
bpr + 8 + 4*N = Argument N
```

### Calling Sequence

**Caller Responsibilities:**

1. **Push arguments in reverse order** (last argument first):
```asm
push arg2                   ; Push last argument first
push arg1
push arg0                   ; First argument pushed last
```

2. **Call the function:**
```asm
call namespace::function    ; Pushes return address, jumps to function
```

3. **Clean up arguments** after return:
```asm
pop zero                    ; Discard arg0 (or pop rg0 to get return value)
pop zero                    ; Discard arg1
pop zero                    ; Discard arg2
```

**Callee Responsibilities:**

1. **Set up stack frame:**
```asm
function:
    push bpr                ; Save caller's base pointer
    mov spr, bpr            ; Establish new base pointer
```

2. **Access arguments:**
```asm
    ldw bpr, rg0, 8         ; Load arg0 from bpr+8
    ldw bpr, rg1, 12        ; Load arg1 from bpr+12
    ldw bpr, rg2, 16        ; Load arg2 from bpr+16
```

3. **Execute function body:**
```asm
    ; Function logic here
    add rg0, rg1, acc       ; Example: acc = arg0 + arg1
```

4. **Store return value** (optional - overwrites arg0 location):
```asm
    stw acc, bpr, 8         ; Store result where arg0 was
```

5. **Restore stack frame:**
```asm
    mov bpr, spr            ; Restore stack pointer to base
    pop bpr                 ; Restore caller's base pointer
```

6. **Return to caller:**
```asm
    return                  ; Pop return address and jump
```

### Stack Evolution During Call

**Before CALL:**
```
    ┌─────────────┐
    │   Arg 2     │
    │   Arg 1     │  
    │   Arg 0     │  ← SPR points here
    └─────────────┘
```

**After CALL (before function prologue):**
```
    ┌─────────────┐
    │   Arg 2     │
    │   Arg 1     │  
    │   Arg 0     │
    │   Ret Addr  │  ← SPR points here (CALL pushed this)
    └─────────────┘
```

**After Function Prologue:**
```
    ┌─────────────┐
    │   Arg 2     │
    │   Arg 1     │  
    │   Arg 0     │
    │   Ret Addr  │
    │   Old BPR   │  ← SPR and BPR point here
    └─────────────┘
```

### Complete Calling Example

```asm
; Function: add two numbers
; Args: arg0, arg1
; Returns: sum (overwrites arg0 position)

add_function:
    ; Prologue
    push bpr                ; Save caller's base pointer
    mov spr, bpr            ; Set up our stack frame
    
    ; Load arguments
    ldw bpr, rg0, 8         ; rg0 = arg0
    ldw bpr, rg1, 12        ; rg1 = arg1
    
    ; Perform operation
    add rg0, rg1, acc       ; acc = arg0 + arg1
    
    ; Store return value (overwrites arg0 position)
    stw acc, bpr, 8         ; Store result at bpr+8
    
    ; Epilogue
    mov bpr, spr            ; Restore stack pointer
    pop bpr                 ; Restore caller's base pointer
    return                  ; Return to caller

; Caller example:
main:
    ; Set up stack
    lwi stack_base, bpr
    mov bpr, spr
    
    ; Prepare arguments
    lli 5, rg0              ; First argument = 5
    lli 7, rg1              ; Second argument = 7
    
    ; Push arguments (reverse order!)
    push rg1                ; Push arg1 (7) first
    push rg0                ; Push arg0 (5) second
    
    ; Call function
    call local::add_function
    
    ; Retrieve result and clean up
    pop rg2                 ; Get result (12) - was at arg0 position
    pop zero                ; Discard arg1 slot
    
    hlt
    
dw stack_base: 0x10000
```

### Register Usage Conventions

| Register(s) | Usage | Preserved Across Calls? |
|-------------|-------|------------------------|
| **rg0-rg3** | Function arguments, temporaries | No (caller-saved) |
| **rg4-rge** | Local variables | Conditional (callee-saved if used) |
| **rgf** | General purpose | Conditional (callee-saved if used) |
| **acc** | Temporary calculations, scratch | **Never** (volatile) |
| **spr** | Stack pointer | Yes (must be restored) |
| **bpr** | Base pointer | Yes (must be restored) |
| **ret** | Return address | Managed by call/return |

**Preservation Rules:**
- **Caller-saved (rg0-rg3, acc):** Caller must save these before calling if needed after
- **Callee-saved (rg4-rgf):** Callee must save/restore if it uses them
- **Always preserved (spr, bpr):** Must be restored to original values
- **Never preserved (acc):** Assume destroyed by any operation

**Example - Callee-Saved Registers:**
```asm
my_function:
    push bpr
    mov spr, bpr
    
    ; We want to use rg4 and rg5 - must save them!
    push rg4
    push rg5
    
    ; Use rg4 and rg5 for local work
    lli 100, rg4
    lli 200, rg5
    add rg4, rg5, acc
    
    ; Restore callee-saved registers before returning
    pop rg5
    pop rg4
    
    mov bpr, spr
    pop bpr
    return
```

## Complete Examples

### Example 1: Multiplication Library

```asm
// multiply.dsa
// Multiplies two numbers using repeated addition
//
// Usage:
//   include multiply "multiply.dsa"
//   push multiplicand
//   push multiplier
//   call multiply::multiply
//   pop result      ; Result is in arg0 position
//   pop zero        ; Clean up arg1

multiply:
    push bpr
    mov spr, bpr

    ldw bpr, rg0, 8         ; Load multiplier (arg0)
    ldw bpr, rg1, 12        ; Load multiplicand (arg1)

    lli 0, acc              ; Initialize result to 0

loop_start:
    add acc, rg0, acc       ; acc += multiplier
    dec rg1                 ; multiplicand--

    cmp rg1, zero
    jgt loop_start, zero    ; Continue if multiplicand > 0

    stw acc, bpr, 8         ; Store result for caller (at arg0)
    
    mov bpr, spr
    pop bpr
    return
```

### Example 2: Print Library

```asm
// print.dsa
// Prints null-terminated string to display memory
//
// Usage:
//   include print "print.dsa"
//   
//   push string_address
//   call print::print
//   pop zero
//
//   call print::reset     ; Reset cursor (no args)

dw display: 0x20000         ; Display memory base address
dw current: 0x20000         ; Current cursor position

// Print function
print:
    push bpr
    mov spr, bpr

    ldw bpr, rg0, 8         ; Get string address argument
    ldw current, rg1        ; Get current cursor position (clobbers acc!)

print_loop:
    ldb rg0, acc, 0         ; Load character
    stb acc, rg1, 0         ; Store to display

    addi rg0, 1, rg0        ; Advance string pointer
    addi rg1, 1, rg1        ; Advance cursor

    cmp acc, zero           ; Check for null terminator
    jne print_loop, zero    ; Continue if not null

    stw rg1, current        ; Save cursor position (clobbers acc!)

    mov bpr, spr
    pop bpr
    return

// Reset cursor function
reset:
    push bpr
    mov spr, bpr
    
    ldw display, rg1        ; Load display base (clobbers acc!)
    stw rg1, current        ; Reset cursor to start (clobbers acc!)
    
    mov bpr, spr
    pop bpr
    return
```

### Example 3: Main Program

```asm
// main.dsa
// Demonstrates using included libraries

include print "./print.dsa"

dw stack: 0x10000
db string: "'To confuse your enemy, you must first confuse yourself' - Probably Sun Tzu.", 0

init:
    // Set up stack
    ldw stack, bpr          ; Load stack base (clobbers acc!)
    mov bpr, spr

start:
    // Load string address
    lwi string, rg1         ; Load address of string

    // Call print function
    push rg1
    call print::print
    pop rg1                 ; Clean up (or pop zero to discard)

    hlt
```

### Example 4: Conditional Logic

```asm
// Demonstrates comparisons and branching

dw value: 42

main:
    ldw value, rg0          ; Load value (clobbers acc!)
    
    cmp rg0, zero
    jeq is_zero, zero
    jgt is_positive, zero
    jlt is_negative, zero

is_zero:
    lwi zero_msg, rg1
    jmp print_and_exit, zero

is_positive:
    lwi positive_msg, rg1
    jmp print_and_exit, zero

is_negative:
    lwi negative_msg, rg1
    jmp print_and_exit, zero

print_and_exit:
    push rg1
    call print::print
    pop zero
    hlt

db zero_msg: "Value is zero", 0
db positive_msg: "Value is positive", 0
db negative_msg: "Value is negative", 0
```

### Example 5: Loop with Counter

```asm
// Count from 0 to 9

dw stack: 0x10000

main:
    ldw stack, bpr          ; Set up stack
    mov bpr, spr
    
    lli 0, rg0              ; Counter = 0
    lli 10, rg1             ; Limit = 10

loop:
    // Process counter value
    push rg0
    call process_value
    pop zero
    
    inc rg0                 ; Counter++
    cmp rg0, rg1            ; Compare with limit
    jlt loop, zero          ; Loop if counter < limit
    
    hlt

process_value:
    push bpr
    mov spr, bpr
    
    ldw bpr, rg0, 8         ; Get value
    ; Process value here...
    
    mov bpr, spr
    pop bpr
    return
```

## Best Practices

### 1. Stack Management
- **Always balance push/pop operations** in the same function
- Set up stack frame (`push bpr; mov spr, bpr`) in every function
- Clean up arguments after function calls (caller's responsibility)
- Use `pop zero` to discard unwanted values
- Remember: stack grows DOWNWARD

### 2. Register Usage
- **Never rely on `acc` being preserved** across ANY operation
- Treat `acc` as write-only temporary storage
- Save caller-saved registers (rg0-rg3) before calls if needed
- Restore callee-saved registers (rg4-rgf) if modified
- Use `zero` register for zero constants

### 3. Memory Access
- Ensure proper alignment for halfword/word access
- Be aware that label-based loads/stores clobber `acc`
- Prefer register-based addressing when `acc` value matters
- Check that labels are defined before use

### 4. Function Design
- **Document calling convention** in function comments
- Always include prologue and epilogue
- Validate input arguments when appropriate
- Use consistent parameter order across related functions
- Return values via stack (overwrite arg0) or designated register

### 5. Code Organization
- Use meaningful label names (e.g., `loop_start` not `l1`)
- Comment complex operations
- Group related functions in modules
- Use includes for code reuse
- Keep functions focused and small

### 6. Performance Considerations
- Minimize memory accesses (use registers when possible)
- Avoid unnecessary comparisons
- Use shifts for multiplication/division by powers of 2:
  ```asm
  shl rg0, 3              ; Multiply by 8 (2^3)
  shr rg0, 2              ; Divide by 4 (2^2)
  ```
- Consider instruction pipelining if CPU supports it

### 7. ACC Register Awareness
**⚠️ CRITICAL - Common Mistakes:**

```asm
; WRONG - acc gets clobbered:
lli 100, acc
ldw data, rg0           ; acc is now GARBAGE!
add acc, rg0, rg1       ; Using garbage value!

; RIGHT - use a different register:
lli 100, rg2
ldw data, rg0           ; acc clobbered (don't care)
add rg2, rg0, rg1       ; rg2 still has 100

; WRONG - assuming acc preserved across call:
lli 42, acc
call some_function
add acc, rg0, rg1       ; acc probably destroyed!

; RIGHT - use caller-saved register:
lli 42, rg0
call some_function
add rg0, rg1, rg2       ; rg0 might be destroyed, so save it first!
```

## Common Patterns

### Loading 32-bit Constants
```asm
lli lower_16_bits, reg
lui upper_16_bits, reg

; Example:
lli 0x1234, rg0         ; rg0 = 0x00001234
lui 0xABCD, rg0         ; rg0 = 0xABCD1234
```

### Zero a Register
```asm
mov zero, reg           ; Method 1 (preferred - clearest)
xor reg, reg, reg       ; Method 2 (clever but less clear)
lli 0, reg              ; Method 3 (works but wastes upper bits clear)
```

### Copy Memory
```asm
ldw src_addr, rg0       ; Load from source (clobbers acc)
stw rg0, dest_addr, 0   ; Store to destination (clobbers acc)

; If you need acc preserved:
lli 0x1234, acc         ; Some value in acc
push acc                ; Save it
ldw src_addr, rg0       ; acc clobbered
stw rg0, dest_addr, 0   ; acc clobbered again
pop acc                 ; Restore acc
```

### Multiply/Divide by Power of 2
```asm
shl reg, 3              ; Multiply by 8 (2^3)
shr reg, 2              ; Divide by 4 (2^2)
```

### Boolean NOT
```asm
cmp reg, zero
jeq was_zero, zero      ; If reg == 0, result is 1
lli 0, reg
jmp done, zero
was_zero:
    lli 1, reg
done:
```

### Min/Max
```asm
; max(rg0, rg1) -> rg2
mov rg0, rg2            ; Assume rg0 is max
cmp rg0, rg1
jge done, zero          ; If rg0 >= rg1, we're done
mov rg1, rg2            ; rg1 was larger
done:
```

### Array Indexing
```asm
; Access array[i] where array is 32-bit words
; rg0 = array base address
; rg1 = index i
; Result in rg2

shl rg1, 2              ; Convert index to byte offset (i * 4)
add rg0, rg1, acc       ; acc = base + offset (use acc for temp)
ldw acc, rg2, 0         ; Load array[i]
```

## Troubleshooting

### Common Errors

**Alignment Fault:**
- Symptom: Exception when loading/storing halfword or word
- Cause: Address not properly aligned
- Fix: Ensure halfword addresses are even, word addresses divisible by 4

**Illegal Instruction:**
- Symptom: Unexpected halt or exception
- Cause: Invalid opcode or malformed instruction
- Fix: Check assembly syntax, verify instruction encoding

**Stack Corruption:**
- Symptom: Function returns to wrong address, registers have wrong values
- Cause: Unbalanced push/pop, incorrect stack frame management
- Fix: 
  - Verify push/pop balance
  - Check function epilogue restores bpr
  - Ensure caller cleans up arguments
  - Verify stack grows downward (push decrements)

**Wrong Results / Unexpected Values:**
- Symptom: Calculations produce incorrect results
- Cause: ACC clobbering, wrong register assumptions
- Fix:
  - Check if acc was assumed preserved (it never is!)
  - Verify lli called before lui for 32-bit constants
  - Check signed vs unsigned loads (ldb vs ldbs)
  - Verify register preservation across calls

**Label Not Found:**
- Symptom: Assembler error about undefined label
- Cause: Label used before definition, typo in label name
- Fix: Define labels before use, check spelling

### Debugging Tips

1. **Add NOP markers** at key points for breakpoints:
   ```asm
   nop                     ; Breakpoint here
   ```

2. **Print register values** using display memory:
   ```asm
   stw rg0, debug_out      ; Store to known location
   ```

3. **Use single-step execution** to trace program flow

4. **Verify stack pointer** values at function boundaries:
   ```asm
   ; After prologue, check:
   ; spr == bpr (should point to same location)
   ; After epilogue, check:
   ; spr restored to entry value
   ```

5. **Check label addresses** in disassembly output

6. **Trace ACC usage**:
   ```asm
   lli 0xDEAD, acc         ; Marker value
   ; ... your code ...
   cmp acc, zero
   jeq acc_was_clobbered, zero  ; If acc==0, it was overwritten
   ```

## Appendix: Instruction Quick Reference

| Category | Instructions |
|----------|-------------|
| **Data Movement** | mov, movs |
| **Memory Load** | ldb, ldbs, ldh, ldhs, ldw |
| **Memory Store** | stb, sth, stw |
| **Immediate Load** | lli, lui |
| **Jump/Branch** | jmp, jeq, jne, jgt, jge, jlt, jle |
| **Comparison** | cmp |
| **Arithmetic** | add, sub, iadd, isub, inc, dec |
| **Logical** | and, or, xor, not, nand, nor, xnor |
| **Shift** | shl, shr |
| **System** | hlt, nop, int, irt |
| **Pseudo - Data** | db, dh, dw, resb, resh, resw |
| **Pseudo - Stack** | push, pop, pusha, popa |
| **Pseudo - Memory** | lwi, ldb/ldh/ldw with labels, stb/sth/stw with labels |
| **Pseudo - Control** | call, return |
| **Pseudo - Module** | include |

## Version History

- **v2.0** - Corrected comprehensive reference based on implementation
  - **CORRECTED:** Stack grows downward (not upward)
  - **CORRECTED:** CALL/RETURN use stack for return addresses
  - **CORRECTED:** Pseudo-instructions use ACC as scratch (not rgf)
  - **CORRECTED:** Label loads use ACC for address calculation
  - **CORRECTED:** IADD/ISUB require destination (not optional)
  - **ADDED:** PUSHA/POPA documentation
  - **ADDED:** Detailed ACC volatility warnings throughout
  - **ADDED:** Stack evolution diagrams
  - **CLARIFIED:** Big-endian data directive encoding
  - **CLARIFIED:** Jump instruction semantics
  - All examples updated to reflect correct stack direction
  - Added extensive troubleshooting for ACC-related issues
