Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e9329eca95 | |||
| 250b780e14 |
+469
-214
File diff suppressed because it is too large
Load Diff
@@ -12,7 +12,9 @@ The Damn Simple Architecture (DSA) is a 32-bit RISC-style architecture designed
|
|||||||
| Halfword | 16 bits | 2-byte aligned |
|
| Halfword | 16 bits | 2-byte aligned |
|
||||||
| Word | 32 bits | 4-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
|
## Registers
|
||||||
|
|
||||||
@@ -23,33 +25,32 @@ DSA provides 32 programmer-accessible registers plus several internal system reg
|
|||||||
| Hex | Register | Type | Description |
|
| Hex | Register | Type | Description |
|
||||||
|-----|----------|------|-------------|
|
|-----|----------|------|-------------|
|
||||||
| 0x00-0x0F | **rg0-rgf** | General Purpose | 16 general-purpose registers for variables and temporary values |
|
| 0x00-0x0F | **rg0-rgf** | General Purpose | 16 general-purpose registers for variables and temporary values |
|
||||||
| 0x10 | **acc** | Special | Accumulator for calculations and temporary storage<br/>⚠️ May be overwritten by pseudo-instructions |
|
| 0x10 | **acc** | Special | Accumulator for calculations and temporary storage<br/>⚠️ Used as scratch by pseudo-instructions - volatile |
|
||||||
| 0x11 | **spr** | Special | Stack pointer - points to top of stack |
|
| 0x11 | **spr** | Special | Stack pointer - points to top of stack |
|
||||||
| 0x12 | **bpr** | Special | Base pointer - used for stack frame management |
|
| 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<br/>Read/write triggers protection fault in user mode |
|
| 0x14 | **idr** | Privileged | Interrupt descriptor table address<br/>Read/write triggers protection fault in user mode |
|
||||||
| 0x15 | **mmr** | Privileged | Hardware memory map table address<br/>Read/write triggers protection fault in user mode |
|
| 0x15 | **mmr** | Privileged | Hardware memory map table address<br/>Read/write triggers protection fault in user mode |
|
||||||
| 0x16 | **zero** | Read-only | Constant zero value<br/>Reads always return 0, writes are discarded |
|
| 0x16 | **zero** | Read-only | Constant zero value<br/>Reads always return 0, writes are discarded |
|
||||||
| 0x17 | **noreg** | Placeholder | Indicates unused register field<br/>Read/write triggers illegal instruction fault |
|
| 0x17 | **noreg** | Placeholder | Indicates unused register field<br/>Read/write triggers illegal instruction fault<br/>Can also be referenced as **null** |
|
||||||
| 0x18-0x1F | - | Reserved | Reserved for future use |
|
| 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):**
|
**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
|
- Writing to PCX triggers a protection fault
|
||||||
- PCX is automatically updated by jump and branch instructions
|
- 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
|
### Status Register (STS) Layout
|
||||||
|
|
||||||
The status register is a 32-bit register with the following flag bits:
|
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:**
|
**Usage:**
|
||||||
- Arithmetic: Immediate is a signed value
|
- Arithmetic: Immediate is a signed value
|
||||||
- Memory access: Immediate is a signed byte offset from base address
|
- 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
|
- Literal loads: Immediate is unsigned 16-bit value
|
||||||
|
|
||||||
### J-Type (Jump) Instructions
|
### J-Type (Jump) Instructions
|
||||||
@@ -131,7 +132,7 @@ Used for absolute jumps with large address ranges.
|
|||||||
|
|
||||||
**Jump Range:** 256MB region around current PC (±128MB)
|
**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
|
## Hardware Instructions
|
||||||
|
|
||||||
@@ -197,8 +198,8 @@ In machine code: SrcReg (SrcReg field), BaseReg (DestReg field), Offset (Immedia
|
|||||||
|
|
||||||
| Hex | Mnemonic | Type | Operands | Description |
|
| Hex | Mnemonic | Type | Operands | Description |
|
||||||
|-----|----------|------|----------|-------------|
|
|-----|----------|------|----------|-------------|
|
||||||
| 0x0B | **LLI** | I | DestReg, Value | Load 16-bit value into lower 16 bits<br/>⚠️ **CLEARS upper 16 bits!** |
|
| 0x0B | **LLI** | I | Value, DestReg | Load 16-bit value into lower 16 bits<br/>⚠️ **CLEARS upper 16 bits!** |
|
||||||
| 0x0C | **LUI** | I | DestReg, Value | Load 16-bit value into upper 16 bits<br/>Lower 16 bits unchanged |
|
| 0x0C | **LUI** | I | Value, DestReg | Load 16-bit value into upper 16 bits<br/>Lower 16 bits unchanged |
|
||||||
|
|
||||||
**Usage for 32-bit Values:**
|
**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!
|
**⚠️ 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:**
|
**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
|
### Jump and Branch Instructions
|
||||||
|
|
||||||
| Hex | Mnemonic | Type | Operands | Description |
|
| Hex | Mnemonic | Type | Operands | Description |
|
||||||
|-----|----------|------|----------|-------------|
|
|-----|----------|------|----------|-------------|
|
||||||
| 0x0D | **JMP** | I | DestReg, Offset | Unconditional jump to (DestReg + Offset) |
|
| 0x0D | **JMP** | I | Offset, BaseReg | Unconditional jump to (BaseReg + Offset) |
|
||||||
| 0x0E | **JEQ** | I | DestReg, Offset | Jump if Equal flag set |
|
| 0x0E | **JEQ** | I | Offset, BaseReg | Jump if Equal flag set |
|
||||||
| 0x0F | **JNE** | I | DestReg, Offset | Jump if Equal flag NOT set |
|
| 0x0F | **JNE** | I | Offset, BaseReg | Jump if Equal flag NOT set |
|
||||||
| 0x10 | **JGT** | I | DestReg, Offset | Jump if GreaterThan flag set |
|
| 0x10 | **JGT** | I | Offset, BaseReg | Jump if GreaterThan flag set |
|
||||||
| 0x11 | **JGE** | I | DestReg, Offset | Jump if GreaterThan OR Equal flag set |
|
| 0x11 | **JGE** | I | Offset, BaseReg | Jump if GreaterThan OR Equal flag set |
|
||||||
| 0x12 | **JLT** | I | DestReg, Offset | Jump if LessThan flag set |
|
| 0x12 | **JLT** | I | Offset, BaseReg | Jump if LessThan flag set |
|
||||||
| 0x13 | **JLE** | I | DestReg, Offset | Jump if LessThan OR Equal flag set |
|
| 0x13 | **JLE** | I | Offset, BaseReg | Jump if LessThan OR Equal flag set |
|
||||||
|
|
||||||
**Jump Calculation:**
|
**Jump Calculation:**
|
||||||
- Target address = DestReg + SignExtend(Offset)
|
- Target address = BaseReg + SignExtend(Offset)
|
||||||
- If DestReg = zero, this becomes absolute addressing with Offset
|
- If BaseReg = zero, this becomes absolute addressing with Offset
|
||||||
- If DestReg = pcx, this becomes PC-relative addressing
|
- If BaseReg = ret, this becomes return-style addressing
|
||||||
- Conditional jumps check flags in STS register
|
- 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:**
|
**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
|
### Comparison
|
||||||
|
|
||||||
@@ -265,8 +275,8 @@ DestReg and ShiftAmt fields unused (set to noreg and 0)
|
|||||||
- Other flags undefined after arithmetic (use CMP for comparisons)
|
- Other flags undefined after arithmetic (use CMP for comparisons)
|
||||||
|
|
||||||
**Encoding Notes:**
|
**Encoding Notes:**
|
||||||
- INC/DEC: Reg in SrcReg1 field, also copied to DestReg field
|
- INC/DEC: Reg in SrcReg1 field, DestReg set to noreg
|
||||||
- IADD/ISUB: Immediate is signed 16-bit value
|
- IADD/ISUB: Immediate is signed 16-bit value, all three operands required
|
||||||
|
|
||||||
### Bitwise Logical Operations
|
### Bitwise Logical Operations
|
||||||
|
|
||||||
@@ -285,7 +295,7 @@ DestReg and ShiftAmt fields unused (set to noreg and 0)
|
|||||||
- Other flags undefined
|
- Other flags undefined
|
||||||
|
|
||||||
**Encoding Note:**
|
**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
|
### 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<br/>Zero-fill from left (logical shift) |
|
| 0x18 | **SHR** | R | Reg, ShiftAmount | Shift Reg right by ShiftAmount bits<br/>Zero-fill from left (logical shift) |
|
||||||
|
|
||||||
**Shift Amount:**
|
**Shift Amount:**
|
||||||
- Can be a 5-bit literal (0-31) in ShiftAmt field
|
- **Literal shifts**: ShiftAmount is a 5-bit literal (0-31) in assembly
|
||||||
- Can be a register value (low 5 bits used)
|
- Stored in ShiftAmt field of instruction
|
||||||
- If using register: Place in SrcReg2, set ShiftAmt to 0
|
- SrcReg2 set to noreg
|
||||||
- If using literal: Place in ShiftAmt field, set SrcReg2 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:**
|
**Flag Effects:**
|
||||||
- Zero flag set if result is zero
|
- Zero flag set if result is zero
|
||||||
|
|
||||||
**Encoding Notes:**
|
**Encoding Notes:**
|
||||||
- Reg in both SrcReg1 and DestReg fields
|
- Reg in both SrcReg1 and DestReg fields (shifted in place)
|
||||||
- For literal shifts: ShiftAmt field contains shift count
|
- For literal shifts: ShiftAmt field contains shift count, SrcReg2 = noreg
|
||||||
- For register shifts: SrcReg2 contains register, ShiftAmt must be 0
|
- For register shifts: SrcReg2 contains register, ShiftAmt must be 0
|
||||||
|
|
||||||
### System and Control Instructions
|
### 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
|
- INT: InterruptCode in low 8 bits of Immediate field
|
||||||
- IRT/HLT: All register fields set to noreg, ShiftAmt to 0
|
- 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
|
## Instruction Summary Table
|
||||||
|
|
||||||
| Opcode | Mnemonic | Type | Category |
|
| Opcode | Mnemonic | Type | Category |
|
||||||
@@ -374,6 +400,8 @@ NOT uses only Src and Dest; SrcReg2 unused (set to noreg)
|
|||||||
| 0x24 | HLT | R | System |
|
| 0x24 | HLT | R | System |
|
||||||
| 0x25 | IADD | I | Arithmetic |
|
| 0x25 | IADD | I | Arithmetic |
|
||||||
| 0x26 | ISUB | I | Arithmetic |
|
| 0x26 | ISUB | I | Arithmetic |
|
||||||
|
| 0x27 | SEGMENT | - | Meta |
|
||||||
|
| 0x3E | DATA | - | Meta |
|
||||||
|
|
||||||
## Exception Conditions
|
## Exception Conditions
|
||||||
|
|
||||||
@@ -393,9 +421,9 @@ See the DSA Assembly Language Reference for the complete calling convention and
|
|||||||
## Notes on Design
|
## Notes on Design
|
||||||
|
|
||||||
1. **Word Size:** All addresses and general computation is 32-bit
|
1. **Word Size:** All addresses and general computation is 32-bit
|
||||||
2. **Endianness:** Little-endian byte order
|
2. **Endianness:** Little-endian for instructions and runtime data; assembler data directives may use big-endian
|
||||||
3. **Stack Growth:** Stack grows upward (incrementing addresses)
|
3. **Stack Growth:** Stack grows **downward** (toward lower addresses) - PUSH decrements SPR
|
||||||
4. **Alignment:** Natural alignment required for halfword and word accesses
|
4. **Alignment:** Natural alignment required for halfword and word accesses
|
||||||
5. **Sign Extension:** All immediate values are sign-extended unless noted
|
5. **Sign Extension:** All immediate values are sign-extended unless noted
|
||||||
6. **Zero Register:** Provides constant zero, writes are legal but discarded
|
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
|
||||||
|
|||||||
+10
-10
@@ -263,12 +263,12 @@
|
|||||||
- [ ] Array syntax
|
- [ ] Array syntax
|
||||||
- [ ] Struct syntax
|
- [ ] Struct syntax
|
||||||
- [x] Pointer syntax
|
- [x] Pointer syntax
|
||||||
- [ ] Namespaced call syntax
|
- [x] Namespaced call syntax
|
||||||
- [x] AST node definitions
|
- [x] AST node definitions
|
||||||
- [ ] Error recovery mechanisms
|
- [ ] Error recovery mechanisms
|
||||||
- [ ] Comprehensive parser tests
|
- [ ] Comprehensive parser tests
|
||||||
- [ ] Syntax error message quality testing
|
- [ ] 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)
|
- [ ] 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
|
- [ ] Optimize register allocation further
|
||||||
- [x] Implement proper function calling conventions
|
- [x] Implement proper function calling conventions
|
||||||
- [ ] Add constant folding optimization
|
- [ ] Add constant folding optimization
|
||||||
- [ ] Dead code elimination
|
- [x] Dead code elimination
|
||||||
- [ ] Test each feature thoroughly
|
- [ ] Test each feature thoroughly
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -376,7 +376,7 @@
|
|||||||
**Dependencies:** None
|
**Dependencies:** None
|
||||||
**Deliverable:** `docs/build-system-design.md`
|
**Deliverable:** `docs/build-system-design.md`
|
||||||
|
|
||||||
- [ ] Define project structure conventions
|
- [x] Define project structure conventions
|
||||||
- [ ] Design build manifest format (`dsa-project.toml` or similar)
|
- [ ] Design build manifest format (`dsa-project.toml` or similar)
|
||||||
- [ ] Dependency resolution strategy
|
- [ ] Dependency resolution strategy
|
||||||
- [ ] Build cache design
|
- [ ] Build cache design
|
||||||
@@ -391,12 +391,12 @@
|
|||||||
**Dependencies:** 3.1.1, 1.2.2, 1.1.3, 2.1.3
|
**Dependencies:** 3.1.1, 1.2.2, 1.1.3, 2.1.3
|
||||||
**Deliverable:** `dsa-build` executable
|
**Deliverable:** `dsa-build` executable
|
||||||
|
|
||||||
- [ ] Create crate: `dsa-build`
|
- [x] Create crate: `dsa-build`
|
||||||
- [ ] Manifest parser
|
- [ ] Manifest parser
|
||||||
- [ ] Dependency graph builder
|
- [ ] Dependency graph builder
|
||||||
- [ ] Task orchestrator
|
- [ ] Task orchestrator
|
||||||
- [ ] Compilation tasks
|
- [x] Compilation tasks
|
||||||
- [ ] Assembly tasks
|
- [x] Assembly tasks
|
||||||
- [ ] Linking tasks
|
- [ ] Linking tasks
|
||||||
- [ ] Build cache implementation
|
- [ ] Build cache implementation
|
||||||
- [ ] Parallel build support
|
- [ ] Parallel build support
|
||||||
@@ -412,11 +412,11 @@
|
|||||||
**Dependencies:** 3.1.2
|
**Dependencies:** 3.1.2
|
||||||
**Deliverable:** Enhanced `dsa-build` with project management
|
**Deliverable:** Enhanced `dsa-build` with project management
|
||||||
|
|
||||||
- [ ] `dsa new <project>` — Create new project
|
- [x] `dsa new <project>` — Create new project
|
||||||
- [ ] `dsa init` — Initialize in existing directory
|
- [x] `dsa init` — Initialize in existing directory
|
||||||
- [ ] `dsa add <dependency>` — Add dependency
|
- [ ] `dsa add <dependency>` — Add dependency
|
||||||
- [ ] Binary vs library project types
|
- [ ] Binary vs library project types
|
||||||
- [ ] Template system for project scaffolding
|
- [x] Template system for project scaffolding
|
||||||
- [ ] Documentation for each command
|
- [ ] Documentation for each command
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -0,0 +1,589 @@
|
|||||||
|
pub trait Template {
|
||||||
|
fn lib(project: &str) -> String;
|
||||||
|
fn bin(project: &str) -> String;
|
||||||
|
|
||||||
|
fn create(project: &str, lib: bool) -> String {
|
||||||
|
if lib {
|
||||||
|
Self::lib(project)
|
||||||
|
} else {
|
||||||
|
Self::bin(project)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Dsa;
|
||||||
|
pub struct Dsc;
|
||||||
|
|
||||||
|
impl Template for Dsa {
|
||||||
|
fn lib(project: &str) -> String {
|
||||||
|
format!(
|
||||||
|
r#"//
|
||||||
|
lib.dsa
|
||||||
|
// usage:
|
||||||
|
//
|
||||||
|
// include {project} "<relative path>"
|
||||||
|
//
|
||||||
|
// usage for {project}_main:
|
||||||
|
// push (arg1)
|
||||||
|
// push (arg0)
|
||||||
|
// call {project}::{project}_main
|
||||||
|
// pop (arg0)
|
||||||
|
// pop (arg1)
|
||||||
|
|
||||||
|
// Example data declarations
|
||||||
|
// dw example_data: 0x0000
|
||||||
|
|
||||||
|
// Main function template
|
||||||
|
{project}_main:
|
||||||
|
// the correct way to start a function as defined by the calling convention
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
// explanation of how to access args
|
||||||
|
ldw bpr, rg0, 8 // arg 0
|
||||||
|
ldw bpr, rg0, 12 // arg 1
|
||||||
|
|
||||||
|
// your code goes here
|
||||||
|
// Example: load example_data into rg1
|
||||||
|
// ldw example_data, rg1
|
||||||
|
|
||||||
|
// the correct way to end a function as defined by the calling convention
|
||||||
|
mov bpr, spr
|
||||||
|
pop bpr
|
||||||
|
return
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bin(project: &str) -> String {
|
||||||
|
format!(
|
||||||
|
r#"
|
||||||
|
// GENERATED BY DSX-BUILD
|
||||||
|
// Generated at: {timestamp}
|
||||||
|
// Project name: {project}
|
||||||
|
|
||||||
|
// Imports
|
||||||
|
include print: "./lib/print.dsa"
|
||||||
|
|
||||||
|
// Globals & Reserved Memory
|
||||||
|
dw stack: 0x10000
|
||||||
|
db message: "Process Exited with code:"
|
||||||
|
|
||||||
|
// Entry Point
|
||||||
|
_init:
|
||||||
|
ldw stack, bpr
|
||||||
|
mov bpr, spr
|
||||||
|
push zero
|
||||||
|
call main
|
||||||
|
call print::print_newline
|
||||||
|
lwi message, rg0
|
||||||
|
push rg0
|
||||||
|
call print::print
|
||||||
|
pop zero
|
||||||
|
call print::print_hex_word
|
||||||
|
pop zero
|
||||||
|
hlt
|
||||||
|
|
||||||
|
main:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
// Your code goes here
|
||||||
|
|
||||||
|
// Return zero
|
||||||
|
stw zero, bpr, 8
|
||||||
|
|
||||||
|
mov bpr, spr
|
||||||
|
pop bpr
|
||||||
|
return"#,
|
||||||
|
timestamp = chrono::Utc::now().format("%Y-%m-%d %H:%M:%S").to_string()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Template for Dsc {
|
||||||
|
fn lib(project: &str) -> String {
|
||||||
|
format!(
|
||||||
|
r#"
|
||||||
|
// GENERATED BY DSX-BUILD
|
||||||
|
// Generated at: {timestamp}
|
||||||
|
// Project name: {project}
|
||||||
|
|
||||||
|
// Imports
|
||||||
|
include print: "./lib/print.dsa";
|
||||||
|
|
||||||
|
// Main Function
|
||||||
|
fn {project}_main() -> u32 {{
|
||||||
|
return 0;
|
||||||
|
}}"#,
|
||||||
|
timestamp = chrono::Utc::now().format("%Y-%m-%d %H:%M:%S").to_string()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bin(project: &str) -> String {
|
||||||
|
format!(
|
||||||
|
r#"
|
||||||
|
// GENERATED BY DSX-BUILD
|
||||||
|
// Generated at: {timestamp}
|
||||||
|
// Project name: {project}
|
||||||
|
|
||||||
|
// Imports
|
||||||
|
include print: "./lib/print.dsa";
|
||||||
|
|
||||||
|
// Main Function
|
||||||
|
fn main() -> u32 {{
|
||||||
|
return 0;
|
||||||
|
}}"#,
|
||||||
|
timestamp = chrono::Utc::now().format("%Y-%m-%d %H:%M:%S").to_string()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_print_lib() -> String {
|
||||||
|
format!(
|
||||||
|
r#"
|
||||||
|
// lib:
|
||||||
|
// print.dsa
|
||||||
|
|
||||||
|
// usage:
|
||||||
|
//
|
||||||
|
// include print "<relative path>""
|
||||||
|
//
|
||||||
|
// usage for print:
|
||||||
|
// push (register containing address of string)
|
||||||
|
// push pcx
|
||||||
|
// jmp print::print
|
||||||
|
//
|
||||||
|
// usage for reset:
|
||||||
|
// push pcx
|
||||||
|
// jmp print::reset
|
||||||
|
//
|
||||||
|
// usage for clear:
|
||||||
|
// push pcx
|
||||||
|
// jmp print::clear
|
||||||
|
//
|
||||||
|
// usage for print_byte:
|
||||||
|
// push (register containing byte)
|
||||||
|
// push pcx
|
||||||
|
// jmp print::print_byte
|
||||||
|
//
|
||||||
|
// usage for print_word:
|
||||||
|
// push (register containing word)
|
||||||
|
// push pcx
|
||||||
|
// jmp print::print_word
|
||||||
|
//
|
||||||
|
// usage for print_num:
|
||||||
|
// push (register containing number to print in decimal)
|
||||||
|
// push pcx
|
||||||
|
// jmp print::print_num
|
||||||
|
//
|
||||||
|
|
||||||
|
include maths "./maths.dsa"
|
||||||
|
|
||||||
|
dw display: 0x20000
|
||||||
|
dw current: 0x20000
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// prints the string at addr(arg[0]) to the screen. (no trailing whitespace unless explicitly provided)
|
||||||
|
print:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
ldw bpr, rg0, 8
|
||||||
|
ldw current, rg1
|
||||||
|
|
||||||
|
_print_loop:
|
||||||
|
ldb rg0, acc
|
||||||
|
cmp acc, zero
|
||||||
|
jeq _end
|
||||||
|
stb acc, rg1
|
||||||
|
|
||||||
|
addi rg0, 1
|
||||||
|
addi rg1, 1
|
||||||
|
|
||||||
|
jmp _print_loop
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
println:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
ldw bpr, rg0, 8
|
||||||
|
ldw current, rg1
|
||||||
|
|
||||||
|
_println_loop:
|
||||||
|
ldb rg0, acc
|
||||||
|
cmp acc, zero
|
||||||
|
jeq _println_end
|
||||||
|
stb acc, rg1
|
||||||
|
|
||||||
|
addi rg0, 1
|
||||||
|
addi rg1, 1
|
||||||
|
|
||||||
|
jmp _println_loop
|
||||||
|
|
||||||
|
_println_end:
|
||||||
|
call print_newline
|
||||||
|
jmp _end
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// prints the value of arg[0] to the screen.
|
||||||
|
print_word:
|
||||||
|
// initialise
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
// load byte into acc
|
||||||
|
ldw bpr, rg0, 8
|
||||||
|
ldw current, rg1
|
||||||
|
|
||||||
|
addi rg1, 3
|
||||||
|
|
||||||
|
stb rg0, rg1
|
||||||
|
subi rg1, 1
|
||||||
|
shr rg0, 8
|
||||||
|
stb rg0, rg1
|
||||||
|
subi rg1, 1
|
||||||
|
shr rg0, 8
|
||||||
|
stb rg0, rg1
|
||||||
|
subi rg1, 1
|
||||||
|
shr rg0, 8
|
||||||
|
stb rg0, rg1
|
||||||
|
|
||||||
|
addi rg1, 4
|
||||||
|
jmp _end
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// prints the last byte of arg[0] to the screen.
|
||||||
|
print_byte:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
ldw bpr, rg0, 8
|
||||||
|
ldw current, rg1
|
||||||
|
|
||||||
|
stb rg0, rg1
|
||||||
|
addi rg1, 1
|
||||||
|
jmp _end
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// prints the value of arg[0] to the screen in hex.
|
||||||
|
print_hex_word:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
ldw current, rg1
|
||||||
|
|
||||||
|
ldb bpr, rg0, 8
|
||||||
|
push rg0
|
||||||
|
call _print_hex_byte
|
||||||
|
addi spr, 4
|
||||||
|
|
||||||
|
ldb bpr, rg0, 9
|
||||||
|
push rg0
|
||||||
|
call _print_hex_byte
|
||||||
|
addi spr, 4
|
||||||
|
|
||||||
|
ldb bpr, rg0, 10
|
||||||
|
push rg0
|
||||||
|
call _print_hex_byte
|
||||||
|
addi spr, 4
|
||||||
|
|
||||||
|
ldb bpr, rg0, 11
|
||||||
|
push rg0
|
||||||
|
call _print_hex_byte
|
||||||
|
addi spr, 4
|
||||||
|
|
||||||
|
jmp _end
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// prints the last byte of arg[0] to the screen in hex.
|
||||||
|
print_hex_byte:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
ldw bpr, rg0, 8
|
||||||
|
ldw current, rg1
|
||||||
|
|
||||||
|
call _print_hex_byte
|
||||||
|
jmp _end
|
||||||
|
|
||||||
|
// function body
|
||||||
|
_print_hex_byte:
|
||||||
|
// mask to get lower nibble
|
||||||
|
lli 0xF, rg2
|
||||||
|
// save rg0 state
|
||||||
|
push rg0
|
||||||
|
|
||||||
|
shr rg0, 4
|
||||||
|
and rg0, rg2, rg0
|
||||||
|
call _print_hex_nibble
|
||||||
|
pop rg0
|
||||||
|
|
||||||
|
and rg0, rg2, rg0
|
||||||
|
call _print_hex_nibble
|
||||||
|
return
|
||||||
|
|
||||||
|
// print a hex digit
|
||||||
|
_print_hex_nibble:
|
||||||
|
lli 10, rg3
|
||||||
|
cmp rg0, rg3
|
||||||
|
jlt _print_hex_nibble_number
|
||||||
|
addi rg0, 0x37, rg0
|
||||||
|
stb rg0, rg1
|
||||||
|
addi rg1, 1
|
||||||
|
return
|
||||||
|
|
||||||
|
// helper function.
|
||||||
|
_print_hex_nibble_number:
|
||||||
|
addi rg0, 0x30, rg0
|
||||||
|
stb rg0, rg1
|
||||||
|
addi rg1, 1
|
||||||
|
return
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// print whitespace
|
||||||
|
print_whitespace:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
ldw current, rg1
|
||||||
|
lli 0x20, rg0
|
||||||
|
stb rg0, rg1
|
||||||
|
addi rg1, 1
|
||||||
|
jmp _end
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// print newline
|
||||||
|
print_newline:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
// load variables into registers
|
||||||
|
ldw display, rg0
|
||||||
|
ldw current, rg1
|
||||||
|
|
||||||
|
// get the offset from the display base
|
||||||
|
sub rg1, rg0, rg0
|
||||||
|
|
||||||
|
lwi 80, rg2
|
||||||
|
pusha 3
|
||||||
|
push rg0
|
||||||
|
push rg2
|
||||||
|
call maths::divmod
|
||||||
|
pop zero // result
|
||||||
|
pop rg3 // remainder
|
||||||
|
popa 3
|
||||||
|
|
||||||
|
sub rg1, rg3, rg2
|
||||||
|
addi rg2, 80, rg1
|
||||||
|
|
||||||
|
// _end saves the display state
|
||||||
|
jmp _end
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// prints arg[0] as a decimal number to the screen.
|
||||||
|
print_num:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
ldw bpr, rg0, 8 // load number to print
|
||||||
|
lli 0, rg5 // rg5 = digit counter
|
||||||
|
|
||||||
|
// check if number is zero
|
||||||
|
cmp rg0, zero
|
||||||
|
jne _print_num_extract_digits
|
||||||
|
|
||||||
|
// special case: print '0' for zero
|
||||||
|
lli 0x30, rg6
|
||||||
|
push rg6 // push digit to stack buffer
|
||||||
|
lli 1, rg5 // we have 1 digit
|
||||||
|
jmp _print_num_output
|
||||||
|
|
||||||
|
_print_num_extract_digits:
|
||||||
|
// divide by 10 repeatedly to get digits
|
||||||
|
cmp rg0, zero
|
||||||
|
jeq _print_num_output
|
||||||
|
|
||||||
|
// call divmod(rg0, 10)
|
||||||
|
push rg0 // dividend
|
||||||
|
lli 10, rg1
|
||||||
|
push rg1 // divisor (10)
|
||||||
|
call maths::divmod
|
||||||
|
pop rg0 // quotient (continue dividing this)
|
||||||
|
pop rg1 // remainder (the digit)
|
||||||
|
|
||||||
|
// convert digit to ASCII and push to stack buffer
|
||||||
|
addi rg1, 0x30, rg6 // convert to ASCII
|
||||||
|
push rg6 // push digit to stack
|
||||||
|
inc rg5 // increment digit counter
|
||||||
|
|
||||||
|
jmp _print_num_extract_digits
|
||||||
|
|
||||||
|
_print_num_output:
|
||||||
|
// now print digits (pop them off in reverse order)
|
||||||
|
ldw current, rg1 // get display pointer
|
||||||
|
|
||||||
|
_print_num_output_loop:
|
||||||
|
// check if we've printed all digits
|
||||||
|
cmp rg5, zero
|
||||||
|
jeq _print_num_done
|
||||||
|
|
||||||
|
// pop digit and print it
|
||||||
|
pop rg6
|
||||||
|
stb rg6, rg1
|
||||||
|
addi rg1, 1
|
||||||
|
dec rg5
|
||||||
|
|
||||||
|
jmp _print_num_output_loop
|
||||||
|
|
||||||
|
_print_num_done:
|
||||||
|
jmp _end
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// resets the cursor position on the screen to 0x20000. (0,0)
|
||||||
|
reset:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
ldw display, rg1
|
||||||
|
jmp _end
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// clears the screen
|
||||||
|
clear:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
// display size = 2000 bytes / 500 words
|
||||||
|
lli 500 rg0
|
||||||
|
ldw display, rg1
|
||||||
|
|
||||||
|
_clear_loop:
|
||||||
|
dec rg0
|
||||||
|
stw zero, rg1
|
||||||
|
addi rg1, 4
|
||||||
|
cmp rg0, zero
|
||||||
|
jgt _clear_loop
|
||||||
|
jmp _end
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// return
|
||||||
|
_end:
|
||||||
|
stw rg1, current
|
||||||
|
|
||||||
|
mov bpr, spr
|
||||||
|
pop bpr
|
||||||
|
return
|
||||||
|
"#
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_maths_lib() -> String {
|
||||||
|
format!(
|
||||||
|
r#"
|
||||||
|
// multiply.dsa
|
||||||
|
// usage:
|
||||||
|
//
|
||||||
|
// include multiply "<relative path>"
|
||||||
|
//
|
||||||
|
// usage for multiply:
|
||||||
|
// push (arg1)
|
||||||
|
// push (arg0)
|
||||||
|
// call multiply::multiply
|
||||||
|
// pop (arg0)
|
||||||
|
// pop (arg1)
|
||||||
|
|
||||||
|
multiply:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
ldw bpr, rg0, 8 // load op 2
|
||||||
|
ldw bpr, rg1, 12 // load op 1
|
||||||
|
lwi 0, rg2 // initialise rg2 to zero
|
||||||
|
|
||||||
|
_multiply_loop:
|
||||||
|
add rg2, rg0, rg2
|
||||||
|
dec rg1
|
||||||
|
|
||||||
|
cmp rg1, zero
|
||||||
|
jgt _multiply_loop
|
||||||
|
|
||||||
|
_multiply_end:
|
||||||
|
stw rg2, bpr, 8
|
||||||
|
|
||||||
|
mov bpr, spr
|
||||||
|
pop bpr
|
||||||
|
return
|
||||||
|
|
||||||
|
divmod:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
ldw bpr, rg1, 8 // load op 2
|
||||||
|
ldw bpr, rg0, 12 // load op 1
|
||||||
|
|
||||||
|
lli 0, rg3
|
||||||
|
|
||||||
|
_divmod_loop:
|
||||||
|
cmp rg0, rg1
|
||||||
|
jlt _divmod_end
|
||||||
|
|
||||||
|
sub rg0, rg1, rg0
|
||||||
|
inc rg3
|
||||||
|
|
||||||
|
jmp _divmod_loop
|
||||||
|
|
||||||
|
_divmod_end:
|
||||||
|
// store div in first arg
|
||||||
|
// store mod in second arg
|
||||||
|
stw rg3, bpr, 8
|
||||||
|
stw rg0, bpr, 12
|
||||||
|
|
||||||
|
mov bpr, spr
|
||||||
|
pop bpr
|
||||||
|
return
|
||||||
|
|
||||||
|
// multiply.dsa - improved version
|
||||||
|
// Multiplies two 32-bit numbers using shift-and-add
|
||||||
|
//
|
||||||
|
// Usage:
|
||||||
|
// push operand2 (multiplier)
|
||||||
|
// push operand1 (multiplicand)
|
||||||
|
// call multiply::multiply
|
||||||
|
// pop result
|
||||||
|
// pop zero (discard second argument)
|
||||||
|
|
||||||
|
new_multiply:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
ldw bpr, rg0, 8 // rg0 = multiplicand
|
||||||
|
ldw bpr, rg1, 12 // rg1 = multiplier
|
||||||
|
|
||||||
|
lli 0, rg2 // rg2 = result (accumulator)
|
||||||
|
lli 32, rg3 // rg3 = bit counter
|
||||||
|
|
||||||
|
mult_loop:
|
||||||
|
// Check if lowest bit of multiplier is 1
|
||||||
|
lli 1, acc
|
||||||
|
and rg1, acc, acc // acc = rg1 & 1
|
||||||
|
cmp acc, zero
|
||||||
|
jeq skip_add // if (rg1 & 1) == 0, skip addition
|
||||||
|
|
||||||
|
// Add multiplicand to result
|
||||||
|
add rg2, rg0, rg2
|
||||||
|
|
||||||
|
skip_add:
|
||||||
|
shl rg0, 1 // shift multiplicand left
|
||||||
|
shr rg1, 1 // shift multiplier right
|
||||||
|
|
||||||
|
dec rg3
|
||||||
|
cmp rg3, zero
|
||||||
|
jgt mult_loop
|
||||||
|
|
||||||
|
stw rg2, bpr, 8 // store result
|
||||||
|
mov bpr, spr
|
||||||
|
pop bpr
|
||||||
|
return
|
||||||
|
"#
|
||||||
|
)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user