mirror of
https://github.com/Noratrieb/rustv32i.git
synced 2026-01-14 13:25:01 +01:00
finish base
This commit is contained in:
parent
7026e5c1b8
commit
b8d9f28059
6 changed files with 98 additions and 11 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ pub struct Elf {
|
|||
pub content: Vec<u8>,
|
||||
}
|
||||
|
||||
#[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,
|
||||
|
|
|
|||
|
|
@ -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<Reg> 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)?;
|
||||
}
|
||||
|
|
|
|||
89
src/inst.rs
89
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 {
|
||||
|
|
|
|||
3
src/lib.rs
Normal file
3
src/lib.rs
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
pub mod elf;
|
||||
pub mod emu;
|
||||
pub mod inst;
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue