more optimisations test program ~54MIPS -> ~110MIPS

This commit is contained in:
2025-06-29 02:04:14 +01:00
parent 05a25447b2
commit 98668c681e
9 changed files with 119 additions and 132 deletions
+53
View File
@@ -0,0 +1,53 @@
use common::prelude::Instruction;
use rustc_hash::FxHashMap;
#[derive(Debug)]
pub struct Cache {
addr: u32,
instruction_block: Option<[u8; 256]>,
instruction_lookup: FxHashMap<u32, Instruction>,
}
impl Cache {
#[must_use]
pub fn new() -> Self {
Self {
addr: 0,
instruction_block: None,
instruction_lookup: FxHashMap::default(),
}
}
pub fn lookup_value(&mut self, addr: u32) -> Option<u32> {
if addr < self.addr || addr >= self.addr + 256 || self.instruction_block.is_none()
{
return None;
}
Some(u32::from_be_bytes(
self.instruction_block.expect("this should not be none!")
[(addr - self.addr) as usize..(addr - self.addr + 4) as usize]
.try_into()
.expect("Failed to convert bytes to u32"),
))
}
pub const fn set(&mut self, addr: u32, block: &[u8; 256]) {
self.addr = addr - addr % 256;
self.instruction_block = Some(*block);
}
pub fn lookup_instruction(&mut self, instruction: u32) -> Option<Instruction> {
self.instruction_lookup.get(&instruction).copied()
}
pub fn insert(&mut self, value: u32, instruction: Instruction) {
self.instruction_lookup.insert(value, instruction);
}
}
impl Default for Cache {
fn default() -> Self {
Self::new()
}
}
+17 -29
View File
@@ -25,9 +25,11 @@ pub fn run_emulator(
let mut running = Running::Paused; let mut running = Running::Paused;
let mut step = 0; let mut step = 0;
let mut addr; let mut addr;
let mut history = Vec::<(u32, Instruction)>::with_capacity(32768); let mut history = Vec::<(u32, u32)>::with_capacity(32768);
let size = 256; let size = 256;
let record_history = true;
state_tx state_tx
.send(StateUpdate::Running(Running::Paused)) .send(StateUpdate::Running(Running::Paused))
.expect("Failed to send initial state!"); .expect("Failed to send initial state!");
@@ -164,33 +166,11 @@ pub fn run_emulator(
} }
} }
if running == Running::Paused && step > 0 {
step -= 1;
update = true;
// Execute one cycle.
match processor.cycle() {
Ok((addr, instruction)) => {
history.push((addr, instruction));
}
Err(why) => {
let pcx = processor
.get(Register::Pcx)
.expect("SPR should never be invalid");
report_err(
state_tx,
&format!(
"Could not decode instruction at {pcx:x}. Reason: {why}"
),
&mut processor,
);
}
}
instruction_count += 1;
continue;
}
if running == Running::Running { if running == Running::Running {
step += 1;
}
if step > 0 {
step -= 1; step -= 1;
update = true; update = true;
@@ -212,8 +192,16 @@ pub fn run_emulator(
} }
}; };
history.push(instruction); if record_history {
if matches!(instruction.1, Instruction::Halt) { history.push((
instruction.0,
processor
.get(Register::Cir)
.expect("CIR should never be invalid"),
));
}
if matches!(instruction, (_, Instruction::Halt)) {
running = Running::Halted; running = Running::Halted;
step = 0; step = 0;
} }
+10 -18
View File
@@ -36,15 +36,7 @@ pub struct MainStore {
pub data: FxHashMap<u32, Block>, pub data: FxHashMap<u32, Block>,
} }
pub struct Block { pub type Block = [u8; 256];
data: [u8; 256],
}
impl Default for Block {
fn default() -> Self {
Self { data: [0; 256] }
}
}
impl Default for MainStore { impl Default for MainStore {
fn default() -> Self { fn default() -> Self {
@@ -67,12 +59,12 @@ impl MainStore {
#[inline] #[inline]
fn mut_block(&mut self, addr: u32) -> &mut Block { fn mut_block(&mut self, addr: u32) -> &mut Block {
self.data.entry(addr).or_default() self.data.entry(addr).or_insert([0; 256])
} }
#[inline] #[inline]
fn block(&mut self, addr: u32) -> &Block { fn block(&mut self, addr: u32) -> &Block {
self.data.entry(addr).or_default() self.data.entry(addr).or_insert([0; 256])
} }
} }
@@ -86,7 +78,7 @@ impl MemoryUnit for MainStore {
fn read_byte(&mut self, addr: u32) -> u8 { fn read_byte(&mut self, addr: u32) -> u8 {
let (block_addr, offset) = Self::segment_addr(addr); let (block_addr, offset) = Self::segment_addr(addr);
let block = self.block(block_addr); let block = self.block(block_addr);
block.data[offset as usize] block[offset as usize]
} }
#[inline] #[inline]
@@ -99,7 +91,7 @@ impl MemoryUnit for MainStore {
let offset = offset as usize; let offset = offset as usize;
let block = self.block(block_addr); let block = self.block(block_addr);
Ok(u32::from_be_bytes( Ok(u32::from_be_bytes(
block.data[offset..=offset + 3] block[offset..=offset + 3]
.try_into() .try_into()
.expect("Failed to read word!"), .expect("Failed to read word!"),
)) ))
@@ -119,7 +111,7 @@ impl MemoryUnit for MainStore {
fn write_byte(&mut self, addr: u32, value: u8) { fn write_byte(&mut self, addr: u32, value: u8) {
let (block_addr, offset) = Self::segment_addr(addr); let (block_addr, offset) = Self::segment_addr(addr);
let block = self.mut_block(block_addr); let block = self.mut_block(block_addr);
block.data[offset as usize] = value; block[offset as usize] = value;
} }
#[inline] #[inline]
@@ -130,7 +122,7 @@ impl MemoryUnit for MainStore {
let (block_addr, offset) = Self::segment_addr(addr); let (block_addr, offset) = Self::segment_addr(addr);
let block = self.mut_block(block_addr); let block = self.mut_block(block_addr);
block.data[offset as usize..=(offset + 3) as usize] block[offset as usize..=(offset + 3) as usize]
.copy_from_slice(&value.to_be_bytes()); .copy_from_slice(&value.to_be_bytes());
Ok(()) Ok(())
} }
@@ -141,7 +133,7 @@ impl MemoryUnit for MainStore {
let mut current_block = self.mut_block(current_block_addr); let mut current_block = self.mut_block(current_block_addr);
let mut offset = addr % 256; let mut offset = addr % 256;
for byte in value { for byte in value {
current_block.data[offset as usize] = byte; current_block[offset as usize] = byte;
offset += 1; offset += 1;
if offset >= 256 { if offset >= 256 {
offset = 0; offset = 0;
@@ -154,12 +146,12 @@ impl MemoryUnit for MainStore {
#[inline] #[inline]
fn read_block(&mut self, addr: u32) -> &[u8; 256] { fn read_block(&mut self, addr: u32) -> &[u8; 256] {
let (block_addr, _) = Self::segment_addr(addr); let (block_addr, _) = Self::segment_addr(addr);
&self.block(block_addr).data self.block(block_addr)
} }
#[inline] #[inline]
fn write_block(&mut self, addr: u32, data: &[u8; 256]) { fn write_block(&mut self, addr: u32, data: &[u8; 256]) {
let (block_addr, _) = Self::segment_addr(addr); let (block_addr, _) = Self::segment_addr(addr);
let _ = self.data.insert(block_addr, Block { data: *data }); let _ = self.data.insert(block_addr, *data);
} }
} }
+1
View File
@@ -1,3 +1,4 @@
pub mod cache;
pub mod emulator; pub mod emulator;
pub mod memory; pub mod memory;
pub mod model; pub mod model;
+2 -2
View File
@@ -78,7 +78,7 @@ pub struct State {
pub error_log: Vec<String>, pub error_log: Vec<String>,
pub instruction_history: Vec<(u32, Instruction)>, pub instruction_history: Vec<(u32, u32)>,
} }
impl State { impl State {
@@ -154,7 +154,7 @@ pub enum StateUpdate {
MemoryView(Vec<u8>), MemoryView(Vec<u8>),
DisplayView(Vec<u8>), DisplayView(Vec<u8>),
Error(String), Error(String),
InstructionHistory(Vec<(u32, Instruction)>), InstructionHistory(Vec<(u32, u32)>),
} }
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)] #[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
+24 -7
View File
@@ -4,6 +4,7 @@ use std::{
}; };
use crate::emulator::system::{ use crate::emulator::system::{
cache::Cache,
memory::MemoryUnit, memory::MemoryUnit,
model::{IODevice, ProcessorError, RegFile}, model::{IODevice, ProcessorError, RegFile},
}; };
@@ -17,6 +18,7 @@ pub struct Processor {
pub io_devices: Vec<Arc<dyn IODevice>>, pub io_devices: Vec<Arc<dyn IODevice>>,
pub void: u32, pub void: u32,
pub cache: Cache,
} }
fn log(message: &str) { fn log(message: &str) {
@@ -32,6 +34,7 @@ impl Processor {
halted: false, halted: false,
io_devices, io_devices,
void: 0, void: 0,
cache: Cache::new(),
} }
} }
@@ -55,17 +58,31 @@ impl Processor {
// Set MAR to the previous value of PCX. // Set MAR to the previous value of PCX.
*self.reg(Register::Mar)? = addr; *self.reg(Register::Mar)? = addr;
let val = self.memory.read_word(addr)?;
let encoded = if let Some(val) = self.cache.lookup_value(addr) {
val
} else {
let block = self.memory.read_block(addr);
self.cache.set(addr, block);
self.cache
.lookup_value(addr)
.expect("Failed to lookup value!")
};
// Set CIR to the value of RAM[MAR]. // Set CIR to the value of RAM[MAR].
*self.reg(Register::Mar)? = val; *self.reg(Register::Cir)? = encoded;
// Decode and execute the instruction. let decoded = if let Some(val) = self.cache.lookup_instruction(addr) {
let instruction = Instruction::decode(val) val
.map_err(|_| ProcessorError::InvalidInstruction(val))?; } else {
let decoded = Instruction::decode(encoded)
.map_err(|_| ProcessorError::InvalidInstruction(encoded))?;
self.cache.insert(addr, decoded);
decoded
};
instruction.execute(self)?; decoded.execute(self)?;
Ok((addr, instruction)) Ok((addr, decoded))
} }
const fn fetch(&self) -> Result<u32, ProcessorError> { const fn fetch(&self) -> Result<u32, ProcessorError> {
+5 -1
View File
@@ -1,3 +1,4 @@
use common::prelude::Instruction;
use egui::{Context, Ui}; use egui::{Context, Ui};
use crate::emulator::{ use crate::emulator::{
@@ -57,8 +58,11 @@ impl Component for History {
.color(egui::Color32::from_rgb(255, 200, 200)), .color(egui::Color32::from_rgb(255, 200, 200)),
); );
let decoded = Instruction::decode(instruction.1)
.unwrap_or(Instruction::Nop);
ui.label( ui.label(
egui::RichText::new(instruction.1.to_string()) egui::RichText::new(decoded.to_string())
.font(egui::FontId::monospace(12.0)) .font(egui::FontId::monospace(12.0))
.color(egui::Color32::from_rgb(200, 255, 200)), .color(egui::Color32::from_rgb(200, 255, 200)),
); );
BIN
View File
Binary file not shown.
+8 -76
View File
@@ -1,80 +1,12 @@
include fib: "./lib/maths/fib.dsa" // program to just test compute power
include maths: "./lib/maths/core.dsa"
include print: "./lib/io/print.dsa"
dw idt: 0xFFFF0000 dw large_num: 0x333333 // 333,333 instructions
dw stack: 0x10000
init:
// setup interrupt handlers
ldw idt, idr
lwi handle_hard_fault, rg0
stw rg0, idr, 4
// set up a stack.
ldw stack, bpr
mov bpr, spr
dw string: "hello world"
start: start:
ldw large_num, rg0
lwi 37, rg0 // run approx 1m instructions
lwi 12, rg1 loop:
push rg0 dec rg0
push rg1 cmp rg0, zero
call maths::divmod jgt loop
pop rg0 // result
pop rg1 // remainder
push rg1
push rg0
call print::print_hex_byte
call print::print_whitespace
pop zero
call print::print_hex_byte
call print::print_newline
lwi string, rg0
//lwi 10, rg0
pusha 4
push rg0
call print::print
//call fib::fib_n
pop zero
call print::print_newline
popa 4
pusha 4
push rg0
call print::print
//call fib::fib_n
pop zero
call print::print_newline
popa 4
pusha 4
push rg0
call print::print
//call fib::fib_n
pop zero
call print::print_newline
popa 4
pusha 4
push rg0
call print::print
//call fib::fib_n
pop zero
call print::print_newline
popa 4
hlt
// fault handler in case we fail DSA.
dw hard_fault_err: "FATAL: Illegal Instruction or Memory Access!"
handle_hard_fault:
call print::clear
call print::reset
lwi hard_fault_err, rg0
push rg0
call print::print
pop zero
hlt hlt