From b8d9f28059de4ffa6eaa9cebb91b77dce63a0568 Mon Sep 17 00:00:00 2001 From: Noratrieb <48135649+Noratrieb@users.noreply.github.com> Date: Sun, 9 Mar 2025 14:46:50 +0100 Subject: [PATCH] finish base --- README.md | 3 +- src/elf.rs | 2 -- src/emu.rs | 3 +- src/inst.rs | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 3 ++ src/main.rs | 9 +++--- 6 files changed, 98 insertions(+), 11 deletions(-) create mode 100644 src/lib.rs diff --git a/README.md b/README.md index 0797992..d07b26e 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,7 @@ A small RISC-V emulator written in Rust. ## Features -- [ ] Base RV32I instruction set - - missing fence and pause +- [x] Base RV32I instruction set - [x] M standard extension - [ ] A standard extension - [ ] F standard extension diff --git a/src/elf.rs b/src/elf.rs index cb6767c..5d9eb3b 100644 --- a/src/elf.rs +++ b/src/elf.rs @@ -4,7 +4,6 @@ pub struct Elf { pub content: Vec, } -#[expect(dead_code)] #[derive(Debug)] pub struct Header { pub e_entry: u32, @@ -19,7 +18,6 @@ pub struct Header { pub e_shstrndx: u16, } -#[expect(dead_code)] #[derive(Debug)] pub struct Phdr { pub p_type: u32, diff --git a/src/emu.rs b/src/emu.rs index 362ece6..8bed9b9 100644 --- a/src/emu.rs +++ b/src/emu.rs @@ -66,7 +66,6 @@ impl Memory { } #[derive(Debug)] -#[expect(dead_code)] pub enum Error { Trap(&'static str), IllegalInstruction(InstCode, &'static str), @@ -109,7 +108,6 @@ impl IndexMut for Emulator { #[derive(Clone, Copy)] pub struct Reg(pub u32); -#[expect(dead_code)] impl Reg { pub const RA: Reg = Reg(1); pub const SP: Reg = Reg(2); @@ -307,6 +305,7 @@ impl Emulator { } Inst::Or { dest, src1, src2 } => self[dest] = self[src1] | self[src2], Inst::And { dest, src1, src2 } => self[dest] = self[src1] & self[src2], + Inst::Fence { fence: _ } => { /* dont care */ } Inst::Ecall => { (self.ecall_handler)(&mut self.mem, &mut self.xreg)?; } diff --git a/src/inst.rs b/src/inst.rs index 6dcbea8..6b525f0 100644 --- a/src/inst.rs +++ b/src/inst.rs @@ -2,6 +2,7 @@ use crate::emu::{Error, Reg}; use std::fmt::{Debug, Display}; use std::ops::RangeInclusive; +#[derive(Clone, Copy)] pub enum Inst { Lui { uimm: u32, dest: Reg }, Auipc { uimm: u32, dest: Reg }, @@ -47,6 +48,8 @@ pub enum Inst { Or { dest: Reg, src1: Reg, src2: Reg }, And { dest: Reg, src1: Reg, src2: Reg }, + Fence { fence: Fence }, + Ecall, Ebreak, @@ -61,6 +64,23 @@ pub enum Inst { Remu { dest: Reg, src1: Reg, src2: Reg }, } +#[derive(Clone, Copy)] +pub struct Fence { + pub fm: u32, + pub pred: FenceSet, + pub succ: FenceSet, + pub dest: Reg, + pub src: Reg, +} + +#[derive(Clone, Copy, PartialEq, Eq)] +pub struct FenceSet { + pub device_input: bool, + pub device_output: bool, + pub memory_read: bool, + pub memory_write: bool, +} + impl Debug for Inst { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { Display::fmt(&self, f) @@ -162,6 +182,28 @@ impl Display for Inst { Inst::Sra { dest, src1, src2 } => write!(f, "sra {dest}, {src1}, {src2}"), Inst::Or { dest, src1, src2 } => write!(f, "or {dest}, {src1}, {src2}"), Inst::And { dest, src1, src2 } => write!(f, "and {dest}, {src1}, {src2}"), + Inst::Fence { fence } => match fence.fm { + 0b1000 => write!(f, "fence.TSO"), + 0b0000 + if fence.pred + == FenceSet { + device_input: false, + device_output: false, + memory_read: false, + memory_write: true, + } + && fence.succ + == FenceSet { + device_input: false, + device_output: false, + memory_read: false, + memory_write: false, + } => + { + write!(f, "pause") + } + _ => write!(f, "fence {},{}", fence.pred, fence.succ), + }, Inst::Ecall => write!(f, "ecall"), Inst::Ebreak => write!(f, "ebreak"), Inst::Mul { dest, src1, src2 } => write!(f, "mul {dest}, {src1}, {src2}"), @@ -176,6 +218,24 @@ impl Display for Inst { } } +impl Display for FenceSet { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + if self.device_input { + write!(f, "i")?; + } + if self.device_output { + write!(f, "o")?; + } + if self.memory_read { + write!(f, "r")?; + } + if self.memory_write { + write!(f, "w")?; + } + Ok(()) + } +} + fn sign_extend(value: u32, size: u32) -> u32 { assert!(size <= u32::BITS); let sign = value >> (size - 1); @@ -439,6 +499,35 @@ impl Inst { _ => return Err(Error::IllegalInstruction(code, "funct3/funct7")), } } + // MISC-MEM + 0b0001111 => { + let fm = code.extract(28..=31); + let pred = FenceSet { + device_input: code.extract(27..=27) == 1, + device_output: code.extract(26..=26) == 1, + memory_read: code.extract(25..=25) == 1, + memory_write: code.extract(24..=24) == 1, + }; + let succ = FenceSet { + device_input: code.extract(23..=23) == 1, + device_output: code.extract(22..=22) == 1, + memory_read: code.extract(21..=21) == 1, + memory_write: code.extract(20..=20) == 1, + }; + + match code.funct3() { + 0b000 => Inst::Fence { + fence: Fence { + fm, + pred, + succ, + dest: code.rd(), + src: code.rs1(), + }, + }, + _ => return Err(Error::IllegalInstruction(code, "funct3")), + } + } // SYSTEM 0b1110011 => { if code.0 == 0b11000000000000000001000001110011 { diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..07e05b5 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,3 @@ +pub mod elf; +pub mod emu; +pub mod inst; diff --git a/src/main.rs b/src/main.rs index 9d82d94..bf27ed3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,8 @@ -use emu::{Memory, Reg}; use eyre::{OptionExt, bail, eyre}; - -mod elf; -mod emu; -mod inst; +use rustv32i::{ + elf, + emu::{self, Memory, Reg}, +}; // 2 MiB const MEMORY_SIZE: usize = 2 << 21;