that's kinda neat

This commit is contained in:
Ben Kyd
2023-07-11 22:47:30 +01:00
parent 75c25dc1cc
commit 2910eded98
6 changed files with 162 additions and 85 deletions

35
Cargo.lock generated
View File

@@ -28,6 +28,12 @@ dependencies = [
"syn 1.0.109",
]
[[package]]
name = "heck"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]]
name = "modular-bitfield"
version = "0.11.2"
@@ -157,14 +163,43 @@ dependencies = [
"enum_dispatch",
"modular-bitfield",
"num",
"strum",
]
[[package]]
name = "rustversion"
version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc31bd9b61a32c31f9650d18add92aa83a49ba979c143eefd27fe7177b05bd5f"
[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "strum"
version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125"
dependencies = [
"strum_macros",
]
[[package]]
name = "strum_macros"
version = "0.25.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6069ca09d878a33f883cc06aaa9718ede171841d3832450354410b718b097232"
dependencies = [
"heck",
"proc-macro2",
"quote",
"rustversion",
"syn 2.0.18",
]
[[package]]
name = "syn"
version = "1.0.109"

View File

@@ -10,3 +10,4 @@ path = "lib/bits"
enum_dispatch = "0.3.11"
modular-bitfield = "0.11.2"
num = "0.4.0"
strum = { version = "0.25.0", features = ["derive"] }

View File

@@ -1,8 +1,8 @@
use std::{cell::RefCell, rc::Rc};
use crate::system::bus::*;
use std::{cell::RefCell, rc::Rc};
use crate::system::ram;
use crate::system::rv32;
use crate::inst;
use crate::ext::decode;
// Register ABI Description Saver
// x0 zero Zero Immutable
@@ -18,19 +18,27 @@ use crate::inst;
// x12-x17 a2-a7 Fn args Caller
// x18-x27 s2-s11 Saved registers Callee
// x28-x31 t3-t6 Temporaries Caller
pub struct CPU {
pub struct CPUState {
x: [rv32::Word; 32],
pc: rv32::Word,
}
pub struct CPU {
state: CPUState,
bus: Rc<RefCell<Bus>>,
instruction_decoder: Rc<RefCell<decode::DecodeCycle>>,
// extensions:
}
impl CPU {
pub fn new(bus: Rc<RefCell<Bus>>) -> CPU {
pub fn new(bus: Rc<RefCell<Bus>>, instruction_decoder: Rc<RefCell<decode::DecodeCycle>>) -> CPU {
CPU {
x: [0; 32],
pc: 0,
state: CPUState {
x: [0; 32],
pc: 0,
},
bus,
instruction_decoder,
}
}
@@ -39,75 +47,74 @@ impl CPU {
println!("-----------------");
println!("VM > Initializing CPU");
self.pc = DRAM_BASE as rv32::Word;
self.x[0] = 0x00000000; // x0 is tied to ground
self.x[2] = ram::DRAM_SIZE as u32; // x2 the addressable
self.state.pc = DRAM_BASE as rv32::Word;
self.state.x[0] = 0x00000000; // x0 is tied to ground
self.state.x[2] = ram::DRAM_SIZE as u32; // x2 the addressable
}
pub fn get_pc(&mut self) -> rv32::Word {
return self.pc;
pub fn get_pc(&self) -> rv32::Word {
return self.state.pc;
}
fn fetch(&mut self) -> inst::Instruction {
inst::Instruction {
inst: self.bus.borrow_mut().load_32(self.pc),
}
fn fetch(&self) -> rv32::Word {
self.bus.borrow_mut().load_32(self.state.pc)
}
pub fn exec(&mut self) {
while self.pc - DRAM_BASE < ram::DRAM_SIZE as u32 {
pub fn exec(&mut self) -> Result<(), String> {
while self.state.pc - DRAM_BASE < ram::DRAM_SIZE as u32 {
// fetch
let inst = self.fetch();
println!("VM > Fetched 0x{:08x}: 0x{:08x}", self.pc, unsafe {
inst.inst
});
self.pc = self.pc + rv32::WORD as u32;
self.x[0] = 0x00000000;
println!("VM > Fetched 0x{:08x}: 0x{:08x}", self.state.pc, inst );
self.state.pc = self.state.pc + rv32::WORD as u32;
self.state.x[0] = 0x00000000;
// decode and execute
// we can use nulltype to extract the opcode
let opcode = unsafe { inst.null.opcode() };
// then we can match the opcode to extract the op type
match opcode {
inst::I_TYPE => {
let inst = unsafe { inst.I };
println!("VM > Decoded I Type instruction {:?}", inst);
match inst.funct3() {
0x0 => {
self.x[inst.rd() as usize] =
self.x[inst.rs1() as usize].wrapping_add(inst.imm() as u32);
}
_ => println!("VM > INST {:03b} not implemented", inst.funct3()),
};
}
inst::R_TYPE => {
let inst = unsafe { inst.R };
println!("VM > Decoded R Type instruction {:?}", inst);
match inst.funct3() {
0x0 => {
self.x[inst.rd() as usize] = self.x[inst.rs1() as usize]
.wrapping_add(self.x[inst.rs2() as usize]);
}
_ => println!("VM > INST {:03b} not implemented", inst.funct3()),
}
}
inst::S_TYPE => {
println!("VM > OPCODE S TYPE not implemented");
}
_ => println!("VM > OPCODE {:08b} not implemented", opcode),
};
self.instruction_decoder.borrow_mut().decode_exec_inst(inst, &mut self.state)?;
// // decode and execute
// // we can use nulltype to extract the opcode
// let opcode = unsafe { inst.null.opcode() };
// // then we can match the opcode to extract the op type
// match opcode {
// inst::I_TYPE => {
// let inst = unsafe { inst.I };
// println!("VM > Decoded I Type instruction {:?}", inst);
// match inst.funct3() {
// 0x0 => {
// self.x[inst.rd() as usize] =
// self.x[inst.rs1() as usize].wrapping_add(inst.imm() as u32);
// }
// _ => println!("VM > INST {:03b} not implemented", inst.funct3()),
// };
// }
// inst::R_TYPE => {
// let inst = unsafe { inst.R };
// println!("VM > Decoded R Type instruction {:?}", inst);
// match inst.funct3() {
// 0x0 => {
// self.x[inst.rd() as usize] = self.x[inst.rs1() as usize]
// .wrapping_add(self.x[inst.rs2() as usize]);
// }
// _ => println!("VM > INST {:03b} not implemented", inst.funct3()),
// }
// }
// inst::S_TYPE => {
// println!("VM > OPCODE S TYPE not implemented");
// }
// _ => println!("VM > OPCODE {:08b} not implemented", opcode),
// };
//
self.dump_reg();
}
Ok(())
}
fn dump_reg(&mut self) {
println!("VM > Dumping registers");
println!("PC : 0x{:08x}", self.pc);
println!("PC : 0x{:08x}", self.state.pc);
for i in 0..4 {
for j in 0..8 {
let coord = (i * 8) + j;
print!("x{0: <2}: {1: <4}", coord, self.x[coord]);
print!("x{0: <2}: {1: <4}", coord, self.state.x[coord]);
}
println!("");
}

View File

@@ -1,5 +1,6 @@
use bits::match_mask;
use enum_dispatch::*;
use strum::{IntoEnumIterator, EnumIter};
use modular_bitfield::prelude::*;
use crate::cpu;
@@ -75,35 +76,56 @@ pub union GenInstruction {
#[enum_dispatch]
trait Instruction {
fn name(&self) -> &'static str;
fn match_inst(&self, inst: rv32::Word) -> bool;
fn step(&self, inst: rv32::Word, state: &mut cpu::CPU);
fn step(&self, inst: rv32::Word, state: &mut cpu::CPUState);
}
#[derive(Copy, Clone)]
#[derive(Default, Copy, Clone)]
struct ADDI;
impl Instruction for ADDI {
fn name(&self) -> &'static str {
"ADDI"
}
fn match_inst(&self, inst: rv32::Word) -> bool {
println!("VM > Checking ADDI");
println!("VM > ADDI: 0b{:032b}", inst);
println!("VM > ADDI: 0bxxxxxxxxxxxxxxxxxx000xxxx0010011");
match_mask!(inst, "xxxxxxxxxxxxxxxxxx000xxxx0010011")
}
fn step(&self, inst: rv32::Word, state: &mut cpu::CPU) {
fn step(&self, inst: rv32::Word, state: &mut cpu::CPUState) {
println!("VM > Decoded I Type instruction 0x{:08x}", inst);
println!("VM > Executing ADDI");
// self.x[inst.rd() as usize] = self.x[inst.rs1() as usize].wrapping_add(inst.imm() as u32);
}
}
#[derive(Copy, Clone)]
#[derive(Default, Copy, Clone)]
struct ADD;
impl Instruction for ADD {
fn name(&self) -> &'static str {
"ADD"
}
fn match_inst(&self, inst: rv32::Word) -> bool {
println!("VM > Checking ADD");
println!("VM > ADD: 0b{:032b}", inst);
println!("VM > ADD: 0b0000000xxxxxxxxxxx000xxxx0110011");
match_mask!(inst, "0000000xxxxxxxxxxx000xxxx0110011")
}
fn step(&self, inst: rv32::Word, state: &mut cpu::CPU) {}
fn step(&self, inst: rv32::Word, state: &mut cpu::CPUState) {
println!("VM > Decoded R Type instruction 0x{:08x}", inst);
println!("VM > Executing ADD");
}
}
#[enum_dispatch(Instruction)]
#[derive(EnumIter)]
enum ExtensionI {
ADDI(ADDI),
ADD(ADD),
@@ -114,32 +136,37 @@ enum Extensions {
}
pub struct DecodeCycle {
extensions: Vec<Extensions>,
extensions: Vec<char>,
}
impl DecodeCycle {
pub fn new(&mut self, ext: Vec<char>) {
for extension in ext {
pub fn new(ext: Vec<char>) -> DecodeCycle {
DecodeCycle { extensions: ext }
}
pub fn decode_exec_inst(&self, inst: rv32::Word, state: &mut cpu::CPUState) -> Result<(), String> {
// we want to go through each extension and then go through each instruction in that extension
// if we find a match, we want to execute it
// if we don't find a match, we want to return an error
for extension in self.extensions.iter() {
match extension {
'i' => {
self.extensions.push(Extensions::ExtensionI(None));
println!("VM > Attempting to decode instruction as I extension: 0x{:08x}", inst);
for instruction in ExtensionI::iter() {
println!("VM > Checking instruction: {:?}", instruction.name());
if instruction.match_inst(inst) {
println!("VM > Decoded instruction as I extension: 0x{:08x}", inst);
instruction.step(inst, state);
return Ok(());
}
}
}
_ => {
println!("VM > Unknown Extension '{}'", extension);
println!("VM > Unknown Extension");
}
}
}
}
pub fn decode_inst(&self, inst: rv32::Word) -> Option<Instruction> {
// we need to go over every instruction and see if it matches
// we can do smarter things with cacheing later - this aint blazin
for extension in &self.extensions {
match extension.match_inst(inst) {
Some(inst) => return Some(inst),
None => continue,
};
};
None
}
Ok(())
}
}

View File

@@ -1,6 +1,6 @@
use crate::system::rv32;
mod decode;
pub mod decode;
// Instruction bitmasks
// This will be awkward as the instruction types
@@ -8,5 +8,3 @@ mod decode;
// Instruction parsing
// Extensibility
type Instruction = rv32::Word;

View File

@@ -13,19 +13,25 @@ mod system;
mod inst;
use crate::system::bus;
use crate::ext::decode;
use crate::cpu::*;
struct VMRV32I {
bus: Rc<RefCell<bus::Bus>>,
cpu: cpu::CPU,
instruction_decoder: Rc<RefCell<decode::DecodeCycle>>,
}
impl VMRV32I {
fn new() -> VMRV32I {
let extensions = vec!['i'];
let bus = Rc::new(RefCell::new(bus::Bus::new()));
let mut cpu = CPU::new(Rc::clone(&bus));
let instruction_decoder = Rc::new(RefCell::new(decode::DecodeCycle::new(extensions)));
let mut cpu = CPU::new(Rc::clone(&bus), Rc::clone(&instruction_decoder));
cpu.init();
VMRV32I { cpu, bus }
VMRV32I { cpu, bus, instruction_decoder }
}
fn load_prog(&mut self, file: &str) {
@@ -62,7 +68,10 @@ impl VMRV32I {
}
fn dispatch(&mut self) {
self.cpu.exec();
match self.cpu.exec() {
Ok(_) => println!("VM > Program exited peacefully"),
Err(e) => println!("VM > Program exited violently with error: {}", e),
}
}
}