Skip to content

Commit

Permalink
Add Mstatus helpers to allow setting fields in Mstatus
Browse files Browse the repository at this point in the history
Without needing to touch the CSR. This allows multiple changes in a
single register write.
  • Loading branch information
jsgf committed May 7, 2024
1 parent 260f0a5 commit a10e637
Show file tree
Hide file tree
Showing 3 changed files with 153 additions and 3 deletions.
2 changes: 2 additions & 0 deletions riscv/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Add `Mcause::from(usize)` for use in unit tests
- Add `Mstatus::from(usize)` for use in unit tests
- Add `Mstatus.bits()`
- Add `Mstatus::set_*` helpers to manipulate Mstatus values without touching the
CSR
- Export `riscv::register::macros` module macros for external use

### Fixed
Expand Down
6 changes: 3 additions & 3 deletions riscv/src/register/misa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ pub struct Misa {
/// Base integer ISA width
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum XLEN {
XLEN32,
XLEN64,
XLEN128,
XLEN32 = 1,
XLEN64 = 2,
XLEN128 = 3,
}

impl XLEN {
Expand Down
148 changes: 148 additions & 0 deletions riscv/src/register/mstatus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,15 @@ impl From<bool> for Endianness {
}

impl Mstatus {
/// Helper to insert a bitfield into Mstatus
#[inline]
fn bf_insert(&self, bit: usize, width: usize, val: usize) -> Self {
let mask = (1 << width) - 1;
Self {
bits: self.bits & !(mask << bit) | (val & mask << bit),
}
}

/// Returns the contents of the register as raw bits
#[inline]
pub fn bits(&self) -> usize {
Expand All @@ -84,30 +93,60 @@ impl Mstatus {
self.bits & (1 << 1) != 0
}

/// Set Supervisor Interrupt Enable
#[inline]
pub fn set_sie(&self, sie: bool) -> Self {
self.bf_insert(1, 1, sie as usize)
}

/// Machine Interrupt Enable
#[inline]
pub fn mie(&self) -> bool {
self.bits & (1 << 3) != 0
}

/// Set Machine Interrupt Enable
#[inline]
pub fn set_mie(&self, mie: bool) -> Self {
self.bf_insert(3, 1, mie as usize)
}

/// Supervisor Previous Interrupt Enable
#[inline]
pub fn spie(&self) -> bool {
self.bits & (1 << 5) != 0
}

/// Supervisor Previous Interrupt Enable
#[inline]
pub fn set_spie(&self, spie: bool) -> Self {
self.bf_insert(5, 1, spie as usize)
}

/// U-mode non-instruction-fetch memory endianness
#[inline]
pub fn ube(&self) -> Endianness {
Endianness::from(self.bits & (1 << 6) != 0)
}

/// Set U-mode non-instruction-fetch memory endianness
#[inline]
pub fn set_ube(&self, endianness: Endianness) -> Self {
self.bf_insert(6, 1, endianness as usize)
}

/// Machine Previous Interrupt Enable
#[inline]
pub fn mpie(&self) -> bool {
self.bits & (1 << 7) != 0
}

/// Set Machine Previous Interrupt Enable
#[inline]
pub fn set_mpie(&self, mpie: bool) -> Self {
self.bf_insert(7, 1, mpie as usize)
}

/// Supervisor Previous Privilege Mode
#[inline]
pub fn spp(&self) -> SPP {
Expand All @@ -117,6 +156,12 @@ impl Mstatus {
}
}

/// Set Supervisor Previous Privilege Mode
#[inline]
pub fn set_spp(&self, spp: SPP) -> Self {
self.bf_insert(8, 1, spp as usize)
}

/// Machine Previous Privilege Mode
#[inline]
pub fn mpp(&self) -> MPP {
Expand All @@ -129,6 +174,12 @@ impl Mstatus {
}
}

/// Set Machine Previous Privilege Mode
#[inline]
pub fn set_mpp(&self, mpp: MPP) -> Self {
self.bf_insert(11, 2, mpp as usize)
}

/// Floating-point extension state
///
/// Encodes the status of the floating-point unit,
Expand All @@ -145,6 +196,12 @@ impl Mstatus {
}
}

/// Set Floating-point extension state
#[inline]
pub fn set_fs(&self, fs: FS) -> Self {
self.bf_insert(13, 2, fs as usize)
}

/// Additional extension state
///
/// Encodes the status of additional user-mode extensions and associated state.
Expand All @@ -160,24 +217,48 @@ impl Mstatus {
}
}

/// Set Additional extension state
#[inline]
pub fn set_xs(&self, xs: XS) -> Self {
self.bf_insert(15, 2, xs as usize)
}

/// Modify Memory PRiVilege
#[inline]
pub fn mprv(&self) -> bool {
self.bits & (1 << 17) != 0
}

/// Set Modify Memory PRiVilege
#[inline]
pub fn set_mprv(&self, mprv: bool) -> Self {
self.bf_insert(17, 1, mprv as usize)
}

/// Permit Supervisor User Memory access
#[inline]
pub fn sum(&self) -> bool {
self.bits & (1 << 18) != 0
}

/// Set Permit Supervisor User Memory access
#[inline]
pub fn set_sum(&self, sum: bool) -> Self {
self.bf_insert(18, 1, sum as usize)
}

/// Make eXecutable Readable
#[inline]
pub fn mxr(&self) -> bool {
self.bits & (1 << 19) != 0
}

/// Set Make eXecutable Readable
#[inline]
pub fn set_mxr(&self, mxr: bool) -> Self {
self.bf_insert(19, 1, mxr as usize)
}

/// Trap Virtual Memory
///
/// If this bit is set, reads or writes to `satp` CSR or execute `sfence.vma`
Expand All @@ -189,6 +270,12 @@ impl Mstatus {
self.bits & (1 << 20) != 0
}

/// Set Trap Virtual Memory
#[inline]
pub fn set_tvm(&self, tvm: bool) -> Self {
self.bf_insert(20, 1, tvm as usize)
}

/// Timeout Wait
///
/// Indicates that if WFI instruction should be intercepted.
Expand All @@ -203,6 +290,12 @@ impl Mstatus {
self.bits & (1 << 21) != 0
}

/// Set Timeout Wait
#[inline]
pub fn set_tw(&self, tw: bool) -> Self {
self.bf_insert(21, 1, tw as usize)
}

/// Trap SRET
///
/// Indicates that if SRET instruction should be trapped to raise illegal
Expand All @@ -214,6 +307,12 @@ impl Mstatus {
self.bits & (1 << 22) != 0
}

/// Set Trap SRET
#[inline]
pub fn set_tsr(&self, tsr: bool) -> Self {
self.bf_insert(22, 1, tsr as usize)
}

/// Effective xlen in U-mode (i.e., `UXLEN`).
///
/// In RISCV-32, UXL does not exist, and `UXLEN` is always [`XLEN::XLEN32`].
Expand All @@ -227,6 +326,17 @@ impl Mstatus {
}
}

/// Set Effective xlen in U-mode (i.e., `UXLEN`).
#[inline]
pub fn set_uxl(&self, uxl: XLEN) -> Self {
#[cfg(riscv32)]
{
*self
}
#[cfg(not(riscv32))]
self.bf_insert(32, 2, uxl as usize)
}

/// Effective xlen in S-mode (i.e., `SXLEN`).
///
/// In RISCV-32, SXL does not exist, and SXLEN is always [`XLEN::XLEN32`].
Expand All @@ -240,6 +350,17 @@ impl Mstatus {
}
}

