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 args = node.args();
// println!("{node}");
match opcode {
Opcode::Nop => Ok(Instruction::Nop),
Opcode::Mov => {
+41 -19
View File
@@ -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<Node>) -> 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<Node>) -> 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<Node>) -> Result<(), AssembleError>
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> {
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<Token>, size: usize) -> Result<Vec<u32>, 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)
+8 -2
View File
@@ -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);
+12 -8
View File
@@ -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
-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;
res.insert(
0,
+5 -1
View File
@@ -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),
+29 -6
View File
@@ -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<u8>,
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,
}
}
+2
View File
@@ -205,6 +205,7 @@ pub struct State {
pub stack_view: Vec<u8>,
pub memory_view: Vec<u8>,
pub display_view: Vec<u8>,
pub history: Vec<(u32, Instruction)>,
pub error: Option<String>,
}
@@ -217,6 +218,7 @@ impl Default for State {
stack_view: vec![],
memory_view: vec![],
display_view: vec![],
history: vec![],
error: None,
}
}
@@ -38,7 +38,7 @@ impl Processor {
self.memory.reset();
}
pub fn cycle(&mut self) -> Result<Instruction, InstructionDecodeError> {
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 {
+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 display;
pub mod editor;
pub mod history;
pub mod interface;
pub mod memory_inspector;
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 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();
+3
View File
@@ -101,5 +101,8 @@ fn setup_ui(cmd_sender: Sender<Command>, state_reciever: Receiver<State>) -> 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
}