arbritrary execution is functional with the extension system

This commit is contained in:
Benjamin Kyd
2023-07-12 19:33:55 +01:00
parent 13b3d05792
commit 4ae6a02181
3 changed files with 84 additions and 80 deletions

View File

@@ -1,8 +1,8 @@
use crate::ext::decode;
use crate::system::bus::*;
use std::{cell::RefCell, rc::Rc};
use crate::system::ram;
use crate::system::rv32;
use crate::ext::decode;
use std::{cell::RefCell, rc::Rc};
// Register ABI Description Saver
// x0 zero Zero Immutable
@@ -19,26 +19,28 @@ use crate::ext::decode;
// x18-x27 s2-s11 Saved registers Callee
// x28-x31 t3-t6 Temporaries Caller
pub struct CPUState {
x: [rv32::Word; 32],
pc: rv32::Word,
pub x: [rv32::Word; 32],
pub pc: rv32::Word,
}
pub struct CPU {
state: CPUState,
bus: Rc<RefCell<Bus>>,
instruction_decoder: Rc<RefCell<decode::DecodeCycle>>,
// extensions:
extensions: Vec<char>,
}
impl CPU {
pub fn new(bus: Rc<RefCell<Bus>>, instruction_decoder: Rc<RefCell<decode::DecodeCycle>>) -> CPU {
pub fn new(
bus: Rc<RefCell<Bus>>,
instruction_decoder: Rc<RefCell<decode::DecodeCycle>>,
extensions: Vec<char>,
) -> CPU {
CPU {
state: CPUState {
x: [0; 32],
pc: 0,
},
state: CPUState { x: [0; 32], pc: 0 },
bus,
instruction_decoder,
extensions,
}
}
@@ -50,6 +52,7 @@ impl CPU {
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
println!("VM > CPU Initialisd with extensions {:?}", self.extensions);
}
pub fn get_pc(&self) -> rv32::Word {
@@ -64,45 +67,14 @@ impl CPU {
while self.state.pc - DRAM_BASE < ram::DRAM_SIZE as u32 {
// fetch
let inst = self.fetch();
println!("VM > Fetched 0x{:08x}: 0x{:08x}", self.state.pc, inst );
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;
self.instruction_decoder.borrow_mut().decode_exec_inst(inst, &mut self.state)?;
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(())

View File

@@ -1,7 +1,7 @@
use bits::match_mask;
use enum_dispatch::*;
use strum::{IntoEnumIterator, EnumIter};
use modular_bitfield::prelude::*;
use strum::{EnumIter, IntoEnumIterator};
use crate::cpu;
use crate::system::rv32;
@@ -78,7 +78,7 @@ pub union GenInstruction {
trait Instruction {
fn name(&self) -> &'static str;
fn match_inst(&self, inst: rv32::Word) -> bool;
fn step(&self, inst: rv32::Word, state: &mut cpu::CPUState);
fn step(&self, inst: GenInstruction, state: &mut cpu::CPUState);
}
#[derive(Default, Copy, Clone)]
@@ -96,10 +96,10 @@ impl Instruction for ADDI {
match_mask!(inst, "xxxxxxxxxxxxxxxxx000xxxxx0010011")
}
fn step(&self, inst: rv32::Word, state: &mut cpu::CPUState) {
println!("VM > Decoded I Type instruction 0x{:08x}", inst);
fn step(&self, inst: GenInstruction, state: &mut cpu::CPUState) {
println!("VM > Executing ADDI");
// self.x[inst.rd() as usize] = self.x[inst.rs1() as usize].wrapping_add(inst.imm() as u32);
let inst = unsafe { inst.I };
state.x[inst.rd() as usize] = state.x[inst.rs1() as usize].wrapping_add(inst.imm() as u32);
}
}
@@ -118,9 +118,31 @@ impl Instruction for ADD {
match_mask!(inst, "0000000xxxxxxxxxx000xxxxx0110011")
}
fn step(&self, inst: rv32::Word, state: &mut cpu::CPUState) {
println!("VM > Decoded R Type instruction 0x{:08x}", inst);
fn step(&self, inst: GenInstruction, state: &mut cpu::CPUState) {
println!("VM > Executing ADD");
let inst = unsafe { inst.R };
state.x[inst.rd() as usize] =
state.x[inst.rs1() as usize].wrapping_add(state.x[inst.rs2() as usize]);
}
}
#[derive(Default, Copy, Clone)]
struct GENERICM;
impl Instruction for GENERICM {
fn name(&self) -> &'static str {
"GENERICM"
}
fn match_inst(&self,inst:rv32::Word) -> bool {
println!("VM > Checking GENERICM");
println!("VM > GENERICM: 0b{:032b}", inst);
println!("VM > GENERICM: 0b0000000xxxxxxxxxx000xxxxx0110011");
match_mask!(inst, "0000000xxxxxxxxxx000xxxxx0110011")
}
fn step(&self,inst:GenInstruction,state: &mut cpu::CPUState) {
println!("epc")
}
}
@@ -131,8 +153,10 @@ enum ExtensionI {
ADD(ADD),
}
enum Extensions {
ExtensionI(Option<ExtensionI>),
#[enum_dispatch(Instruction)]
#[derive(EnumIter)]
enum ExtensionM {
GENERICM(GENERICM)
}
pub struct DecodeCycle {
@@ -144,29 +168,33 @@ impl DecodeCycle {
DecodeCycle { extensions: ext }
}
pub fn decode_exec_inst(&self, inst: rv32::Word, state: &mut cpu::CPUState) -> Result<(), String> {
pub fn decode_exec_inst(
&self,
inst: rv32::Word,
state: &mut cpu::CPUState,
) -> Result<(), &str> {
// 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' => {
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");
fn enumerate_extension<T: IntoEnumIterator + Instruction>(inst: rv32::Word, state: &mut cpu::CPUState) -> Option<()> {
for instruction in T::iter() {
if instruction.match_inst(inst) {
let geninst = GenInstruction { inst };
instruction.step(geninst, state);
return Some(());
}
}
None
}
Ok(())
}
for extension in self.extensions.iter() {
match extension {
'm' => if let Some(()) = enumerate_extension::<ExtensionM>(inst, state) { return Ok(()); },
'i' => if let Some(()) = enumerate_extension::<ExtensionI>(inst, state) { return Ok(()); },
_ => println!("VM > Unknown Extension"),
}
}
Err("No instruction found")
}
}

View File

@@ -7,14 +7,14 @@ use std::io::Read;
use std::{cell::RefCell, rc::Rc};
mod cpu;
mod ext;
mod err;
mod system;
mod ext;
mod inst;
mod system;
use crate::system::bus;
use crate::ext::decode;
use crate::cpu::*;
use crate::ext::decode;
use crate::system::bus;
struct VMRV32I {
bus: Rc<RefCell<bus::Bus>>,
@@ -24,14 +24,18 @@ struct VMRV32I {
impl VMRV32I {
fn new() -> VMRV32I {
let extensions = vec!['i'];
let extensions = vec!['i', 'm'];
let bus = Rc::new(RefCell::new(bus::Bus::new()));
let instruction_decoder = Rc::new(RefCell::new(decode::DecodeCycle::new(extensions)));
let mut cpu = CPU::new(Rc::clone(&bus), Rc::clone(&instruction_decoder));
let instruction_decoder = Rc::new(RefCell::new(decode::DecodeCycle::new(extensions.clone())));
let mut cpu = CPU::new(Rc::clone(&bus), Rc::clone(&instruction_decoder), extensions.clone());
cpu.init();
VMRV32I { cpu, bus, instruction_decoder }
VMRV32I {
cpu,
bus,
instruction_decoder,
}
}
fn load_prog(&mut self, file: &str) {