/// Set Effective xlen in S-mode (i.e., `SXLEN`).
#[inline]
pub fn set_sxl(&self, sxl: XLEN) -> Self {
#[cfg(riscv32)]
{
*self
}
#[cfg(not(riscv32))]
self.bf_insert(34, 2, sxl as usize)
}

/// S-mode non-instruction-fetch memory endianness.
///
/// In RISCV-32, this field is read from the [`crate::register::mstatush`] register.
Expand All @@ -252,6 +373,17 @@ impl Mstatus {
}
}

/// Set S-mode non-instruction-fetch memory endianness
#[inline]
pub fn set_sbe(&self, endianness: Endianness) -> Self {
#[cfg(riscv32)]
{
*self
}
#[cfg(not(riscv32))]
self.bf_insert(36, 1, endianness as usize)
}

/// M-mode non-instruction-fetch memory endianness
///
/// In RISCV-32, this field is read from the [`crate::register::mstatush`] register
Expand All @@ -264,11 +396,27 @@ impl Mstatus {
}
}

/// Set M-mode non-instruction-fetch memory endianness
pub fn set_mbe(&self, endianness: Endianness) -> Self {
#[cfg(riscv32)]
{
*self
}
#[cfg(not(riscv32))]
self.bf_insert(37, 1, endianness as usize)
}

/// Whether either the FS field or XS field signals the presence of some dirty state
#[inline]
pub fn sd(&self) -> bool {
self.bits & (1 << (usize::BITS as usize - 1)) != 0
}

/// Set whether either the FS field or XS field signals the presence of some dirty state
#[inline]
pub fn set_sd(&self, sd: bool) -> Self {
self.bf_insert(usize::BITS as usize - 1, 1, sd as usize)
}
}

read_csr_as!(Mstatus, 0x300);
Expand Down

0 comments on commit a10e637

Please sign in to comment.