Merge compiler and emulator progress from last few months into main. #11

Merged
zxq5 merged 55 commits from compiler into main 2026-02-14 11:54:15 +00:00
9 changed files with 1750 additions and 17 deletions
Showing only changes of commit 8f7163c459 - Show all commits
+21 -5
View File
@@ -4,12 +4,15 @@ use std::str::Chars;
#[derive(Debug, PartialEq, Clone)]
pub enum Token {
// Keywords
Fn,
Let,
If,
Else,
Loop,
Break,
Return,
Continue,
Include,
// Identifiers and literals
Identifier(String),
@@ -24,7 +27,7 @@ pub enum Token {
Semicolon, // ;
Colon, // :
Comma, // ,
Pipe, // |
// Pipe, // |
// Operators
Plus, // +
@@ -39,6 +42,7 @@ pub enum Token {
LessEqual, // <=
Greater, // >
GreaterEqual, // >=
RightArrow, // ->
// Special
Eof,
@@ -47,7 +51,10 @@ pub enum Token {
impl Token {
pub fn tt(&self) -> &str {
match self {
Token::Include => "Include",
Token::Fn => "Fn",
Token::If => "If",
Token::Let => "Let",
Token::Else => "Else",
Token::Loop => "Loop",
Token::Break => "Break",
@@ -63,7 +70,8 @@ impl Token {
Token::Semicolon => "Semicolon",
Token::Colon => "Colon",
Token::Comma => "Comma",
Token::Pipe => "Pipe",
Token::RightArrow => "RightArrow",
// Token::Pipe => "Pipe",
Token::Plus => "Plus",
Token::Minus => "Minus",
Token::Star => "Star",
@@ -168,11 +176,17 @@ impl<'a> Lexer<'a> {
Some(';') => Token::Semicolon,
Some(':') => Token::Colon,
Some(',') => Token::Comma,
Some('|') => Token::Pipe,
// Some('|') => Token::Pipe,
Some('+') => Token::Plus,
Some('-') => Token::Minus,
Some('*') => Token::Star,
Some('/') => Token::Slash,
Some('-') => {
if self.match_next('>') {
Token::RightArrow
} else {
Token::Minus
}
}
Some('!') => {
if self.match_next('=') {
Token::BangEqual
@@ -218,12 +232,14 @@ impl<'a> Lexer<'a> {
let mut ident = c.to_string();
ident.push_str(&self.read_identifier());
match ident.as_str() {
"fn" => Token::Fn,
"if" => Token::If,
"else" => Token::Else,
"loop" => Token::Loop,
"break" => Token::Break,
"return" => Token::Return,
"continue" => Token::Continue,
"include" => Token::Include,
_ => Token::Identifier(ident),
}
} else if c.is_ascii_digit() {
@@ -331,7 +347,7 @@ mod tests {
assert_eq!(lexer.next_token(), Token::Colon);
assert_eq!(lexer.next_token(), Token::Identifier("Func".to_string()));
assert_eq!(lexer.next_token(), Token::Assign);
assert_eq!(lexer.next_token(), Token::Pipe);
// assert_eq!(lexer.next_token(), Token::Pipe);
assert_eq!(lexer.next_token(), Token::Identifier("x".to_string()));
assert_eq!(lexer.next_token(), Token::Colon);
assert_eq!(lexer.next_token(), Token::Identifier("U32".to_string()));
+12 -4
View File
@@ -1,7 +1,12 @@
#![feature(try_trait_v2)]
use std::{fs, path::Path};
pub mod lexer;
pub mod parser;
pub mod parserprototype;
use parserprototype::Parser;
use crate::parserprototype::ParseResult;
fn main() {
println!("Hello, world!");
@@ -13,13 +18,16 @@ fn main() {
let tokens = lexer.collect::<Vec<_>>();
println!("{tokens:?}");
let mut parser = parser::Parser::new(tokens);
let mut parser = Parser::new(tokens);
let ast = match parser.parse() {
Ok(ast) => ast,
Err(e) => {
ParseResult::Accept(ast) => ast,
ParseResult::Reject(e) => {
eprintln!("Error: {e:?}");
return;
}
ParseResult::Deny => {
panic!("Parser denied parsing")
}
};
println!("{ast:?}");
}
+435
View File
@@ -0,0 +1,435 @@
use crate::lexer::Token;
use crate::{expect_tt, expect_value};
use core::fmt;
use std::ops::{ControlFlow, FromResidual, Try};
#[derive(Debug, Clone)]
pub enum ParseResult<T, E> {
Accept(T),
Deny,
Reject(E),
}
#[derive(Debug, Clone)]
pub enum CompilerError {
UnexpectedToken(Token),
UnexpectedEndOfInput,
UnexpectedCharacter(char),
InvalidSyntax(String),
Generic(String),
}
pub struct Parser {
tokens: Vec<Token>,
idx: usize,
}
impl Parser {
pub fn new(tokens: Vec<Token>) -> Self {
Self { tokens, idx: 0 }
}
pub fn parse(&mut self) -> ParseResult<Program, CompilerError> {
let mut declarations = Vec::new();
while let ParseResult::Accept(_) = self.peek_next() {
declarations.push(self.parse_declaration()?);
}
ParseResult::Accept(Program {
imports: vec![],
declarations,
})
}
fn parse_declaration(&mut self) -> ParseResult<Declaration, CompilerError> {
if expect_tt!(self.peek_next()?, Fn).accepted() {
let x = self.parse_func();
println!("function {:?}", x);
return x;
}
println!("{:?}", self.peek_next()?);
ParseResult::Reject(CompilerError::UnexpectedEndOfInput)
}
fn parse_func(&mut self) -> ParseResult<Declaration, CompilerError> {
// expect function keyword
//
println!("pre name! {:?}", self.peek_next()?);
let _ = expect_tt!(self.next()?, Fn);
println!("this is the name! {:?}", self.peek_next()?);
// expect function name
let name = match self.next()? {
Token::Identifier(name) => name,
id => return ParseResult::Reject(CompilerError::UnexpectedToken(id)),
};
// expect left paren
let _ = expect_tt!(self.next()?, LParen);
let mut params = Vec::new();
while expect_tt!(self.peek_next()?, Identifier).accepted() {
let arg = self.parse_var_decl()?;
params.push(arg);
}
// expect right paren
let _ = expect_tt!(self.next()?, RParen);
// see if we can parse the return type!
let mut return_type = TypeId::Void;
if expect_tt!(self.peek_next()?, RightArrow).accepted() {
let _ = self.next();
return_type = self.parse_type()?;
}
// expect left brace
let _ = expect_tt!(self.next()?, LBrace);
let mut body = Vec::new();
// expect right brace
let _ = expect_tt!(self.next()?, RBrace);
ParseResult::Accept(Declaration::Function {
name,
params,
return_type,
body,
})
}
fn parse_var_decl(&mut self) -> ParseResult<Variable, CompilerError> {
let name = match self.next()? {
Token::Identifier(name) => name,
id => return ParseResult::Reject(CompilerError::UnexpectedToken(id)),
};
let _ = expect_tt!(self.next()?, Colon);
let type_ = self.parse_type()?;
ParseResult::Accept(Variable {
name,
param_type: Some(type_),
})
}
fn parse_type(&mut self) -> ParseResult<TypeId, CompilerError> {
// get the type name incl namespace
let typename = self.parse_identifier()?;
match typename.name.as_str() {
"u32" => ParseResult::Accept(TypeId::U32),
"u16" => ParseResult::Accept(TypeId::U16),
"u8" => ParseResult::Accept(TypeId::U8),
"i32" => ParseResult::Accept(TypeId::I32),
"i16" => ParseResult::Accept(TypeId::I16),
"i8" => ParseResult::Accept(TypeId::I8),
"void" => ParseResult::Accept(TypeId::Void),
"char" => ParseResult::Accept(TypeId::Char),
_ => todo!("Implement parsing for other types!!"),
}
}
fn parse_identifier(&mut self) -> ParseResult<Name, CompilerError> {
let primary = match self.next()? {
Token::Identifier(namespace) => namespace,
id => return ParseResult::Reject(CompilerError::UnexpectedToken(id)),
};
if expect_tt!(self.peek_next()?, Colon).accepted() {
let _ = expect_tt!(self.next()?, Colon);
let _ = expect_tt!(self.next()?, Colon);
let secondary = match self.next()? {
Token::Identifier(name) => name,
id => return ParseResult::Reject(CompilerError::UnexpectedToken(id)),
};
ParseResult::Accept(Name {
namespace: Some(primary),
name: secondary,
})
} else {
ParseResult::Accept(Name {
namespace: None,
name: primary,
})
}
}
fn next(&mut self) -> ParseResult<Token, CompilerError> {
if self.idx >= self.tokens.len() {
ParseResult::Reject(CompilerError::UnexpectedEndOfInput)
} else {
let token = self.tokens[self.idx].clone();
println!("NEXT {:?}", token);
self.idx += 1;
ParseResult::Accept(token)
}
}
fn peek_next(&self) -> ParseResult<Token, CompilerError> {
if self.idx >= self.tokens.len() {
ParseResult::Reject(CompilerError::UnexpectedEndOfInput)
} else {
ParseResult::Accept(self.tokens[self.idx].clone())
}
}
}
#[derive(Debug, Clone)]
pub struct Program {
pub imports: Vec<Dependency>,
pub declarations: Vec<Declaration>,
}
#[derive(Debug, Clone)]
pub enum Declaration {
Function {
name: String,
return_type: TypeId,
params: Vec<Variable>,
body: Block,
},
Variable {
name: String,
init: Option<ConstExpr>,
},
}
#[derive(Debug, Clone)]
pub struct Dependency {
pub name: String,
pub path: String,
}
#[derive(Debug, Clone)]
pub struct Variable {
pub name: String,
pub param_type: Option<TypeId>,
}
#[derive(Debug, Clone)]
pub struct Name {
pub name: String,
pub namespace: Option<String>,
}
#[derive(Debug, Clone)]
pub enum TypeId {
U8,
U16,
U32,
I8,
I16,
I32,
Char,
Void,
Ptr(Box<TypeId>),
Ref(Box<TypeId>),
Array(Box<TypeId>, usize),
Struct {
name: Name,
fields: Vec<(String, TypeId)>,
},
}
pub type Block = Vec<Statement>;
#[derive(Debug, Clone)]
pub enum Statement {
Block(Block),
Assign {
var: Variable,
value: Option<Box<Expression>>,
},
Expression {
expr: Expression,
},
If {
condition: Expression,
then_stmt: Block,
else_stmt: Block,
},
While {
condition: Expression,
body: Vec<Statement>,
},
Loop(Block),
Break,
Continue,
Return(Option<Expression>),
}
#[derive(Debug, Clone)]
pub enum ConstExpr {
Number(i32),
String(String),
}
impl fmt::Display for ConstExpr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
ConstExpr::Number(n) => write!(f, "{}", n),
ConstExpr::String(s) => write!(f, "\"{}\"", s),
}
}
}
#[derive(Debug, Clone)]
pub enum Expression {
Empty,
Binary {
op: BinaryOperator,
left: Box<Expression>,
right: Box<Expression>,
},
Unary {
op: UnaryOperator,
operand: Box<Expression>,
},
Variable {
name: Name,
expr_type: Option<TypeId>,
},
Number {
value: i32,
},
Call {
name: Name,
args: Vec<Expression>,
},
}
#[derive(Debug, Clone, PartialEq)]
pub enum BinaryOperator {
Add,
Sub,
Mul,
Div,
Eq,
Ne,
Lt,
Gt,
Le,
Ge,
}
impl fmt::Display for BinaryOperator {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
BinaryOperator::Add => write!(f, "+"),
BinaryOperator::Sub => write!(f, "-"),
BinaryOperator::Mul => write!(f, "*"),
BinaryOperator::Div => write!(f, "/"),
BinaryOperator::Eq => write!(f, "=="),
BinaryOperator::Ne => write!(f, "!="),
BinaryOperator::Lt => write!(f, "<"),
BinaryOperator::Gt => write!(f, ">"),
BinaryOperator::Le => write!(f, "<="),
BinaryOperator::Ge => write!(f, ">="),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum UnaryOperator {
Plus,
Minus,
}
impl fmt::Display for UnaryOperator {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
UnaryOperator::Plus => write!(f, "+"),
UnaryOperator::Minus => write!(f, "-"),
}
}
}
impl<T, E> ParseResult<T, E> {
pub fn accepted(&self) -> bool {
matches!(self, ParseResult::Accept(_))
}
}
pub enum ParseResultResidual<T> {
Deny,
Reject(T),
}
impl<T, E> Try for ParseResult<T, E> {
type Output = T;
type Residual = ParseResultResidual<E>;
fn from_output(output: T) -> Self {
ParseResult::Accept(output)
}
fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
match self {
ParseResult::Accept(v) => ControlFlow::Continue(v),
ParseResult::Deny => ControlFlow::Break(ParseResultResidual::Deny),
ParseResult::Reject(e) => ControlFlow::Break(ParseResultResidual::Reject(e)),
}
}
}
impl<T, E> FromResidual for ParseResult<T, E> {
fn from_residual(residual: ParseResultResidual<E>) -> Self {
match residual {
ParseResultResidual::Deny => ParseResult::Deny,
ParseResultResidual::Reject(e) => ParseResult::Reject(e),
}
}
}
#[macro_export]
macro_rules! expect_tt {
($token:expr, $($variant:ident),+) => {{
let tt = $token.tt().to_string();
// for some reason the code trips tf out without this line
println!("token {:?}", $token);
let mut vs = String::new();
$(
let s = stringify!($variant);
vs.push_str(s);
vs.push_str("|");
)+
match tt.as_str() {
$(
stringify!($variant) => ParseResult::Accept($token.clone()),
)+
_ => {
println!("EXPECTED!! {} [{}]", tt, vs);
// let expected = format!("[{}]", vec![$(stringify!($variant)),+].join(" | "));
ParseResult::Reject(CompilerError::UnexpectedToken($token.clone()))
}
}
}};
}
#[macro_export]
macro_rules! expect_value {
($token:expr, $variant:expr) => {{
match $token {
$variant(x) => ParseResult::Accept(x),
_ => {
let expected = format!("[{}]")
ParseResult::Reject(CompilerError::UnexpectedToken($token.clone()))
}
}
}};
}
+2 -8
View File
@@ -1,8 +1,2 @@
main: Func = | x: U32, y: U32 | {
res = add(x, y);
print(res);
if res > 10 {
print("res is greater than 10");
}
}
fn factorial(n: u32) -> u32 {}
fn main(x: u32, y: u32) -> u32 {}
+843
View File
@@ -0,0 +1,843 @@
# DSA Project Roadmap & Task Breakdown
> **Damn Simple Architecture** — Full ecosystem development plan including emulator, assembler, compiler, debugger, and tooling infrastructure.
---
## Table of Contents
1. [Phase 1: Foundation & Core Infrastructure](#phase-1-foundation--core-infrastructure)
- [1.1 Binary Format & Linking System](#11-binary-format--linking-system)
- [1.2 Assembler Rewrite](#12-assembler-rewrite)
- [1.3 Documentation Updates](#13-documentation-updates)
2. [Phase 2: Compiler Development](#phase-2-compiler-development)
- [2.1 Language Design & Implementation](#21-language-design--implementation)
- [2.2 Standard Library](#22-standard-library)
3. [Phase 3: Build System & Package Management](#phase-3-build-system--package-management)
- [3.1 Build System](#31-build-system)
- [3.2 Package Management System](#32-package-management-system)
4. [Phase 4: Debugger & Development Tools](#phase-4-debugger--development-tools)
- [4.1 Debug Symbol System](#41-debug-symbol-system)
- [4.2 Debugger Implementation](#42-debugger-implementation)
- [4.3 Enhanced Editor Integration](#43-enhanced-editor-integration)
5. [Phase 5: Integration & Polish](#phase-5-integration--polish)
6. [Phase 6: Future Enhancements (NTH)](#phase-6-future-enhancements-nth)
7. [Summary Timeline](#summary-timeline)
8. [Critical Path](#critical-path)
9. [Recommended Work Order](#recommended-work-order)
---
## Phase 1: Foundation & Core Infrastructure
**Estimated Duration: 34 weeks**
---
### 1.1 Binary Format & Linking System
> **Priority: CRITICAL** — Everything depends on this.
> **Total Estimate: 1.5 weeks**
---
#### 1.1.1 Design New Binary Format Specification
**Estimate: 2 days**
**Dependencies:** None
**Deliverable:** `docs/binary-format-spec.md`
- [ ] Research existing object file formats (ELF, COFF, Mach-O) for inspiration
- [ ] Design `.dsb` object file format specification
- [ ] Symbol table structure
- [ ] Relocation table format
- [ ] Section definitions (code, data, rodata, bss)
- [ ] Debug information structure
- [ ] Metadata headers
- [ ] Design `.dse` executable format specification
- [ ] Entry point definition
- [ ] Memory layout requirements
- [ ] Linking metadata
- [ ] Document format specifications in markdown
- [ ] Create format version strategy for future compatibility
---
#### 1.1.2 Implement DSB Object File Writer
**Estimate: 3 days**
**Dependencies:** 1.1.1
**Deliverable:** `dsa-binary-format` crate v0.1.0
- [ ] Create new crate: `dsa-binary-format`
- [ ] Implement object file structures
- [ ] Header structure
- [ ] Symbol table builder
- [ ] Section manager
- [ ] Relocation entry creator
- [ ] Write serialization logic
- [ ] Add validation and error handling
- [ ] Write unit tests for each structure
- [ ] Integration tests for complete object files
---
#### 1.1.3 Build Linker Program
**Estimate: 4 days**
**Dependencies:** 1.1.2
**Deliverable:** `dsa-link` executable
- [ ] Create new crate: `dsa-linker`
- [ ] Implement symbol resolution
- [ ] Global symbol table
- [ ] Symbol conflict detection
- [ ] Weak symbol handling
- [ ] Implement relocation processing
- [ ] Address calculation
- [ ] Patch generation
- [ ] Cross-section references
- [ ] Build executable generator
- [ ] Combine sections
- [ ] Generate final memory layout
- [ ] Write `.dse` output
- [ ] Add linker script support (basic)
- [ ] Comprehensive error messages
- [ ] Test suite with complex linking scenarios
---
### 1.2 Assembler Rewrite
> **Priority: HIGH** — Required for all compiled code.
> **Total Estimate: 1.5 weeks**
---
#### 1.2.1 Assembler Architecture Design
**Estimate: 1 day**
**Dependencies:** 1.1.1
**Deliverable:** `docs/assembler-architecture.md`
- [ ] Design multi-pass architecture
- [ ] Pass 1: Symbol collection
- [ ] Pass 2: Macro expansion
- [ ] Pass 3: Code generation
- [ ] Pass 4: Relocation generation
- [ ] Plan error handling strategy
- [ ] Design threading model for parallel file processing
- [ ] Define module/import resolution system
- [ ] Plan integration points with DSC compiler
---
#### 1.2.2 Implement Core Assembler
**Estimate: 5 days**
**Dependencies:** 1.1.2, 1.2.1
**Deliverable:** `dsa-asm` executable v2.0.0
- [ ] Create new crate: `dsa-assembler-ng` (next-gen)
- [ ] Implement lexer with better error recovery
- [ ] Build parser with detailed error messages
- [ ] Instruction parsing
- [ ] Directive handling
- [ ] Macro system
- [ ] Include resolution
- [ ] Symbol table management
- [ ] Code generator outputting to DSB format
- [ ] Multi-threading for file parsing
- [ ] Comprehensive test suite
- [ ] Error message testing
---
#### 1.2.3 Import System & DSC Integration
**Estimate: 2 days**
**Dependencies:** 1.2.2, 2.1.2
**Deliverable:** Working import system
- [ ] Design import protocol between DSC and assembler
- [ ] Implement symbol table merging
- [ ] Handle pre-compiled object imports
- [ ] Test DSC → Assembly → Object pipeline
- [ ] Document integration process
---
### 1.3 Documentation Updates
> **Priority: MEDIUM** — Can be done alongside development.
> **Total Estimate: 3 days (distributed)**
---
#### 1.3.1 Update Assembly Documentation
**Estimate: 1 day**
**Dependencies:** 1.2.2
**Deliverable:** Updated `docs/dsa-assembly-reference.md`
- [ ] Review all instruction documentation
- [ ] Document new pseudo-instructions
- [ ] Update calling convention docs
- [ ] Add examples for new features
- [ ] Document assembler directives
- [ ] Macro system documentation
---
#### 1.3.2 Architecture Documentation
**Estimate: 1 day**
**Dependencies:** None (can start anytime)
**Deliverable:** `docs/dsa-architecture.md`
- [ ] Document ISA specification
- [ ] Memory model documentation
- [ ] Interrupt handling
- [ ] Hardware peripheral specs
- [ ] Timing/performance characteristics
---
#### 1.3.3 Build Tools Documentation
**Estimate: 1 day**
**Dependencies:** 1.2.2, 1.1.3, 3.1.2
**Deliverable:** `docs/build-tools-guide.md`
- [ ] Assembler usage guide
- [ ] Linker usage guide
- [ ] Build system guide
- [ ] Tutorial: Building a simple program
- [ ] Tutorial: Multi-file projects
---
## Phase 2: Compiler Development
**Estimated Duration: 34 weeks**
---
### 2.1 Language Design & Implementation
> **Priority: HIGH** — Core functionality.
> **Total Estimate: 2.5 weeks**
---
#### 2.1.1 Language Syntax Design
**Estimate: 2 days**
**Dependencies:** None
**Deliverable:** `docs/language-spec.md`
- [ ] Define syntax goals (simplicity, systems programming)
- [ ] Design type system
- [ ] Primitive types
- [ ] Pointers/references
- [ ] Structs
- [ ] Arrays
- [ ] Function types
- [ ] Control flow syntax
- [ ] Function declaration syntax
- [ ] Module/import system
- [ ] Operator precedence
- [ ] Write EBNF grammar
- [ ] Create example programs
---
#### 2.1.2 Lexer & Parser Implementation
**Estimate: 4 days**
**Dependencies:** 2.1.1
**Deliverable:** Parser in `dsc-compiler` crate
- [ ] Adapt existing C lexer to new syntax
- [ ] Implement new parser for designed syntax
- [ ] AST node definitions
- [ ] Error recovery mechanisms
- [ ] Comprehensive parser tests
- [ ] Syntax error message quality testing
---
#### 2.1.3 Code Generation Improvements
**Estimate: 5 days**
**Dependencies:** 2.1.2, 1.2.2
**Deliverable:** Working code generator
- [ ] Review and fix existing codegen issues
- [ ] Implement missing language features
- [ ] Structs
- [ ] Arrays
- [ ] Pointers/memory operations
- [ ] For loops
- [ ] Switch statements
- [ ] Break/continue
- [ ] Optimize register allocation further
- [ ] Implement proper function calling conventions
- [ ] Add constant folding optimization
- [ ] Dead code elimination
- [ ] Test each feature thoroughly
---
#### 2.1.4 Type Checking & Semantic Analysis
**Estimate: 3 days**
**Dependencies:** 2.1.2
**Deliverable:** Type checker integrated in compiler
- [ ] Implement type checker
- [ ] Symbol table for scoping
- [ ] Type inference where applicable
- [ ] Const checking
- [ ] Definite assignment analysis
- [ ] Comprehensive semantic error messages
- [ ] Test suite for type errors
---
### 2.2 Standard Library
> **Priority: MEDIUM** — Needed for useful programs.
> **Total Estimate: 1 week**
---
#### 2.2.1 Core Runtime Library (in Assembly)
**Estimate: 3 days**
**Dependencies:** 1.2.2
**Deliverable:** `lib/runtime/` directory
- [ ] Memory allocation (malloc/free)
- [ ] String operations
- [ ] Math functions
- [ ] I/O functions (improved print, read)
- [ ] System call interface
- [ ] Tests for each function
---
#### 2.2.2 Standard Library (in DSC)
**Estimate: 2 days**
**Dependencies:** 2.1.3, 2.2.1
**Deliverable:** `lib/std/` directory
- [ ] String module
- [ ] Collections (array utilities, maybe simple list)
- [ ] File I/O module
- [ ] Math utilities
- [ ] Tests and examples
---
## Phase 3: Build System & Package Management
**Estimated Duration: 23 weeks**
---
### 3.1 Build System
> **Priority: HIGH** — Required for complex projects.
> **Total Estimate: 1.5 weeks**
---
#### 3.1.1 Build System Design
**Estimate: 1 day**
**Dependencies:** None
**Deliverable:** `docs/build-system-design.md`
- [ ] Define project structure conventions
- [ ] Design build manifest format (`dsa-project.toml` or similar)
- [ ] Dependency resolution strategy
- [ ] Build cache design
- [ ] Incremental build strategy
- [ ] Multi-target support
---
#### 3.1.2 Build Tool Implementation
**Estimate: 5 days**
**Dependencies:** 3.1.1, 1.2.2, 1.1.3, 2.1.3
**Deliverable:** `dsa-build` executable
- [ ] Create crate: `dsa-build`
- [ ] Manifest parser
- [ ] Dependency graph builder
- [ ] Task orchestrator
- [ ] Compilation tasks
- [ ] Assembly tasks
- [ ] Linking tasks
- [ ] Build cache implementation
- [ ] Parallel build support
- [ ] Clean, rebuild commands
- [ ] Watch mode for development
- [ ] Comprehensive tests
---
#### 3.1.3 Project Management Commands
**Estimate: 2 days**
**Dependencies:** 3.1.2
**Deliverable:** Enhanced `dsa-build` with project management
- [ ] `dsa new <project>` — Create new project
- [ ] `dsa init` — Initialize in existing directory
- [ ] `dsa add <dependency>` — Add dependency
- [ ] Binary vs library project types
- [ ] Template system for project scaffolding
- [ ] Documentation for each command
---
### 3.2 Package Management System
> **Priority: MEDIUM** — Enables code sharing.
> **Total Estimate: 1.5 weeks**
---
#### 3.2.1 Package Registry Design
**Estimate: 2 days**
**Dependencies:** 3.1.1
**Deliverable:** `docs/package-registry-design.md`
- [ ] Decide: Git monorepo vs custom hosting
- [ ] Design package naming conventions
- [ ] Version resolution strategy (semver)
- [ ] Package manifest format
- [ ] Security considerations
- [ ] Package storage format (source/binary/both)
- [ ] API design for registry server
---
#### 3.2.2 Local Package Manager Tool
**Estimate: 4 days**
**Dependencies:** 3.2.1, 3.1.2
**Deliverable:** `dsa-pkg` tool integrated with `dsa-build`
- [ ] Create crate: `dsa-pkg`
- [ ] Package index synchronization
- [ ] Dependency resolver
- [ ] Package download/cache system
- [ ] Integration with build system
- [ ] Commands:
- [ ] `dsa install <package>`
- [ ] `dsa publish`
- [ ] `dsa search <query>`
- [ ] `dsa update`
- [ ] Lock file generation
- [ ] Test with mock registry
---
#### 3.2.3 Package Registry Implementation
**Estimate: 3 days**
**Dependencies:** 3.2.1
**Deliverable:** Package registry (URL or repo)
- [ ] If **Git monorepo** approach:
- [ ] Set up repository structure
- [ ] CI/CD for validation
- [ ] Submission process
- [ ] Package browser website
- [ ] If **custom hosting**:
- [ ] Simple web server (Rust + Axum/Actix)
- [ ] Package upload API
- [ ] Package search API
- [ ] Basic web UI
- [ ] Database for metadata
- [ ] Documentation for publishing
---
## Phase 4: Debugger & Development Tools
**Estimated Duration: 34 weeks**
---
### 4.1 Debug Symbol System
> **Priority: HIGH** — Foundation for debugging.
> **Total Estimate: 1 week**
---
#### 4.1.1 Debug Symbol Format Design
**Estimate: 1 day**
**Dependencies:** 1.1.1
**Deliverable:** `docs/debug-symbol-format.md`
- [ ] Design symbol table format
- [ ] Function addresses → names
- [ ] Line number → address mapping
- [ ] Variable location information
- [ ] Type information
- [ ] Define symbol table file format
- [ ] Plan for embedding in DSE/DSB files
---
#### 4.1.2 Symbol Generation in Tools
**Estimate: 3 days**
**Dependencies:** 4.1.1, 1.2.2, 2.1.3
**Deliverable:** Debug symbols in build output
- [ ] Modify assembler to emit debug symbols
- [ ] Modify compiler to emit debug symbols
- [ ] Source file/line tracking
- [ ] Variable scope tracking
- [ ] Linker merges debug symbols
- [ ] Test symbol generation pipeline
---
#### 4.1.3 Symbol Table Loader in Emulator
**Estimate: 2 days**
**Dependencies:** 4.1.2
**Deliverable:** Symbol loading in emulator crate
- [ ] Implement symbol table parser
- [ ] Build address → symbol lookup (HashMap)
- [ ] Build symbol → address lookup
- [ ] Memory efficient storage
- [ ] Tests for symbol resolution
---
### 4.2 Debugger Implementation
> **Priority: HIGH** — Major productivity boost.
> **Total Estimate: 2 weeks**
---
#### 4.2.1 Core Debugger Features
**Estimate: 5 days**
**Dependencies:** 4.1.3
**Deliverable:** Debugger backend
- [ ] Execution control
- [ ] Step instruction
- [ ] Step over function calls
- [ ] Continue to breakpoint
- [ ] Run to cursor
- [ ] Breakpoint system
- [ ] Address breakpoints
- [ ] Conditional breakpoints
- [ ] Watchpoints (memory access)
- [ ] Register inspection
- [ ] Memory inspection
- [ ] Stack trace generation
- [ ] Test debugger commands
---
#### 4.2.2 Disassembler with Symbol Resolution
**Estimate: 3 days**
**Dependencies:** 4.1.3
**Deliverable:** Enhanced disassembler
- [ ] Instruction decoder
- [ ] Format with labels instead of addresses
- [ ] Show function names at call sites
- [ ] Inline comments with variable names
- [ ] Color coding for instruction types
- [ ] Tests for disassembly output
---
#### 4.2.3 Pseudo-Instruction Decompiler
> ⚠️ **COMPLEX TASK** — Separate pass to decompile assembly into readable pseudo-instructions.
**Estimate: 4 days**
**Dependencies:** 4.2.2
**Deliverable:** Pseudo-instruction view mode
- [ ] Pattern recognition for common sequences
- [ ] Function prologue/epilogue
- [ ] Multiplication using shifts/adds
- [ ] Division
- [ ] Conditional moves
- [ ] Control flow reconstruction
- [ ] If/else detection
- [ ] Loop detection
- [ ] Switch statement detection
- [ ] Expression reconstruction
- [ ] Format as higher-level pseudo-code
- [ ] Extensive pattern testing
---
#### 4.2.4 Execution History Tracking
**Estimate: 2 days**
**Dependencies:** 4.2.1
**Deliverable:** Execution trace feature
- [ ] Circular buffer for instruction history
- [ ] Register state snapshots over time
- [ ] Configurable history depth
- [ ] Efficient memory usage
- [ ] Playback/reverse debugging (basic)
- [ ] Export trace to file
---
### 4.3 Enhanced Editor Integration
> **Priority: MEDIUM** — UX improvement.
> **Total Estimate: 1 week**
---
#### 4.3.1 Tiling Window System
**Estimate: 2 days**
**Dependencies:** None (UI work)
**Deliverable:** Panel system in emulator
- [ ] Research Rust tiling libraries (`egui_tiles`, or custom)
- [ ] Design panel layout system
- [ ] Code editor panel
- [ ] Disassembly panel
- [ ] Register panel
- [ ] Memory panel
- [ ] Console panel
- [ ] Implement drag-and-drop panel management
- [ ] Save/load layouts
---
#### 4.3.2 Assembly Editor Improvements
**Estimate: 2 days**
**Dependencies:** 4.3.1
**Deliverable:** Enhanced assembly editor
- [ ] Syntax highlighting for DSA assembly
- [ ] Auto-completion for instructions
- [ ] Label/symbol auto-completion
- [ ] Error highlighting
- [ ] Inline documentation tooltips
- [ ] Jump-to-definition for labels
---
#### 4.3.3 High-Level Language Editor
**Estimate: 2 days**
**Dependencies:** 4.3.1, 2.1.4
**Deliverable:** DSC language editor
- [ ] Syntax highlighting for DSC language
- [ ] Basic auto-completion
- [ ] Bracket matching
- [ ] Error highlighting from compiler
- [ ] Go-to-definition (using debug symbols)
- [ ] Inline type hints
---
#### 4.3.4 Integrate Build Tools in Editor
**Estimate: 1 day**
**Dependencies:** 4.3.1, 3.1.2
**Deliverable:** Integrated build experience
- [ ] Build button/command in UI
- [ ] Show build output in console panel
- [ ] Error navigation (click to jump to source)
- [ ] Hot reload on successful build
- [ ] Build status indicator
---
## Phase 5: Integration & Polish
**Estimated Duration: 12 weeks**
---
### 5.1 Tool Integration
> **Priority: HIGH** — Everything works together.
> **Total Estimate: 1 week**
---
#### 5.1.1 Unified Toolchain
**Estimate: 3 days**
**Dependencies:** All previous phases
**Deliverable:** `dsa` unified command-line tool
- [ ] Create meta-crate: `dsa-tools`
- [ ] Unified CLI with subcommands
- [ ] `dsa build`
- [ ] `dsa run`
- [ ] `dsa debug`
- [ ] `dsa test`
- [ ] `dsa pkg`
- [ ] Shared configuration system
- [ ] Tool interop testing
- [ ] Documentation for workflow
---
#### 5.1.2 Emulator Integration
**Estimate: 2 days**
**Dependencies:** 5.1.1, 4.3.4
**Deliverable:** Fully integrated development environment
- [ ] Add build tools as emulator dependencies
- [ ] In-editor build triggered from emulator
- [ ] Debugger uses build output directly
- [ ] Source-level debugging with line mapping
- [ ] Test full edit → build → debug cycle
---
#### 5.1.3 Documentation & Tutorials
**Estimate: 2 days**
**Dependencies:** 5.1.2
**Deliverable:** Complete documentation suite
- [ ] Getting started guide
- [ ] Full tutorial: Building a simple game
- [ ] Debugger usage guide
- [ ] Best practices document
- [ ] Troubleshooting guide
---
## Phase 6: Future Enhancements (NTH)
> **Priority: LOW** — Nice to have, long-term goal.
> **Estimated Duration: 4+ weeks**
---
### 6.1 Command-Line Emulator
> ⚠️ **COMPLEX LONG-TERM GOAL** — Requires significant design and UX consideration.
---
#### 6.1.1 Design Phase
**Estimate: 1 week**
**Dependencies:** None
**Deliverable:** `docs/cli-emulator-design.md`
- [ ] UX research for terminal-based debuggers
- [ ] Design TUI layout (using `ratatui` or similar)
- [ ] Command syntax design
- [ ] Scripting support design
- [ ] Accessibility considerations
---
#### 6.1.2 Implementation
**Estimate: 3+ weeks**
**Dependencies:** 6.1.1, Phase 4 complete
**Deliverable:** `dsa-emu-cli` executable
- [ ] TUI framework setup
- [ ] Core emulator integration
- [ ] Command parser
- [ ] Panel rendering (code, registers, memory, etc.)
- [ ] Keyboard shortcuts
- [ ] Mouse support
- [ ] Configuration system
- [ ] Extensive usability testing
---
## Summary Timeline
| Phase | Duration | Key Dependencies |
|---|---|---|
| Phase 1: Foundation | 34 weeks | None |
| Phase 2: Compiler | 34 weeks | Phase 1 complete |
| Phase 3: Build System | 23 weeks | Phases 12 complete |
| Phase 4: Debugger | 34 weeks | Phases 13 complete |
| Phase 5: Integration | 12 weeks | Phases 14 complete |
| Phase 6: CLI Emulator *(NTH)* | 4+ weeks | Phase 4 complete |
**Total Estimated Time: 1217 weeks (34 months) for Phases 15**
---
## Critical Path
The following tasks are on the critical path and will block other work if delayed:
```
1.1.1 Binary format design
└── 1.1.2 Object file writer
└── 1.1.3 Linker
└── 1.2.2 Assembler rewrite
└── 2.1.3 Compiler codegen
└── 3.1.2 Build system
└── 4.1.2 Debug symbols
└── 4.2.1 Debugger
```
---
## Recommended Work Order
| Weeks | Focus | Tasks |
|---|---|---|
| 12 | Binary Format & Linker | 1.1.1 → 1.1.2 → 1.1.3 |
| 34 | Assembler Rewrite | 1.2.1 → 1.2.2 |
| 56 | Compiler Syntax & Parser | 2.1.1 → 2.1.2 *(start 1.3 docs in parallel)* |
| 79 | Compiler Codegen & Types | 2.1.3 → 2.1.4 *(start 2.2.1 runtime in parallel)* |
| 1011 | Build System | 3.1.1 → 3.1.2 → 3.1.3 |
| 1213 | Package Management *(if desired now)* | 3.2.1 → 3.2.2 → 3.2.3 |
| 1415 | Debug Symbols | 4.1.1 → 4.1.2 → 4.1.3 |
| 1618 | Core Debugger | 4.2.1 → 4.2.2 → 4.2.4 |
| 1920 | Editor Enhancements | 4.3.1 → 4.3.2 → 4.3.3 → 4.3.4 |
| 2122 | Integration & Polish | 5.1.1 → 5.1.2 → 5.1.3 |
---
## Notes
- Time estimates assume ~68 productive hours per day.
- Add **2030% buffer** for unexpected issues.
- Testing time is included in each estimate.
- Documentation is distributed throughout rather than batched at the end.
- Package management (3.2) can be deferred if time-constrained.
- Pseudo-instruction decompiler (4.2.3) can be a stretch goal.
- CLI emulator (Phase 6) is explicitly a "nice to have" and should not block other work.
Binary file not shown.
View File
+427
View File
@@ -0,0 +1,427 @@
# DSA Assembly Language Instruction Reference
## Overview
This document provides a comprehensive reference for the DSA (Damn Simple Architecture) assembly language, including all hardware instructions and pseudo-instructions with their syntax variations and usage examples.
## Calling Convention
| Step | Responsibility | Action | Description |
|------|----------------|--------|-------------|
| 1 | **Caller** | Push arguments | Push exactly n arguments to the stack (in order, last argument pushed first) |
| 2 | **Caller** | Call function | Execute `call namespace::function` - this automatically pushes the return address (pcx) and jumps to the function |
| 3 | **Function** | Set up stack frame | Execute `push bpr; mov spr, bpr` to establish new stack frame |
| 4 | **Function** | Access arguments | Read arguments starting at `spr+8` (first 3 args at offsets 8, 12, 16) |
| 5 | **Function** | Execute function | Perform the function's operations using the arguments |
| 6 | **Function** | Store return value | Write return value (if any) to `spr+8` |
| 7 | **Function** | Restore stack frame | Execute `mov bpr, spr; pop bpr` to restore previous stack frame |
| 8 | **Function** | Return | Execute `return` pseudo-instruction to return to caller |
| 9 | **Caller** | Clean up stack | Pop exactly n arguments from the stack to clean up |
| 10 | **Caller** | Handle unused values | Use `pop zero` to discard any unused stack values if needed |
**Notes:**
- The namespace in step 2 is the name assigned in the `include` statement
- The `call` pseudo-instruction automatically handles return address management so long as the callee does not mess with the stack
- Arguments are accessed by the callee using offsets from the base pointer (bpr)
## Registers
| Register | Type | Description |
|----------|------|---------------------------------------------------------------------------------------------------|
| `rg0-rgf` | General Purpose | General-purpose registers. |
| `acc` | Special | Accumulator for calculations and temporary storage - don't use this for variables as pseudo instructions may overwrite this implicitly! |
| `spr` | Special | Stack pointer |
| `bpr` | Special | Base pointer for stack frames |
| `ret` | Special | Return address register |
| `idr` | Privileged | Interrupt descriptor table address<br/>**on-read/write: protection fault (unless in kernel mode)** |
| `mmr` | Privileged | Hardware memory map table address<br/>**on-read/write: protection fault (unless in kernel mode)** |
| `zero` | Read-only | Always contains zero<br/>**on-read: always returns zero**<br/>**on-write: value is voided** |
| `pcx` | Read-only | Program counter<br/>**on-write: protection fault** |
| `noreg` | Placeholder | Indicates absence of register argument<br/>**on-read/write: illegal instruction fault** |
## Hardware Instructions
### Data Movement Instructions
| Mnemonic | Operands | Description |
|----------|----------|-------------|
| **MOV** | `src_reg, dest_reg` | Copy value from source to destination register |
| **MOVS** | `src_reg, dest_reg` | Copy with sign extension |
**Examples:**
```asm
mov rg0, rg1 ; Copy rg0 to rg1
movs rg0, rg1 ; Copy rg0 to rg1 with sign extension
```
### Memory Access Instructions
#### Load Instructions
| Mnemonic | Operands | Description |
|----------|----------|-------------|
| **LDB** | `base_reg, dest_reg [, offset]`<br>`label, dest_reg [, offset]` | Load byte from memory |
| **LDBS** | `base_reg, dest_reg [, offset]`<br>`label, dest_reg [, offset]` | Load byte with sign extension |
| **LDH** | `base_reg, dest_reg [, offset]`<br>`label, dest_reg [, offset]` | Load half-word (16-bit) |
| **LDHS** | `base_reg, dest_reg [, offset]`<br>`label, dest_reg [, offset]` | Load half-word with sign extension |
| **LDW** | `base_reg, dest_reg [, offset]`<br>`label, dest_reg [, offset]` | Load word (32-bit) |
**Examples:**
```asm
; Direct register addressing
ldb rg0, rg1 ; Load byte from address in rg0
ldw rg0, rg1, 8 ; Load word from (rg0 + 8)
; Label addressing
ldb buffer, rg2 ; Load byte from label 'buffer'
ldw stack, bpr ; Load stack address into base pointer
```
**Label Expansions:**
```asm
; ldb buffer, rg2 expands to:
lli buffer, rg2 ; Load lower 16 bits of buffer address
lui buffer, rg2 ; Load upper 16 bits of buffer address
ldb rg2, rg2 ; Load byte from address in rg2
; ldw stack, bpr expands to:
lli stack, bpr ; Load lower 16 bits of stack address
lui stack, bpr ; Load upper 16 bits of stack address
ldw bpr, bpr ; Load word from address in bpr
```
#### Store Instructions
| Mnemonic | Operands | Description |
|----------|----------|-------------|
| **STB** | `src_reg, base_reg [, offset]`<br>`src_reg, label [, offset]` | Store byte to memory |
| **STH** | `src_reg, base_reg [, offset]`<br>`src_reg, label [, offset]` | Store half-word to memory |
| **STW** | `src_reg, base_reg [, offset]`<br>`src_reg, label [, offset]` | Store word to memory |
**Examples:**
```asm
; Direct register addressing
stb rg0, rg1 ; Store byte from rg0 to address in rg1
stw rg0, rg1, 12 ; Store word to (rg1 + 12)
; Label addressing
stb acc, buffer ; Store byte from accumulator to 'buffer'
stw rg1, current ; Store word to 'current' variable
```
**Label Expansions:**
```asm
; stb acc, buffer expands to:
lli buffer, rgf ; Load lower 16 bits of buffer address
lui buffer, rgf ; Load upper 16 bits of buffer address
stb acc, rgf ; Store byte from acc to address in rgf
; 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 ; Store word from rg1 to address in rgf
```
### Immediate Load Instructions
| Mnemonic | Operands | Description |
|----------|----------|------------------------------------------------------------------------|
| **LLI** | `imm, dest_reg` | Load 16-bit immediate into lower 16 bits<br/>**Clears upper 16 bits!** |
| **LUI** | `imm, dest_reg` | Load 16-bit immediate into upper 16 bits |
**Usage**
ensure that you always run **Lli** before **Lui** as **Lli** clears the upper 16 bits.
**Examples:**
```asm
lli 0x1234, rg0 ; Load 0x1234 into lower 16 bits of rg0
lui 0xABCD, rg0 ; Load 0xABCD into upper 16 bits of rg0
```
### Jump Instructions
| Mnemonic | Operands | Description |
|----------|----------|-------------|
| **JMP** | `addr [, offset_reg]`<br>`imm, offset_reg` | Unconditional jump |
| **JEQ** | `addr [, offset_reg]` | Jump if equal flag set |
| **JNE** | `addr [, offset_reg]` | Jump if not equal flag set |
| **JGT** | `addr [, offset_reg]` | Jump if greater than flag set |
| **JGE** | `addr [, offset_reg]` | Jump if greater or equal flags set |
| **JLT** | `addr [, offset_reg]` | Jump if less than flag set |
| **JLE** | `addr [, offset_reg]` | Jump if less or equal flags set |
**Examples:**
```asm
jmp start ; Jump to label 'start'
jmp 4, ret ; Jump to address (4 + ret register)
jeq end ; Jump to 'end' if equal flag set
jgt loop ; Jump to 'loop' if greater than flag set
```
### Arithmetic Instructions
| Mnemonic | Operands | Description |
|----------|----------|-------------|
| **ADD** | `src1_reg, src2_reg, dest_reg` | Addition |
| **SUB** | `src1_reg, src2_reg, dest_reg` | Subtraction |
| **IADD** | `src_reg, imm [, dest_reg]` | Immediate addition |
| **ISUB** | `src_reg, imm [, dest_reg]` | Immediate subtraction |
| **INC** | `reg` | Increment register by 1 |
| **DEC** | `reg` | Decrement register by 1 |
**Examples:**
```asm
add rg0, rg1, rg2 ; rg2 = rg0 + rg1
sub rg0, rg1, rg2 ; rg2 = rg0 - rg1
iadd rg0, 10 ; rg0 = rg0 + 10
// or using alternate syntax
addi rg0, 1 ; rg0 = rg0 + 1
inc rg0 ; rg0 = rg0 + 1
```
### Bitwise Operations
| Mnemonic | Operands | Description |
|----------|----------|-------------|
| **AND** | `src1_reg, src2_reg, dest_reg` | Bitwise AND |
| **OR** | `src1_reg, src2_reg, dest_reg` | Bitwise OR |
| **XOR** | `src1_reg, src2_reg, dest_reg` | Bitwise XOR |
| **NOT** | `src_reg, dest_reg` | Bitwise NOT |
| **NAND** | `src1_reg, src2_reg, dest_reg` | Bitwise NAND |
| **NOR** | `src1_reg, src2_reg, dest_reg` | Bitwise NOR |
| **XNOR** | `src1_reg, src2_reg, dest_reg` | Bitwise XNOR |
**Examples:**
```asm
and rg0, rg1, rg2 ; rg2 = rg0 & rg1
not rg0, rg1 ; rg1 = ~rg0
```
### Shift Operations
| Mnemonic | Operands | Description |
|----------|----------|-------------|
| **SHL** | `reg, shift_amount` | Shift left |
| **SHR** | `reg, shift_amount` | Shift right |
**Examples:**
```asm
shl rg0, 2 ; Shift rg0 left by 2 bits
shr rg0, 3 ; Shift rg0 right by 3 bits
```
### Comparison and Control
| Mnemonic | Operands | Description |
|----------|----------|-------------|
| **CMP** | `reg1, reg2` | Compare registers and set flags |
**Examples:**
```asm
cmp rg0, zero ; Compare rg0 with zero register
cmp rg1, rg2 ; Compare rg1 with rg2
```
### System Instructions
| Mnemonic | Operands | Description |
|----------|----------|-------------|
| **HLT** | - | Halt processor execution |
| **NOP** | - | No operation |
| **INT** | `interrupt_code` | Trigger interrupt |
| **IRT** | - | Return from interrupt |
**Examples:**
```asm
hlt ; Stop processor execution
int 0x21 ; Trigger interrupt 0x21
```
## Pseudo-Instructions
### Data Definition
| Mnemonic | Syntax | Description |
|----------|--------|-------------|
| **DB** | `name: value1 [, value2, ...]` | Define bytes |
| **DH** | `name: value1 [, value2, ...]` | Define half-words |
| **DW** | `name: value1 [, value2, ...]` | Define words |
**Examples:**
```asm
db message: "Hello World", 0
dh numbers: 1000, 2000, 3000
dw stack: 0x10000
```
### Memory Reservation
| Mnemonic | Syntax | Description |
|----------|--------|-------------|
| **RESB** | `name: size` | Reserve bytes |
| **RESH** | `name: size` | Reserve half-words |
| **RESW** | `name: size` | Reserve words |
**Examples:**
```asm
resb buffer: 256 ; Reserve 256 bytes
resh array: 100 ; Reserve space for 100 half-words
resw heap: 1024 ; Reserve space for 1024 words
```
### Stack Operations
| Mnemonic | Operands | Description |
|----------|----------|-------------|
| **PUSH** | `reg` | Push register value onto stack |
| **POP** | `reg` | Pop stack value into register |
**Examples:**
```asm
push rg0 ; Push rg0 value onto stack
pop ret ; Pop return address
```
### Memory Access Shortcuts
| Mnemonic | Operands | Description |
|----------|----------|-------------|
| **LWI** | `name, reg` | Load address into register |
**Examples:**
```asm
lwi string, rg1 ; Load address of 'string' into rg1
```
### Function Control
| Mnemonic | Operands | Description |
|----------|----------|-------------|
| **CALL** | `namespace::function` | Call a function with automatic return address management |
| **RETURN** | - | Return from a function to the caller |
**Examples:**
```asm
call print::print ; Call the print function from the print namespace
return ; Return from the current function
```
### Module System
| Mnemonic | Syntax | Description |
|----------|--------|-------------|
| **INCLUDE** | `module_name "path"` | Include module |
**Examples:**
```asm
include print "print.dsa"
include fib "fib.dsa"
```
## Library Examples
### Multiplication Library (multiply.dsa)
```asm
// 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 1
ldw bpr, rg1, 12 // load op 2
lli 0, acc // initialize accumulator
start:
add acc, rg0, acc
dec rg1
cmp rg1, zero
jgt start
end:
stw acc, bpr, 8 // store result for caller
mov bpr, spr
pop bpr
return
```
### Print Library (print.dsa)
```asm
// print.dsa
// usage:
//
// include print "<relative path>"
//
// usage for print:
// push (register containing address of string)
// call print::print
// pop zero
//
// usage for reset:
// call print::reset
dw display: 0x20000
dw current: 0x20000
// prints the given text to the screen.
print:
push bpr
mov spr, bpr
ldw bpr, rg0, 8 // get string address argument
ldw current, rg1 // get current display position
print_loop:
ldb rg0, acc
stb acc, rg1
iadd rg0, 1
iadd rg1, 1
cmp acc, zero
jne print_loop
jmp end
// return
end:
stw rg1, current
mov bpr, spr
pop bpr
return
// resets the cursor position on the screen
reset:
push bpr
mov spr, bpr
ldw display, rg1
stw rg1, current
mov bpr, spr
pop bpr
return
```
### Example Program (main.dsa)
```asm
include print "./print.dsa"
dw stack: 0x10000
db string: "'To confuse your enemy, you must first confuse yourself' - Probably Sun Tzu."
init:
// set up a stack.
ldw stack, bpr
mov bpr, spr
start:
lwi string, rg1
// push string address argument
push rg1
// call print function
call print::print
// clean up stack
pop rg1
hlt
```
+10
View File
@@ -0,0 +1,10 @@
# DSA File formatting specification.
First, a clarification on what formats this document references.
- .dsb: DSA Binary object, similar to a .o object file
- .dse: DSA Executable file, similar to a .exe/ELF binary
## Format Specification
### DSB binary format