mirror of
https://github.com/Noratrieb/rustv32i.git
synced 2026-01-14 21:35:02 +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
|
## Features
|
||||||
|
|
||||||
- [ ] Base RV32I instruction set
|
- [x] Base RV32I instruction set
|
||||||
- missing fence and pause
|
|
||||||
- [x] M standard extension
|
- [x] M standard extension
|
||||||
- [ ] A standard extension
|
- [ ] A standard extension
|
||||||
- [ ] F standard extension
|
- [ ] F standard extension
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ pub struct Elf {
|
||||||
pub content: Vec<u8>,
|
pub content: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(dead_code)]
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Header {
|
pub struct Header {
|
||||||
pub e_entry: u32,
|
pub e_entry: u32,
|
||||||
|
|
@ -19,7 +18,6 @@ pub struct Header {
|
||||||
pub e_shstrndx: u16,
|
pub e_shstrndx: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(dead_code)]
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Phdr {
|
pub struct Phdr {
|
||||||
pub p_type: u32,
|
pub p_type: u32,
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,6 @@ impl Memory {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[expect(dead_code)]
|
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
Trap(&'static str),
|
Trap(&'static str),
|
||||||
IllegalInstruction(InstCode, &'static str),
|
IllegalInstruction(InstCode, &'static str),
|
||||||
|
|
@ -109,7 +108,6 @@ impl IndexMut<Reg> for Emulator {
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct Reg(pub u32);
|
pub struct Reg(pub u32);
|
||||||
|
|
||||||
#[expect(dead_code)]
|
|
||||||
impl Reg {
|
impl Reg {
|
||||||
pub const RA: Reg = Reg(1);
|
pub const RA: Reg = Reg(1);
|
||||||
pub const SP: Reg = Reg(2);
|
pub const SP: Reg = Reg(2);
|
||||||
|
|
@ -307,6 +305,7 @@ impl Emulator {
|
||||||
}
|
}
|
||||||
Inst::Or { dest, src1, src2 } => self[dest] = self[src1] | self[src2],
|
Inst::Or { dest, src1, src2 } => self[dest] = self[src1] | self[src2],
|
||||||
Inst::And { 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 => {
|
Inst::Ecall => {
|
||||||
(self.ecall_handler)(&mut self.mem, &mut self.xreg)?;
|
(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::fmt::{Debug, Display};
|
||||||
use std::ops::RangeInclusive;
|
use std::ops::RangeInclusive;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
pub enum Inst {
|
pub enum Inst {
|
||||||
Lui { uimm: u32, dest: Reg },
|
Lui { uimm: u32, dest: Reg },
|
||||||
Auipc { uimm: u32, dest: Reg },
|
Auipc { uimm: u32, dest: Reg },
|
||||||
|
|
@ -47,6 +48,8 @@ pub enum Inst {
|
||||||
Or { dest: Reg, src1: Reg, src2: Reg },
|
Or { dest: Reg, src1: Reg, src2: Reg },
|
||||||
And { dest: Reg, src1: Reg, src2: Reg },
|
And { dest: Reg, src1: Reg, src2: Reg },
|
||||||
|
|
||||||
|
Fence { fence: Fence },
|
||||||
|
|
||||||
Ecall,
|
Ecall,
|
||||||
Ebreak,
|
Ebreak,
|
||||||
|
|
||||||
|
|
@ -61,6 +64,23 @@ pub enum Inst {
|
||||||
Remu { dest: Reg, src1: Reg, src2: Reg },
|
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 {
|
impl Debug for Inst {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
Display::fmt(&self, f)
|
Display::fmt(&self, f)
|
||||||
|
|
@ -162,6 +182,28 @@ impl Display for Inst {
|
||||||
Inst::Sra { dest, src1, src2 } => write!(f, "sra {dest}, {src1}, {src2}"),
|
Inst::Sra { dest, src1, src2 } => write!(f, "sra {dest}, {src1}, {src2}"),
|
||||||
Inst::Or { dest, src1, src2 } => write!(f, "or {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::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::Ecall => write!(f, "ecall"),
|
||||||
Inst::Ebreak => write!(f, "ebreak"),
|
Inst::Ebreak => write!(f, "ebreak"),
|
||||||
Inst::Mul { dest, src1, src2 } => write!(f, "mul {dest}, {src1}, {src2}"),
|
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 {
|
fn sign_extend(value: u32, size: u32) -> u32 {
|
||||||
assert!(size <= u32::BITS);
|
assert!(size <= u32::BITS);
|
||||||
let sign = value >> (size - 1);
|
let sign = value >> (size - 1);
|
||||||
|
|
@ -439,6 +499,35 @@ impl Inst {
|
||||||
_ => return Err(Error::IllegalInstruction(code, "funct3/funct7")),
|
_ => 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
|
// SYSTEM
|
||||||
0b1110011 => {
|
0b1110011 => {
|
||||||
if code.0 == 0b11000000000000000001000001110011 {
|
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};
|
use eyre::{OptionExt, bail, eyre};
|
||||||
|
use rustv32i::{
|
||||||
mod elf;
|
elf,
|
||||||
mod emu;
|
emu::{self, Memory, Reg},
|
||||||
mod inst;
|
};
|
||||||
|
|
||||||
// 2 MiB
|
// 2 MiB
|
||||||
const MEMORY_SIZE: usize = 2 << 21;
|
const MEMORY_SIZE: usize = 2 << 21;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue