arbritrary execution is functional with the extension system
This commit is contained in:
@@ -1,8 +1,8 @@
|
|||||||
|
use crate::ext::decode;
|
||||||
use crate::system::bus::*;
|
use crate::system::bus::*;
|
||||||
use std::{cell::RefCell, rc::Rc};
|
|
||||||
use crate::system::ram;
|
use crate::system::ram;
|
||||||
use crate::system::rv32;
|
use crate::system::rv32;
|
||||||
use crate::ext::decode;
|
use std::{cell::RefCell, rc::Rc};
|
||||||
|
|
||||||
// Register ABI Description Saver
|
// Register ABI Description Saver
|
||||||
// x0 zero Zero Immutable
|
// x0 zero Zero Immutable
|
||||||
@@ -19,26 +19,28 @@ use crate::ext::decode;
|
|||||||
// x18-x27 s2-s11 Saved registers Callee
|
// x18-x27 s2-s11 Saved registers Callee
|
||||||
// x28-x31 t3-t6 Temporaries Caller
|
// x28-x31 t3-t6 Temporaries Caller
|
||||||
pub struct CPUState {
|
pub struct CPUState {
|
||||||
x: [rv32::Word; 32],
|
pub x: [rv32::Word; 32],
|
||||||
pc: rv32::Word,
|
pub pc: rv32::Word,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CPU {
|
pub struct CPU {
|
||||||
state: CPUState,
|
state: CPUState,
|
||||||
bus: Rc<RefCell<Bus>>,
|
bus: Rc<RefCell<Bus>>,
|
||||||
instruction_decoder: Rc<RefCell<decode::DecodeCycle>>,
|
instruction_decoder: Rc<RefCell<decode::DecodeCycle>>,
|
||||||
// extensions:
|
extensions: Vec<char>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CPU {
|
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 {
|
CPU {
|
||||||
state: CPUState {
|
state: CPUState { x: [0; 32], pc: 0 },
|
||||||
x: [0; 32],
|
|
||||||
pc: 0,
|
|
||||||
},
|
|
||||||
bus,
|
bus,
|
||||||
instruction_decoder,
|
instruction_decoder,
|
||||||
|
extensions,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,6 +52,7 @@ impl CPU {
|
|||||||
self.state.pc = DRAM_BASE as rv32::Word;
|
self.state.pc = DRAM_BASE as rv32::Word;
|
||||||
self.state.x[0] = 0x00000000; // x0 is tied to ground
|
self.state.x[0] = 0x00000000; // x0 is tied to ground
|
||||||
self.state.x[2] = ram::DRAM_SIZE as u32; // x2 the addressable
|
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 {
|
pub fn get_pc(&self) -> rv32::Word {
|
||||||
@@ -64,45 +67,14 @@ impl CPU {
|
|||||||
while self.state.pc - DRAM_BASE < ram::DRAM_SIZE as u32 {
|
while self.state.pc - DRAM_BASE < ram::DRAM_SIZE as u32 {
|
||||||
// fetch
|
// fetch
|
||||||
let inst = self.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.pc = self.state.pc + rv32::WORD as u32;
|
||||||
self.state.x[0] = 0x00000000;
|
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();
|
self.dump_reg();
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use bits::match_mask;
|
use bits::match_mask;
|
||||||
use enum_dispatch::*;
|
use enum_dispatch::*;
|
||||||
use strum::{IntoEnumIterator, EnumIter};
|
|
||||||
use modular_bitfield::prelude::*;
|
use modular_bitfield::prelude::*;
|
||||||
|
use strum::{EnumIter, IntoEnumIterator};
|
||||||
|
|
||||||
use crate::cpu;
|
use crate::cpu;
|
||||||
use crate::system::rv32;
|
use crate::system::rv32;
|
||||||
@@ -78,7 +78,7 @@ pub union GenInstruction {
|
|||||||
trait Instruction {
|
trait Instruction {
|
||||||
fn name(&self) -> &'static str;
|
fn name(&self) -> &'static str;
|
||||||
fn match_inst(&self, inst: rv32::Word) -> bool;
|
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)]
|
#[derive(Default, Copy, Clone)]
|
||||||
@@ -96,10 +96,10 @@ impl Instruction for ADDI {
|
|||||||
match_mask!(inst, "xxxxxxxxxxxxxxxxx000xxxxx0010011")
|
match_mask!(inst, "xxxxxxxxxxxxxxxxx000xxxxx0010011")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn step(&self, inst: rv32::Word, state: &mut cpu::CPUState) {
|
fn step(&self, inst: GenInstruction, state: &mut cpu::CPUState) {
|
||||||
println!("VM > Decoded I Type instruction 0x{:08x}", inst);
|
|
||||||
println!("VM > Executing ADDI");
|
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")
|
match_mask!(inst, "0000000xxxxxxxxxx000xxxxx0110011")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn step(&self, inst: rv32::Word, state: &mut cpu::CPUState) {
|
fn step(&self, inst: GenInstruction, state: &mut cpu::CPUState) {
|
||||||
println!("VM > Decoded R Type instruction 0x{:08x}", inst);
|
|
||||||
println!("VM > Executing ADD");
|
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),
|
ADD(ADD),
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Extensions {
|
#[enum_dispatch(Instruction)]
|
||||||
ExtensionI(Option<ExtensionI>),
|
#[derive(EnumIter)]
|
||||||
|
enum ExtensionM {
|
||||||
|
GENERICM(GENERICM)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DecodeCycle {
|
pub struct DecodeCycle {
|
||||||
@@ -144,29 +168,33 @@ impl DecodeCycle {
|
|||||||
DecodeCycle { extensions: ext }
|
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
|
// 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 find a match, we want to execute it
|
||||||
// if we don't find a match, we want to return an error
|
// if we don't find a match, we want to return an error
|
||||||
|
|
||||||
for extension in self.extensions.iter() {
|
fn enumerate_extension<T: IntoEnumIterator + Instruction>(inst: rv32::Word, state: &mut cpu::CPUState) -> Option<()> {
|
||||||
match extension {
|
for instruction in T::iter() {
|
||||||
'i' => {
|
if instruction.match_inst(inst) {
|
||||||
println!("VM > Attempting to decode instruction as I extension: 0x{:08x}", inst);
|
let geninst = GenInstruction { inst };
|
||||||
for instruction in ExtensionI::iter() {
|
instruction.step(geninst, state);
|
||||||
println!("VM > Checking instruction: {:?}", instruction.name());
|
return Some(());
|
||||||
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");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
20
src/main.rs
20
src/main.rs
@@ -7,14 +7,14 @@ use std::io::Read;
|
|||||||
use std::{cell::RefCell, rc::Rc};
|
use std::{cell::RefCell, rc::Rc};
|
||||||
|
|
||||||
mod cpu;
|
mod cpu;
|
||||||
mod ext;
|
|
||||||
mod err;
|
mod err;
|
||||||
mod system;
|
mod ext;
|
||||||
mod inst;
|
mod inst;
|
||||||
|
mod system;
|
||||||
|
|
||||||
use crate::system::bus;
|
|
||||||
use crate::ext::decode;
|
|
||||||
use crate::cpu::*;
|
use crate::cpu::*;
|
||||||
|
use crate::ext::decode;
|
||||||
|
use crate::system::bus;
|
||||||
|
|
||||||
struct VMRV32I {
|
struct VMRV32I {
|
||||||
bus: Rc<RefCell<bus::Bus>>,
|
bus: Rc<RefCell<bus::Bus>>,
|
||||||
@@ -24,14 +24,18 @@ struct VMRV32I {
|
|||||||
|
|
||||||
impl VMRV32I {
|
impl VMRV32I {
|
||||||
fn new() -> VMRV32I {
|
fn new() -> VMRV32I {
|
||||||
let extensions = vec!['i'];
|
let extensions = vec!['i', 'm'];
|
||||||
|
|
||||||
let bus = Rc::new(RefCell::new(bus::Bus::new()));
|
let bus = Rc::new(RefCell::new(bus::Bus::new()));
|
||||||
let instruction_decoder = Rc::new(RefCell::new(decode::DecodeCycle::new(extensions)));
|
let instruction_decoder = Rc::new(RefCell::new(decode::DecodeCycle::new(extensions.clone())));
|
||||||
let mut cpu = CPU::new(Rc::clone(&bus), Rc::clone(&instruction_decoder));
|
let mut cpu = CPU::new(Rc::clone(&bus), Rc::clone(&instruction_decoder), extensions.clone());
|
||||||
|
|
||||||
cpu.init();
|
cpu.init();
|
||||||
VMRV32I { cpu, bus, instruction_decoder }
|
VMRV32I {
|
||||||
|
cpu,
|
||||||
|
bus,
|
||||||
|
instruction_decoder,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_prog(&mut self, file: &str) {
|
fn load_prog(&mut self, file: &str) {
|
||||||
|
|||||||
Reference in New Issue
Block a user