Implement full SSD1306 OLED display support: - Splash screen on boot (1.5s) with project name, version, board - Dashboard showing radio state, config, counters, RSSI/SNR - RSSI history sparkline (64-sample ring buffer, 2px-wide bars) - DisplayOn/DisplayOff host commands routed via dedicated channel - Pure render functions against generic DrawTarget (no hardware coupling) - Display on/off control bypasses radio task entirely Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
654 lines
18 KiB
Rust
654 lines
18 KiB
Rust
//! mstatus register
|
||
|
||
pub use super::misa::XLEN;
|
||
use crate::bits::{bf_extract, bf_insert};
|
||
|
||
/// mstatus register
|
||
#[derive(Clone, Copy, Debug)]
|
||
pub struct Mstatus {
|
||
bits: usize,
|
||
}
|
||
|
||
impl From<usize> for Mstatus {
|
||
#[inline]
|
||
fn from(bits: usize) -> Self {
|
||
Self { bits }
|
||
}
|
||
}
|
||
|
||
/// Additional extension state
|
||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||
pub enum XS {
|
||
/// All off
|
||
AllOff = 0,
|
||
|
||
/// None dirty or clean, some on
|
||
NoneDirtyOrClean = 1,
|
||
|
||
/// None dirty, some clean
|
||
NoneDirtySomeClean = 2,
|
||
|
||
/// Some dirty
|
||
SomeDirty = 3,
|
||
}
|
||
|
||
/// Floating-point extension state
|
||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||
pub enum FS {
|
||
Off = 0,
|
||
Initial = 1,
|
||
Clean = 2,
|
||
Dirty = 3,
|
||
}
|
||
|
||
/// Vector extension state
|
||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||
pub enum VS {
|
||
Off = 0,
|
||
Initial = 1,
|
||
Clean = 2,
|
||
Dirty = 3,
|
||
}
|
||
|
||
/// Machine Previous Privilege Mode
|
||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||
pub enum MPP {
|
||
Machine = 3,
|
||
Supervisor = 1,
|
||
User = 0,
|
||
}
|
||
|
||
/// Supervisor Previous Privilege Mode
|
||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||
pub enum SPP {
|
||
Supervisor = 1,
|
||
User = 0,
|
||
}
|
||
|
||
/// Non-instruction-fetch memory endianness
|
||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||
pub enum Endianness {
|
||
BigEndian = 1,
|
||
LittleEndian = 0,
|
||
}
|
||
|
||
impl From<bool> for Endianness {
|
||
fn from(value: bool) -> Self {
|
||
match value {
|
||
true => Self::BigEndian,
|
||
false => Self::LittleEndian,
|
||
}
|
||
}
|
||
}
|
||
|
||
impl Mstatus {
|
||
/// Returns the contents of the register as raw bits
|
||
#[inline]
|
||
pub fn bits(&self) -> usize {
|
||
self.bits
|
||
}
|
||
|
||
/// Supervisor Interrupt Enable
|
||
#[inline]
|
||
pub fn sie(&self) -> bool {
|
||
bf_extract(self.bits, 1, 1) != 0
|
||
}
|
||
|
||
/// Update Supervisor Interrupt Enable
|
||
///
|
||
/// Note this updates a previously read [`Mstatus`] value, but does not
|
||
/// affect the mstatus CSR itself. See [`set_sie`]/[`clear_sie`] to directly
|
||
/// update the CSR.
|
||
#[inline]
|
||
pub fn set_sie(&mut self, sie: bool) {
|
||
self.bits = bf_insert(self.bits, 1, 1, sie as usize);
|
||
}
|
||
|
||
/// Machine Interrupt Enable
|
||
#[inline]
|
||
pub fn mie(&self) -> bool {
|
||
bf_extract(self.bits, 3, 1) != 0
|
||
}
|
||
|
||
/// Update Machine Interrupt Enable
|
||
///
|
||
/// Note this updates a previously read [`Mstatus`] value, but does not
|
||
/// affect the mstatus CSR itself. See [`set_mie`]/[`clear_mie`] to directly
|
||
/// update the CSR.
|
||
#[inline]
|
||
pub fn set_mie(&mut self, mie: bool) {
|
||
self.bits = bf_insert(self.bits, 3, 1, mie as usize);
|
||
}
|
||
|
||
/// Supervisor Previous Interrupt Enable
|
||
#[inline]
|
||
pub fn spie(&self) -> bool {
|
||
bf_extract(self.bits, 5, 1) != 0
|
||
}
|
||
|
||
/// Update Supervisor Previous Interrupt Enable
|
||
///
|
||
/// Note this updates a previously read [`Mstatus`] value, but does not
|
||
/// affect the mstatus CSR itself. See [`set_spie`]` to directly update the
|
||
/// CSR.
|
||
#[inline]
|
||
pub fn set_spie(&mut self, spie: bool) {
|
||
self.bits = bf_insert(self.bits, 5, 1, spie as usize);
|
||
}
|
||
|
||
/// U-mode non-instruction-fetch memory endianness
|
||
#[inline]
|
||
pub fn ube(&self) -> Endianness {
|
||
Endianness::from(bf_extract(self.bits, 6, 1) != 0)
|
||
}
|
||
|
||
/// Update U-mode non-instruction-fetch memory endianness
|
||
///
|
||
/// Note this updates a previously read [`Mstatus`] value, but does not
|
||
/// affect the mstatus CSR itself. See [`set_ube`] to directly update the
|
||
/// CSR.
|
||
#[inline]
|
||
pub fn set_ube(&mut self, endianness: Endianness) {
|
||
self.bits = bf_insert(self.bits, 6, 1, endianness as usize);
|
||
}
|
||
|
||
/// Machine Previous Interrupt Enable
|
||
#[inline]
|
||
pub fn mpie(&self) -> bool {
|
||
bf_extract(self.bits, 7, 1) != 0
|
||
}
|
||
|
||
/// Update Machine Previous Interrupt Enable
|
||
///
|
||
/// Note this updates a previously read [`Mstatus`] value, but does not
|
||
/// affect the mstatus CSR itself. See [`set_mpie`] to directly update the
|
||
/// CSR.
|
||
#[inline]
|
||
pub fn set_mpie(&mut self, mpie: bool) {
|
||
self.bits = bf_insert(self.bits, 7, 1, mpie as usize);
|
||
}
|
||
|
||
/// Supervisor Previous Privilege Mode
|
||
#[inline]
|
||
pub fn spp(&self) -> SPP {
|
||
match bf_extract(self.bits, 8, 1) != 0 {
|
||
true => SPP::Supervisor,
|
||
false => SPP::User,
|
||
}
|
||
}
|
||
|
||
/// Update Supervisor Previous Privilege Mode
|
||
///
|
||
/// Note this updates a previously read [`Mstatus`] value, but does not
|
||
/// affect the mstatus CSR itself. See [`set_spp`] to directly update the
|
||
/// CSR.
|
||
#[inline]
|
||
pub fn set_spp(&mut self, spp: SPP) {
|
||
self.bits = bf_insert(self.bits, 8, 1, spp as usize);
|
||
}
|
||
|
||
/// Machine Previous Privilege Mode
|
||
#[inline]
|
||
pub fn mpp(&self) -> MPP {
|
||
let mpp = bf_extract(self.bits, 11, 2); // bits 11-12
|
||
match mpp {
|
||
0b00 => MPP::User,
|
||
0b01 => MPP::Supervisor,
|
||
0b11 => MPP::Machine,
|
||
_ => unreachable!(),
|
||
}
|
||
}
|
||
|
||
/// Update Machine Previous Privilege Mode
|
||
///
|
||
/// Note this updates a previously read [`Mstatus`] value, but does not
|
||
/// affect the mstatus CSR itself. See [`set_mpp`] to directly update the
|
||
/// CSR.
|
||
#[inline]
|
||
pub fn set_mpp(&mut self, mpp: MPP) {
|
||
self.bits = bf_insert(self.bits, 11, 2, mpp as usize);
|
||
}
|
||
|
||
/// Floating-point extension state
|
||
///
|
||
/// Encodes the status of the floating-point unit, including the CSR `fcsr`
|
||
/// and floating-point data registers `f0–f31`.
|
||
#[inline]
|
||
pub fn fs(&self) -> FS {
|
||
let fs = bf_extract(self.bits, 13, 2); // bits 13-14
|
||
match fs {
|
||
0b00 => FS::Off,
|
||
0b01 => FS::Initial,
|
||
0b10 => FS::Clean,
|
||
0b11 => FS::Dirty,
|
||
_ => unreachable!(),
|
||
}
|
||
}
|
||
|
||
/// Vector extension state
|
||
#[inline]
|
||
pub fn vs(&self) -> VS {
|
||
let fs = bf_extract(self.bits, 9, 2); // bits 9-10
|
||
match fs {
|
||
0b00 => VS::Off,
|
||
0b01 => VS::Initial,
|
||
0b10 => VS::Clean,
|
||
0b11 => VS::Dirty,
|
||
_ => unreachable!(),
|
||
}
|
||
}
|
||
|
||
/// Update Floating-point extension state
|
||
///
|
||
/// Note this updates a previously read [`Mstatus`] value, but does not
|
||
/// affect the mstatus CSR itself. See [`set_fs`] to directly update the
|
||
/// CSR.
|
||
#[inline]
|
||
pub fn set_fs(&mut self, fs: FS) {
|
||
self.bits = bf_insert(self.bits, 13, 2, fs as usize);
|
||
}
|
||
|
||
/// Update vector extension state
|
||
///
|
||
/// Note this updates a previously read [`Mstatus`] value, but does not
|
||
/// affect the mstatus CSR itself. See [`set_vs`] to directly update the
|
||
/// CSR.
|
||
#[inline]
|
||
pub fn set_vs(&mut self, vs: VS) {
|
||
self.bits = bf_insert(self.bits, 9, 2, vs as usize);
|
||
}
|
||
|
||
/// Additional extension state
|
||
///
|
||
/// Encodes the status of additional user-mode extensions and associated
|
||
/// state.
|
||
#[inline]
|
||
pub fn xs(&self) -> XS {
|
||
let xs = bf_extract(self.bits, 15, 2); // bits 15-16
|
||
match xs {
|
||
0b00 => XS::AllOff,
|
||
0b01 => XS::NoneDirtyOrClean,
|
||
0b10 => XS::NoneDirtySomeClean,
|
||
0b11 => XS::SomeDirty,
|
||
_ => unreachable!(),
|
||
}
|
||
}
|
||
|
||
/// Update Additional extension state
|
||
///
|
||
/// Note this updates a previously read [`Mstatus`] value, but does not
|
||
/// affect the mstatus CSR itself.
|
||
#[inline]
|
||
pub fn set_xs(&mut self, xs: XS) {
|
||
self.bits = bf_insert(self.bits, 15, 2, xs as usize);
|
||
}
|
||
|
||
/// Modify Memory PRiVilege
|
||
#[inline]
|
||
pub fn mprv(&self) -> bool {
|
||
bf_extract(self.bits, 17, 1) != 0
|
||
}
|
||
|
||
/// Update Modify Memory PRiVilege
|
||
///
|
||
/// Note this updates a previously read [`Mstatus`] value, but does not
|
||
/// affect the mstatus CSR itself. See [`set_mprv`]/[`clear_mprv`] to
|
||
/// directly update the CSR.
|
||
#[inline]
|
||
pub fn set_mprv(&mut self, mprv: bool) {
|
||
self.bits = bf_insert(self.bits, 17, 1, mprv as usize);
|
||
}
|
||
|
||
/// Permit Supervisor User Memory access
|
||
#[inline]
|
||
pub fn sum(&self) -> bool {
|
||
bf_extract(self.bits, 18, 1) != 0
|
||
}
|
||
|
||
/// Update Permit Supervisor User Memory access
|
||
///
|
||
/// Note this updates a previously read [`Mstatus`] value, but does not
|
||
/// affect the mstatus CSR itself. See [`set_sum`]/[`clear_sum`] to directly
|
||
/// update the CSR.
|
||
#[inline]
|
||
pub fn set_sum(&mut self, sum: bool) {
|
||
self.bits = bf_insert(self.bits, 18, 1, sum as usize);
|
||
}
|
||
|
||
/// Make eXecutable Readable
|
||
#[inline]
|
||
pub fn mxr(&self) -> bool {
|
||
bf_extract(self.bits, 19, 1) != 0
|
||
}
|
||
|
||
/// Update Make eXecutable Readable
|
||
///
|
||
/// Note this updates a previously read [`Mstatus`] value, but does not affect
|
||
/// the mstatus CSR itself. See [`set_mxr`]/[`clear_mxr`] to directly update
|
||
/// the CSR.
|
||
#[inline]
|
||
pub fn set_mxr(&mut self, mxr: bool) {
|
||
self.bits = bf_insert(self.bits, 19, 1, mxr as usize);
|
||
}
|
||
|
||
/// Trap Virtual Memory
|
||
///
|
||
/// If this bit is set, reads or writes to `satp` CSR or execute `sfence.vma`
|
||
/// instruction when in S-mode will raise an illegal instruction exception.
|
||
///
|
||
/// TVM is hard-wired to 0 when S-mode is not supported.
|
||
#[inline]
|
||
pub fn tvm(&self) -> bool {
|
||
bf_extract(self.bits, 20, 1) != 0
|
||
}
|
||
|
||
/// Update Trap Virtual Memory
|
||
///
|
||
/// Note this updates a previously read [`Mstatus`] value, but does not
|
||
/// affect the mstatus CSR itself. See [`set_tvm`]/[`clear_tvm`] to directly
|
||
/// update the CSR.
|
||
#[inline]
|
||
pub fn set_tvm(&mut self, tvm: bool) {
|
||
self.bits = bf_insert(self.bits, 20, 1, tvm as usize);
|
||
}
|
||
|
||
/// Timeout Wait
|
||
///
|
||
/// Indicates that if WFI instruction should be intercepted.
|
||
///
|
||
/// If this bit is set, when WFI is executed in S-mode, and it does not complete
|
||
/// within an implementation specific, bounded time limit, the WFI instruction will cause
|
||
/// an illegal instruction trap; or could always cause trap then the time limit is zero.
|
||
///
|
||
/// TW is hard-wired to 0 when S-mode is not supported.
|
||
#[inline]
|
||
pub fn tw(&self) -> bool {
|
||
bf_extract(self.bits, 21, 1) != 0
|
||
}
|
||
|
||
/// Update Timeout Wait
|
||
///
|
||
/// Note this updates a previously read [`Mstatus`] value, but does not
|
||
/// affect the mstatus CSR itself. See [`set_tw`]/[`clear_tw`] to directly
|
||
/// update the CSR.
|
||
#[inline]
|
||
pub fn set_tw(&mut self, tw: bool) {
|
||
self.bits = bf_insert(self.bits, 21, 1, tw as usize);
|
||
}
|
||
|
||
/// Trap SRET
|
||
///
|
||
/// Indicates that if SRET instruction should be trapped to raise illegal
|
||
/// instruction exception.
|
||
///
|
||
/// If S-mode is not supported, TSR bit is hard-wired to 0.
|
||
#[inline]
|
||
pub fn tsr(&self) -> bool {
|
||
bf_extract(self.bits, 22, 1) != 0
|
||
}
|
||
|
||
/// Update Trap SRET
|
||
///
|
||
/// Note this updates a previously read [`Mstatus`] value, but does not
|
||
/// affect the mstatus CSR itself. See [`set_tsr`]/[`clear_tsr`] to directly
|
||
/// update the CSR.
|
||
#[inline]
|
||
pub fn set_tsr(&mut self, tsr: bool) {
|
||
self.bits = bf_insert(self.bits, 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`].
|
||
#[inline]
|
||
pub fn uxl(&self) -> XLEN {
|
||
match () {
|
||
#[cfg(riscv32)]
|
||
() => XLEN::XLEN32,
|
||
#[cfg(not(riscv32))]
|
||
() => XLEN::from(bf_extract(self.bits, 32, 2) as u8),
|
||
}
|
||
}
|
||
|
||
/// Update Effective xlen in U-mode (i.e., `UXLEN`).
|
||
///
|
||
/// Note this updates a previously read [`Mstatus`] value, but does not
|
||
/// affect the mstatus CSR itself.
|
||
#[inline]
|
||
pub fn set_uxl(&mut self, uxl: XLEN) {
|
||
#[cfg(not(riscv32))]
|
||
{
|
||
self.bits = bf_insert(self.bits, 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`].
|
||
#[inline]
|
||
pub fn sxl(&self) -> XLEN {
|
||
match () {
|
||
#[cfg(riscv32)]
|
||
() => XLEN::XLEN32,
|
||
#[cfg(not(riscv32))]
|
||
() => XLEN::from(bf_extract(self.bits, 34, 2) as u8),
|
||
}
|
||
}
|
||
|
||
/// Update Effective xlen in S-mode (i.e., `SXLEN`).
|
||
///
|
||
/// Note this updates a previously read [`Mstatus`] value, but does not
|
||
/// affect the mstatus CSR itself.
|
||
#[inline]
|
||
pub fn set_sxl(&mut self, sxl: XLEN) {
|
||
#[cfg(not(riscv32))]
|
||
{
|
||
self.bits = bf_insert(self.bits, 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.
|
||
pub fn sbe(&self) -> Endianness {
|
||
match () {
|
||
#[cfg(riscv32)]
|
||
() => super::mstatush::read().sbe(),
|
||
#[cfg(not(riscv32))]
|
||
() => Endianness::from(bf_extract(self.bits, 36, 1) != 0),
|
||
}
|
||
}
|
||
|
||
/// Update S-mode non-instruction-fetch memory endianness
|
||
///
|
||
/// Note this updates a previously read [`Mstatus`] value, but does not
|
||
/// affect the mstatus CSR itself. See [`set_sbe`] to directly update the
|
||
/// CSR.
|
||
#[inline]
|
||
pub fn set_sbe(&mut self, endianness: Endianness) {
|
||
#[cfg(not(riscv32))]
|
||
{
|
||
self.bits = bf_insert(self.bits, 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
|
||
pub fn mbe(&self) -> Endianness {
|
||
match () {
|
||
#[cfg(riscv32)]
|
||
() => super::mstatush::read().mbe(),
|
||
#[cfg(not(riscv32))]
|
||
() => Endianness::from(bf_extract(self.bits, 37, 1) != 0),
|
||
}
|
||
}
|
||
/// Update M-mode non-instruction-fetch memory endianness
|
||
///
|
||
/// Note this updates a previously read [`Mstatus`] value, but does not
|
||
/// affect the mstatus CSR itself. See [`set_mbe`] to directly update the
|
||
/// CSR.
|
||
#[inline]
|
||
pub fn set_mbe(&mut self, endianness: Endianness) {
|
||
#[cfg(not(riscv32))]
|
||
{
|
||
self.bits = bf_insert(self.bits, 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 {
|
||
bf_extract(self.bits, usize::BITS as usize - 1, 1) != 0
|
||
}
|
||
|
||
/// Update whether either the FS field or XS field signals the presence of
|
||
/// some dirty state
|
||
///
|
||
/// Note this updates a previously read [`Mstatus`] value, but does not
|
||
/// affect the mstatus CSR itself.
|
||
#[inline]
|
||
pub fn set_sd(&mut self, sd: bool) {
|
||
self.bits = bf_insert(self.bits, usize::BITS as usize - 1, 1, sd as usize);
|
||
}
|
||
}
|
||
|
||
read_csr_as!(Mstatus, 0x300);
|
||
write_csr_as!(Mstatus, 0x300);
|
||
set!(0x300);
|
||
clear!(0x300);
|
||
|
||
set_clear_csr!(
|
||
/// User Interrupt Enable
|
||
, set_uie, clear_uie, 1 << 0);
|
||
set_clear_csr!(
|
||
/// Supervisor Interrupt Enable
|
||
, set_sie, clear_sie, 1 << 1);
|
||
set_clear_csr!(
|
||
/// Machine Interrupt Enable
|
||
, set_mie, clear_mie, 1 << 3);
|
||
set_csr!(
|
||
/// User Previous Interrupt Enable
|
||
, set_upie, 1 << 4);
|
||
set_csr!(
|
||
/// Supervisor Previous Interrupt Enable
|
||
, set_spie, 1 << 5);
|
||
set_csr!(
|
||
/// Machine Previous Interrupt Enable
|
||
, set_mpie, 1 << 7);
|
||
set_clear_csr!(
|
||
/// Modify Memory PRiVilege
|
||
, set_mprv, clear_mprv, 1 << 17);
|
||
set_clear_csr!(
|
||
/// Permit Supervisor User Memory access
|
||
, set_sum, clear_sum, 1 << 18);
|
||
set_clear_csr!(
|
||
/// Make eXecutable Readable
|
||
, set_mxr, clear_mxr, 1 << 19);
|
||
set_clear_csr!(
|
||
/// Trap Virtual Memory
|
||
, set_tvm, clear_tvm, 1 << 20);
|
||
set_clear_csr!(
|
||
/// Timeout Wait
|
||
, set_tw, clear_tw, 1 << 21);
|
||
set_clear_csr!(
|
||
/// Trap SRET
|
||
, set_tsr, clear_tsr, 1 << 22);
|
||
|
||
/// Set U-mode non-instruction-fetch memory endianness
|
||
#[inline]
|
||
pub unsafe fn set_ube(endianness: Endianness) {
|
||
match endianness {
|
||
Endianness::BigEndian => _set(1 << 6),
|
||
Endianness::LittleEndian => _clear(1 << 6),
|
||
}
|
||
}
|
||
|
||
/// Supervisor Previous Privilege Mode
|
||
#[inline]
|
||
pub unsafe fn set_spp(spp: SPP) {
|
||
match spp {
|
||
SPP::Supervisor => _set(1 << 8),
|
||
SPP::User => _clear(1 << 8),
|
||
}
|
||
}
|
||
|
||
/// Machine Previous Privilege Mode
|
||
#[inline]
|
||
pub unsafe fn set_mpp(mpp: MPP) {
|
||
let mut value = _read();
|
||
value &= !(0x3 << 11); // clear previous value
|
||
value |= (mpp as usize) << 11;
|
||
_write(value);
|
||
}
|
||
|
||
/// Floating-point extension state
|
||
#[inline]
|
||
pub unsafe fn set_fs(fs: FS) {
|
||
let mut value = _read();
|
||
value &= !(0x3 << 13); // clear previous value
|
||
value |= (fs as usize) << 13;
|
||
_write(value);
|
||
}
|
||
|
||
/// Vector extension state
|
||
#[inline]
|
||
pub unsafe fn set_vs(vs: VS) {
|
||
let mut value = _read();
|
||
value &= !(0x3 << 9); // clear previous value
|
||
value |= (vs as usize) << 9;
|
||
_write(value);
|
||
}
|
||
|
||
/// Set S-mode non-instruction-fetch memory endianness
|
||
///
|
||
/// # Note
|
||
///
|
||
/// In RISCV-32, this function calls [`crate::register::mstatush::set_sbe`]
|
||
#[inline]
|
||
pub unsafe fn set_sbe(endianness: Endianness) {
|
||
match () {
|
||
#[cfg(riscv32)]
|
||
() => super::mstatush::set_sbe(endianness),
|
||
#[cfg(not(riscv32))]
|
||
() => match endianness {
|
||
Endianness::BigEndian => _set(1 << 36),
|
||
Endianness::LittleEndian => _clear(1 << 36),
|
||
},
|
||
}
|
||
}
|
||
|
||
/// Set M-mode non-instruction-fetch memory endianness
|
||
///
|
||
/// # Note
|
||
///
|
||
/// In RISCV-32, this function calls [`crate::register::mstatush::set_mbe`]
|
||
#[inline]
|
||
pub unsafe fn set_mbe(endianness: Endianness) {
|
||
match () {
|
||
#[cfg(riscv32)]
|
||
() => super::mstatush::set_mbe(endianness),
|
||
#[cfg(not(riscv32))]
|
||
() => match endianness {
|
||
Endianness::BigEndian => _set(1 << 37),
|
||
Endianness::LittleEndian => _clear(1 << 37),
|
||
},
|
||
}
|
||
}
|
||
|
||
#[cfg(test)]
|
||
mod test {
|
||
use super::*;
|
||
|
||
#[test]
|
||
fn test_mpp() {
|
||
let mut mstatus = Mstatus { bits: 0 };
|
||
mstatus.set_mpp(MPP::User);
|
||
assert_eq!(mstatus.mpp(), MPP::User);
|
||
mstatus.set_mpp(MPP::Machine);
|
||
assert_eq!(mstatus.mpp(), MPP::Machine);
|
||
mstatus.set_mpp(MPP::Supervisor);
|
||
assert_eq!(mstatus.mpp(), MPP::Supervisor);
|
||
}
|
||
}
|