fixed a lot of bugs with the emulator, instruction set and assembler

This commit is contained in:
2025-06-19 01:57:36 +01:00
parent e281bc2d1d
commit 6b58a17f03
13 changed files with 209 additions and 47 deletions
-2
View File
@@ -22,8 +22,6 @@ fn build_instruction(node: Node) -> Result<Instruction, AssembleError> {
let opcode = node.opcode(); let opcode = node.opcode();
let args = node.args(); let args = node.args();
// println!("{node}");
match opcode { match opcode {
Opcode::Nop => Ok(Instruction::Nop), Opcode::Nop => Ok(Instruction::Nop),
Opcode::Mov => { Opcode::Mov => {
+41 -19
View File
@@ -29,14 +29,11 @@ fn try_expand(
match node.opcode() { match node.opcode() {
Opcode::Push => expand_push(node.clone(), result)?, Opcode::Push => expand_push(node.clone(), result)?,
Opcode::Pop => expand_pop(node.clone(), result)?, Opcode::Pop => expand_pop(node.clone(), result)?,
Opcode::Ldb Opcode::Ldb | Opcode::Ldbs | Opcode::Ldh | Opcode::Ldhs | Opcode::Ldw => {
| Opcode::Ldbs expand_ldx(node.clone(), result)?
| Opcode::Ldh }
| Opcode::Ldhs Opcode::Stb | Opcode::Sth | Opcode::Stw => expand_stx(node.clone(), result)?,
| Opcode::Ldw
| Opcode::Stb
| Opcode::Sth
| Opcode::Stw => expand_ldx(node.clone(), result)?,
Opcode::Lwi => expand_lwi(node.clone(), result)?, Opcode::Lwi => expand_lwi(node.clone(), result)?,
Opcode::Resb | Opcode::Resh | Opcode::Resw => expand_resx(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)?, Opcode::Db | Opcode::Dh | Opcode::Dw => expand_dx(node.clone(), result)?,
@@ -52,10 +49,10 @@ fn expand_push(current: Node, nodes: &mut Vec<Node>) -> Result<(), AssembleError
nodes.extend(vec![ nodes.extend(vec![
node!( node!(
label, label,
Opcode::Iadd, Opcode::Isub,
reg.clone(), Token::Register(Register::Spr),
Token::Immediate(4), Token::Immediate(4),
reg.clone() Token::Register(Register::Spr)
), ),
node!( node!(
None, None,
@@ -76,17 +73,17 @@ fn expand_pop(current: Node, nodes: &mut Vec<Node>) -> Result<(), AssembleError>
nodes.extend(vec![ nodes.extend(vec![
node!( node!(
label, label,
Opcode::Isub, Opcode::Ldw,
reg.clone(), Token::Register(Register::Spr),
Token::Immediate(4), reg,
reg.clone() Token::Immediate(0)
), ),
node!( node!(
None, None,
Opcode::Ldw, Opcode::Iadd,
reg,
Token::Register(Register::Spr), 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<Node>) -> Result<(), AssembleError>
Ok(()) Ok(())
} }
fn expand_stx(current: Node, nodes: &mut Vec<Node>) -> 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<Node>) -> Result<(), AssembleError> { fn expand_lwi(current: Node, nodes: &mut Vec<Node>) -> Result<(), AssembleError> {
let val = expect_type!(current.arg(0).unwrap(), Symbol, Immediate)?; let val = expect_type!(current.arg(0).unwrap(), Symbol, Immediate)?;
let reg = expect_type!(current.arg(1).unwrap(), Register)?; let reg = expect_type!(current.arg(1).unwrap(), Register)?;
@@ -174,7 +195,8 @@ fn process_dx_data(args: Vec<Token>, size: usize) -> Result<Vec<u32>, AssembleEr
// Process each token // Process each token
for token in args { for token in args {
match token { match token {
Token::StringLit(s) => { Token::StringLit(mut s) => {
s.push('\0');
// Split string into chars and write as bytes // Split string into chars and write as bytes
for ch in s.chars() { for ch in s.chars() {
// Convert char to bytes (UTF-8 encoding) // Convert char to bytes (UTF-8 encoding)
+8 -2
View File
@@ -11,7 +11,7 @@ use common::prelude::Instruction;
use crate::{ use crate::{
codegen::codegen, codegen::codegen,
expand::expand_pseudo_ops, expand::expand_pseudo_ops,
model::{Node, Symbol, Token, TokenType}, model::{Node, Opcode, Symbol, Token, TokenType},
parser::{Parser, Program}, parser::{Parser, Program},
resolver::{create_sections, resolve_dependencies, resolve_symbols}, resolver::{create_sections, resolve_dependencies, resolve_symbols},
}; };
@@ -78,7 +78,13 @@ fn prepare_dependency(
"{:20} {:20}", "{:20} {:20}",
"Expanding PseudoInstructions", filename "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() { for n in nodes.iter() {
println!("{}", n); println!("{}", n);
+12 -8
View File
@@ -87,14 +87,7 @@ impl Parser {
args = vec![reg1, reg2]; args = vec![reg1, reg2];
} }
Opcode::Ldb Opcode::Ldb | Opcode::Ldbs | Opcode::Ldh | Opcode::Ldhs | Opcode::Ldw => {
| Opcode::Ldbs
| Opcode::Ldh
| Opcode::Ldhs
| Opcode::Ldw
| Opcode::Stb
| Opcode::Sth
| Opcode::Stw => {
let base = expect_type!(self.next()?, Register, Symbol)?; let base = expect_type!(self.next()?, Register, Symbol)?;
let dest = expect_type!(self.next()?, Register)?; let dest = expect_type!(self.next()?, Register)?;
@@ -107,6 +100,17 @@ impl Parser {
args = vec![base, dest, offset]; 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::Add
| Opcode::Sub | Opcode::Sub
-1
View File
@@ -133,7 +133,6 @@ pub fn create_sections(nodes: &mut Vec<Node>) -> Result<(), AssembleError> {
} }
} }
res.push(node!(None, Opcode::Segment, Token::Immediate(1)));
let start = res.len() + 1; let start = res.len() + 1;
res.insert( res.insert(
0, 0,
+5 -1
View File
@@ -408,7 +408,11 @@ impl std::fmt::Display for Instruction {
write!(f, " {}, {}, {}", args.sr1, args.sr2, args.dr) 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::Interrupt(a) => write!(f, " {}", a.as_u8()),
Self::Data(a) => write!(f, " {}", a), Self::Data(a) => write!(f, " {}", a),
Self::Segment(x) => write!(f, " [SEGMENT {}]", x), Self::Segment(x) => write!(f, " [SEGMENT {}]", x),
+29 -6
View File
@@ -27,10 +27,11 @@ pub fn run_emulator(
let mut running = Running::Paused; let mut running = Running::Paused;
let mut addr = 0u32; let mut addr = 0u32;
let mut history = Vec::<(u32, Instruction)>::new();
let size = 256; let size = 256;
let memory_view = processor.memory.read_range(addr, size); 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 _ = state_tx.send(initial_state);
let mut instruction_count = 0; let mut instruction_count = 0;
@@ -79,7 +80,9 @@ pub fn run_emulator(
// Execute one cycle. // Execute one cycle.
match processor.cycle() { match processor.cycle() {
Ok(_) => {} Ok((addr, instruction)) => {
history.push((addr, instruction.clone()));
}
Err(why) => { Err(why) => {
let pcx = processor.get(Register::Pcx); let pcx = processor.get(Register::Pcx);
eprintln!( eprintln!(
@@ -103,7 +106,15 @@ pub fn run_emulator(
} }
let memory_view = processor.memory.read_range(addr, size); 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); 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)) // let instruction = match Instruction::decode(cpu_lock.get(Register::Cir))
// {}; // {};
if matches!(instruction, Instruction::Halt) { if matches!(instruction.1, Instruction::Halt) {
running = Running::Halted; running = Running::Halted;
update = true; update = true;
} }
@@ -138,8 +151,13 @@ pub fn run_emulator(
if update { if update {
let memory_view = processor.memory.read_range(addr, size); let memory_view = processor.memory.read_range(addr, size);
let state = let state = state(
state(&mut processor, running, instruction_count, memory_view); &mut processor,
running,
instruction_count,
memory_view,
&mut history,
);
let _ = state_tx.send(state); let _ = state_tx.send(state);
} }
} else { } else {
@@ -153,7 +171,11 @@ fn state(
running: Running, running: Running,
instruction_count: usize, instruction_count: usize,
memory_view: Vec<u8>, memory_view: Vec<u8>,
history: &mut Vec<(u32, Instruction)>,
) -> State { ) -> State {
let hsclone = history.clone();
history.clear();
State { State {
// TODO: Replace with actual register access from your CPU. // TODO: Replace with actual register access from your CPU.
reg_file: cpu_lock.registers, reg_file: cpu_lock.registers,
@@ -163,5 +185,6 @@ fn state(
memory_view, memory_view,
display_view: cpu_lock.display(), display_view: cpu_lock.display(),
error: None, error: None,
history: hsclone,
} }
} }
+2
View File
@@ -205,6 +205,7 @@ pub struct State {
pub stack_view: Vec<u8>, pub stack_view: Vec<u8>,
pub memory_view: Vec<u8>, pub memory_view: Vec<u8>,
pub display_view: Vec<u8>, pub display_view: Vec<u8>,
pub history: Vec<(u32, Instruction)>,
pub error: Option<String>, pub error: Option<String>,
} }
@@ -217,6 +218,7 @@ impl Default for State {
stack_view: vec![], stack_view: vec![],
memory_view: vec![], memory_view: vec![],
display_view: vec![], display_view: vec![],
history: vec![],
error: None, error: None,
} }
} }
@@ -38,7 +38,7 @@ impl Processor {
self.memory.reset(); self.memory.reset();
} }
pub fn cycle(&mut self) -> Result<Instruction, InstructionDecodeError> { pub fn cycle(&mut self) -> Result<(u32, Instruction), InstructionDecodeError> {
self.halted = false; self.halted = false;
// Get value from PCX. // Get value from PCX.
@@ -58,7 +58,7 @@ impl Processor {
instruction.execute(self); instruction.execute(self);
Ok(instruction) Ok((addr, instruction))
} }
fn fetch(&self) -> u32 { fn fetch(&self) -> u32 {
@@ -405,11 +405,11 @@ impl Executable for Instruction {
// mathematical and logical functions & other operations // mathematical and logical functions & other operations
const fn add(a: u32, b: u32) -> u32 { const fn add(a: u32, b: u32) -> u32 {
a + b a.wrapping_add(b)
} }
const fn sub(a: u32, b: u32) -> u32 { const fn sub(a: u32, b: u32) -> u32 {
a - b a.wrapping_sub(b)
} }
const fn and(a: u32, b: u32) -> u32 { 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 { const fn inc(a: u32) -> u32 {
a + 1 a.wrapping_add(1)
} }
const fn dec(a: u32) -> u32 { const fn dec(a: u32) -> u32 {
a - 1 a.wrapping_sub(1)
} }
const fn shl(a: u32, amount: u8) -> u32 { const fn shl(a: u32, amount: u8) -> u32 {
+95
View File
@@ -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);
}
}
}
+1
View File
@@ -1,6 +1,7 @@
pub mod control_unit; pub mod control_unit;
pub mod display; pub mod display;
pub mod editor; pub mod editor;
pub mod history;
pub mod interface; pub mod interface;
pub mod memory_inspector; pub mod memory_inspector;
pub mod menu; pub mod menu;
+7 -2
View File
@@ -1,3 +1,5 @@
use std::io::Read;
use crate::emulator::{system::model::State, ui::interface::Component}; use crate::emulator::{system::model::State, ui::interface::Component};
use common::instructions::Register; use common::instructions::Register;
@@ -47,11 +49,14 @@ impl Component for StackInspector {
ui.label("Value"); ui.label("Value");
ui.end_row(); 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!( ui.label(format!(
"{} [{}]", "{} [{}]",
i, 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.label(format!("0x{value:08X} ({value})"));
ui.end_row(); ui.end_row();
+3
View File
@@ -101,5 +101,8 @@ fn setup_ui(cmd_sender: Sender<Command>, state_reciever: Receiver<State>) -> Emu
let display = Display::new(); let display = Display::new();
ui.add_component(Box::new(display)); ui.add_component(Box::new(display));
let history = dsa_rs::emulator::ui::history::History::new();
ui.add_component(Box::new(history));
ui ui
} }