diff --git a/assembler/src/lexer.rs b/assembler/src/lexer.rs index 0202a2c..5879317 100644 --- a/assembler/src/lexer.rs +++ b/assembler/src/lexer.rs @@ -1,20 +1,12 @@ use std::str::FromStr; -use crate::{AssembleError, parser::Opcode}; +use crate::{ + AssembleError, + model::{Module, Opcode, Symbol, Token}, +}; use common::prelude::Register; -pub type Symbol = String; - -#[derive(Debug, Clone)] -pub enum Token { - Symbol(Symbol), - Register(Register), - Immediate(u32), - StringLit(String), - Opcode(Opcode), -} - -pub fn lexer(mut program: String) -> Result, AssembleError> { +pub fn lexer(mut program: String, module: u64) -> Result, AssembleError> { let mut tokens = Vec::new(); program = program.replace(",", ""); @@ -30,7 +22,6 @@ pub fn lexer(mut program: String) -> Result, AssembleError> { if let Some(stripped) = token.strip_prefix('"') { literal.push_str(stripped); - println!("literal: {literal}"); } if !literal.is_empty() { @@ -61,9 +52,9 @@ pub fn lexer(mut program: String) -> Result, AssembleError> { tokens.push(token); } else if let Some(token) = parse_decimal(token)? { tokens.push(token); - } else if let Some(token) = parse_label(token)? { + } else if let Some(token) = parse_label(token, module)? { tokens.push(token); - } else if let Some(token) = parse_symbol(token)? { + } else if let Some(token) = parse_symbol(token, module)? { tokens.push(token); } else { return Err(AssembleError::Generic); @@ -126,18 +117,34 @@ pub fn parse_decimal(token: &str) -> Result, AssembleError> { } } -pub fn parse_label(token: &str) -> Result, AssembleError> { +pub fn parse_label(token: &str, module: u64) -> Result, AssembleError> { if !token.ends_with(":") { Ok(None) } else { - Ok(Some(Token::Symbol(token[0..token.len() - 1].to_string()))) + Ok(Some(Token::Symbol(Symbol { + name: token[0..token.len() - 1].to_string(), + module: Module::Resolved(module), + }))) } } -pub fn parse_symbol(token: &str) -> Result, AssembleError> { +pub fn parse_symbol(token: &str, module: u64) -> Result, AssembleError> { if token.chars().next().unwrap().is_numeric() { return Ok(None); } - Ok(Some(Token::Symbol(token.to_string()))) + let mut split = token.splitn(2, "::"); + let symbol1 = split.next().unwrap().to_string(); + + if let Some(symbol2) = split.next() { + Ok(Some(Token::Symbol(Symbol { + name: symbol2.to_string(), + module: Module::Unresolved(symbol1), + }))) + } else { + Ok(Some(Token::Symbol(Symbol { + name: symbol1, + module: Module::Resolved(module), + }))) + } } diff --git a/assembler/src/lib.rs b/assembler/src/lib.rs index 477f968..d7fdb55 100644 --- a/assembler/src/lib.rs +++ b/assembler/src/lib.rs @@ -1,14 +1,91 @@ use core::fmt; +use std::{ + collections::HashSet, + fs, + hash::{DefaultHasher, Hash, Hasher}, + path::PathBuf, +}; use common::prelude::Instruction; -use crate::{lexer::Token, parser::TokenType}; +use crate::{ + model::{Node, Token, TokenType}, + parser::{Parser, Program}, +}; pub mod lexer; +pub mod model; pub mod parser; -pub fn assemble(_src: &str) -> Vec { - todo!() +pub fn assemble(src: &PathBuf) -> Vec { + let mut modules = HashSet::::new(); + let mut program = Program::new(); + + let hash = quick_hash(src); + modules.insert(hash); + + match prepare_dependency(src.clone(), &mut modules, &mut program) { + Ok(_) => {} + Err(err) => println!("BIG ERROR {:?}", err), + } + + for node in program.nodes { + println!("{:?}", node); + } + + vec![] +} + +fn prepare_dependency( + path: PathBuf, + modules: &mut HashSet, + program: &mut Program, +) -> Result<(), AssembleError> { + let filename = path.file_name().unwrap().to_str().unwrap(); + if let Ok(path) = path.canonicalize() { + log(&format!( + "{:20} {:20} [{}]", + "Building", + filename, + path.display() + )); + } + + let src = fs::read_to_string(&path) + .map_err(|_| AssembleError::InvalidFile(path.clone()))?; + let file_hash = quick_hash(&path); + + log(&format!("{:20} {:20}", "Tokenising", filename)); + let tokens = lexer::lexer(src, file_hash)?; + + log(&format!("{:20} {:20}", "Parsing", filename)); + let mut parser = Parser::new(tokens); + + log(&format!("{:20} {:20}", "Resolving Deps", filename)); + let deps = parser + .parse_nodes()? + .resolve_dependencies()? + .get_dependencies()?; + program.add_module(parser.get()); + + for dep in deps { + log(&format!( + "{:20} {:20}", + "Including", + dep.file_name().unwrap().to_str().unwrap() + )); + + if !modules.contains(&quick_hash(&dep)) { + modules.insert(quick_hash(&dep)); + prepare_dependency(dep, modules, program)? + } + } + + Ok(()) +} + +fn build(src: Vec) -> Result, AssembleError> { + Ok(vec![]) } /// TODO: disassembling functionality @@ -23,6 +100,7 @@ pub fn disassemble(_: Vec) -> String { #[derive(Debug)] pub enum AssembleError { Generic, + InvalidFile(PathBuf), UnexpectedToken(Token, TokenType), } @@ -33,6 +111,17 @@ impl fmt::Display for AssembleError { AssembleError::UnexpectedToken(tok, expected) => { write!(f, "Unexpected token {tok:?}, expected {expected:?}") } + AssembleError::InvalidFile(path) => write!(f, "Invalid file {path:?}"), } } } + +fn quick_hash(value: &PathBuf) -> u64 { + let mut hasher = DefaultHasher::new(); + value.canonicalize().unwrap().to_str().hash(&mut hasher); + hasher.finish() +} + +fn log(message: &str) { + println!("\x1b[32mINFO:\x1b[0m {}", message); +} diff --git a/assembler/src/main.rs b/assembler/src/main.rs index 469040c..7645a1a 100644 --- a/assembler/src/main.rs +++ b/assembler/src/main.rs @@ -1,17 +1,25 @@ -use std::fs; +use std::{fs, io::Write, path::PathBuf}; use assembler::{lexer, parser::Parser}; use common::prelude::{ITypeArgs, Instruction, RTypeArgs, Register}; fn main() { - let program = fs::read_to_string("../resources/dsa/print.dsa").unwrap(); - let tokens = lexer::lexer(program).unwrap(); - - println!("{tokens:?}"); - - let parser = Parser::new(tokens); - - for node in parser { - println!("{node:?}"); + // parse args: + let args: Vec = std::env::args().collect(); + if args.len() != 5 || args[1] != "-i" || args[3] != "-o" { + eprintln!("Usage: binary_name -i input_path -o output_path"); + std::process::exit(1); } + let input_path = &args[2]; + let output_path = &args[4]; + + let src = PathBuf::from(input_path); + let mut output_file = fs::File::create(output_path).unwrap(); + + let res = assembler::assemble(&src) + .iter() + .map(|i| i.encode()) + .for_each(|i| { + output_file.write_all(&i.to_be_bytes()).unwrap(); + }); } diff --git a/assembler/src/model.rs b/assembler/src/model.rs new file mode 100644 index 0000000..dd5aeae --- /dev/null +++ b/assembler/src/model.rs @@ -0,0 +1,282 @@ +use std::{fmt, str::FromStr}; + +use common::prelude::Register; + +#[derive(Debug, Clone)] +#[expect(dead_code)] +pub struct Node(pub Option, pub Opcode, pub Vec); + +impl fmt::Display for Node { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let symbol = match &self.0 { + Some(symbol) => format!("{}", symbol), + None => "".to_string(), + }; + + write!(f, "Node: {} {} {:?}", symbol, self.1, self.2) + } +} + +impl fmt::Display for Symbol { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}::{}", self.module, self.name) + } +} + +impl fmt::Display for Module { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Module::Unresolved(name) => write!(f, "{}", name), + Module::Resolved(name) => write!(f, "{}", name), + } + } +} + +impl fmt::Display for Opcode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self) + } +} + +#[derive(Debug, Clone)] +pub struct Symbol { + pub name: String, + pub module: Module, +} + +#[derive(Debug, Clone)] +pub enum Module { + Resolved(u64), + Unresolved(String), +} + +#[derive(Debug, Clone)] +pub enum Token { + Symbol(Symbol), + Register(Register), + Immediate(u32), + StringLit(String), + Opcode(Opcode), +} + +#[derive(Debug, PartialEq, Copy, Clone)] +pub enum TokenType { + Symbol, + Register, + Immediate, + StringLit, + Opcode, +} + +impl TokenType { + pub fn from_token(token: &Token) -> TokenType { + match token { + Token::Symbol(_) => TokenType::Symbol, + Token::Register(_) => TokenType::Register, + Token::Immediate(_) => TokenType::Immediate, + Token::StringLit(_) => TokenType::StringLit, + Token::Opcode(_) => TokenType::Opcode, + } + } +} + +#[derive(Debug, Clone, PartialEq)] +pub enum Opcode { + // Real instructions (0x00-0x26) + Nop, + Mov, + Movs, + Ldb, + Ldbs, + Ldh, + Ldhs, + Ldw, + Stb, + Sth, + Stw, + Lli, + Lui, + Jmp, + Jeq, + Jne, + Jgt, + Jge, + Jlt, + Jle, + Cmp, + Inc, + Dec, + Shl, + Shr, + Add, + Sub, + And, + Or, + Not, + Xor, + Nand, + Nor, + Xnor, + Int, + Irt, + Hlt, + Iadd, + Isub, + // Pseudo-instructions + Db, + Dh, + Dw, + Resb, + Resh, + Resw, + Push, + Pop, + Lwi, + Include, +} + +#[derive(Debug)] +pub enum OpcodeFromStrError { + InvalidRegister(&'static str), +} + +impl std::fmt::Display for OpcodeFromStrError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::InvalidRegister(reg) => write!(f, "register does not exist: {reg}"), + } + } +} + +impl std::error::Error for OpcodeFromStrError {} + +impl FromStr for Opcode { + type Err = OpcodeFromStrError; + + fn from_str(s: &str) -> Result { + match s.to_lowercase().as_str() { + "nop" => Ok(Self::Nop), + "mov" => Ok(Self::Mov), + "movs" => Ok(Self::Movs), + "ldb" => Ok(Self::Ldb), + "ldbs" => Ok(Self::Ldbs), + "ldh" => Ok(Self::Ldh), + "ldhs" => Ok(Self::Ldhs), + "ldw" => Ok(Self::Ldw), + "stb" => Ok(Self::Stb), + "sth" => Ok(Self::Sth), + "stw" => Ok(Self::Stw), + "lli" => Ok(Self::Lli), + "lui" => Ok(Self::Lui), + "jmp" => Ok(Self::Jmp), + "jeq" => Ok(Self::Jeq), + "jne" => Ok(Self::Jne), + "jgt" => Ok(Self::Jgt), + "jge" => Ok(Self::Jge), + "jlt" => Ok(Self::Jlt), + "jle" => Ok(Self::Jle), + "cmp" => Ok(Self::Cmp), + "inc" => Ok(Self::Inc), + "dec" => Ok(Self::Dec), + "shl" => Ok(Self::Shl), + "shr" => Ok(Self::Shr), + "add" => Ok(Self::Add), + "sub" => Ok(Self::Sub), + "and" => Ok(Self::And), + "or" => Ok(Self::Or), + "not" => Ok(Self::Not), + "xor" => Ok(Self::Xor), + "nand" => Ok(Self::Nand), + "nor" => Ok(Self::Nor), + "xnor" => Ok(Self::Xnor), + "int" => Ok(Self::Int), + "irt" => Ok(Self::Irt), + "hlt" => Ok(Self::Hlt), + "iadd" => Ok(Self::Iadd), + "isub" => Ok(Self::Isub), + "db" => Ok(Self::Db), + "dh" => Ok(Self::Dh), + "dw" => Ok(Self::Dw), + "resb" => Ok(Self::Resb), + "resh" => Ok(Self::Resh), + "resw" => Ok(Self::Resw), + "push" => Ok(Self::Push), + "pop" => Ok(Self::Pop), + "lwi" => Ok(Self::Lwi), + "include" => Ok(Self::Include), + _ => Err(OpcodeFromStrError::InvalidRegister("unknown opcode")), + } + } +} + +impl Opcode { + pub const OPCODES: &[&str] = &[ + // Real instructions (0x00-0x26) + "nop", "mov", "movs", "ldb", "ldbs", "ldh", "ldhs", "ldw", "stb", "sth", "stw", + "lli", "lui", "jmp", "jeq", "jne", "jgt", "jge", "jlt", "jle", "cmp", "inc", + "dec", "shl", "shr", "add", "sub", "and", "or", "not", "xor", "nand", "nor", + "xnor", "int", "irt", "hlt", "iadd", "isub", // Pseudo-instructions + "db", "dh", "dw", "resb", "resh", "resw", "push", "pop", "lwi", "include", + ]; + + pub fn to_opcode_value(&self) -> Option { + match self { + Self::Nop => Some(0x00), + Self::Mov => Some(0x01), + Self::Movs => Some(0x02), + Self::Ldb => Some(0x03), + Self::Ldbs => Some(0x04), + Self::Ldh => Some(0x05), + Self::Ldhs => Some(0x06), + Self::Ldw => Some(0x07), + Self::Stb => Some(0x08), + Self::Sth => Some(0x09), + Self::Stw => Some(0x0A), + Self::Lli => Some(0x0B), + Self::Lui => Some(0x0C), + Self::Jmp => Some(0x0D), + Self::Jeq => Some(0x0E), + Self::Jne => Some(0x0F), + Self::Jgt => Some(0x10), + Self::Jge => Some(0x11), + Self::Jlt => Some(0x12), + Self::Jle => Some(0x13), + Self::Cmp => Some(0x14), + Self::Inc => Some(0x15), + Self::Dec => Some(0x16), + Self::Shl => Some(0x17), + Self::Shr => Some(0x18), + Self::Add => Some(0x19), + Self::Sub => Some(0x1A), + Self::And => Some(0x1B), + Self::Or => Some(0x1C), + Self::Not => Some(0x1D), + Self::Xor => Some(0x1E), + Self::Nand => Some(0x1F), + Self::Nor => Some(0x20), + Self::Xnor => Some(0x21), + Self::Int => Some(0x22), + Self::Irt => Some(0x23), + Self::Hlt => Some(0x24), + Self::Iadd => Some(0x25), + Self::Isub => Some(0x26), + // Pseudo-instructions don't have opcode values + _ => None, + } + } + + pub fn is_pseudo_instruction(&self) -> bool { + matches!( + self, + Self::Db + | Self::Dh + | Self::Dw + | Self::Resb + | Self::Resh + | Self::Resw + | Self::Push + | Self::Pop + | Self::Lwi + ) + } +} diff --git a/assembler/src/parser.rs b/assembler/src/parser.rs index 6cd39d6..eb1457e 100644 --- a/assembler/src/parser.rs +++ b/assembler/src/parser.rs @@ -1,73 +1,35 @@ +use core::fmt; +use std::path::PathBuf; use std::str::FromStr; -use crate::AssembleError; -use crate::lexer::{Symbol, Token}; +use common::prelude::{Instruction, Register}; + +use crate::model::{Module, Node, Opcode, Symbol, Token, TokenType}; +use crate::{AssembleError, quick_hash}; pub struct Parser { tokens: Vec, + nodes: Vec, } -#[derive(Debug, PartialEq, Copy, Clone)] -pub enum TokenType { - Symbol, - Register, - Immediate, - StringLit, - Opcode, +pub struct Program { + pub nodes: Vec, } -impl TokenType { - fn from_token(token: &Token) -> TokenType { - match token { - Token::Symbol(_) => TokenType::Symbol, - Token::Register(_) => TokenType::Register, - Token::Immediate(_) => TokenType::Immediate, - Token::StringLit(_) => TokenType::StringLit, - Token::Opcode(_) => TokenType::Opcode, - } +impl Program { + pub fn new() -> Program { + Program { nodes: vec![] } } -} -// TODO: MAKE SURE I DO THE BIT SHIFT FOR LUI CODEGEN -// TODO: MAKE SURE I DO THE BIT SHIFT FOR LUI CODEGEN -// TODO: MAKE SURE I DO THE BIT SHIFT FOR LUI CODEGEN -// TODO: MAKE SURE I DO THE BIT SHIFT FOR LUI CODEGEN -// TODO: MAKE SURE I DO THE BIT SHIFT FOR LUI CODEGEN -// TODO: MAKE SURE I DO THE BIT SHIFT FOR LUI CODEGEN -// TODO: MAKE SURE I DO THE BIT SHIFT FOR LUI CODEGEN -// TODO: MAKE SURE I DO THE BIT SHIFT FOR LUI CODEGEN -// TODO: MAKE SURE I DO THE BIT SHIFT FOR LUI CODEGEN -// TODO: MAKE SURE I DO THE BIT SHIFT FOR LUI CODEGEN -// TODO: MAKE SURE I DO THE BIT SHIFT FOR LUI CODEGEN -// TODO: MAKE SURE I DO THE BIT SHIFT FOR LUI CODEGEN -// TODO: MAKE SURE I DO THE BIT SHIFT FOR LUI CODEGEN -// TODO: MAKE SURE I DO THE BIT SHIFT FOR LUI CODEGEN -// TODO: MAKE SURE I DO THE BIT SHIFT FOR LUI CODEGEN -// TODO: MAKE SURE I DO THE BIT SHIFT FOR LUI CODEGEN -// TODO: MAKE SURE I DO THE BIT SHIFT FOR LUI CODEGEN -// TODO: MAKE SURE I DO THE BIT SHIFT FOR LUI CODEGEN -// TODO: MAKE SURE I DO THE BIT SHIFT FOR LUI CODEGEN -// TODO: MAKE SURE I DO THE BIT SHIFT FOR LUI CODEGEN -// TODO: MAKE SURE I DO THE BIT SHIFT FOR LUI CODEGEN -// TODO: MAKE SURE I DO THE BIT SHIFT FOR LUI CODEGEN -// TODO: MAKE SURE I DO THE BIT SHIFT FOR LUI CODEGEN -// TODO: MAKE SURE I DO THE BIT SHIFT FOR LUI CODEGEN -// TODO: MAKE SURE I DO THE BIT SHIFT FOR LUI CODEGEN -// TODO: MAKE SURE I DO THE BIT SHIFT FOR LUI CODEGEN + pub fn add_module(&mut self, module: Vec) { + self.nodes.extend(module); + } -#[derive(Debug)] -#[expect(dead_code)] -pub struct Node(Option, Opcode, Vec); - -impl Iterator for Parser { - type Item = Result; - - fn next(&mut self) -> Option> { - if self.tokens.is_empty() { - return None; + pub fn parser(&mut self) -> Parser { + Parser { + tokens: vec![], + nodes: self.nodes.clone(), } - - Some(self.parse_instruction()) } } @@ -75,9 +37,128 @@ impl Parser { pub fn new(tokens: Vec) -> Parser { Parser { tokens: tokens.into_iter().rev().collect(), + nodes: vec![], } } + pub fn parse_nodes(&mut self) -> Result<&mut Self, AssembleError> { + while !self.tokens.is_empty() { + let ins = self.parse_instruction()?; + self.nodes.push(ins); + } + + Ok(self) + } + + pub fn get_dependencies(&mut self) -> Result, AssembleError> { + let mut dependencies = Vec::new(); + for node in &self.nodes { + if let Opcode::Include = node.1 { + if let Token::StringLit(path) = node.2.get(1).unwrap() { + dependencies.push(PathBuf::from(path)); + } + } + } + Ok(dependencies) + } + + pub fn resolve_dependencies(&mut self) -> Result<&mut Self, AssembleError> { + // first we get a list of imports + let mut dependencies = Vec::new(); + for node in &self.nodes { + if let Opcode::Include = node.1 { + // we want the path, and the name + let name = if let Token::Symbol(name) = node.2.get(0).unwrap() { + name.name.clone() + } else { + unreachable!() + }; //node.2.get(0).unwrap() + let path = if let Token::StringLit(path) = node.2.get(1).unwrap() { + path + } else { + unreachable!() + }; + let hash = quick_hash(&PathBuf::from(path).canonicalize().unwrap()); + + dependencies.push((name, hash)); + } + } + + let mut changes = Vec::<(u32, u32, Symbol)>::new(); + // now we resolve the symbols on all the nodes + // we need to check all operands for unresolved signals + for (i, node) in self.nodes.clone().iter().enumerate() { + let Node(_, _, operands) = node; + for (j, token) in operands.iter().enumerate() { + if let Token::Symbol(symbol) = token { + for d in &dependencies { + if let Module::Unresolved(name) = symbol.module.clone() { + if name != d.0 { + continue; + } + + let symbol = Symbol { + name: symbol.name.clone(), + module: Module::Resolved(d.1), + }; + changes.push((i as u32, j as u32, symbol)); + } + } + } + } + } + + for (i, j, symbol) in changes { + self.nodes[i as usize].2[j as usize] = Token::Symbol(symbol); + } + + Ok(self) + } + + pub fn get(&self) -> Vec { + self.nodes.clone() + } + + pub fn expand_pseudo_ops(&mut self) -> Result<&mut Self, AssembleError> { + for node in self.nodes.iter_mut() { + match node.1 { + Opcode::Db | Opcode::Dh | Opcode::Dw => todo!(), + Opcode::Resb | Opcode::Resh | Opcode::Resw => todo!(), + + Opcode::Push => { + // inc SPR + // STW reg, SPR + let label = node.0.clone(); + let reg = node.2.get(0).unwrap(); + + vec![ + Node( + label.clone(), + Opcode::Inc, + vec![Token::Register(Register::Spr)], + ), + Node( + label.clone(), + Opcode::Stw, + vec![reg.clone(), Token::Register(Register::Spr)], + ), + ]; + } + _ => continue, + } + } + + Ok(self) + } + + pub fn resolve_symbols(&mut self) -> Result<&mut Self, AssembleError> { + Ok(self) + } + + pub fn instructions(&mut self) -> Vec { + vec![] + } + fn parse_instruction(&mut self) -> Result { if self.tokens.is_empty() { unreachable!(); @@ -170,6 +251,12 @@ impl Parser { args = vec![reg]; } + Opcode::Include => { + let mod_name = self.expect(TokenType::Symbol)?; + let path = self.expect(TokenType::StringLit)?; + args = vec![mod_name, path]; + } + // J-type instructions Opcode::Jmp | Opcode::Jeq @@ -312,202 +399,3 @@ impl Parser { } } } - -#[derive(Debug, Clone, PartialEq)] -pub enum Opcode { - // Real instructions (0x00-0x26) - Nop, - Mov, - Movs, - Ldb, - Ldbs, - Ldh, - Ldhs, - Ldw, - Stb, - Sth, - Stw, - Lli, - Lui, - Jmp, - Jeq, - Jne, - Jgt, - Jge, - Jlt, - Jle, - Cmp, - Inc, - Dec, - Shl, - Shr, - Add, - Sub, - And, - Or, - Not, - Xor, - Nand, - Nor, - Xnor, - Int, - Irt, - Hlt, - Iadd, - Isub, - // Pseudo-instructions - Db, - Dh, - Dw, - Resb, - Resh, - Resw, - Push, - Pop, - Lwi, -} - -#[derive(Debug)] -pub enum OpcodeFromStrError { - InvalidRegister(&'static str), -} - -impl std::fmt::Display for OpcodeFromStrError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::InvalidRegister(reg) => write!(f, "register does not exist: {reg}"), - } - } -} - -impl std::error::Error for OpcodeFromStrError {} - -impl FromStr for Opcode { - type Err = OpcodeFromStrError; - - fn from_str(s: &str) -> Result { - match s.to_lowercase().as_str() { - "nop" => Ok(Self::Nop), - "mov" => Ok(Self::Mov), - "movs" => Ok(Self::Movs), - "ldb" => Ok(Self::Ldb), - "ldbs" => Ok(Self::Ldbs), - "ldh" => Ok(Self::Ldh), - "ldhs" => Ok(Self::Ldhs), - "ldw" => Ok(Self::Ldw), - "stb" => Ok(Self::Stb), - "sth" => Ok(Self::Sth), - "stw" => Ok(Self::Stw), - "lli" => Ok(Self::Lli), - "lui" => Ok(Self::Lui), - "jmp" => Ok(Self::Jmp), - "jeq" => Ok(Self::Jeq), - "jne" => Ok(Self::Jne), - "jgt" => Ok(Self::Jgt), - "jge" => Ok(Self::Jge), - "jlt" => Ok(Self::Jlt), - "jle" => Ok(Self::Jle), - "cmp" => Ok(Self::Cmp), - "inc" => Ok(Self::Inc), - "dec" => Ok(Self::Dec), - "shl" => Ok(Self::Shl), - "shr" => Ok(Self::Shr), - "add" => Ok(Self::Add), - "sub" => Ok(Self::Sub), - "and" => Ok(Self::And), - "or" => Ok(Self::Or), - "not" => Ok(Self::Not), - "xor" => Ok(Self::Xor), - "nand" => Ok(Self::Nand), - "nor" => Ok(Self::Nor), - "xnor" => Ok(Self::Xnor), - "int" => Ok(Self::Int), - "irt" => Ok(Self::Irt), - "hlt" => Ok(Self::Hlt), - "iadd" => Ok(Self::Iadd), - "isub" => Ok(Self::Isub), - "db" => Ok(Self::Db), - "dh" => Ok(Self::Dh), - "dw" => Ok(Self::Dw), - "resb" => Ok(Self::Resb), - "resh" => Ok(Self::Resh), - "resw" => Ok(Self::Resw), - "push" => Ok(Self::Push), - "pop" => Ok(Self::Pop), - "lwi" => Ok(Self::Lwi), - _ => Err(OpcodeFromStrError::InvalidRegister("unknown opcode")), - } - } -} - -impl Opcode { - pub const OPCODES: &[&str] = &[ - // Real instructions (0x00-0x26) - "nop", "mov", "movs", "ldb", "ldbs", "ldh", "ldhs", "ldw", "stb", "sth", "stw", - "lli", "lui", "jmp", "jeq", "jne", "jgt", "jge", "jlt", "jle", "cmp", "inc", - "dec", "shl", "shr", "add", "sub", "and", "or", "not", "xor", "nand", "nor", - "xnor", "int", "irt", "hlt", "iadd", "isub", // Pseudo-instructions - "db", "dh", "dw", "resb", "resh", "resw", "push", "pop", "lwi", - ]; - - pub fn to_opcode_value(&self) -> Option { - match self { - Self::Nop => Some(0x00), - Self::Mov => Some(0x01), - Self::Movs => Some(0x02), - Self::Ldb => Some(0x03), - Self::Ldbs => Some(0x04), - Self::Ldh => Some(0x05), - Self::Ldhs => Some(0x06), - Self::Ldw => Some(0x07), - Self::Stb => Some(0x08), - Self::Sth => Some(0x09), - Self::Stw => Some(0x0A), - Self::Lli => Some(0x0B), - Self::Lui => Some(0x0C), - Self::Jmp => Some(0x0D), - Self::Jeq => Some(0x0E), - Self::Jne => Some(0x0F), - Self::Jgt => Some(0x10), - Self::Jge => Some(0x11), - Self::Jlt => Some(0x12), - Self::Jle => Some(0x13), - Self::Cmp => Some(0x14), - Self::Inc => Some(0x15), - Self::Dec => Some(0x16), - Self::Shl => Some(0x17), - Self::Shr => Some(0x18), - Self::Add => Some(0x19), - Self::Sub => Some(0x1A), - Self::And => Some(0x1B), - Self::Or => Some(0x1C), - Self::Not => Some(0x1D), - Self::Xor => Some(0x1E), - Self::Nand => Some(0x1F), - Self::Nor => Some(0x20), - Self::Xnor => Some(0x21), - Self::Int => Some(0x22), - Self::Irt => Some(0x23), - Self::Hlt => Some(0x24), - Self::Iadd => Some(0x25), - Self::Isub => Some(0x26), - // Pseudo-instructions don't have opcode values - _ => None, - } - } - - pub fn is_pseudo_instruction(&self) -> bool { - matches!( - self, - Self::Db - | Self::Dh - | Self::Dw - | Self::Resb - | Self::Resh - | Self::Resw - | Self::Push - | Self::Pop - | Self::Lwi - ) - } -} diff --git a/emulator/src/emulator/system/memory.rs b/emulator/src/emulator/system/memory.rs index ff620d0..aa655e7 100644 --- a/emulator/src/emulator/system/memory.rs +++ b/emulator/src/emulator/system/memory.rs @@ -86,6 +86,9 @@ impl MemoryUnit for MainStore { for i in 0..size { data.push(self.read_byte(addr + i)); } + + // println!("reading {data:?} from {addr:x?}"); + data } @@ -105,8 +108,10 @@ impl MemoryUnit for MainStore { } fn write_range(&mut self, addr: u32, value: Vec) { - for byte in value { - let (block_addr, offset) = Self::segment_addr(addr); + // println!("writing {value:?} to {addr:x?}"); + + for (i, byte) in value.into_iter().enumerate() { + let (block_addr, offset) = Self::segment_addr(addr + i as u32); let block = self.mut_block(block_addr); block.data[offset as usize] = byte; } diff --git a/emulator/src/emulator/ui/editor.rs b/emulator/src/emulator/ui/editor.rs index e608718..70343c7 100644 --- a/emulator/src/emulator/ui/editor.rs +++ b/emulator/src/emulator/ui/editor.rs @@ -1,6 +1,5 @@ use std::{ffi::OsStr, path::PathBuf, sync::mpsc::Sender}; -use assembler::lexer::Symbol; use common::prelude::Instruction; use egui::{Align, Context, Key, Layout, Ui}; use rfd::FileDialog; diff --git a/resources/dsa/fib.dsa b/resources/dsa/fib.dsa new file mode 100644 index 0000000..cd52942 --- /dev/null +++ b/resources/dsa/fib.dsa @@ -0,0 +1,34 @@ +include print "../resources/dsa/print.dsa" +// Fibonacci sequence calculator in DSA assembly +// Calculates the first 8 Fibonacci numbers: 0, 1, 1, 2, 3, 5, 8, 13 +dw fib_count: 6 // How many more numbers to calculate after F(0) and F(1) + +init: + // Initialize the first two Fibonacci numbers + lli 0, rg0 // F(0) = 0 + lli 1, rg1 // F(1) = 1 + + // Load loop counter + ldw fib_count, zero, rg2 // Load number of iterations remaining + +fibonacci_loop: + // Calculate next Fibonacci number: F(n) = F(n-1) + F(n-2) + add rg0, rg1, rg4 // rg4 = rg0 + rg1 (new Fibonacci number) + + // Shift the sequence forward + mov rg1, rg0 // rg0 = previous rg1 (F(n-2) = F(n-1)) + mov rg4, rg1 // rg1 = rg4 (F(n-1) = F(n)) + + // Decrement loop counter + dec rg2 // rg2 = rg2 - 1 + + // Check if we should continue looping + cmp rg2, zero // Compare counter with 0 + jgt fibonacci_loop // Jump back if counter > 0 + +finish: + mov rg1, acc // Final Fibonacci number is in acc + hlt + + jmp print::run + diff --git a/resources/dsb/fib.dsb b/resources/dsb/fib.dsb new file mode 100644 index 0000000..e69de29