Big refactor
This commit is contained in:
@@ -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
57
src/ext/encoding.rs
Normal 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>,
|
||||
}
|
||||
@@ -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),
|
||||
}
|
||||
|
||||
|
||||
@@ -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
15
src/helpers.rs
Normal 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
|
||||
}
|
||||
}
|
||||
111
src/inst.rs
111
src/inst.rs
@@ -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>,
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user