From 6b58a17f03cfe9ca1219683ab9373119a1c8a0bb Mon Sep 17 00:00:00 2001 From: zxq5 Date: Thu, 19 Jun 2025 01:57:36 +0100 Subject: [PATCH] fixed a lot of bugs with the emulator, instruction set and assembler --- assembler/src/codegen.rs | 2 - assembler/src/expand.rs | 60 ++++++++---- assembler/src/lib.rs | 10 +- assembler/src/parser.rs | 20 ++-- assembler/src/resolver.rs | 1 - common/src/instructions.rs | 6 +- emulator/src/emulator/system/emulator.rs | 35 +++++-- emulator/src/emulator/system/model.rs | 2 + emulator/src/emulator/system/processor/mod.rs | 12 +-- emulator/src/emulator/ui/history.rs | 95 +++++++++++++++++++ emulator/src/emulator/ui/mod.rs | 1 + emulator/src/emulator/ui/stack_inspector.rs | 9 +- emulator/src/main.rs | 3 + 13 files changed, 209 insertions(+), 47 deletions(-) create mode 100644 emulator/src/emulator/ui/history.rs diff --git a/assembler/src/codegen.rs b/assembler/src/codegen.rs index 2d1a005..f8ca549 100644 --- a/assembler/src/codegen.rs +++ b/assembler/src/codegen.rs @@ -22,8 +22,6 @@ fn build_instruction(node: Node) -> Result { let opcode = node.opcode(); let args = node.args(); - // println!("{node}"); - match opcode { Opcode::Nop => Ok(Instruction::Nop), Opcode::Mov => { diff --git a/assembler/src/expand.rs b/assembler/src/expand.rs index deb60d2..3e64313 100644 --- a/assembler/src/expand.rs +++ b/assembler/src/expand.rs @@ -29,14 +29,11 @@ fn try_expand( match node.opcode() { Opcode::Push => expand_push(node.clone(), result)?, Opcode::Pop => expand_pop(node.clone(), result)?, - Opcode::Ldb - | Opcode::Ldbs - | Opcode::Ldh - | Opcode::Ldhs - | Opcode::Ldw - | Opcode::Stb - | Opcode::Sth - | Opcode::Stw => expand_ldx(node.clone(), result)?, + Opcode::Ldb | Opcode::Ldbs | Opcode::Ldh | Opcode::Ldhs | Opcode::Ldw => { + expand_ldx(node.clone(), result)? + } + Opcode::Stb | Opcode::Sth | Opcode::Stw => expand_stx(node.clone(), result)?, + Opcode::Lwi => expand_lwi(node.clone(), result)?, Opcode::Resb | Opcode::Resh | Opcode::Resw => expand_resx(node.clone(), result)?, Opcode::Db | Opcode::Dh | Opcode::Dw => expand_dx(node.clone(), result)?, @@ -52,10 +49,10 @@ fn expand_push(current: Node, nodes: &mut Vec) -> Result<(), AssembleError nodes.extend(vec![ node!( label, - Opcode::Iadd, - reg.clone(), + Opcode::Isub, + Token::Register(Register::Spr), Token::Immediate(4), - reg.clone() + Token::Register(Register::Spr) ), node!( None, @@ -76,17 +73,17 @@ fn expand_pop(current: Node, nodes: &mut Vec) -> Result<(), AssembleError> nodes.extend(vec![ node!( label, - Opcode::Isub, - reg.clone(), - Token::Immediate(4), - reg.clone() + Opcode::Ldw, + Token::Register(Register::Spr), + reg, + Token::Immediate(0) ), node!( None, - Opcode::Ldw, - reg, + Opcode::Iadd, Token::Register(Register::Spr), - Token::Immediate(0) + Token::Immediate(4), + Token::Register(Register::Spr) ), ]); @@ -108,6 +105,30 @@ fn expand_ldx(current: Node, nodes: &mut Vec) -> Result<(), AssembleError> Ok(()) } +fn expand_stx(current: Node, nodes: &mut Vec) -> Result<(), AssembleError> { + let opcode = current.opcode(); + let base = expect_type!(current.arg(0).unwrap(), Register)?; + let dest = expect_type!(current.arg(1).unwrap(), Symbol)?; + let offset = expect_type!(current.arg(2).unwrap(), Immediate)?; + nodes.extend(vec![ + node!( + current.label(), + Opcode::Lli, + dest.clone(), + Token::Register(Register::Rgf) + ), + node!( + None, + Opcode::Lui, + dest.clone(), + Token::Register(Register::Rgf) + ), + node!(None, opcode, base, Token::Register(Register::Rgf), offset), + ]); + + Ok(()) +} + fn expand_lwi(current: Node, nodes: &mut Vec) -> Result<(), AssembleError> { let val = expect_type!(current.arg(0).unwrap(), Symbol, Immediate)?; let reg = expect_type!(current.arg(1).unwrap(), Register)?; @@ -174,7 +195,8 @@ fn process_dx_data(args: Vec, size: usize) -> Result, AssembleEr // Process each token for token in args { match token { - Token::StringLit(s) => { + Token::StringLit(mut s) => { + s.push('\0'); // Split string into chars and write as bytes for ch in s.chars() { // Convert char to bytes (UTF-8 encoding) diff --git a/assembler/src/lib.rs b/assembler/src/lib.rs index 1be29e5..0b21934 100644 --- a/assembler/src/lib.rs +++ b/assembler/src/lib.rs @@ -11,7 +11,7 @@ use common::prelude::Instruction; use crate::{ codegen::codegen, expand::expand_pseudo_ops, - model::{Node, Symbol, Token, TokenType}, + model::{Node, Opcode, Symbol, Token, TokenType}, parser::{Parser, Program}, resolver::{create_sections, resolve_dependencies, resolve_symbols}, }; @@ -78,7 +78,13 @@ fn prepare_dependency( "{:20} {:20}", "Expanding PseudoInstructions", filename )); - let nodes = expand_pseudo_ops(nodes, file_hash)?; + let mut nodes = expand_pseudo_ops(nodes, file_hash)?; + + // add a section instruction + nodes.insert( + 0, + node!(None, Opcode::Segment, Token::Immediate(file_hash as u32)), + ); for n in nodes.iter() { println!("{}", n); diff --git a/assembler/src/parser.rs b/assembler/src/parser.rs index c7d4c96..4eef966 100644 --- a/assembler/src/parser.rs +++ b/assembler/src/parser.rs @@ -87,14 +87,7 @@ impl Parser { args = vec![reg1, reg2]; } - Opcode::Ldb - | Opcode::Ldbs - | Opcode::Ldh - | Opcode::Ldhs - | Opcode::Ldw - | Opcode::Stb - | Opcode::Sth - | Opcode::Stw => { + Opcode::Ldb | Opcode::Ldbs | Opcode::Ldh | Opcode::Ldhs | Opcode::Ldw => { let base = expect_type!(self.next()?, Register, Symbol)?; let dest = expect_type!(self.next()?, Register)?; @@ -107,6 +100,17 @@ impl Parser { args = vec![base, dest, offset]; } + Opcode::Stb | Opcode::Sth | Opcode::Stw => { + let base = expect_type!(self.next()?, Register)?; + let dest = expect_type!(self.next()?, Register, Symbol)?; + let mut offset = Token::Immediate(0); + if let Ok(next) = self.peek_next() { + if let Ok(_) = expect_type!(next, Immediate) { + offset = self.next()?; + } + } + args = vec![base, dest, offset]; + } Opcode::Add | Opcode::Sub diff --git a/assembler/src/resolver.rs b/assembler/src/resolver.rs index 9a82028..d2518be 100644 --- a/assembler/src/resolver.rs +++ b/assembler/src/resolver.rs @@ -133,7 +133,6 @@ pub fn create_sections(nodes: &mut Vec) -> Result<(), AssembleError> { } } - res.push(node!(None, Opcode::Segment, Token::Immediate(1))); let start = res.len() + 1; res.insert( 0, diff --git a/common/src/instructions.rs b/common/src/instructions.rs index de9ee7f..a02ddb1 100644 --- a/common/src/instructions.rs +++ b/common/src/instructions.rs @@ -408,7 +408,11 @@ impl std::fmt::Display for Instruction { write!(f, " {}, {}, {}", args.sr1, args.sr2, args.dr) } - Self::Increment(a) | Self::Decrement(a) => write!(f, " {}", a.dr), + Self::AddImmediate(args) | Self::SubImmediate(args) => { + write!(f, " {}, {}, {}", args.r1, args.immediate, args.r2) + } + + Self::Increment(a) | Self::Decrement(a) => write!(f, " {}", a.sr1), Self::Interrupt(a) => write!(f, " {}", a.as_u8()), Self::Data(a) => write!(f, " {}", a), Self::Segment(x) => write!(f, " [SEGMENT {}]", x), diff --git a/emulator/src/emulator/system/emulator.rs b/emulator/src/emulator/system/emulator.rs index ef341ef..a3416e8 100644 --- a/emulator/src/emulator/system/emulator.rs +++ b/emulator/src/emulator/system/emulator.rs @@ -27,10 +27,11 @@ pub fn run_emulator( let mut running = Running::Paused; let mut addr = 0u32; + let mut history = Vec::<(u32, Instruction)>::new(); let size = 256; let memory_view = processor.memory.read_range(addr, size); - let initial_state = state(&mut processor, running, 0, memory_view); + let initial_state = state(&mut processor, running, 0, memory_view, &mut history); let _ = state_tx.send(initial_state); let mut instruction_count = 0; @@ -79,7 +80,9 @@ pub fn run_emulator( // Execute one cycle. match processor.cycle() { - Ok(_) => {} + Ok((addr, instruction)) => { + history.push((addr, instruction.clone())); + } Err(why) => { let pcx = processor.get(Register::Pcx); eprintln!( @@ -103,7 +106,15 @@ pub fn run_emulator( } let memory_view = processor.memory.read_range(addr, size); - let state = state(&mut processor, running, instruction_count, memory_view); + let state = state( + &mut processor, + running, + instruction_count, + memory_view, + &mut history, + ); + + println!("state"); let _ = state_tx.send(state); } @@ -121,10 +132,12 @@ pub fn run_emulator( } }; + history.push(instruction.clone()); + // let instruction = match Instruction::decode(cpu_lock.get(Register::Cir)) // {}; - if matches!(instruction, Instruction::Halt) { + if matches!(instruction.1, Instruction::Halt) { running = Running::Halted; update = true; } @@ -138,8 +151,13 @@ pub fn run_emulator( if update { let memory_view = processor.memory.read_range(addr, size); - let state = - state(&mut processor, running, instruction_count, memory_view); + let state = state( + &mut processor, + running, + instruction_count, + memory_view, + &mut history, + ); let _ = state_tx.send(state); } } else { @@ -153,7 +171,11 @@ fn state( running: Running, instruction_count: usize, memory_view: Vec, + history: &mut Vec<(u32, Instruction)>, ) -> State { + let hsclone = history.clone(); + history.clear(); + State { // TODO: Replace with actual register access from your CPU. reg_file: cpu_lock.registers, @@ -163,5 +185,6 @@ fn state( memory_view, display_view: cpu_lock.display(), error: None, + history: hsclone, } } diff --git a/emulator/src/emulator/system/model.rs b/emulator/src/emulator/system/model.rs index 305d123..5fdceb1 100644 --- a/emulator/src/emulator/system/model.rs +++ b/emulator/src/emulator/system/model.rs @@ -205,6 +205,7 @@ pub struct State { pub stack_view: Vec, pub memory_view: Vec, pub display_view: Vec, + pub history: Vec<(u32, Instruction)>, pub error: Option, } @@ -217,6 +218,7 @@ impl Default for State { stack_view: vec![], memory_view: vec![], display_view: vec![], + history: vec![], error: None, } } diff --git a/emulator/src/emulator/system/processor/mod.rs b/emulator/src/emulator/system/processor/mod.rs index 8db8e0b..64a049d 100644 --- a/emulator/src/emulator/system/processor/mod.rs +++ b/emulator/src/emulator/system/processor/mod.rs @@ -38,7 +38,7 @@ impl Processor { self.memory.reset(); } - pub fn cycle(&mut self) -> Result { + pub fn cycle(&mut self) -> Result<(u32, Instruction), InstructionDecodeError> { self.halted = false; // Get value from PCX. @@ -58,7 +58,7 @@ impl Processor { instruction.execute(self); - Ok(instruction) + Ok((addr, instruction)) } fn fetch(&self) -> u32 { @@ -405,11 +405,11 @@ impl Executable for Instruction { // mathematical and logical functions & other operations const fn add(a: u32, b: u32) -> u32 { - a + b + a.wrapping_add(b) } const fn sub(a: u32, b: u32) -> u32 { - a - b + a.wrapping_sub(b) } const fn and(a: u32, b: u32) -> u32 { @@ -417,11 +417,11 @@ const fn and(a: u32, b: u32) -> u32 { } const fn inc(a: u32) -> u32 { - a + 1 + a.wrapping_add(1) } const fn dec(a: u32) -> u32 { - a - 1 + a.wrapping_sub(1) } const fn shl(a: u32, amount: u8) -> u32 { diff --git a/emulator/src/emulator/ui/history.rs b/emulator/src/emulator/ui/history.rs new file mode 100644 index 0000000..1f0a95d --- /dev/null +++ b/emulator/src/emulator/ui/history.rs @@ -0,0 +1,95 @@ +use std::{ffi::OsStr, path::PathBuf, sync::mpsc::Sender}; + +use common::prelude::Instruction; +use egui::{Align, Context, Key, Layout, Ui}; +use rfd::FileDialog; + +use dsa_editor::{CodeEditor, ColorTheme, Syntax}; + +use crate::emulator::{ + system::model::{Command, State}, + ui::interface::Component, +}; + +pub struct History { + visible: bool, + history: Vec<(u32, Instruction)>, +} + +impl Component for History { + fn name(&self) -> &'static str { + "Instruction History" + } + + fn visible(&mut self) -> &mut bool { + &mut self.visible + } + + fn category(&self) -> super::interface::Category { + super::interface::Category::Control + } + + fn render(&mut self, state: &mut State, ui: &mut Ui, ctx: &Context) { + self.update(state); + + egui::ScrollArea::vertical() + .id_salt("output_scroll") + .max_width(400.0) + .show(ui, |ui| { + if self.history.is_empty() { + ui.label( + egui::RichText::new("No output data") + .font(egui::FontId::monospace(12.0)) + .color(egui::Color32::GRAY), + ); + return; + } + + egui::Grid::new("output_grid") + .spacing([5.0, 2.0]) // Horizontal and vertical spacing + .num_columns(4) + .striped(false) + .show(ui, |ui| { + // Process bytes in chunks of 4 + for (idx, instruction) in self.history.iter().enumerate() { + ui.label(format!("{}: ", idx)); + + // Hex column + let addr = instruction.0; + ui.label( + egui::RichText::new(format!("0x{addr:08X}")) + .font(egui::FontId::monospace(12.0)) + .color(egui::Color32::from_rgb(255, 200, 200)), + ); + + ui.label( + egui::RichText::new(instruction.1.to_string()) + .font(egui::FontId::monospace(12.0)) + .color(egui::Color32::from_rgb(200, 255, 200)), + ); + + ui.end_row(); + } + }); + }); + } +} + +impl History { + #[must_use] + pub fn new() -> Self { + Self { + visible: false, + history: Vec::with_capacity(1000), + } + } + + fn update(&mut self, state: &mut State) { + self.history.extend(state.history.clone()); + state.history.clear(); + if self.history.len() > 1000 { + let len = self.history.len() - 1000; + self.history.drain(..len); + } + } +} diff --git a/emulator/src/emulator/ui/mod.rs b/emulator/src/emulator/ui/mod.rs index fabc0b6..a4790e1 100644 --- a/emulator/src/emulator/ui/mod.rs +++ b/emulator/src/emulator/ui/mod.rs @@ -1,6 +1,7 @@ pub mod control_unit; pub mod display; pub mod editor; +pub mod history; pub mod interface; pub mod memory_inspector; pub mod menu; diff --git a/emulator/src/emulator/ui/stack_inspector.rs b/emulator/src/emulator/ui/stack_inspector.rs index 452eaf2..f169505 100644 --- a/emulator/src/emulator/ui/stack_inspector.rs +++ b/emulator/src/emulator/ui/stack_inspector.rs @@ -1,3 +1,5 @@ +use std::io::Read; + use crate::emulator::{system::model::State, ui::interface::Component}; use common::instructions::Register; @@ -47,11 +49,14 @@ impl Component for StackInspector { ui.label("Value"); ui.end_row(); - for (i, value) in (0u32..).zip(state.stack_view.iter().take(32)) { + for (i, value) in + state.stack_view.chunks(4).take(32).enumerate() + { + let value = u32::from_be_bytes(value.try_into().unwrap()); ui.label(format!( "{} [{}]", i, - state.reg_file.get(Register::Spr) - i * 4 + state.reg_file.get(Register::Spr) - i as u32 * 4 )); ui.label(format!("0x{value:08X} ({value})")); ui.end_row(); diff --git a/emulator/src/main.rs b/emulator/src/main.rs index 3cd99e3..fef27a5 100644 --- a/emulator/src/main.rs +++ b/emulator/src/main.rs @@ -101,5 +101,8 @@ fn setup_ui(cmd_sender: Sender, state_reciever: Receiver) -> Emu let display = Display::new(); ui.add_component(Box::new(display)); + let history = dsa_rs::emulator::ui::history::History::new(); + ui.add_component(Box::new(history)); + ui }