mirror of
https://github.com/Noratrieb/rustv32i.git
synced 2026-01-14 13:25:01 +01:00
A
This commit is contained in:
parent
105706e862
commit
ca565ddeb3
5 changed files with 208 additions and 4 deletions
|
|
@ -6,9 +6,9 @@ A small RISC-V emulator written in Rust.
|
|||
|
||||
- [x] Base RV32I instruction set
|
||||
- [x] M standard extension
|
||||
- [ ] A standard extension
|
||||
- [ ] Zalrsc standard extension
|
||||
- [ ] Zaamo standard extension
|
||||
- [x] A standard extension
|
||||
- [x] Zalrsc standard extension
|
||||
- [x] Zaamo standard extension
|
||||
- [ ] F standard extension
|
||||
- [ ] D standard extension
|
||||
- [ ] C standard extension
|
||||
|
|
|
|||
51
src/emu.rs
51
src/emu.rs
|
|
@ -1,4 +1,4 @@
|
|||
use crate::inst::{Inst, InstCode};
|
||||
use crate::inst::{AmoOp, Inst, InstCode};
|
||||
use std::{
|
||||
fmt::{Debug, Display},
|
||||
ops::{Index, IndexMut},
|
||||
|
|
@ -82,6 +82,9 @@ pub struct Emulator {
|
|||
/// Written to insterad of xreg[0].
|
||||
pub xreg0_value: u32,
|
||||
pub pc: u32,
|
||||
/// We need to store the most recent reservation set for LR/SC
|
||||
/// to make SC fail if it's not to this address.
|
||||
pub reservation_set: Option<u32>,
|
||||
|
||||
pub debug: bool,
|
||||
|
||||
|
|
@ -356,6 +359,52 @@ impl Emulator {
|
|||
self[dest] = self[src1] % self[src2];
|
||||
}
|
||||
}
|
||||
Inst::AmoW {
|
||||
order: _,
|
||||
op,
|
||||
dest,
|
||||
addr,
|
||||
src,
|
||||
} => {
|
||||
let addr = self[addr];
|
||||
self[dest] = self.mem.load_u32(addr)?;
|
||||
let result = match op {
|
||||
AmoOp::Swap => self[src],
|
||||
AmoOp::Add => self[dest].wrapping_add(self[src]),
|
||||
AmoOp::Xor => self[dest] ^ self[src],
|
||||
AmoOp::And => self[dest] & self[src],
|
||||
AmoOp::Or => self[dest] | self[src],
|
||||
AmoOp::Min => (self[dest] as i32).min(self[src] as i32) as u32,
|
||||
AmoOp::Max => (self[dest] as i32).max(self[src] as i32) as u32,
|
||||
AmoOp::Minu => self[dest].min(self[src]),
|
||||
AmoOp::Maxu => self[dest].max(self[src]),
|
||||
};
|
||||
self.mem.store_u32(addr, result)?;
|
||||
}
|
||||
Inst::LrW {
|
||||
order: _,
|
||||
dest,
|
||||
addr,
|
||||
} => {
|
||||
let addr = self[addr];
|
||||
self[dest] = self.mem.load_u32(addr)?;
|
||||
self.reservation_set = Some(addr);
|
||||
}
|
||||
Inst::ScW {
|
||||
order: _,
|
||||
dest,
|
||||
addr,
|
||||
src,
|
||||
} => {
|
||||
let addr = self[addr];
|
||||
self.mem.store_u32(addr, self[src])?;
|
||||
if self.reservation_set != Some(addr) {
|
||||
self[dest] = 1; // error
|
||||
} else {
|
||||
self[dest] = 0; // success
|
||||
}
|
||||
self.reservation_set = None;
|
||||
}
|
||||
}
|
||||
|
||||
if !jumped {
|
||||
|
|
|
|||
151
src/inst.rs
151
src/inst.rs
|
|
@ -3,6 +3,7 @@ use std::fmt::{Debug, Display};
|
|||
use std::ops::RangeInclusive;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[rustfmt::skip]
|
||||
pub enum Inst {
|
||||
Lui { uimm: u32, dest: Reg },
|
||||
Auipc { uimm: u32, dest: Reg },
|
||||
|
|
@ -62,6 +63,26 @@ pub enum Inst {
|
|||
Divu { dest: Reg, src1: Reg, src2: Reg },
|
||||
Rem { dest: Reg, src1: Reg, src2: Reg },
|
||||
Remu { dest: Reg, src1: Reg, src2: Reg },
|
||||
|
||||
// A
|
||||
LrW {
|
||||
order: AmoOrdering,
|
||||
dest: Reg,
|
||||
addr: Reg,
|
||||
},
|
||||
ScW {
|
||||
order: AmoOrdering,
|
||||
dest: Reg,
|
||||
addr: Reg,
|
||||
src: Reg,
|
||||
},
|
||||
AmoW {
|
||||
order: AmoOrdering,
|
||||
op: AmoOp,
|
||||
dest: Reg,
|
||||
addr: Reg,
|
||||
src: Reg,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
|
|
@ -81,6 +102,27 @@ pub struct FenceSet {
|
|||
pub memory_write: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum AmoOrdering {
|
||||
Relaxed,
|
||||
Acquire,
|
||||
Release,
|
||||
SeqCst,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum AmoOp {
|
||||
Swap,
|
||||
Add,
|
||||
Xor,
|
||||
And,
|
||||
Or,
|
||||
Min,
|
||||
Max,
|
||||
Minu,
|
||||
Maxu,
|
||||
}
|
||||
|
||||
impl Fence {
|
||||
pub fn is_pause(&self) -> bool {
|
||||
self.pred
|
||||
|
|
@ -102,11 +144,23 @@ impl Fence {
|
|||
}
|
||||
}
|
||||
|
||||
impl AmoOrdering {
|
||||
pub fn from_ac_rl(ac: bool, rl: bool) -> Self {
|
||||
match (ac, rl) {
|
||||
(false, false) => Self::Relaxed,
|
||||
(true, false) => Self::Acquire,
|
||||
(false, true) => Self::Release,
|
||||
(true, true) => Self::SeqCst,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Inst {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
Display::fmt(&self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Inst {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match *self {
|
||||
|
|
@ -220,6 +274,20 @@ impl Display for Inst {
|
|||
Inst::Divu { dest, src1, src2 } => write!(f, "divu {dest}, {src1}, {src2}"),
|
||||
Inst::Rem { dest, src1, src2 } => write!(f, "rem {dest}, {src1}, {src2}"),
|
||||
Inst::Remu { dest, src1, src2 } => write!(f, "remu {dest}, {src1}, {src2}"),
|
||||
Inst::LrW { order, dest, addr } => write!(f, "lr.w{order} {dest}, ({addr})",),
|
||||
Inst::ScW {
|
||||
order,
|
||||
dest,
|
||||
addr,
|
||||
src,
|
||||
} => write!(f, "sc.w{order} {dest}, {src}, ({addr})"),
|
||||
Inst::AmoW {
|
||||
order,
|
||||
op,
|
||||
dest,
|
||||
addr,
|
||||
src,
|
||||
} => write!(f, "am{op}.w{order} {dest}, {src}, ({addr})",),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -242,6 +310,33 @@ impl Display for FenceSet {
|
|||
}
|
||||
}
|
||||
|
||||
impl Display for AmoOrdering {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
AmoOrdering::Relaxed => write!(f, ""),
|
||||
AmoOrdering::Acquire => write!(f, ".ac"),
|
||||
AmoOrdering::Release => write!(f, ".rl"),
|
||||
AmoOrdering::SeqCst => write!(f, ".acrl"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for AmoOp {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
AmoOp::Swap => write!(f, "swap"),
|
||||
AmoOp::Add => write!(f, "add"),
|
||||
AmoOp::Xor => write!(f, "xor"),
|
||||
AmoOp::And => write!(f, "and"),
|
||||
AmoOp::Or => write!(f, "or"),
|
||||
AmoOp::Min => write!(f, "min"),
|
||||
AmoOp::Max => write!(f, "max"),
|
||||
AmoOp::Minu => write!(f, "minu"),
|
||||
AmoOp::Maxu => write!(f, "maxu"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn sign_extend(value: u32, size: u32) -> u32 {
|
||||
assert!(size <= u32::BITS);
|
||||
let sign = value >> (size - 1);
|
||||
|
|
@ -554,6 +649,62 @@ impl Inst {
|
|||
_ => return Err(Error::IllegalInstruction(code, "imm")),
|
||||
}
|
||||
}
|
||||
// AMO
|
||||
00101111 => {
|
||||
// width must be W
|
||||
if code.funct3() != 0b010 {
|
||||
return Err(Error::IllegalInstruction(code, "funct3"));
|
||||
}
|
||||
|
||||
let kind = code.extract(27..=31);
|
||||
let ac = code.extract(26..=26) == 1;
|
||||
let rl = code.extract(25..=25) == 1;
|
||||
|
||||
let order = AmoOrdering::from_ac_rl(ac, rl);
|
||||
|
||||
match kind {
|
||||
// LR
|
||||
0b00010 => {
|
||||
if code.rs2().0 != 0 {
|
||||
return Err(Error::IllegalInstruction(code, "rs2"));
|
||||
}
|
||||
|
||||
Inst::LrW {
|
||||
order,
|
||||
dest: code.rd(),
|
||||
addr: code.rs1(),
|
||||
}
|
||||
}
|
||||
// SC
|
||||
0b00011 => Inst::ScW {
|
||||
order,
|
||||
dest: code.rd(),
|
||||
addr: code.rs1(),
|
||||
src: code.rs2(),
|
||||
},
|
||||
_ => {
|
||||
let op = match kind {
|
||||
0b00001 => AmoOp::Swap,
|
||||
0b00000 => AmoOp::Add,
|
||||
0b00100 => AmoOp::Xor,
|
||||
0b01100 => AmoOp::And,
|
||||
0b01000 => AmoOp::Or,
|
||||
0b10000 => AmoOp::Min,
|
||||
0b10100 => AmoOp::Max,
|
||||
0b11000 => AmoOp::Minu,
|
||||
0b11100 => AmoOp::Maxu,
|
||||
_ => return Err(Error::IllegalInstruction(code, "funct7")),
|
||||
};
|
||||
Inst::AmoW {
|
||||
order,
|
||||
op,
|
||||
dest: code.rd(),
|
||||
addr: code.rs1(),
|
||||
src: code.rs2(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => return Err(Error::IllegalInstruction(code, "opcode")),
|
||||
};
|
||||
Ok(inst)
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ fn main() -> eyre::Result<()> {
|
|||
xreg: [0; 32],
|
||||
xreg0_value: 0,
|
||||
pc: start,
|
||||
reservation_set: None,
|
||||
|
||||
debug: std::env::args().any(|arg| arg == "--debug"),
|
||||
|
||||
|
|
|
|||
|
|
@ -98,6 +98,9 @@ fn input() -> u64 {
|
|||
fn _start() -> ! {
|
||||
let random_number = 45;
|
||||
|
||||
let num = core::sync::atomic::AtomicI32::new(0);
|
||||
num.swap(10, core::sync::atomic::Ordering::SeqCst);
|
||||
|
||||
loop {
|
||||
let n = input();
|
||||
if n == random_number {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue