Big refactor

This commit is contained in:
Benjamin Kyd
2023-07-12 21:02:10 +01:00
parent 58ba71e514
commit fe83680d27
7 changed files with 149 additions and 273 deletions

View File

@@ -1,163 +1,10 @@
use bits::match_mask;
use enum_dispatch::*;
use modular_bitfield::prelude::*;
use strum::{EnumIter, IntoEnumIterator};
use strum::IntoEnumIterator;
use super::encoding::{GenInstruction, Instruction};
use crate::cpu;
use crate::system::rv32;
// trait Instruction {
// fn impl_register(&self, exts: &mut Vec<Extension>, name: &'static str) {
// for ext in exts {
// if ext.name == name {
// exts.add(self)
// }
// }
// }
// }
//
// fn main() {
// let mut extensions = vec![ext1, ext2, ...];
// ADDI.register(&extensions);
// SUBI.register(&extensions);
// }
//
// // ...
//
// impl Instruction for ADDI {
// fn register(&self, exts: &mut Vec<Extension>) {
// self.impl_register(exts, "instr_set")
// }
// }
// Null undecided type
#[bitfield]
#[derive(Debug)]
pub struct NullType {
pub opcode: B7,
pub _unused: B25,
}
// Arithmetic logic
#[bitfield]
#[derive(Debug)]
pub struct RType {
pub opcode: B7,
pub rd: B5,
pub funct3: B3,
pub rs1: B5,
pub rs2: B5,
pub funct7: B7,
}
// Loads & immeiate arithmetic
#[bitfield]
#[derive(Debug)]
pub struct IType {
pub opcode: B7,
pub rd: B5,
pub funct3: B3,
pub rs1: B5,
pub imm: B12,
}
enum EncodingType {
R(RType),
I(IType),
}
#[repr(align(8))]
pub union GenInstruction {
pub inst: rv32::Word,
pub null: std::mem::ManuallyDrop<NullType>,
pub R: std::mem::ManuallyDrop<RType>,
pub I: std::mem::ManuallyDrop<IType>,
}
#[enum_dispatch]
trait Instruction {
fn name(&self) -> &'static str;
fn match_inst(&self, inst: rv32::Word) -> bool;
fn step(&self, inst: GenInstruction, state: &mut cpu::CPUState);
}
#[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: 0bxxxxxxxxxxxxxxxxx000xxxxx0010011");
match_mask!(inst, "xxxxxxxxxxxxxxxxx000xxxxx0010011")
}
fn step(&self, inst: GenInstruction, state: &mut cpu::CPUState) {
println!("VM > Executing ADDI");
let inst = unsafe { inst.I };
state.x[inst.rd() as usize] = state.x[inst.rs1() as usize].wrapping_add(inst.imm() as u32);
}
}
#[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: 0b0000000xxxxxxxxxx000xxxxx0110011");
match_mask!(inst, "0000000xxxxxxxxxx000xxxxx0110011")
}
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")
}
}
#[enum_dispatch(Instruction)]
#[derive(EnumIter)]
enum ExtensionI {
ADDI(ADDI),
ADD(ADD),
}
#[enum_dispatch(Instruction)]
#[derive(EnumIter)]
enum ExtensionM {
GENERICM(GENERICM)
}
use crate::ext::i;
pub struct DecodeCycle {
extensions: Vec<char>,
@@ -177,7 +24,10 @@ impl DecodeCycle {
// if we find a match, we want to execute it
// if we don't find a match, we want to return an error
fn enumerate_extension<T: IntoEnumIterator + Instruction>(inst: rv32::Word, state: &mut cpu::CPUState) -> Option<()> {
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 };
@@ -190,8 +40,11 @@ impl DecodeCycle {
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(()); },
'i' => {
if let Some(()) = enumerate_extension::<i::ExtensionI>(inst, state) {
return Ok(());
}
}
_ => println!("VM > Unknown Extension"),
}
}

57
src/ext/encoding.rs Normal file
View File

@@ -0,0 +1,57 @@
use modular_bitfield::prelude::*;
use enum_dispatch::*;
use crate::system::rv32;
use crate::cpu;
#[enum_dispatch]
pub trait Instruction {
fn name(&self) -> &'static str;
fn match_inst(&self, inst: rv32::Word) -> bool;
fn step(&self, inst: GenInstruction, state: &mut cpu::CPUState);
}
// Null undecided type
#[bitfield]
#[derive(Debug)]
pub struct NullType {
pub opcode: B7,
pub _unused: B25,
}
// Arithmetic logic
#[bitfield]
#[derive(Debug)]
pub struct RType {
pub opcode: B7,
pub rd: B5,
pub funct3: B3,
pub rs1: B5,
pub rs2: B5,
pub funct7: B7,
}
// Loads & immeiate arithmetic
#[bitfield]
#[derive(Debug)]
pub struct IType {
pub opcode: B7,
pub rd: B5,
pub funct3: B3,
pub rs1: B5,
pub imm: B12,
}
enum EncodingType {
R(RType),
I(IType),
}
#[repr(align(8))]
pub union GenInstruction {
pub inst: rv32::Word,
pub null: std::mem::ManuallyDrop<NullType>,
pub R: std::mem::ManuallyDrop<RType>,
pub I: std::mem::ManuallyDrop<IType>,
}

View File

