diff options
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | Cargo.lock | 7 | ||||
| -rw-r--r-- | Cargo.toml | 6 | ||||
| -rw-r--r-- | src/extension/extension.rs | 5 | ||||
| -rw-r--r-- | src/extension/mod.rs | 1 | ||||
| -rw-r--r-- | src/instruction/instruction.rs | 15 | ||||
| -rw-r--r-- | src/instruction/mod.rs | 1 | ||||
| -rw-r--r-- | src/main.rs | 30 | ||||
| -rw-r--r-- | src/rv32_cpu/mod.rs | 1 | ||||
| -rw-r--r-- | src/rv32_cpu/rv32_cpu.rs | 89 | ||||
| -rw-r--r-- | src/rv32a/mod.rs | 0 | ||||
| -rw-r--r-- | src/rv32i/mod.rs | 2 | ||||
| -rw-r--r-- | src/rv32i/rv32i.rs | 14 | ||||
| -rw-r--r-- | src/rv32i/slti.rs | 18 | ||||
| -rw-r--r-- | src/rv32m/mod.rs | 1 | ||||
| -rw-r--r-- | src/rv32m/rv32m.rs | 11 |
16 files changed, 202 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..6d820d5 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "rustv32im_emu" +version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..5d4dee7 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "rustv32im_emu" +version = "0.1.0" +edition = "2024" + +[dependencies] diff --git a/src/extension/extension.rs b/src/extension/extension.rs new file mode 100644 index 0000000..d50565a --- /dev/null +++ b/src/extension/extension.rs @@ -0,0 +1,5 @@ +use crate::rv32_cpu::rv32_cpu::Rv32Cpu; + +pub trait Extension { + fn add_instructions(cpu: &mut Rv32Cpu) -> &mut Rv32Cpu; +}
\ No newline at end of file diff --git a/src/extension/mod.rs b/src/extension/mod.rs new file mode 100644 index 0000000..f339dde --- /dev/null +++ b/src/extension/mod.rs @@ -0,0 +1 @@ +pub mod extension;
\ No newline at end of file diff --git a/src/instruction/instruction.rs b/src/instruction/instruction.rs new file mode 100644 index 0000000..2779023 --- /dev/null +++ b/src/instruction/instruction.rs @@ -0,0 +1,15 @@ +use crate::rv32_cpu::rv32_cpu::State; +use std::error::Error; +use std::fmt::Debug; + +#[derive(Debug, Clone, Hash, PartialEq, Eq)] +pub struct Opcode { + pub opcode6_2: u32, + pub opcode14_12: Option<u32>, + pub opcode31_27: Option<u32>, +} + +pub trait Instruction: Debug { + fn opcode(&self) -> Opcode; + fn execute(&self, instruction: u32, cpu: &mut State) -> Result<(), Box<dyn Error>>; +} diff --git a/src/instruction/mod.rs b/src/instruction/mod.rs new file mode 100644 index 0000000..bf06da5 --- /dev/null +++ b/src/instruction/mod.rs @@ -0,0 +1 @@ +pub mod instruction;
\ No newline at end of file diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..6fae7c0 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,30 @@ +mod rv32_cpu; +use rv32_cpu::rv32_cpu::Rv32Cpu; +mod instruction; +mod rv32i; +use rv32i::rv32i::Rv32i; +mod rv32m; +use rv32m::rv32m::Rv32m; +mod extension; +use std::error::Error; +use std::thread; + +const HART_CNT: usize = 4; + +fn main() -> Result<(), Box<dyn Error>> { + let mut handles = vec![]; + + for i in 0..HART_CNT { + let handle = thread::spawn(move || { + let mut cpu: Rv32Cpu = Rv32Cpu::new(i as u32).add_extension::<Rv32i>().add_extension::<Rv32m>(); + cpu.execute(0b00000000000000000001000000010011).unwrap(); + }); + handles.push(handle); + } + + for handle in handles { + handle.join().unwrap(); + } + + Ok(()) +}
\ No newline at end of file diff --git a/src/rv32_cpu/mod.rs b/src/rv32_cpu/mod.rs new file mode 100644 index 0000000..ec271da --- /dev/null +++ b/src/rv32_cpu/mod.rs @@ -0,0 +1 @@ +pub mod rv32_cpu;
\ No newline at end of file diff --git a/src/rv32_cpu/rv32_cpu.rs b/src/rv32_cpu/rv32_cpu.rs new file mode 100644 index 0000000..aefd1c0 --- /dev/null +++ b/src/rv32_cpu/rv32_cpu.rs @@ -0,0 +1,89 @@ +use std::collections::HashMap; +use std::error::Error; +use crate::instruction::instruction::{Instruction, Opcode}; +use crate::extension::extension::Extension; + +#[derive(Default)] +pub struct GPRegisters { + pub registers: [u32; 32] +} + +#[derive(Default)] +pub struct SMRegisters { + sie: u32, + stvec: u32, +} + +#[derive(Default)] +pub struct MMRegisters { + pub mie: u32, + pub mtvec: u32, + pub mepc: u32, + pub mcause: u32, + pub mhart: u32, +} + +#[derive(Default)] +pub struct State { + pub pc: u32, + pub gp_regs: GPRegisters, + pub sm_regs: SMRegisters, + pub mm_regs: MMRegisters, +} + +pub struct Rv32Cpu { + decoders: HashMap<Opcode, Box<dyn Instruction>>, + state: State, +} + +impl Rv32Cpu { + pub fn new(id: u32) -> Self { + let mut state = State::default(); + state.mm_regs.mhart = id; + Rv32Cpu { + decoders: HashMap::new(), + state + } + } + + pub fn add_extension<T: Extension>(mut self) -> Self { + T::add_instructions(&mut self); + self + } + + pub fn add_decode(&mut self, key: Opcode, instruction: Box<dyn Instruction>) { + self.decoders.insert(key, instruction); + } + + fn decode(decoders: &HashMap<Opcode, Box<dyn Instruction>>, instruction: u32) -> Result<&Box<dyn Instruction>, Box<dyn Error>> { + if instruction & 0x3 != 0x3 { + return Err("Invalid opcode".into()); + } + + let op: [u32; 3] = [(instruction >> 2) & 0x1F, (instruction >> 12) & 0x7, (instruction >> 27) & 0x7F]; + + let key3 = Opcode{opcode6_2: op[0], opcode14_12: Some(op[1]), opcode31_27: Some(op[2])}; + if let Some(x) = decoders.get(&key3) { + return Ok(x); + } + + let key2 = Opcode{opcode6_2: op[0], opcode14_12: Some(op[1]), opcode31_27: None}; + if let Some(x) = decoders.get(&key2) { + return Ok(x); + } + + let key1 = Opcode{opcode6_2: op[0], opcode14_12: None, opcode31_27: None}; + if let Some(x) = decoders.get(&key1) { + return Ok(x); + } + + Err("Invalid opcode".into()) + } + + pub fn execute(&mut self, instruction: u32) -> Result<(), Box<dyn Error>> { + let instr: &Box<dyn Instruction> = Self::decode(&self.decoders, instruction)?; + instr.execute(instruction, &mut self.state)?; + Ok(()) + } + +} diff --git a/src/rv32a/mod.rs b/src/rv32a/mod.rs new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/rv32a/mod.rs diff --git a/src/rv32i/mod.rs b/src/rv32i/mod.rs new file mode 100644 index 0000000..2fb36ce --- /dev/null +++ b/src/rv32i/mod.rs @@ -0,0 +1,2 @@ +pub mod rv32i; +pub mod slti;
\ No newline at end of file diff --git a/src/rv32i/rv32i.rs b/src/rv32i/rv32i.rs new file mode 100644 index 0000000..88826b2 --- /dev/null +++ b/src/rv32i/rv32i.rs @@ -0,0 +1,14 @@ +use crate::rv32_cpu::rv32_cpu::Rv32Cpu; +use crate::extension::extension::Extension; +use super::slti::Slti; +use crate::instruction::instruction::Instruction; + +pub struct Rv32i { +} + +impl Extension for Rv32i { + fn add_instructions(cpu: &mut Rv32Cpu) -> &mut Rv32Cpu { + cpu.add_decode(Slti.opcode(), Box::new(Slti)); + cpu + } +}
\ No newline at end of file diff --git a/src/rv32i/slti.rs b/src/rv32i/slti.rs new file mode 100644 index 0000000..09d166c --- /dev/null +++ b/src/rv32i/slti.rs @@ -0,0 +1,18 @@ +use crate::rv32_cpu::rv32_cpu::State; +use crate::instruction::instruction::{Instruction, Opcode}; + +#[derive(Debug)] +pub struct Slti; + +impl Instruction for Slti { + fn opcode(&self) -> Opcode { + Opcode { + opcode6_2: 0b00100, + opcode14_12: Some(0b001), + opcode31_27: Some(0b00000), + } + } + fn execute(&self, instruction: u32, state: &mut State) -> Result<(), Box<dyn std::error::Error>> { + Ok(()) + } +} diff --git a/src/rv32m/mod.rs b/src/rv32m/mod.rs new file mode 100644 index 0000000..cbf410d --- /dev/null +++ b/src/rv32m/mod.rs @@ -0,0 +1 @@ +pub mod rv32m;
\ No newline at end of file diff --git a/src/rv32m/rv32m.rs b/src/rv32m/rv32m.rs new file mode 100644 index 0000000..a931491 --- /dev/null +++ b/src/rv32m/rv32m.rs @@ -0,0 +1,11 @@ +use crate::rv32_cpu::rv32_cpu::Rv32Cpu; +use crate::extension::extension::Extension; + +pub struct Rv32m { +} + +impl Extension for Rv32m { + fn add_instructions(cpu: &mut Rv32Cpu) -> &mut Rv32Cpu { + cpu + } +}
\ No newline at end of file |
