mirror of
https://github.com/Noratrieb/rustv32i.git
synced 2026-01-14 13:25:01 +01:00
This commit is contained in:
parent
92dc3cb349
commit
78aa1e8d75
4 changed files with 202 additions and 116 deletions
|
|
@ -1,3 +1,8 @@
|
||||||
|
## 2.0.0
|
||||||
|
|
||||||
|
- BREAKING CHANGE: Make `Inst` `#[non_exhaustive]`
|
||||||
|
- BREAKING CHANGE: Change immediate fields in `Inst` to `Imm`
|
||||||
|
|
||||||
## 0.1.1
|
## 0.1.1
|
||||||
|
|
||||||
- Add `Fence::is_tso`
|
- Add `Fence::is_tso`
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,9 @@ The main function is [`Inst::decode`], which will decode an instruction into the
|
||||||
The [`core::fmt::Display`] impl of [`Inst`] provides disassembly functionality
|
The [`core::fmt::Display`] impl of [`Inst`] provides disassembly functionality
|
||||||
(note that the precise output of that implementation is not considered stable).
|
(note that the precise output of that implementation is not considered stable).
|
||||||
|
|
||||||
# Register size support
|
# XLEN (Register size) support
|
||||||
|
|
||||||
|
RISC-V calls the parameter of the instruction size `XLEN`, and this crate refers to it as such.
|
||||||
|
|
||||||
This crate currenly only supports RV32 instructions.
|
This crate currenly only supports RV32 instructions.
|
||||||
RV64 instructions that are the same between versions will still be decoded successfully, but the user
|
RV64 instructions that are the same between versions will still be decoded successfully, but the user
|
||||||
|
|
@ -13,7 +15,7 @@ has to be careful around sign-extended immediates to preserve the correct value
|
||||||
RV64-specific instructions are not yet implemented, but will be in the future.
|
RV64-specific instructions are not yet implemented, but will be in the future.
|
||||||
The immediates will also be switched to `u64` in the future to allow for easier usage of RV64.
|
The immediates will also be switched to `u64` in the future to allow for easier usage of RV64.
|
||||||
|
|
||||||
RV128 is not intended to be supported.
|
RV128 is currently not intended to be supported.
|
||||||
|
|
||||||
# Extension support
|
# Extension support
|
||||||
|
|
||||||
|
|
@ -34,7 +36,7 @@ More extensions may be implemented in the future.
|
||||||
```rust
|
```rust
|
||||||
// addi sp, sp, -0x20 (compressed)
|
// addi sp, sp, -0x20 (compressed)
|
||||||
let x = 0x1101_u32;
|
let x = 0x1101_u32;
|
||||||
let expected = rvdc::Inst::Addi { imm: (-0x20_i32) as u32, dest: rvdc::Reg::SP, src1: rvdc::Reg::SP };
|
let expected = rvdc::Inst::Addi { imm: rvdc::Imm::new_i32(-0x20), dest: rvdc::Reg::SP, src1: rvdc::Reg::SP };
|
||||||
|
|
||||||
let (inst, is_compressed) = rvdc::Inst::decode(x).unwrap();
|
let (inst, is_compressed) = rvdc::Inst::decode(x).unwrap();
|
||||||
assert_eq!(inst, expected);
|
assert_eq!(inst, expected);
|
||||||
|
|
@ -45,7 +47,7 @@ assert_eq!(format!("{inst}"), "addi sp, sp, -32")
|
||||||
```rust
|
```rust
|
||||||
// auipc t1, 0xa
|
// auipc t1, 0xa
|
||||||
let x = 0x0000a317;
|
let x = 0x0000a317;
|
||||||
let expected = rvdc::Inst::Auipc { uimm: 0xa << 12, dest: rvdc::Reg::T1 };
|
let expected = rvdc::Inst::Auipc { uimm: rvdc::Imm::new_u32(0xa << 12), dest: rvdc::Reg::T1 };
|
||||||
|
|
||||||
let (inst, is_compressed) = rvdc::Inst::decode(x).unwrap();
|
let (inst, is_compressed) = rvdc::Inst::decode(x).unwrap();
|
||||||
assert_eq!(inst, expected);
|
assert_eq!(inst, expected);
|
||||||
|
|
|
||||||
241
rvdc/src/lib.rs
241
rvdc/src/lib.rs
|
|
@ -102,6 +102,65 @@ impl Display for Reg {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An immediate in an instruction.
|
||||||
|
/// This represents the real value that will be put in the register,
|
||||||
|
/// so sign extension has been performed if necessary, and for instructions
|
||||||
|
/// like `lui` the value will have been shifted.
|
||||||
|
///
|
||||||
|
/// This type is XLEN-agnostic, use the XLEN-specific accessors to get the correct value.
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct Imm(u32);
|
||||||
|
|
||||||
|
impl Imm {
|
||||||
|
/// The immediate `0`.
|
||||||
|
/// Useful as a shortcut for `Imm::new_u32(0)` and for patterns.
|
||||||
|
pub const ZERO: Self = Self::new_u32(0);
|
||||||
|
|
||||||
|
/// Create a new immediate from the (if necessary) sign-extended value.
|
||||||
|
pub const fn new_i32(value: i32) -> Self {
|
||||||
|
Self(value as u32)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new immediate from the (if necessary) zero-extended value.
|
||||||
|
pub const fn new_u32(value: u32) -> Self {
|
||||||
|
Self(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the `u32` (RV32) value of the immediate.
|
||||||
|
pub const fn as_u32(self) -> u32 {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the `i32` (RV32) value of the immediate.
|
||||||
|
pub const fn as_i32(self) -> i32 {
|
||||||
|
self.0 as i32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<i32> for Imm {
|
||||||
|
fn from(value: i32) -> Self {
|
||||||
|
Self::new_i32(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<u32> for Imm {
|
||||||
|
fn from(value: u32) -> Self {
|
||||||
|
Self::new_u32(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Imm> for u32 {
|
||||||
|
fn from(value: Imm) -> Self {
|
||||||
|
value.as_u32()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Imm> for i32 {
|
||||||
|
fn from(value: Imm) -> Self {
|
||||||
|
value.as_i32()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A RISC-V instruction.
|
/// A RISC-V instruction.
|
||||||
///
|
///
|
||||||
/// Every variant is a different instruction, with immediates as `u32`.
|
/// Every variant is a different instruction, with immediates as `u32`.
|
||||||
|
|
@ -112,66 +171,67 @@ impl Display for Reg {
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
#[expect(missing_docs)] // enum variant fields
|
#[expect(missing_docs)] // enum variant fields
|
||||||
|
#[non_exhaustive]
|
||||||
pub enum Inst {
|
pub enum Inst {
|
||||||
/// Load Upper Immediate
|
/// Load Upper Immediate
|
||||||
Lui { uimm: u32, dest: Reg },
|
Lui { uimm: Imm, dest: Reg },
|
||||||
/// Add Upper Immediate to PC
|
/// Add Upper Immediate to PC
|
||||||
Auipc { uimm: u32, dest: Reg },
|
Auipc { uimm: Imm, dest: Reg },
|
||||||
|
|
||||||
/// Jump And Link
|
/// Jump And Link
|
||||||
Jal { offset: u32, dest: Reg },
|
Jal { offset: Imm, dest: Reg },
|
||||||
/// Jump And Link Register (indirect)
|
/// Jump And Link Register (indirect)
|
||||||
Jalr { offset: u32, base: Reg, dest: Reg },
|
Jalr { offset: Imm, base: Reg, dest: Reg },
|
||||||
|
|
||||||
/// Branch Equal
|
/// Branch Equal
|
||||||
Beq { offset: u32, src1: Reg, src2: Reg },
|
Beq { offset: Imm, src1: Reg, src2: Reg },
|
||||||
/// Branch Not Equal
|
/// Branch Not Equal
|
||||||
Bne { offset: u32, src1: Reg, src2: Reg },
|
Bne { offset: Imm, src1: Reg, src2: Reg },
|
||||||
/// Branch Less Than (signed)
|
/// Branch Less Than (signed)
|
||||||
Blt { offset: u32, src1: Reg, src2: Reg },
|
Blt { offset: Imm, src1: Reg, src2: Reg },
|
||||||
/// Branch Greater or Equal (signed)
|
/// Branch Greater or Equal (signed)
|
||||||
Bge { offset: u32, src1: Reg, src2: Reg },
|
Bge { offset: Imm, src1: Reg, src2: Reg },
|
||||||
/// Branch Less Than Unsigned
|
/// Branch Less Than Unsigned
|
||||||
Bltu { offset: u32, src1: Reg, src2: Reg },
|
Bltu { offset: Imm, src1: Reg, src2: Reg },
|
||||||
/// Branch Greater or Equal Unsigned
|
/// Branch Greater or Equal Unsigned
|
||||||
Bgeu { offset: u32, src1: Reg, src2: Reg },
|
Bgeu { offset: Imm, src1: Reg, src2: Reg },
|
||||||
|
|
||||||
/// Load Byte (sign-ext)
|
/// Load Byte (sign-ext)
|
||||||
Lb { offset: u32, dest: Reg, base: Reg },
|
Lb { offset: Imm, dest: Reg, base: Reg },
|
||||||
/// Load Unsigned Byte (zero-ext)
|
/// Load Unsigned Byte (zero-ext)
|
||||||
Lbu { offset: u32, dest: Reg, base: Reg },
|
Lbu { offset: Imm, dest: Reg, base: Reg },
|
||||||
/// Load Half (sign-ext)
|
/// Load Half (sign-ext)
|
||||||
Lh { offset: u32, dest: Reg, base: Reg },
|
Lh { offset: Imm, dest: Reg, base: Reg },
|
||||||
/// Load Unsigned Half (zero-ext)
|
/// Load Unsigned Half (zero-ext)
|
||||||
Lhu { offset: u32, dest: Reg, base: Reg },
|
Lhu { offset: Imm, dest: Reg, base: Reg },
|
||||||
/// Load Word
|
/// Load Word
|
||||||
Lw { offset: u32, dest: Reg, base: Reg },
|
Lw { offset: Imm, dest: Reg, base: Reg },
|
||||||
|
|
||||||
/// Store Byte
|
/// Store Byte
|
||||||
Sb { offset: u32, src: Reg, base: Reg },
|
Sb { offset: Imm, src: Reg, base: Reg },
|
||||||
/// Store Half
|
/// Store Half
|
||||||
Sh { offset: u32, src: Reg, base: Reg },
|
Sh { offset: Imm, src: Reg, base: Reg },
|
||||||
/// Store Word
|
/// Store Word
|
||||||
Sw { offset: u32, src: Reg, base: Reg },
|
Sw { offset: Imm, src: Reg, base: Reg },
|
||||||
|
|
||||||
/// Add Immediate
|
/// Add Immediate
|
||||||
Addi { imm: u32, dest: Reg, src1: Reg },
|
Addi { imm: Imm, dest: Reg, src1: Reg },
|
||||||
/// Set Less Than Immediate (signed)
|
/// Set Less Than Immediate (signed)
|
||||||
Slti { imm: u32, dest: Reg, src1: Reg },
|
Slti { imm: Imm, dest: Reg, src1: Reg },
|
||||||
/// Set Less Than Immediate Unsigned
|
/// Set Less Than Immediate Unsigned
|
||||||
Sltiu { imm: u32, dest: Reg, src1: Reg },
|
Sltiu { imm: Imm, dest: Reg, src1: Reg },
|
||||||
/// XOR Immediate
|
/// XOR Immediate
|
||||||
Xori { imm: u32, dest: Reg, src1: Reg },
|
Xori { imm: Imm, dest: Reg, src1: Reg },
|
||||||
/// OR Immediate
|
/// OR Immediate
|
||||||
Ori { imm: u32, dest: Reg, src1: Reg },
|
Ori { imm: Imm, dest: Reg, src1: Reg },
|
||||||
/// AND Immediate
|
/// AND Immediate
|
||||||
Andi { imm: u32, dest: Reg, src1: Reg },
|
Andi { imm: Imm, dest: Reg, src1: Reg },
|
||||||
/// Shift Left Logical Immediate
|
/// Shift Left Logical Immediate
|
||||||
Slli { imm: u32, dest: Reg, src1: Reg },
|
Slli { imm: Imm, dest: Reg, src1: Reg },
|
||||||
/// Shift Right Logical Immediate (unsigned)
|
/// Shift Right Logical Immediate (unsigned)
|
||||||
Srli { imm: u32, dest: Reg, src1: Reg },
|
Srli { imm: Imm, dest: Reg, src1: Reg },
|
||||||
/// Shift Right Arithmetic Immediate (signed)
|
/// Shift Right Arithmetic Immediate (signed)
|
||||||
Srai { imm: u32, dest: Reg, src1: Reg },
|
Srai { imm: Imm, dest: Reg, src1: Reg },
|
||||||
|
|
||||||
/// Add
|
/// Add
|
||||||
Add { dest: Reg, src1: Reg, src2: Reg },
|
Add { dest: Reg, src1: Reg, src2: Reg },
|
||||||
|
|
@ -385,91 +445,103 @@ impl Debug for Inst {
|
||||||
impl Display for Inst {
|
impl Display for Inst {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
Inst::Lui { uimm, dest } => write!(f, "lui {dest}, {}", uimm >> 12),
|
Inst::Lui { uimm, dest } => write!(f, "lui {dest}, {}", uimm.as_u32() >> 12),
|
||||||
Inst::Auipc { uimm, dest } => write!(f, "auipc {dest}, {}", uimm >> 12),
|
Inst::Auipc { uimm, dest } => write!(f, "auipc {dest}, {}", uimm.as_u32() >> 12),
|
||||||
Inst::Jal { offset, dest } => {
|
Inst::Jal { offset, dest } => {
|
||||||
if dest.0 == 0 {
|
if dest.0 == 0 {
|
||||||
write!(f, "j {}", offset as i32)
|
write!(f, "j {}", offset.as_i32())
|
||||||
} else {
|
} else {
|
||||||
write!(f, "jal {dest}, {}", offset as i32)
|
write!(f, "jal {dest}, {}", offset.as_i32())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Inst::Jalr { offset, base, dest } => {
|
Inst::Jalr { offset, base, dest } => {
|
||||||
if dest == Reg::ZERO && offset == 0 && base == Reg::RA {
|
if dest == Reg::ZERO && offset.as_u32() == 0 && base == Reg::RA {
|
||||||
write!(f, "ret")
|
write!(f, "ret")
|
||||||
} else {
|
} else {
|
||||||
write!(f, "jalr {dest}, {}({base})", offset as i32)
|
write!(f, "jalr {dest}, {}({base})", offset.as_i32())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Inst::Beq { offset, src1, src2 } => write!(f, "beq {src1}, {src2}, {}", offset as i32),
|
Inst::Beq { offset, src1, src2 } => {
|
||||||
Inst::Bne { offset, src1, src2 } => write!(f, "bne {src1}, {src2}, {}", offset as i32),
|
write!(f, "beq {src1}, {src2}, {}", offset.as_i32())
|
||||||
Inst::Blt { offset, src1, src2 } => write!(f, "blt {src1}, {src2}, {}", offset as i32),
|
}
|
||||||
Inst::Bge { offset, src1, src2 } => write!(f, "bge {src1}, {src2}, {}", offset as i32),
|
Inst::Bne { offset, src1, src2 } => {
|
||||||
|
write!(f, "bne {src1}, {src2}, {}", offset.as_i32())
|
||||||
|
}
|
||||||
|
Inst::Blt { offset, src1, src2 } => {
|
||||||
|
write!(f, "blt {src1}, {src2}, {}", offset.as_i32())
|
||||||
|
}
|
||||||
|
Inst::Bge { offset, src1, src2 } => {
|
||||||
|
write!(f, "bge {src1}, {src2}, {}", offset.as_i32())
|
||||||
|
}
|
||||||
Inst::Bltu { offset, src1, src2 } => {
|
Inst::Bltu { offset, src1, src2 } => {
|
||||||
write!(f, "bltu {src1}, {src2}, {}", offset as i32)
|
write!(f, "bltu {src1}, {src2}, {}", offset.as_i32())
|
||||||
}
|
}
|
||||||
Inst::Bgeu { offset, src1, src2 } => {
|
Inst::Bgeu { offset, src1, src2 } => {
|
||||||
write!(f, "bgeu {src1}, {src2}, {}", offset as i32)
|
write!(f, "bgeu {src1}, {src2}, {}", offset.as_i32())
|
||||||
}
|
}
|
||||||
Inst::Lb { offset, dest, base } => write!(f, "lb {dest}, {}({base})", offset as i32),
|
Inst::Lb { offset, dest, base } => write!(f, "lb {dest}, {}({base})", offset.as_i32()),
|
||||||
Inst::Lbu { offset, dest, base } => write!(f, "lbu {dest}, {}({base})", offset as i32),
|
Inst::Lbu { offset, dest, base } => {
|
||||||
Inst::Lh { offset, dest, base } => write!(f, "lh {dest}, {}({base})", offset as i32),
|
write!(f, "lbu {dest}, {}({base})", offset.as_i32())
|
||||||
Inst::Lhu { offset, dest, base } => write!(f, "lhu {dest}, {}({base})", offset as i32),
|
}
|
||||||
Inst::Lw { offset, dest, base } => write!(f, "lw {dest}, {}({base})", offset as i32),
|
Inst::Lh { offset, dest, base } => write!(f, "lh {dest}, {}({base})", offset.as_i32()),
|
||||||
Inst::Sb { offset, src, base } => write!(f, "sb {src}, {}({base})", offset as i32),
|
Inst::Lhu { offset, dest, base } => {
|
||||||
Inst::Sh { offset, src, base } => write!(f, "sh {src}, {}({base})", offset as i32),
|
write!(f, "lhu {dest}, {}({base})", offset.as_i32())
|
||||||
Inst::Sw { offset, src, base } => write!(f, "sw {src}, {}({base})", offset as i32),
|
}
|
||||||
|
Inst::Lw { offset, dest, base } => write!(f, "lw {dest}, {}({base})", offset.as_i32()),
|
||||||
|
Inst::Sb { offset, src, base } => write!(f, "sb {src}, {}({base})", offset.as_i32()),
|
||||||
|
Inst::Sh { offset, src, base } => write!(f, "sh {src}, {}({base})", offset.as_i32()),
|
||||||
|
Inst::Sw { offset, src, base } => write!(f, "sw {src}, {}({base})", offset.as_i32()),
|
||||||
Inst::Addi { imm, dest, src1 } => {
|
Inst::Addi { imm, dest, src1 } => {
|
||||||
if dest.0 == 0 && src1.0 == 0 && imm == 0 {
|
if dest.0 == 0 && src1.0 == 0 && imm.as_u32() == 0 {
|
||||||
write!(f, "nop")
|
write!(f, "nop")
|
||||||
} else if src1.0 == 0 {
|
} else if src1.0 == 0 {
|
||||||
write!(f, "li {dest}, {}", imm as i32)
|
write!(f, "li {dest}, {}", imm.as_i32())
|
||||||
} else if imm == 0 {
|
} else if imm.as_u32() == 0 {
|
||||||
write!(f, "mv {dest}, {src1}")
|
write!(f, "mv {dest}, {src1}")
|
||||||
} else {
|
} else {
|
||||||
write!(f, "addi {dest}, {src1}, {}", imm as i32)
|
write!(f, "addi {dest}, {src1}, {}", imm.as_i32())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Inst::Slti {
|
Inst::Slti {
|
||||||
imm,
|
imm,
|
||||||
dest,
|
dest,
|
||||||
src1: rs1,
|
src1: rs1,
|
||||||
} => write!(f, "slti {dest}, {rs1}, {}", imm as i32),
|
} => write!(f, "slti {dest}, {rs1}, {}", imm.as_i32()),
|
||||||
Inst::Sltiu {
|
Inst::Sltiu {
|
||||||
imm,
|
imm,
|
||||||
dest,
|
dest,
|
||||||
src1: rs1,
|
src1: rs1,
|
||||||
} => write!(f, "sltiu {dest}, {rs1}, {}", imm as i32),
|
} => write!(f, "sltiu {dest}, {rs1}, {}", imm.as_i32()),
|
||||||
Inst::Andi {
|
Inst::Andi {
|
||||||
imm,
|
imm,
|
||||||
dest,
|
dest,
|
||||||
src1: rs1,
|
src1: rs1,
|
||||||
} => write!(f, "andi {dest}, {rs1}, {}", imm as i32),
|
} => write!(f, "andi {dest}, {rs1}, {}", imm.as_i32()),
|
||||||
Inst::Ori {
|
Inst::Ori {
|
||||||
imm,
|
imm,
|
||||||
dest,
|
dest,
|
||||||
src1: rs1,
|
src1: rs1,
|
||||||
} => write!(f, "ori {dest}, {rs1}, {}", imm as i32),
|
} => write!(f, "ori {dest}, {rs1}, {}", imm.as_i32()),
|
||||||
Inst::Xori {
|
Inst::Xori {
|
||||||
imm,
|
imm,
|
||||||
dest,
|
dest,
|
||||||
src1: rs1,
|
src1: rs1,
|
||||||
} => write!(f, "xori {dest}, {rs1}, {}", imm as i32),
|
} => write!(f, "xori {dest}, {rs1}, {}", imm.as_i32()),
|
||||||
Inst::Slli {
|
Inst::Slli {
|
||||||
imm,
|
imm,
|
||||||
dest,
|
dest,
|
||||||
src1: rs1,
|
src1: rs1,
|
||||||
} => write!(f, "slli {dest}, {rs1}, {}", imm as i32),
|
} => write!(f, "slli {dest}, {rs1}, {}", imm.as_i32()),
|
||||||
Inst::Srli {
|
Inst::Srli {
|
||||||
imm,
|
imm,
|
||||||
dest,
|
dest,
|
||||||
src1: rs1,
|
src1: rs1,
|
||||||
} => write!(f, "srli {dest}, {rs1}, {}", imm as i32),
|
} => write!(f, "srli {dest}, {rs1}, {}", imm.as_i32()),
|
||||||
Inst::Srai {
|
Inst::Srai {
|
||||||
imm,
|
imm,
|
||||||
dest,
|
dest,
|
||||||
src1: rs1,
|
src1: rs1,
|
||||||
} => write!(f, "srai {dest}, {rs1}, {}", imm as i32),
|
} => write!(f, "srai {dest}, {rs1}, {}", imm.as_i32()),
|
||||||
Inst::Add { dest, src1, src2 } => {
|
Inst::Add { dest, src1, src2 } => {
|
||||||
write!(f, "add {dest}, {src1}, {src2}")
|
write!(f, "add {dest}, {src1}, {src2}")
|
||||||
}
|
}
|
||||||
|
|
@ -604,15 +676,15 @@ impl InstCode {
|
||||||
let end_span = 32 - (range.end() + 1);
|
let end_span = 32 - (range.end() + 1);
|
||||||
(self.0 << (end_span)) >> (end_span + range.start())
|
(self.0 << (end_span)) >> (end_span + range.start())
|
||||||
}
|
}
|
||||||
fn immediate_u(self, mappings: &[(RangeInclusive<u32>, u32)]) -> u32 {
|
fn immediate_u(self, mappings: &[(RangeInclusive<u32>, u32)]) -> Imm {
|
||||||
let mut imm = 0;
|
let mut imm = 0;
|
||||||
for (from, to) in mappings {
|
for (from, to) in mappings {
|
||||||
let value = self.extract(from.clone());
|
let value = self.extract(from.clone());
|
||||||
imm |= value << to;
|
imm |= value << to;
|
||||||
}
|
}
|
||||||
imm
|
Imm::new_u32(imm)
|
||||||
}
|
}
|
||||||
fn immediate_s(self, mappings: &[(RangeInclusive<u32>, u32)]) -> u32 {
|
fn immediate_s(self, mappings: &[(RangeInclusive<u32>, u32)]) -> Imm {
|
||||||
let mut imm = 0;
|
let mut imm = 0;
|
||||||
let mut size = 0;
|
let mut size = 0;
|
||||||
for (from, to) in mappings {
|
for (from, to) in mappings {
|
||||||
|
|
@ -621,7 +693,7 @@ impl InstCode {
|
||||||
let this_size = from.end() - from.start() + 1;
|
let this_size = from.end() - from.start() + 1;
|
||||||
size = size.max(*to + this_size);
|
size = size.max(*to + this_size);
|
||||||
}
|
}
|
||||||
sign_extend(imm, size)
|
Imm::new_i32(sign_extend(imm, size) as i32)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn opcode(self) -> u32 {
|
fn opcode(self) -> u32 {
|
||||||
|
|
@ -645,19 +717,19 @@ impl InstCode {
|
||||||
fn rd(self) -> Reg {
|
fn rd(self) -> Reg {
|
||||||
Reg(self.extract(7..=11) as u8)
|
Reg(self.extract(7..=11) as u8)
|
||||||
}
|
}
|
||||||
fn imm_i(self) -> u32 {
|
fn imm_i(self) -> Imm {
|
||||||
self.immediate_s(&[(20..=31, 0)])
|
self.immediate_s(&[(20..=31, 0)])
|
||||||
}
|
}
|
||||||
fn imm_s(self) -> u32 {
|
fn imm_s(self) -> Imm {
|
||||||
self.immediate_s(&[(25..=31, 5), (7..=11, 0)])
|
self.immediate_s(&[(25..=31, 5), (7..=11, 0)])
|
||||||
}
|
}
|
||||||
fn imm_b(self) -> u32 {
|
fn imm_b(self) -> Imm {
|
||||||
self.immediate_s(&[(31..=31, 12), (7..=7, 11), (25..=30, 5), (8..=11, 1)])
|
self.immediate_s(&[(31..=31, 12), (7..=7, 11), (25..=30, 5), (8..=11, 1)])
|
||||||
}
|
}
|
||||||
fn imm_u(self) -> u32 {
|
fn imm_u(self) -> Imm {
|
||||||
self.immediate_u(&[(12..=31, 12)])
|
self.immediate_u(&[(12..=31, 12)])
|
||||||
}
|
}
|
||||||
fn imm_j(self) -> u32 {
|
fn imm_j(self) -> Imm {
|
||||||
self.immediate_s(&[(31..=31, 20), (21..=30, 1), (20..=20, 11), (12..=19, 12)])
|
self.immediate_s(&[(31..=31, 20), (21..=30, 1), (20..=20, 11), (12..=19, 12)])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -670,15 +742,15 @@ impl InstCodeC {
|
||||||
let end_span = u16::BITS - (range.end() + 1);
|
let end_span = u16::BITS - (range.end() + 1);
|
||||||
((self.0 << (end_span)) >> (end_span + range.start())) as u32
|
((self.0 << (end_span)) >> (end_span + range.start())) as u32
|
||||||
}
|
}
|
||||||
fn immediate_u(self, mappings: &[(RangeInclusive<u32>, u32)]) -> u32 {
|
fn immediate_u(self, mappings: &[(RangeInclusive<u32>, u32)]) -> Imm {
|
||||||
let mut imm = 0;
|
let mut imm = 0;
|
||||||
for (from, to) in mappings {
|
for (from, to) in mappings {
|
||||||
let value = self.extract(from.clone());
|
let value = self.extract(from.clone());
|
||||||
imm |= value << to;
|
imm |= value << to;
|
||||||
}
|
}
|
||||||
imm
|
Imm::new_u32(imm)
|
||||||
}
|
}
|
||||||
fn immediate_s(self, mappings: &[(RangeInclusive<u32>, u32)]) -> u32 {
|
fn immediate_s(self, mappings: &[(RangeInclusive<u32>, u32)]) -> Imm {
|
||||||
let mut imm = 0;
|
let mut imm = 0;
|
||||||
let mut size = 0;
|
let mut size = 0;
|
||||||
for (from, to) in mappings {
|
for (from, to) in mappings {
|
||||||
|
|
@ -688,7 +760,7 @@ impl InstCodeC {
|
||||||
let this_size = from.end() - from.start() + 1;
|
let this_size = from.end() - from.start() + 1;
|
||||||
size = size.max(*to + this_size);
|
size = size.max(*to + this_size);
|
||||||
}
|
}
|
||||||
sign_extend(imm, size)
|
Imm::new_i32(sign_extend(imm, size) as i32)
|
||||||
}
|
}
|
||||||
fn quadrant(self) -> u16 {
|
fn quadrant(self) -> u16 {
|
||||||
self.0 & 0b11
|
self.0 & 0b11
|
||||||
|
|
@ -790,7 +862,7 @@ impl Inst {
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// // Compressed addi sp, sp, -0x20
|
/// // Compressed addi sp, sp, -0x20
|
||||||
/// let x = 0x1101_u16;
|
/// let x = 0x1101_u16;
|
||||||
/// let expected = rvdc::Inst::Addi { imm: (-0x20_i32) as u32, dest: rvdc::Reg::SP, src1: rvdc::Reg::SP };
|
/// let expected = rvdc::Inst::Addi { imm: rvdc::Imm::new_i32(-0x20), dest: rvdc::Reg::SP, src1: rvdc::Reg::SP };
|
||||||
///
|
///
|
||||||
/// let inst = rvdc::Inst::decode_compressed(x).unwrap();
|
/// let inst = rvdc::Inst::decode_compressed(x).unwrap();
|
||||||
/// assert_eq!(inst, expected);
|
/// assert_eq!(inst, expected);
|
||||||
|
|
@ -807,7 +879,7 @@ impl Inst {
|
||||||
0b000 => {
|
0b000 => {
|
||||||
let imm =
|
let imm =
|
||||||
code.immediate_u(&[(5..=5, 3), (6..=6, 2), (7..=10, 6), (11..=12, 4)]);
|
code.immediate_u(&[(5..=5, 3), (6..=6, 2), (7..=10, 6), (11..=12, 4)]);
|
||||||
if imm == 0 {
|
if imm.as_u32() == 0 {
|
||||||
return Err(decode_error(code, "uimm=0 for C.ADDISPN is reserved"));
|
return Err(decode_error(code, "uimm=0 for C.ADDISPN is reserved"));
|
||||||
}
|
}
|
||||||
Inst::Addi {
|
Inst::Addi {
|
||||||
|
|
@ -959,7 +1031,7 @@ impl Inst {
|
||||||
// C.LUI -> lui \rd, \imm
|
// C.LUI -> lui \rd, \imm
|
||||||
_ => {
|
_ => {
|
||||||
let uimm = code.immediate_s(&[(2..=6, 12), (12..=12, 17)]);
|
let uimm = code.immediate_s(&[(2..=6, 12), (12..=12, 17)]);
|
||||||
if uimm == 0 {
|
if uimm.as_u32() == 0 {
|
||||||
return Err(decode_error(code, "imm"));
|
return Err(decode_error(code, "imm"));
|
||||||
}
|
}
|
||||||
Inst::Lui {
|
Inst::Lui {
|
||||||
|
|
@ -1032,7 +1104,7 @@ impl Inst {
|
||||||
return Err(decode_error(code, "rs1"));
|
return Err(decode_error(code, "rs1"));
|
||||||
}
|
}
|
||||||
Inst::Jalr {
|
Inst::Jalr {
|
||||||
offset: 0,
|
offset: Imm::ZERO,
|
||||||
base: rd_rs1,
|
base: rd_rs1,
|
||||||
dest: Reg::ZERO,
|
dest: Reg::ZERO,
|
||||||
}
|
}
|
||||||
|
|
@ -1047,7 +1119,7 @@ impl Inst {
|
||||||
(1, 0, 0) => Inst::Ebreak,
|
(1, 0, 0) => Inst::Ebreak,
|
||||||
// C.JALR -> jalr ra, 0(\rs1)
|
// C.JALR -> jalr ra, 0(\rs1)
|
||||||
(1, _, 0) if rd_rs1.0 != 0 => Inst::Jalr {
|
(1, _, 0) if rd_rs1.0 != 0 => Inst::Jalr {
|
||||||
offset: 0,
|
offset: Imm::ZERO,
|
||||||
base: rd_rs1,
|
base: rd_rs1,
|
||||||
dest: Reg::RA,
|
dest: Reg::RA,
|
||||||
},
|
},
|
||||||
|
|
@ -1227,12 +1299,12 @@ impl Inst {
|
||||||
}
|
}
|
||||||
0b101 => match code.funct7() {
|
0b101 => match code.funct7() {
|
||||||
0b0000000 => Inst::Srli {
|
0b0000000 => Inst::Srli {
|
||||||
imm: code.rs2_imm(),
|
imm: Imm::new_u32(code.rs2_imm()),
|
||||||
dest: code.rd(),
|
dest: code.rd(),
|
||||||
src1: code.rs1(),
|
src1: code.rs1(),
|
||||||
},
|
},
|
||||||
0b0100000 => Inst::Srai {
|
0b0100000 => Inst::Srai {
|
||||||
imm: code.rs2_imm(),
|
imm: Imm::new_u32(code.rs2_imm()),
|
||||||
dest: code.rd(),
|
dest: code.rd(),
|
||||||
src1: code.rs1(),
|
src1: code.rs1(),
|
||||||
},
|
},
|
||||||
|
|
@ -1309,7 +1381,7 @@ impl Inst {
|
||||||
if code.rs1().0 != 0 {
|
if code.rs1().0 != 0 {
|
||||||
return Err(decode_error(code, "rs1"));
|
return Err(decode_error(code, "rs1"));
|
||||||
}
|
}
|
||||||
match code.imm_i() {
|
match code.imm_i().as_u32() {
|
||||||
0b000000000000 => Inst::Ecall,
|
0b000000000000 => Inst::Ecall,
|
||||||
0b000000000001 => Inst::Ebreak,
|
0b000000000001 => Inst::Ebreak,
|
||||||
_ => return Err(decode_error(code, "imm")),
|
_ => return Err(decode_error(code, "imm")),
|
||||||
|
|
@ -1390,6 +1462,7 @@ mod tests {
|
||||||
|
|
||||||
use crate::Fence;
|
use crate::Fence;
|
||||||
use crate::FenceSet;
|
use crate::FenceSet;
|
||||||
|
use crate::Imm;
|
||||||
use crate::Inst;
|
use crate::Inst;
|
||||||
use crate::Reg;
|
use crate::Reg;
|
||||||
|
|
||||||
|
|
@ -1467,7 +1540,7 @@ mod tests {
|
||||||
dest: Reg::ZERO, ..
|
dest: Reg::ZERO, ..
|
||||||
} => false,
|
} => false,
|
||||||
// This does roundtrip, but only through C.MV, not C.ADDI
|
// This does roundtrip, but only through C.MV, not C.ADDI
|
||||||
Inst::Addi { imm: 0, .. } => false,
|
Inst::Addi { imm: Imm::ZERO, .. } => false,
|
||||||
// This does rountrip, but not through C.ADDI
|
// This does rountrip, but not through C.ADDI
|
||||||
Inst::Addi {
|
Inst::Addi {
|
||||||
dest: Reg::SP,
|
dest: Reg::SP,
|
||||||
|
|
@ -1478,15 +1551,15 @@ mod tests {
|
||||||
Inst::Slli {
|
Inst::Slli {
|
||||||
dest: Reg::ZERO, ..
|
dest: Reg::ZERO, ..
|
||||||
}
|
}
|
||||||
| Inst::Slli { imm: 0, .. }
|
| Inst::Slli { imm: Imm::ZERO, .. }
|
||||||
| Inst::Srli {
|
| Inst::Srli {
|
||||||
dest: Reg::ZERO, ..
|
dest: Reg::ZERO, ..
|
||||||
}
|
}
|
||||||
| Inst::Srli { imm: 0, .. }
|
| Inst::Srli { imm: Imm::ZERO, .. }
|
||||||
| Inst::Srai {
|
| Inst::Srai {
|
||||||
dest: Reg::ZERO, ..
|
dest: Reg::ZERO, ..
|
||||||
}
|
}
|
||||||
| Inst::Srai { imm: 0, .. } => false,
|
| Inst::Srai { imm: Imm::ZERO, .. } => false,
|
||||||
// HINT
|
// HINT
|
||||||
Inst::Lui {
|
Inst::Lui {
|
||||||
dest: Reg::ZERO, ..
|
dest: Reg::ZERO, ..
|
||||||
|
|
|
||||||
62
src/emu.rs
62
src/emu.rs
|
|
@ -1,4 +1,4 @@
|
||||||
use rvdc::{AmoOp, DecodeError, Inst, IsCompressed, Reg};
|
use rvdc::{AmoOp, DecodeError, Imm, Inst, IsCompressed, Reg};
|
||||||
use std::{
|
use std::{
|
||||||
fmt::{Debug, Display},
|
fmt::{Debug, Display},
|
||||||
io::Write,
|
io::Write,
|
||||||
|
|
@ -66,6 +66,7 @@ impl Memory {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Status {
|
pub enum Status {
|
||||||
Trap(&'static str),
|
Trap(&'static str),
|
||||||
|
UnsupportedInst(rvdc::Inst),
|
||||||
IllegalInstruction(DecodeError),
|
IllegalInstruction(DecodeError),
|
||||||
InvalidMemoryAccess(usize),
|
InvalidMemoryAccess(usize),
|
||||||
UnalignedPc(u32),
|
UnalignedPc(u32),
|
||||||
|
|
@ -237,17 +238,17 @@ impl<XLEN: XLen> Emulator<XLEN> {
|
||||||
let mut jumped = false;
|
let mut jumped = false;
|
||||||
|
|
||||||
match inst {
|
match inst {
|
||||||
Inst::Lui { uimm, dest } => self[dest] = XLEN::from_32_z(uimm),
|
Inst::Lui { uimm, dest } => self[dest] = XLEN::from_imm(uimm),
|
||||||
Inst::Auipc { uimm, dest } => self[dest] = self.pc.add(XLEN::from_32_z(uimm)),
|
Inst::Auipc { uimm, dest } => self[dest] = self.pc.add(XLEN::from_imm(uimm)),
|
||||||
Inst::Jal { offset, dest } => {
|
Inst::Jal { offset, dest } => {
|
||||||
let target = self.pc.add(XLEN::from_32_s(offset));
|
let target = self.pc.add(XLEN::from_imm(offset));
|
||||||
self[dest] = next_pc;
|
self[dest] = next_pc;
|
||||||
self.set_pc(target)?;
|
self.set_pc(target)?;
|
||||||
jumped = true;
|
jumped = true;
|
||||||
}
|
}
|
||||||
Inst::Jalr { offset, base, dest } => {
|
Inst::Jalr { offset, base, dest } => {
|
||||||
let target = self[base]
|
let target = self[base]
|
||||||
.add(XLEN::from_32_s(offset))
|
.add(XLEN::from_imm(offset))
|
||||||
.and(XLEN::from_32_s(!1));
|
.and(XLEN::from_32_s(!1));
|
||||||
self[dest] = next_pc;
|
self[dest] = next_pc;
|
||||||
self.set_pc(target)?;
|
self.set_pc(target)?;
|
||||||
|
|
@ -256,7 +257,7 @@ impl<XLEN: XLen> Emulator<XLEN> {
|
||||||
Inst::Beq { offset, src1, src2 } => {
|
Inst::Beq { offset, src1, src2 } => {
|
||||||
let take = self[src1] == self[src2];
|
let take = self[src1] == self[src2];
|
||||||
if take {
|
if take {
|
||||||
let target = self.pc.add(XLEN::from_32_s(offset));
|
let target = self.pc.add(XLEN::from_imm(offset));
|
||||||
self.set_pc(target)?;
|
self.set_pc(target)?;
|
||||||
jumped = true;
|
jumped = true;
|
||||||
}
|
}
|
||||||
|
|
@ -264,7 +265,7 @@ impl<XLEN: XLen> Emulator<XLEN> {
|
||||||
Inst::Bne { offset, src1, src2 } => {
|
Inst::Bne { offset, src1, src2 } => {
|
||||||
let take = self[src1] != self[src2];
|
let take = self[src1] != self[src2];
|
||||||
if take {
|
if take {
|
||||||
let target = self.pc.add(XLEN::from_32_s(offset));
|
let target = self.pc.add(XLEN::from_imm(offset));
|
||||||
self.set_pc(target)?;
|
self.set_pc(target)?;
|
||||||
jumped = true;
|
jumped = true;
|
||||||
}
|
}
|
||||||
|
|
@ -272,7 +273,7 @@ impl<XLEN: XLen> Emulator<XLEN> {
|
||||||
Inst::Blt { offset, src1, src2 } => {
|
Inst::Blt { offset, src1, src2 } => {
|
||||||
let take = self[src1].signed_lt(self[src2]);
|
let take = self[src1].signed_lt(self[src2]);
|
||||||
if take {
|
if take {
|
||||||
let target = self.pc.add(XLEN::from_32_s(offset));
|
let target = self.pc.add(XLEN::from_imm(offset));
|
||||||
self.set_pc(target)?;
|
self.set_pc(target)?;
|
||||||
jumped = true;
|
jumped = true;
|
||||||
}
|
}
|
||||||
|
|
@ -280,7 +281,7 @@ impl<XLEN: XLen> Emulator<XLEN> {
|
||||||
Inst::Bge { offset, src1, src2 } => {
|
Inst::Bge { offset, src1, src2 } => {
|
||||||
let take = self[src1].signed_ge(self[src2]);
|
let take = self[src1].signed_ge(self[src2]);
|
||||||
if take {
|
if take {
|
||||||
let target = self.pc.add(XLEN::from_32_s(offset));
|
let target = self.pc.add(XLEN::from_imm(offset));
|
||||||
self.set_pc(target)?;
|
self.set_pc(target)?;
|
||||||
jumped = true;
|
jumped = true;
|
||||||
}
|
}
|
||||||
|
|
@ -288,7 +289,7 @@ impl<XLEN: XLen> Emulator<XLEN> {
|
||||||
Inst::Bltu { offset, src1, src2 } => {
|
Inst::Bltu { offset, src1, src2 } => {
|
||||||
let take = self[src1].unsigned_lt(self[src2]);
|
let take = self[src1].unsigned_lt(self[src2]);
|
||||||
if take {
|
if take {
|
||||||
let target = self.pc.add(XLEN::from_32_s(offset));
|
let target = self.pc.add(XLEN::from_imm(offset));
|
||||||
self.set_pc(target)?;
|
self.set_pc(target)?;
|
||||||
jumped = true;
|
jumped = true;
|
||||||
}
|
}
|
||||||
|
|
@ -296,66 +297,66 @@ impl<XLEN: XLen> Emulator<XLEN> {
|
||||||
Inst::Bgeu { offset, src1, src2 } => {
|
Inst::Bgeu { offset, src1, src2 } => {
|
||||||
let take = self[src1].unsigned_ge(self[src2]);
|
let take = self[src1].unsigned_ge(self[src2]);
|
||||||
if take {
|
if take {
|
||||||
let target = self.pc.add(XLEN::from_32_s(offset));
|
let target = self.pc.add(XLEN::from_imm(offset));
|
||||||
self.set_pc(target)?;
|
self.set_pc(target)?;
|
||||||
jumped = true;
|
jumped = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Inst::Lb { offset, dest, base } => {
|
Inst::Lb { offset, dest, base } => {
|
||||||
let addr = self[base].add(XLEN::from_32_s(offset));
|
let addr = self[base].add(XLEN::from_imm(offset));
|
||||||
self[dest] = XLEN::from_8_s(self.mem.load_u8(addr)?);
|
self[dest] = XLEN::from_8_s(self.mem.load_u8(addr)?);
|
||||||
}
|
}
|
||||||
Inst::Lbu { offset, dest, base } => {
|
Inst::Lbu { offset, dest, base } => {
|
||||||
let addr = self[base].add(XLEN::from_32_s(offset));
|
let addr = self[base].add(XLEN::from_imm(offset));
|
||||||
self[dest] = XLEN::from_8_z(self.mem.load_u8(addr)?);
|
self[dest] = XLEN::from_8_z(self.mem.load_u8(addr)?);
|
||||||
}
|
}
|
||||||
Inst::Lh { offset, dest, base } => {
|
Inst::Lh { offset, dest, base } => {
|
||||||
let addr = self[base].add(XLEN::from_32_s(offset));
|
let addr = self[base].add(XLEN::from_imm(offset));
|
||||||
self[dest] = XLEN::from_16_s(self.mem.load_u16(addr)?);
|
self[dest] = XLEN::from_16_s(self.mem.load_u16(addr)?);
|
||||||
}
|
}
|
||||||
Inst::Lhu { offset, dest, base } => {
|
Inst::Lhu { offset, dest, base } => {
|
||||||
let addr = self[base].add(XLEN::from_32_s(offset));
|
let addr = self[base].add(XLEN::from_imm(offset));
|
||||||
self[dest] = XLEN::from_16_z(self.mem.load_u16(addr)?);
|
self[dest] = XLEN::from_16_z(self.mem.load_u16(addr)?);
|
||||||
}
|
}
|
||||||
Inst::Lw { offset, dest, base } => {
|
Inst::Lw { offset, dest, base } => {
|
||||||
let addr = self[base].add(XLEN::from_32_s(offset));
|
let addr = self[base].add(XLEN::from_imm(offset));
|
||||||
self[dest] = XLEN::from_32_s(self.mem.load_u32(addr)?);
|
self[dest] = XLEN::from_32_s(self.mem.load_u32(addr)?);
|
||||||
}
|
}
|
||||||
Inst::Sb { offset, src, base } => {
|
Inst::Sb { offset, src, base } => {
|
||||||
let addr = self[base].add(XLEN::from_32_s(offset));
|
let addr = self[base].add(XLEN::from_imm(offset));
|
||||||
self.mem.store_u8(addr, self[src].truncate8())?;
|
self.mem.store_u8(addr, self[src].truncate8())?;
|
||||||
}
|
}
|
||||||
Inst::Sh { offset, src, base } => {
|
Inst::Sh { offset, src, base } => {
|
||||||
let addr = self[base].add(XLEN::from_32_s(offset));
|
let addr = self[base].add(XLEN::from_imm(offset));
|
||||||
self.mem.store_u16(addr, self[src].truncate16())?;
|
self.mem.store_u16(addr, self[src].truncate16())?;
|
||||||
}
|
}
|
||||||
Inst::Sw { offset, src, base } => {
|
Inst::Sw { offset, src, base } => {
|
||||||
let addr = self[base].add(XLEN::from_32_s(offset));
|
let addr = self[base].add(XLEN::from_imm(offset));
|
||||||
self.mem.store_u32(addr, self[src].truncate32())?;
|
self.mem.store_u32(addr, self[src].truncate32())?;
|
||||||
}
|
}
|
||||||
Inst::Addi { imm, dest, src1 } => {
|
Inst::Addi { imm, dest, src1 } => {
|
||||||
self[dest] = self[src1].add(XLEN::from_32_s(imm));
|
self[dest] = self[src1].add(XLEN::from_imm(imm));
|
||||||
}
|
}
|
||||||
Inst::Slti { imm, dest, src1 } => {
|
Inst::Slti { imm, dest, src1 } => {
|
||||||
let result = self[src1].signed_lt(XLEN::from_32_s(imm));
|
let result = self[src1].signed_lt(XLEN::from_imm(imm));
|
||||||
self[dest] = XLEN::from_bool(result);
|
self[dest] = XLEN::from_bool(result);
|
||||||
}
|
}
|
||||||
Inst::Sltiu { imm, dest, src1 } => {
|
Inst::Sltiu { imm, dest, src1 } => {
|
||||||
let result = self[src1].unsigned_lt(XLEN::from_32_s(imm));
|
let result = self[src1].unsigned_lt(XLEN::from_imm(imm));
|
||||||
self[dest] = XLEN::from_bool(result);
|
self[dest] = XLEN::from_bool(result);
|
||||||
}
|
}
|
||||||
Inst::Andi { imm, dest, src1 } => {
|
Inst::Andi { imm, dest, src1 } => {
|
||||||
self[dest] = self[src1].and(XLEN::from_32_s(imm));
|
self[dest] = self[src1].and(XLEN::from_imm(imm));
|
||||||
}
|
}
|
||||||
Inst::Ori { imm, dest, src1 } => {
|
Inst::Ori { imm, dest, src1 } => {
|
||||||
self[dest] = self[src1].or(XLEN::from_32_s(imm));
|
self[dest] = self[src1].or(XLEN::from_imm(imm));
|
||||||
}
|
}
|
||||||
Inst::Xori { imm, dest, src1 } => {
|
Inst::Xori { imm, dest, src1 } => {
|
||||||
self[dest] = self[src1].xor(XLEN::from_32_s(imm));
|
self[dest] = self[src1].xor(XLEN::from_imm(imm));
|
||||||
}
|
}
|
||||||
Inst::Slli { imm, dest, src1 } => self[dest] = self[src1].shl(imm),
|
Inst::Slli { imm, dest, src1 } => self[dest] = self[src1].shl(imm.as_u32()),
|
||||||
Inst::Srli { imm, dest, src1 } => self[dest] = self[src1].unsigned_shr(imm),
|
Inst::Srli { imm, dest, src1 } => self[dest] = self[src1].unsigned_shr(imm.as_u32()),
|
||||||
Inst::Srai { imm, dest, src1 } => self[dest] = self[src1].signed_shr(imm),
|
Inst::Srai { imm, dest, src1 } => self[dest] = self[src1].signed_shr(imm.as_u32()),
|
||||||
Inst::Add { dest, src1, src2 } => self[dest] = self[src1].add(self[src2]),
|
Inst::Add { dest, src1, src2 } => self[dest] = self[src1].add(self[src2]),
|
||||||
Inst::Sub { dest, src1, src2 } => self[dest] = self[src1].sub(self[src2]),
|
Inst::Sub { dest, src1, src2 } => self[dest] = self[src1].sub(self[src2]),
|
||||||
Inst::Sll { dest, src1, src2 } => self[dest] = self[src1].shl(self[src2].truncate32()),
|
Inst::Sll { dest, src1, src2 } => self[dest] = self[src1].shl(self[src2].truncate32()),
|
||||||
|
|
@ -473,6 +474,7 @@ impl<XLEN: XLen> Emulator<XLEN> {
|
||||||
}
|
}
|
||||||
self.reservation_set = None;
|
self.reservation_set = None;
|
||||||
}
|
}
|
||||||
|
_ => return Err(Status::UnsupportedInst(inst)),
|
||||||
}
|
}
|
||||||
|
|
||||||
if !jumped {
|
if !jumped {
|
||||||
|
|
@ -666,6 +668,7 @@ pub trait XLen: Copy + PartialEq + Eq {
|
||||||
}
|
}
|
||||||
fn from_32_z(v: u32) -> Self;
|
fn from_32_z(v: u32) -> Self;
|
||||||
fn from_32_s(v: u32) -> Self;
|
fn from_32_s(v: u32) -> Self;
|
||||||
|
fn from_imm(v: Imm) -> Self;
|
||||||
|
|
||||||
fn truncate8(self) -> u8 {
|
fn truncate8(self) -> u8 {
|
||||||
self.truncate32() as u8
|
self.truncate32() as u8
|
||||||
|
|
@ -715,6 +718,9 @@ impl XLen for u32 {
|
||||||
fn from_32_z(v: u32) -> Self {
|
fn from_32_z(v: u32) -> Self {
|
||||||
v
|
v
|
||||||
}
|
}
|
||||||
|
fn from_imm(v: Imm) -> Self {
|
||||||
|
v.as_u32()
|
||||||
|
}
|
||||||
fn as_usize(self) -> usize {
|
fn as_usize(self) -> usize {
|
||||||
self as usize
|
self as usize
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue