summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Cargo.lock7
-rw-r--r--Cargo.toml6
-rw-r--r--src/extension/extension.rs5
-rw-r--r--src/extension/mod.rs1
-rw-r--r--src/instruction/instruction.rs15
-rw-r--r--src/instruction/mod.rs1
-rw-r--r--src/main.rs30
-rw-r--r--src/rv32_cpu/mod.rs1
-rw-r--r--src/rv32_cpu/rv32_cpu.rs89
-rw-r--r--src/rv32a/mod.rs0
-rw-r--r--src/rv32i/mod.rs2
-rw-r--r--src/rv32i/rv32i.rs14
-rw-r--r--src/rv32i/slti.rs18
-rw-r--r--src/rv32m/mod.rs1
-rw-r--r--src/rv32m/rv32m.rs11
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