From e9329eca95bed523d6542016b46da58b45330ad4 Mon Sep 17 00:00:00 2001 From: zxq5 Date: Sat, 7 Feb 2026 18:21:37 +0000 Subject: [PATCH] update roadmap and ISA spec --- docs/DSA_Assembly_Reference.md | 693 ++++++++++++++++++++++----------- docs/DSA_ISA_Specification.md | 118 +++--- docs/DSA_Project_Roadmap.md | 20 +- 3 files changed, 557 insertions(+), 274 deletions(-) diff --git a/docs/DSA_Assembly_Reference.md b/docs/DSA_Assembly_Reference.md index 7f99089..7c6a81d 100644 --- a/docs/DSA_Assembly_Reference.md +++ b/docs/DSA_Assembly_Reference.md @@ -42,20 +42,25 @@ stw rg0, rg1, 8 ; Store rg0 TO address (rg1+8) | Register(s) | Type | Description | Usage Notes | |-------------|------|-------------|-------------| | **rg0-rgf** | General | 16 general-purpose registers | Use for variables, temporaries | -| **acc** | Special | Accumulator | ⚠️ Volatile - pseudo-instructions may overwrite | -| **spr** | Special | Stack pointer | Points to top of stack | +| **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 return address for functions | +| **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**: Used by pseudo-instructions for temporary values - do not rely on it being preserved -- **rgf**: Used by label-addressing pseudo-instructions as a scratch register -- **rg0-rge**: Available for general use; calling convention defines which are preserved +- **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 @@ -130,36 +135,50 @@ 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 addr [, offset_reg] ; Unconditional jump -jeq addr [, offset_reg] ; Jump if equal -jne addr [, offset_reg] ; Jump if not equal -jgt addr [, offset_reg] ; Jump if greater than -jge addr [, offset_reg] ; Jump if greater or equal -jlt addr [, offset_reg] ; Jump if less than -jle addr [, offset_reg] ; Jump if less or equal +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 -jmp 0x4000, zero ; Jump to absolute address 0x4000 -; Register-based jump +; Register-based jump jmp 0, ret ; Jump to address in ret register jmp 4, ret ; Jump to (ret + 4) -; PC-relative (if assembler supports) -jeq loop_start ; Jump to loop_start if equal flag set +; 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 @@ -168,17 +187,17 @@ cmp reg1, reg2 ; Compare reg1 with reg2, set flags **Flags Set:** - Equal: `reg1 == reg2` -- GreaterThan: `reg1 > reg2` -- LessThan: `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 ; Branch if rg0 == 0 -jgt is_positive ; Branch if rg0 > 0 -jlt is_negative ; Branch if rg0 < 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 @@ -186,8 +205,8 @@ jlt is_negative ; Branch if rg0 < 0 ```asm add src1, src2, dest ; dest = src1 + src2 sub src1, src2, dest ; dest = src1 - src2 -iadd src, immediate, dest ; dest = src + immediate -isub src, immediate, dest ; dest = src - immediate +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 ``` @@ -196,13 +215,14 @@ dec reg ; reg = reg - 1 ```asm add rg0, rg1, rg2 ; rg2 = rg0 + rg1 sub rg0, rg1, rg2 ; rg2 = rg0 - rg1 -iadd rg0, 10, rg0 ; rg0 = rg0 + 10 +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`, destination can be the same as source for in-place operations. +**⚠️ 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 @@ -232,14 +252,16 @@ shr reg, shift_amount ; Shift right by amount (0-31) ``` **Shift Amount:** -- Can be a literal: `shl rg0, 2` (shift by 2) -- Can be a register: `shl rg0, rg1` (shift by value in rg1, uses low 5 bits) +- **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 ; rg0 = rg0 << (rg1 & 0x1F) +; shl rg0, rg1 ; May not be supported by assembler ``` **Note:** Shift right is logical (zero-fill), not arithmetic @@ -265,6 +287,8 @@ irt ; Return from interrupt handler 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 @@ -282,7 +306,7 @@ dw stack_base: 0x10000 ; Single word value dw table: 0, 0, 0, 0 ; Array of 4 words ``` -**String Encoding:** Strings are encoded as byte sequences with escape sequences: +**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) @@ -290,6 +314,8 @@ dw table: 0, 0, 0, 0 ; Array of 4 words - `\"` = 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 @@ -314,19 +340,19 @@ 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: -iadd spr, 4, spr ; spr = spr + 4 (stack grows up) +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 -isub spr, 4, spr ; spr = spr - 4 +addi spr, 4, spr ; spr = spr + 4 (deallocate space) ``` -**Note:** DSA stack grows upward (toward higher addresses). - **Examples:** ```asm push rg0 ; Save rg0 on stack @@ -336,6 +362,51 @@ 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 @@ -354,7 +425,7 @@ lui message, rg0 ; Load upper 16 bits of address db message: "Hello!", 0 lwi message, rg0 ; rg0 = address of message -ldb rg0, rg1 ; rg1 = first byte of message ('H') +ldb rg0, rg1, 0 ; rg1 = first byte of message ('H') ``` ### Memory Access with Labels @@ -370,49 +441,66 @@ sth src_reg, label [, offset] stw src_reg, label [, offset] ``` -**Expansion (uses rgf as scratch):** +**⚠️ CRITICAL:** These pseudo-instructions use `acc` as a scratch register! The value in `acc` will be overwritten. + +**Expansion:** ```asm -; ldb buffer, rg2 expands to: -lli buffer, rgf ; Load lower 16 bits of buffer address -lui buffer, rgf ; Load upper 16 bits of buffer address -ldb rgf, rg2, 0 ; Load byte from address in rgf +; 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, rgf ; Load lower 16 bits of current address -lui current, rgf ; Load upper 16 bits of current address -stw rg1, rgf, 0 ; Store word to address in rgf +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 ``` -**⚠️ Important:** These pseudo-instructions use `rgf` as a scratch register! Do not use `rgf` for other purposes when using label-based memory access. - **Examples:** ```asm dw counter: 0 -ldw counter, rg0 ; Load value of counter -iadd rg0, 1, rg0 ; Increment -stw rg0, counter ; Store back +ldw counter, rg0 ; Load value of counter (clobbers acc!) +addi rg0, 1, rg0 ; Increment +stw rg0, counter ; Store back (clobbers acc!) ``` -### Function Call Pseudo-Instructions +**⚠️ 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 ``` -**Expansion:** +**⚠️ CRITICAL:** The calling mechanism uses the **STACK** to store return addresses, not just the `ret` register! + +**CALL Expansion:** ```asm ; call print::print expands to: -lwi print::print, ret ; Load function address into ret -jmp 0, ret ; Jump to function (saves return in pcx) -; (The assembler/linker resolves namespace::function to address) - -; return expands to: -jmp 0, ret ; Jump to address in ret register +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 ``` -**Note:** The actual return address handling may be more complex depending on the calling convention. +**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 @@ -437,25 +525,44 @@ call math::multiply ## Calling Convention -DSA uses a standard calling convention for function calls. +DSA uses a stack-based calling convention with downward-growing stack. ### Stack Frame Layout +**⚠️ CRITICAL:** Stack grows DOWNWARD (toward lower addresses)! + ``` -Higher Addresses -├─────────────┤ -│ Arg N │ ← spr + (8 + 4*(N-1)) -│ ... │ -│ Arg 2 │ ← spr + 16 -│ Arg 1 │ ← spr + 12 -│ Arg 0 │ ← spr + 8 (first argument) -├─────────────┤ -│ Ret Addr │ ← spr + 4 (return address) -├─────────────┤ -│ Old BPR │ ← spr + 0 (saved base pointer) -├─────────────┤ ← bpr, spr (current frame) -│ Locals │ (local variables, if any) -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 @@ -464,19 +571,19 @@ Lower Addresses 1. **Push arguments in reverse order** (last argument first): ```asm -push arg2 +push arg2 ; Push last argument first push arg1 -push arg0 +push arg0 ; First argument pushed last ``` 2. **Call the function:** ```asm -call namespace::function +call namespace::function ; Pushes return address, jumps to function ``` 3. **Clean up arguments** after return: ```asm -pop zero ; Discard or retrieve arg0 +pop zero ; Discard arg0 (or pop rg0 to get return value) pop zero ; Discard arg1 pop zero ; Discard arg2 ``` @@ -486,15 +593,15 @@ pop zero ; Discard arg2 1. **Set up stack frame:** ```asm function: - push bpr ; Save old base pointer + 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 spr+8 - ldw bpr, rg1, 12 ; Load arg1 from spr+12 - ldw bpr, rg2, 16 ; Load arg2 from spr+16 + 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:** @@ -503,56 +610,101 @@ function: add rg0, rg1, acc ; Example: acc = arg0 + arg1 ``` -4. **Store return value** (optional, overwrites arg0): +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 - pop bpr ; Restore old base pointer + mov bpr, spr ; Restore stack pointer to base + pop bpr ; Restore caller's base pointer ``` 6. **Return to caller:** ```asm - return + return ; Pop return address and jump ``` -### Complete Example +### 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 in arg0 position +; Returns: sum (overwrites arg0 position) add_function: - push bpr ; Save base pointer - mov spr, bpr ; Set up stack frame + ; Prologue + push bpr ; Save caller's base pointer + mov spr, bpr ; Set up our stack frame - ldw bpr, rg0, 8 ; Load arg0 - ldw bpr, rg1, 12 ; Load arg1 + ; Load arguments + ldw bpr, rg0, 8 ; rg0 = arg0 + ldw bpr, rg1, 12 ; rg1 = arg1 + + ; Perform operation add rg0, rg1, acc ; acc = arg0 + arg1 - stw acc, bpr, 8 ; Store result + ; Store return value (overwrites arg0 position) + stw acc, bpr, 8 ; Store result at bpr+8 - mov bpr, spr ; Restore stack - pop bpr ; Restore base pointer - return + ; Epilogue + mov bpr, spr ; Restore stack pointer + pop bpr ; Restore caller's base pointer + return ; Return to caller -; Caller: +; Caller example: main: + ; Set up stack lwi stack_base, bpr mov bpr, spr - lli 5, rg0 - lli 7, rg1 + ; Prepare arguments + lli 5, rg0 ; First argument = 5 + lli 7, rg1 ; Second argument = 7 - push rg1 ; Push arg1 (7) - push rg0 ; Push arg0 (5) + ; Push arguments (reverse order!) + push rg1 ; Push arg1 (7) first + push rg0 ; Push arg0 (5) second + + ; Call function call local::add_function - pop rg2 ; Get result (12) - pop zero ; Discard arg1 + + ; Retrieve result and clean up + pop rg2 ; Get result (12) - was at arg0 position + pop zero ; Discard arg1 slot hlt @@ -561,20 +713,45 @@ dw stack_base: 0x10000 ### Register Usage Conventions -| Register(s) | Usage | Preserved? | -|-------------|-------|------------| -| rg0-rg3 | Function arguments, temporaries | No (caller-saved) | -| rg4-rge | Local variables | Yes (callee-saved if used) | -| rgf | Scratch (used by label addressing) | No | -| acc | Temporary calculations | No | -| spr | Stack pointer | Yes (must be restored) | -| bpr | Base pointer | Yes (must be restored) | -| ret | Return address | Managed by call/return | +| 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 | -**Notes:** -- Functions should save and restore rg4-rge if they use them -- rg0-rg3 may be overwritten by called functions -- acc and rgf are volatile - assume they're overwritten +**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 @@ -586,18 +763,18 @@ dw stack_base: 0x10000 // // Usage: // include multiply "multiply.dsa" -// push arg1 -// push arg0 +// push multiplicand +// push multiplier // call multiply::multiply -// pop result -// pop zero ; discard second argument +// pop result ; Result is in arg0 position +// pop zero ; Clean up arg1 multiply: push bpr mov spr, bpr - ldw bpr, rg0, 8 ; Load multiplier - ldw bpr, rg1, 12 ; Load multiplicand + ldw bpr, rg0, 8 ; Load multiplier (arg0) + ldw bpr, rg1, 12 ; Load multiplicand (arg1) lli 0, acc ; Initialize result to 0 @@ -606,9 +783,9 @@ loop_start: dec rg1 ; multiplicand-- cmp rg1, zero - jgt loop_start ; Continue if multiplicand > 0 + jgt loop_start, zero ; Continue if multiplicand > 0 - stw acc, bpr, 8 ; Store result for caller + stw acc, bpr, 8 ; Store result for caller (at arg0) mov bpr, spr pop bpr @@ -639,19 +816,19 @@ print: mov spr, bpr ldw bpr, rg0, 8 ; Get string address argument - ldw current, rg1 ; Get current cursor position + ldw current, rg1 ; Get current cursor position (clobbers acc!) print_loop: - ldb rg0, acc ; Load character - stb acc, rg1 ; Store to display + ldb rg0, acc, 0 ; Load character + stb acc, rg1, 0 ; Store to display - iadd rg0, 1, rg0 ; Advance string pointer - iadd rg1, 1, rg1 ; Advance cursor + addi rg0, 1, rg0 ; Advance string pointer + addi rg1, 1, rg1 ; Advance cursor cmp acc, zero ; Check for null terminator - jne print_loop ; Continue if not null + jne print_loop, zero ; Continue if not null - stw rg1, current ; Save cursor position + stw rg1, current ; Save cursor position (clobbers acc!) mov bpr, spr pop bpr @@ -662,8 +839,8 @@ reset: push bpr mov spr, bpr - ldw display, rg1 ; Load display base - stw rg1, current ; Reset cursor to start + ldw display, rg1 ; Load display base (clobbers acc!) + stw rg1, current ; Reset cursor to start (clobbers acc!) mov bpr, spr pop bpr @@ -683,17 +860,17 @@ db string: "'To confuse your enemy, you must first confuse yourself' - Probably init: // Set up stack - ldw stack, bpr + ldw stack, bpr ; Load stack base (clobbers acc!) mov bpr, spr start: // Load string address - lwi string, rg1 + lwi string, rg1 ; Load address of string // Call print function push rg1 call print::print - pop rg1 ; Clean up (rg1 now contains arg we passed) + pop rg1 ; Clean up (or pop zero to discard) hlt ``` @@ -706,27 +883,24 @@ start: dw value: 42 main: - ldw value, rg0 + ldw value, rg0 ; Load value (clobbers acc!) cmp rg0, zero - jeq is_zero - jgt is_positive - jlt is_negative + jeq is_zero, zero + jgt is_positive, zero + jlt is_negative, zero is_zero: - // Handle zero case lwi zero_msg, rg1 - jmp print_and_exit + jmp print_and_exit, zero is_positive: - // Handle positive case lwi positive_msg, rg1 - jmp print_and_exit + jmp print_and_exit, zero is_negative: - // Handle negative case lwi negative_msg, rg1 - jmp print_and_exit + jmp print_and_exit, zero print_and_exit: push rg1 @@ -747,21 +921,21 @@ db negative_msg: "Value is negative", 0 dw stack: 0x10000 main: - ldw stack, bpr + ldw stack, bpr ; Set up stack mov bpr, spr lli 0, rg0 ; Counter = 0 lli 10, rg1 ; Limit = 10 loop: - // Do something with counter in rg0 + // Process counter value push rg0 call process_value pop zero inc rg0 ; Counter++ cmp rg0, rg1 ; Compare with limit - jlt loop ; Loop if counter < limit + jlt loop, zero ; Loop if counter < limit hlt @@ -780,61 +954,73 @@ process_value: ## Best Practices ### 1. Stack Management -- Always balance push/pop operations -- Set up stack frame in every function -- Clean up arguments after function calls +- **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 -- Don't rely on `acc` being preserved -- Don't use `rgf` for variables (used by label addressing) -- Save callee-saved registers if you modify them +- **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 -- Use label-based addressing for clearer code +- 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 comments +- **Document calling convention** in function comments +- Always include prologue and epilogue - Validate input arguments when appropriate -- Use consistent parameter order -- Return values via stack or designated register +- Use consistent parameter order across related functions +- Return values via stack (overwrite arg0) or designated register ### 5. Code Organization -- Use meaningful label names +- 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 -- Minimize memory accesses (use registers) +### 6. Performance Considerations +- Minimize memory accesses (use registers when possible) - Avoid unnecessary comparisons -- Use shifts for multiplication/division by powers of 2 -- Consider instruction pipelining if supported +- 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 -## Assembler Directives +### 7. ACC Register Awareness +**⚠️ CRITICAL - Common Mistakes:** -### Alignment (if supported) ```asm -.align 4 ; Align to 4-byte boundary -.align 2 ; Align to 2-byte boundary -``` +; WRONG - acc gets clobbered: +lli 100, acc +ldw data, rg0 ; acc is now GARBAGE! +add acc, rg0, rg1 ; Using garbage value! -### Origin (if supported) -```asm -.org 0x1000 ; Set location counter to 0x1000 -``` +; RIGHT - use a different register: +lli 100, rg2 +ldw data, rg0 ; acc clobbered (don't care) +add rg2, rg0, rg1 ; rg2 still has 100 -### Section Control (if supported) -```asm -.text ; Code section -.data ; Data section -.bss ; Uninitialized data section -``` +; WRONG - assuming acc preserved across call: +lli 42, acc +call some_function +add acc, rg0, rg1 ; acc probably destroyed! -**Note:** Assembler directive support depends on the specific DSA assembler implementation. +; 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 @@ -842,82 +1028,139 @@ process_value: ```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 -xor reg, reg, reg ; Method 2 -lli 0, reg ; Method 3 +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 -stw rg0, dest_addr ; Store to destination +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 by Power of 2 +### Multiply/Divide by Power of 2 ```asm -shl reg, 3 ; Multiply by 8 (2^3) -``` - -### Divide by Power of 2 -```asm -shr reg, 2 ; Divide by 4 (2^2) +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 ; If reg == 0, result is 1 +jeq was_zero, zero ; If reg == 0, result is 1 lli 0, reg -jmp done +jmp done, zero was_zero: -lli 1, reg + lli 1, reg done: ``` ### Min/Max ```asm ; max(rg0, rg1) -> rg2 -mov rg0, rg2 ; Assume rg0 is max +mov rg0, rg2 ; Assume rg0 is max cmp rg0, rg1 -jge done -mov rg1, rg2 ; rg1 was larger +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:** -- Check that halfword loads/stores use even addresses -- Check that word loads/stores use addresses divisible by 4 +- 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:** -- Verify opcode is valid -- Check that shift amount is 0 for non-shift instructions -- Ensure you're not using `noreg` as a source/destination +- Symptom: Unexpected halt or exception +- Cause: Invalid opcode or malformed instruction +- Fix: Check assembly syntax, verify instruction encoding **Stack Corruption:** -- Verify push/pop balance -- Check that functions restore `bpr` before returning -- Ensure caller cleans up arguments +- 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:** -- Verify `lli` is called before `lui` when loading constants -- Check that you're not relying on `acc` or `rgf` being preserved -- Verify signed vs. unsigned loads (ldb vs. ldbs) +**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` instructions as breakpoint markers -2. Print register values using display memory -3. Use single-step execution to trace program flow -4. Verify stack pointer values at function boundaries -5. Check label addresses in disassembly +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 @@ -933,12 +1176,24 @@ done: | **Logical** | and, or, xor, not, nand, nor, xnor | | **Shift** | shl, shr | | **System** | hlt, nop, int, irt | -| **Pseudo** | db, dh, dw, resb, resh, resw, push, pop, lwi, call, return, include | +| **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 -- **v1.0** - Initial comprehensive reference - - Combined hardware instructions and pseudo-instructions - - Added complete calling convention - - Included practical examples - - Documented common patterns and best practices +- **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 diff --git a/docs/DSA_ISA_Specification.md b/docs/DSA_ISA_Specification.md index c2973ee..fdb709d 100644 --- a/docs/DSA_ISA_Specification.md +++ b/docs/DSA_ISA_Specification.md @@ -12,7 +12,9 @@ The Damn Simple Architecture (DSA) is a 32-bit RISC-style architecture designed | Halfword | 16 bits | 2-byte aligned | | Word | 32 bits | 4-byte aligned | -All multi-byte values use little-endian byte order. +**Note on Endianness:** +- Instructions and numeric data in memory: Little-endian +- Data defined via `db/dh/dw` directives: Big-endian (assembler-specific) ## Registers @@ -23,33 +25,32 @@ DSA provides 32 programmer-accessible registers plus several internal system reg | Hex | Register | Type | Description | |-----|----------|------|-------------| | 0x00-0x0F | **rg0-rgf** | General Purpose | 16 general-purpose registers for variables and temporary values | -| 0x10 | **acc** | Special | Accumulator for calculations and temporary storage
⚠️ May be overwritten by pseudo-instructions | +| 0x10 | **acc** | Special | Accumulator for calculations and temporary storage
⚠️ Used as scratch by pseudo-instructions - volatile | | 0x11 | **spr** | Special | Stack pointer - points to top of stack | | 0x12 | **bpr** | Special | Base pointer - used for stack frame management | -| 0x13 | **ret** | Special | Return address register - stores function return addresses | +| 0x13 | **ret** | Special | Return address register - used for function returns | | 0x14 | **idr** | Privileged | Interrupt descriptor table address
Read/write triggers protection fault in user mode | | 0x15 | **mmr** | Privileged | Hardware memory map table address
Read/write triggers protection fault in user mode | | 0x16 | **zero** | Read-only | Constant zero value
Reads always return 0, writes are discarded | -| 0x17 | **noreg** | Placeholder | Indicates unused register field
Read/write triggers illegal instruction fault | +| 0x17 | **noreg** | Placeholder | Indicates unused register field
Read/write triggers illegal instruction fault
Can also be referenced as **null** | | 0x18-0x1F | - | Reserved | Reserved for future use | +**System Registers (indices 0x18-0x1C):** +These exist in the encoding space but are internal to the CPU implementation: + +| Hex | Register | Description | +|-----|----------|-------------| +| 0x18 | **mar** | Memory Address Register (CPU internal) | +| 0x19 | **mdr** | Memory Data Register (CPU internal) | +| 0x1A | **sts** | Status Register (CPU internal) | +| 0x1B | **cir** | Current Instruction Register (CPU internal) | +| 0x1C | **pcx** | Program Counter (read-only, special access) | + **Note on PCX (Program Counter):** -- PCX is a read-only system register that can be accessed in some contexts +- PCX can be read in certain contexts (e.g., stored during CALL) - Writing to PCX triggers a protection fault - PCX is automatically updated by jump and branch instructions -### System Registers (Internal) - -These registers are used internally by the CPU and are not directly accessible via assembly instructions: - -| Register | Description | -|----------|-------------| -| **MAR** | Memory Address Register - holds address for memory operations | -| **MDR** | Memory Data Register - holds data for memory transfers | -| **CIR** | Current Instruction Register - holds instruction being executed | -| **STS** | Status Register - stores comparison and arithmetic flags | -| **PCX** | Program Counter - stores address of next instruction | - ### Status Register (STS) Layout The status register is a 32-bit register with the following flag bits: @@ -108,7 +109,7 @@ Used for operations with a 16-bit immediate value. **Usage:** - Arithmetic: Immediate is a signed value - Memory access: Immediate is a signed byte offset from base address -- Branches: Immediate is a signed offset from current PCX +- Branches: Immediate is a signed offset added to base register - Literal loads: Immediate is unsigned 16-bit value ### J-Type (Jump) Instructions @@ -131,7 +132,7 @@ Used for absolute jumps with large address ranges. **Jump Range:** 256MB region around current PC (±128MB) -**Note:** J-type instructions are defined but currently unused. Use I-type JMP with register addressing for long jumps. +**Note:** J-type instructions are defined but currently unused. Use I-type JMP with register addressing for all jumps. ## Hardware Instructions @@ -197,8 +198,8 @@ In machine code: SrcReg (SrcReg field), BaseReg (DestReg field), Offset (Immedia | Hex | Mnemonic | Type | Operands | Description | |-----|----------|------|----------|-------------| -| 0x0B | **LLI** | I | DestReg, Value | Load 16-bit value into lower 16 bits
⚠️ **CLEARS upper 16 bits!** | -| 0x0C | **LUI** | I | DestReg, Value | Load 16-bit value into upper 16 bits
Lower 16 bits unchanged | +| 0x0B | **LLI** | I | Value, DestReg | Load 16-bit value into lower 16 bits
⚠️ **CLEARS upper 16 bits!** | +| 0x0C | **LUI** | I | Value, DestReg | Load 16-bit value into upper 16 bits
Lower 16 bits unchanged | **Usage for 32-bit Values:** ``` @@ -208,29 +209,38 @@ LUI 0xABCD, rg0 ; rg0 = 0xABCD1234 **⚠️ CRITICAL:** Always execute LLI before LUI, as LLI clears the upper 16 bits! +**Note on LUI:** The assembler may shift the immediate value right by 16 bits when encoding, so specify the upper 16 bits directly (e.g., `LUI 0xABCD, rg0` not `LUI 0xABCD0000, rg0`). + **Encoding Note:** -In machine code: Value (Immediate field), DestReg field (SrcReg unused, set to noreg) +In machine code: Value (Immediate field), DestReg (SrcReg field for LLI, SrcReg field for LUI) ### Jump and Branch Instructions | Hex | Mnemonic | Type | Operands | Description | |-----|----------|------|----------|-------------| -| 0x0D | **JMP** | I | DestReg, Offset | Unconditional jump to (DestReg + Offset) | -| 0x0E | **JEQ** | I | DestReg, Offset | Jump if Equal flag set | -| 0x0F | **JNE** | I | DestReg, Offset | Jump if Equal flag NOT set | -| 0x10 | **JGT** | I | DestReg, Offset | Jump if GreaterThan flag set | -| 0x11 | **JGE** | I | DestReg, Offset | Jump if GreaterThan OR Equal flag set | -| 0x12 | **JLT** | I | DestReg, Offset | Jump if LessThan flag set | -| 0x13 | **JLE** | I | DestReg, Offset | Jump if LessThan OR Equal flag set | +| 0x0D | **JMP** | I | Offset, BaseReg | Unconditional jump to (BaseReg + Offset) | +| 0x0E | **JEQ** | I | Offset, BaseReg | Jump if Equal flag set | +| 0x0F | **JNE** | I | Offset, BaseReg | Jump if Equal flag NOT set | +| 0x10 | **JGT** | I | Offset, BaseReg | Jump if GreaterThan flag set | +| 0x11 | **JGE** | I | Offset, BaseReg | Jump if GreaterThan OR Equal flag set | +| 0x12 | **JLT** | I | Offset, BaseReg | Jump if LessThan flag set | +| 0x13 | **JLE** | I | Offset, BaseReg | Jump if LessThan OR Equal flag set | **Jump Calculation:** -- Target address = DestReg + SignExtend(Offset) -- If DestReg = zero, this becomes absolute addressing with Offset -- If DestReg = pcx, this becomes PC-relative addressing +- Target address = BaseReg + SignExtend(Offset) +- If BaseReg = zero, this becomes absolute addressing with Offset +- If BaseReg = ret, this becomes return-style addressing - Conditional jumps check flags in STS register +**Common Patterns:** +``` +JMP label, zero ; Absolute jump to label address +JMP 0, ret ; Jump to address in ret register +JMP 4, ret ; Jump to (ret + 4) +``` + **Encoding Note:** -In machine code: DestReg field, Offset (Immediate field) (SrcReg unused, set to noreg) +In machine code: Offset (Immediate field), BaseReg (SrcReg field) (DestReg unused, set to noreg) ### Comparison @@ -265,8 +275,8 @@ DestReg and ShiftAmt fields unused (set to noreg and 0) - Other flags undefined after arithmetic (use CMP for comparisons) **Encoding Notes:** -- INC/DEC: Reg in SrcReg1 field, also copied to DestReg field -- IADD/ISUB: Immediate is signed 16-bit value +- INC/DEC: Reg in SrcReg1 field, DestReg set to noreg +- IADD/ISUB: Immediate is signed 16-bit value, all three operands required ### Bitwise Logical Operations @@ -285,7 +295,7 @@ DestReg and ShiftAmt fields unused (set to noreg and 0) - Other flags undefined **Encoding Note:** -NOT uses only Src and Dest; SrcReg2 unused (set to noreg) +NOT uses only Src (SrcReg1) and Dest (DestReg); SrcReg2 unused (set to noreg) ### Shift Operations @@ -295,17 +305,22 @@ NOT uses only Src and Dest; SrcReg2 unused (set to noreg) | 0x18 | **SHR** | R | Reg, ShiftAmount | Shift Reg right by ShiftAmount bits
Zero-fill from left (logical shift) | **Shift Amount:** -- Can be a 5-bit literal (0-31) in ShiftAmt field -- Can be a register value (low 5 bits used) - - If using register: Place in SrcReg2, set ShiftAmt to 0 - - If using literal: Place in ShiftAmt field, set SrcReg2 to noreg +- **Literal shifts**: ShiftAmount is a 5-bit literal (0-31) in assembly + - Stored in ShiftAmt field of instruction + - SrcReg2 set to noreg +- **Register shifts**: ShiftAmount is a register containing shift value + - Register specified in SrcReg2 field + - ShiftAmt field must be 0 + - Only low 5 bits of register value used + +**Note:** Current assembler implementation may only support literal shifts. Check assembler documentation. **Flag Effects:** - Zero flag set if result is zero **Encoding Notes:** -- Reg in both SrcReg1 and DestReg fields -- For literal shifts: ShiftAmt field contains shift count +- Reg in both SrcReg1 and DestReg fields (shifted in place) +- For literal shifts: ShiftAmt field contains shift count, SrcReg2 = noreg - For register shifts: SrcReg2 contains register, ShiftAmt must be 0 ### System and Control Instructions @@ -331,6 +346,17 @@ NOT uses only Src and Dest; SrcReg2 unused (set to noreg) - INT: InterruptCode in low 8 bits of Immediate field - IRT/HLT: All register fields set to noreg, ShiftAmt to 0 +### Meta Instructions (Assembler/Linker) + +These instructions are used by the assembler and linker but may not represent real CPU operations. + +| Hex | Mnemonic | Description | +|-----|----------|-------------| +| 0x27 | **SEGMENT** | Segment marker (implementation-specific) | +| 0x3E | **DATA** | Raw data embedding | + +**Note:** The SEGMENT instruction opcode may vary between implementations (0x27 in assembler, 0x3F in some contexts). Consult your specific toolchain documentation. + ## Instruction Summary Table | Opcode | Mnemonic | Type | Category | @@ -374,6 +400,8 @@ NOT uses only Src and Dest; SrcReg2 unused (set to noreg) | 0x24 | HLT | R | System | | 0x25 | IADD | I | Arithmetic | | 0x26 | ISUB | I | Arithmetic | +| 0x27 | SEGMENT | - | Meta | +| 0x3E | DATA | - | Meta | ## Exception Conditions @@ -393,9 +421,9 @@ See the DSA Assembly Language Reference for the complete calling convention and ## Notes on Design 1. **Word Size:** All addresses and general computation is 32-bit -2. **Endianness:** Little-endian byte order -3. **Stack Growth:** Stack grows upward (incrementing addresses) +2. **Endianness:** Little-endian for instructions and runtime data; assembler data directives may use big-endian +3. **Stack Growth:** Stack grows **downward** (toward lower addresses) - PUSH decrements SPR 4. **Alignment:** Natural alignment required for halfword and word accesses 5. **Sign Extension:** All immediate values are sign-extended unless noted 6. **Zero Register:** Provides constant zero, writes are legal but discarded -7. **Reserved Encodings:** Opcodes 0x27-0x3F reserved for future use +7. **Reserved Encodings:** Opcodes 0x27-0x3D and 0x3F reserved or implementation-specific diff --git a/docs/DSA_Project_Roadmap.md b/docs/DSA_Project_Roadmap.md index 9ad612a..19ecaf7 100644 --- a/docs/DSA_Project_Roadmap.md +++ b/docs/DSA_Project_Roadmap.md @@ -263,12 +263,12 @@ - [ ] Array syntax - [ ] Struct syntax - [x] Pointer syntax - - [ ] Namespaced call syntax + - [x] Namespaced call syntax - [x] AST node definitions - [ ] Error recovery mechanisms - [ ] Comprehensive parser tests - [ ] Syntax error message quality testing -- [ ] Implement C frontend by moving lexer/parser from `c_compiler` to the new `compiler` project structure +- [x] Implement C frontend by moving lexer/parser from `c_compiler` to the new `compiler` project structure - [ ] Evaluate possible memory management strategies (e.g., keep all variables on the stack vs spill only when calling functions) --- @@ -290,7 +290,7 @@ - [ ] Optimize register allocation further - [x] Implement proper function calling conventions - [ ] Add constant folding optimization -- [ ] Dead code elimination +- [x] Dead code elimination - [ ] Test each feature thoroughly --- @@ -376,7 +376,7 @@ **Dependencies:** None **Deliverable:** `docs/build-system-design.md` -- [ ] Define project structure conventions +- [x] Define project structure conventions - [ ] Design build manifest format (`dsa-project.toml` or similar) - [ ] Dependency resolution strategy - [ ] Build cache design @@ -391,12 +391,12 @@ **Dependencies:** 3.1.1, 1.2.2, 1.1.3, 2.1.3 **Deliverable:** `dsa-build` executable -- [ ] Create crate: `dsa-build` +- [x] Create crate: `dsa-build` - [ ] Manifest parser - [ ] Dependency graph builder - [ ] Task orchestrator - - [ ] Compilation tasks - - [ ] Assembly tasks + - [x] Compilation tasks + - [x] Assembly tasks - [ ] Linking tasks - [ ] Build cache implementation - [ ] Parallel build support @@ -412,11 +412,11 @@ **Dependencies:** 3.1.2 **Deliverable:** Enhanced `dsa-build` with project management -- [ ] `dsa new ` — Create new project -- [ ] `dsa init` — Initialize in existing directory +- [x] `dsa new ` — Create new project +- [x] `dsa init` — Initialize in existing directory - [ ] `dsa add ` — Add dependency - [ ] Binary vs library project types -- [ ] Template system for project scaffolding +- [x] Template system for project scaffolding - [ ] Documentation for each command ---