Simple CPU and registry emulation
This commit is contained in:
@@ -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
@@ -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}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user