@@ -1 +1,61 @@
use bits::match_mask;
use enum_dispatch::*;
use strum::EnumIter;
use super::encoding::{GenInstruction, Instruction};
use crate::helpers::sext;
use crate::cpu;
use crate::system::rv32;
#[derive(Default, Copy, Clone)]
pub 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: 0bxxxxxxxxxxxxxxxxx000xxxxx0010011");
match_mask!(inst, "xxxxxxxxxxxxxxxxx000xxxxx0010011")
}
fn step(&self, inst: GenInstruction, state: &mut cpu::CPUState) {
println!("VM > Executing ADDI");
let inst = unsafe { inst.I };
state.x[inst.rd() as usize] = state.x[inst.rs1() as usize].wrapping_add(sext(inst.imm() as u32,));
}
}
#[derive(Default, Copy, Clone)]
pub 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: 0b0000000xxxxxxxxxx000xxxxx0110011");
match_mask!(inst, "0000000xxxxxxxxxx000xxxxx0110011")
}
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]);
}
}
#[enum_dispatch(Instruction)]
#[derive(EnumIter)]
pub enum ExtensionI {
ADDI(ADDI),
ADD(ADD),
}

View File

@@ -1,6 +1,8 @@
use crate::system::rv32;
pub mod encoding;
pub mod decode;
pub mod i;
// Instruction bitmasks
// This will be awkward as the instruction types

15
src/helpers.rs Normal file
View File

@@ -0,0 +1,15 @@
pub fn sext(value: u32, len: usize) -> u32 {
let bit_len = std::mem::size_of::<u32>() << 3;
assert!(len > 0 && len <= bit_len);
if len == bit_len {
return value;
}
let sign = value >> (len - 1) as u32 & 0x1;
let mask = ((1 as u32) << (len as u32)) - 1 as u32;
if sign == 0 {
value & mask
} else {
let high = (((1 as u32) << (bit_len as u32 - len as u32)) - 1 as u32) << (len as u32);
value & mask | high
}
}

View File

@@ -1,111 +0,0 @@
use modular_bitfield::prelude::*;
use crate::system::rv32;
pub const R_TYPE: u8 = 0b00110011;
pub const I_TYPE: u8 = 0b00010011;
pub const S_TYPE: u8 = 0b00100011;
pub const B_TYPE: u8 = 0b01100011;
pub const U_TYPE: u8 = 0b00110111;
pub const J_TYPE: u8 = 0b01110011;
// Null undecided type
#[bitfield]
#[derive(Debug)]
pub struct NullType {
pub opcode: B7,
pub _undefined: B25,
}
// Arithmetic logic
#[bitfield]
#[derive(Debug)]
pub struct RType {
pub opcode: B7,
pub rd: B5,
pub funct3: B3,
pub rs1: B5,
pub rs2: B5,
pub funct7: B7,
}
// Loads & immeiate arithmetic
#[bitfield]
#[derive(Debug)]
pub struct IType {
pub opcode: B7,
pub rd: B5,
pub funct3: B3,
pub rs1: B5,
pub imm: B12,
}
// Stores
#[bitfield]
#[derive(Debug)]
pub struct SType {
pub opcode: B7,
pub imm_l: B5,
pub funct3: B3,
pub rs1: B5,
pub rs2: B5,
pub imm_h: B7,
}
// Conditional jump
#[bitfield]
#[derive(Debug)]
pub struct BType {
pub opcode: B7,
pub imm_11: B1,
pub imm_4_1: B4,
pub funct3: B3,
pub rs1: B5,
pub rs2: B5,
pub imm_10_5: B6,
pub imm_12: B1,
}
// Upper immediate
#[bitfield]
#[derive(Debug)]
pub struct UType {
pub opcode: B7,
pub rd: B5,
pub imm: B20,
}
// Unconditional jump
#[bitfield]
#[derive(Debug)]
pub struct JType {
pub opcode: B7,
pub rd: B5,
pub imm_19_12: B8,
pub imm_11: B1,
pub imm_10_1: B10,
pub imm_20: B1,
}
/* #[derive(Debug)]
pub enum Decode {
null(std::mem::ManuallyDrop<NullType>),
R(std::mem::ManuallyDrop<RType>),
I(std::mem::ManuallyDrop<IType>),
S(std::mem::ManuallyDrop<SType>),
B(std::mem::ManuallyDrop<BType>),
U(std::mem::ManuallyDrop<UType>),
J(std::mem::ManuallyDrop<JType>),
} */
#[repr(align(8))]
pub union Instruction {
pub inst: rv32::Word,
pub null: std::mem::ManuallyDrop<NullType>,
pub R: std::mem::ManuallyDrop<RType>,
pub I: std::mem::ManuallyDrop<IType>,
pub S: std::mem::ManuallyDrop<SType>,
pub B: std::mem::ManuallyDrop<BType>,
pub U: std::mem::ManuallyDrop<UType>,
pub J: std::mem::ManuallyDrop<JType>,
}

View File

@@ -9,8 +9,8 @@ use std::{cell::RefCell, rc::Rc};
mod cpu;
mod err;
mod ext;
mod inst;
mod system;
mod helpers;
use crate::cpu::*;
use crate::ext::decode;
@@ -24,7 +24,7 @@ struct VMRV32I {
impl VMRV32I {
fn new() -> VMRV32I {
let extensions = vec!['i', 'm'];
let extensions = vec!['i'];
let bus = Rc::new(RefCell::new(bus::Bus::new()));
let instruction_decoder = Rc::new(RefCell::new(decode::DecodeCycle::new(extensions.clone())));
@@ -83,7 +83,7 @@ fn main() {
println!("VM Starting Up");
let mut vm = VMRV32I::new();
vm.load_prog("./test/add.bin");
vm.load_prog("./test/test.bin");
vm.dump_prog();
vm.dispatch();
}