summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/consts.rs4
-rw-r--r--src/core.rs58
-rw-r--r--src/decode.rs67
-rw-r--r--src/lib.rs2
4 files changed, 130 insertions, 1 deletions
diff --git a/src/consts.rs b/src/consts.rs
index a3e33a2..1e52c92 100644
--- a/src/consts.rs
+++ b/src/consts.rs
@@ -3,5 +3,7 @@ pub type HWord = u16;
pub type Word = u32;
pub type DWord = u64;
-pub type Reg = DWord;
+pub type RegValue = DWord;
pub type Addr = DWord;
+
+pub type RegId = u8;
diff --git a/src/core.rs b/src/core.rs
new file mode 100644
index 0000000..48668b5
--- /dev/null
+++ b/src/core.rs
@@ -0,0 +1,58 @@
+use crate::{
+ consts::{Addr, RegId, RegValue},
+ mem::MemConfig,
+};
+
+#[derive(PartialEq, Debug, Clone, Copy)]
+pub enum ExecutionStatus {
+ Running,
+ Paused,
+ Halted,
+}
+
+pub struct Core {
+ x_regs: [RegValue; 32],
+ pc: Addr,
+ mem: MemConfig,
+ exec_status: ExecutionStatus,
+}
+
+impl Core {
+ pub fn new(mem: MemConfig) -> Self {
+ Self {
+ x_regs: [0; 32],
+ pc: 0,
+ mem,
+ exec_status: ExecutionStatus::Halted,
+ }
+ }
+
+ pub fn reset(&mut self, pc: Addr) {
+ self.pc = pc;
+ self.exec_status = ExecutionStatus::Running;
+ }
+
+ pub fn resume(&mut self) -> ExecutionStatus {
+ if self.exec_status == ExecutionStatus::Halted {
+ ExecutionStatus::Halted
+ } else {
+ self.exec_status = ExecutionStatus::Running;
+ ExecutionStatus::Running
+ }
+ }
+
+ pub fn exec_status(&self) -> ExecutionStatus {
+ self.exec_status
+ }
+
+ fn reg_read(&self, id: RegId) -> RegValue {
+ self.x_regs[id as usize]
+ }
+
+ fn reg_write(&mut self, id: RegId, value: RegValue) {
+ if id == 0 {
+ return;
+ }
+ self.x_regs[id as usize] = value;
+ }
+}
diff --git a/src/decode.rs b/src/decode.rs
new file mode 100644
index 0000000..0da4513
--- /dev/null
+++ b/src/decode.rs
@@ -0,0 +1,67 @@
+use crate::consts::{DWord, RegId, Word};
+
+const MASK_REGISTER: Word = 0x1f;
+
+pub struct Instruction(pub Word);
+
+impl Instruction {
+ pub fn opcode(&self) -> u8 {
+ (self.0 & 0x7f) as u8
+ }
+
+ /// Returns the opcode of the instruction, with the last 2 bits stripped away, as they are always 0b11 in a non-compressed instruction
+ pub fn opcode_noncompressed(&self) -> u8 {
+ debug_assert_eq!(self.0 & 0b11, 0b11);
+ (self.0 >> 2 & 0x1f) as u8
+ }
+
+ pub fn rd(&self) -> RegId {
+ (self.0 >> 7 & MASK_REGISTER) as RegId
+ }
+
+ pub fn funct3(&self) -> u8 {
+ (self.0 >> 12 & 0x7) as u8
+ }
+
+ pub fn rs1(&self) -> RegId {
+ (self.0 >> 15 & MASK_REGISTER) as RegId
+ }
+
+ pub fn rs2(&self) -> RegId {
+ (self.0 >> 20 & MASK_REGISTER) as RegId
+ }
+
+ pub fn funct7(&self) -> u8 {
+ (self.0 >> 25 & 0x7f) as u8
+ }
+
+ pub fn imm_i(&self) -> DWord {
+ (self.0 as i64 >> 20) as DWord
+ }
+
+ pub fn imm_s(&self) -> DWord {
+ (self.0 as i64 >> (25 - 5) & (0x7f << 5)) as DWord | (self.0 >> 7 & 0b1111) as DWord
+ }
+
+ pub fn imm_b(&self) -> DWord {
+ let imm_12 = ((self.0 & 0x8000_0000) as i32 as i64 >> (31 - 12)) as DWord;
+ let imm_10_5 = ((self.0 >> 25 & 0x3f) << 5) as DWord;
+ let imm_4_1 = ((self.0 >> 8 & 0xf) << 1) as DWord;
+ let imm_11 = ((self.0 >> 7 & 1) << 11) as DWord;
+
+ imm_12 | imm_10_5 | imm_4_1 | imm_11
+ }
+
+ pub fn imm_u(&self) -> DWord {
+ (self.0 & 0xffff_f000) as i32 as i64 as DWord
+ }
+
+ pub fn imm_j(&self) -> DWord {
+ let imm_20 = ((self.0 & 0x8000_0000) as i32 as i64 >> (31 - 20)) as DWord;
+ let imm_10_1 = ((self.0 >> 21 & 0x3ff) << 1) as DWord;
+ let imm_11 = ((self.0 >> 20 & 1) << 11) as DWord;
+ let imm_19_12 = ((self.0 >> 12 & 0xff) << 12) as DWord;
+
+ imm_20 | imm_10_1 | imm_11 | imm_19_12
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 8484460..4020af3 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,2 +1,4 @@
mod consts;
+pub mod core;
+mod decode;
pub mod mem;