fixed a lot of bugs with the emulator, instruction set and assembler
This commit is contained in:
@@ -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
@@ -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)
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user