Simple CPU and registry emulation

This commit is contained in:
2025-10-28 20:48:37 +01:00
parent 775000e505
commit b42aeaacab
2 changed files with 134 additions and 11 deletions
+101
View File
@@ -0,0 +1,101 @@
use std::fmt::Display;
use osui::state::{DependencyHandler, State};
#[derive(Debug, Clone)]
pub struct Registry(pub State<[usize; 8]>);
#[derive(Debug, Clone)]
pub enum Instruction {
HLT,
REG(u8, usize),
ADD(u8, u8, u8),
}
pub struct Emulator {
pub pc: State<usize>,
pub instructions: Vec<Instruction>,
pub registers: Registry,
pub inst: State<Instruction>,
}
impl Emulator {
pub fn run(&self) {
loop {
std::thread::sleep(std::time::Duration::from_millis(300));
let mut pc = self.pc.get();
if let Some(inst) = self.instructions.get(**pc) {
**self.inst.get() = inst.clone();
match &inst {
// 1 | Halt
Instruction::HLT => break,
// 2 | Registry set
Instruction::REG(r, v) => self.registers.set(*r, *v),
// 3 | Add
Instruction::ADD(rx, ry, r) => {
let x = self.registers.get(*rx);
let y = self.registers.get(*ry);
self.registers.set(*r, x + y);
}
}
**pc += 1;
} else {
break;
}
}
}
}
impl Registry {
pub fn get(&self, r: u8) -> usize {
match self.0.get().get(r as usize) {
Some(v) => *v,
None => 0,
}
}
pub fn set(&self, r: u8, v: usize) {
if let Some(o) = self.0.get().get_mut(r as usize) {
*o = v;
}
}
}
impl Display for Registry {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"rx: {}, ry: {}\nrz: {}, ra: {}",
self.get(0),
self.get(1),
self.get(2),
self.get(3),
)
}
}
impl DependencyHandler for Registry {
fn add(&self) {
self.0.add()
}
fn check(&self) -> bool {
self.0.check()
}
}
impl Display for Instruction {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
Instruction::HLT => format!("HLT"),
Instruction::REG(a, b) => format!("REG {a}, {b}"),
Instruction::ADD(a, b, c) => format!("ADD {a}, {b}, {c}"),
}
)
}
}
+33 -11
View File
@@ -6,29 +6,51 @@ use std::sync::Arc;
use osui::prelude::*; use osui::prelude::*;
use crate::emulator::{Instruction, Registry};
fn main() { fn main() {
let screen = Screen::new(); let screen = Screen::new();
let instructions = vec![
Instruction::REG(0, 6),
Instruction::REG(1, 7),
Instruction::ADD(0, 1, 2), // 6 + 7
];
app(&screen).draw(&screen); app(&screen, instructions).draw(&screen);
screen.run().unwrap(); screen.run().unwrap();
} }
fn app(_screen: &Arc<Screen>) -> Rsx { fn app(_screen: &Arc<Screen>, instructions: Vec<emulator::Instruction>) -> Rsx {
let pc = use_state::<u32>(0); let pc = use_state::<usize>(0);
let inst = use_state::<Instruction>(Instruction::HLT);
let registers = Registry(use_state([0; 8]));
// Spawn a thread to emulate the program let emulator = emulator::Emulator {
std::thread::spawn({ pc: pc.clone(),
let pc = pc.clone(); registers: registers.clone(),
move || loop { inst: inst.clone(),
**pc.get() += 1; instructions,
} };
});
std::thread::spawn(move || emulator.run());
rsx! { rsx! {
FlexRow { FlexRow, gap: 1, {
@Style { foreground: None, background: Background::RoundedOutline(0x0000ff) };
@Transform::new().padding(1, 1);
%pc %pc
"Program Counter: {pc}" "Program Counter: {pc}"
@Style { foreground: None, background: Background::RoundedOutline(0xff0000) };
@Transform::new().padding(1, 1);
%registers
"{registers}"
} }
@Style { foreground: None, background: Background::RoundedOutline(0x0000ff) };
@Transform::center().padding(2, 2);
%inst
"Current instruction: {inst}"
} }
} }