Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rework on misa and mstatus #142

Merged
merged 2 commits into from
Sep 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,18 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

### Added

- Add `read_csr_as_rv32`, `set_rv32`, and `clear_rv32` macros
- Add `mstatus::uxl` and `mstatus::sxl`
- Add `mstatus::ube`, `mstatus::sbe`, and `mstatus::mbe` endianness bit fields
- Add `mstatush` registers (RISCV-32 only)
- Add generic implementation of a PLIC peripheral
- Add `asm::fence()`, a wrapper for implementing a `fence` instruction
- Add `asm::fence_i()`, a wrapper for implementing a `fence.i` instruction
- Add `TryFrom` implementation for `mcause::{Interrupt, Exception}` and `scause::{Interrupt, Exception}`

### Changed

- `misa::MXL` renamed to `misa::XLEN`
- Removed `bit_field` dependency
- CI actions updated. They now use `checkout@v3` and `dtolnay/rust-toolchain`.
- `mcause::{Interrupt, Exception}` and `scause::{Interrupt, Exception}` now implement `From` trait for `usize`
Expand All @@ -24,7 +29,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

- Fix `scause::Exception` missing `LoadMisaligned`
- Fix `scause::Exception` missing `SupervisorEnvCall`
- Removed user-level interrupts from `mcause::Interrupt` and `scause::Interrupt`
- Removed user-level interrupts from `mcause::Interrupt` and `scause::Interrupt`
- Removed user-level interrupts from `mstatus`

## [v0.10.1] - 2023-01-18

Expand Down
2 changes: 2 additions & 0 deletions src/register/mod.rs → src/register.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
//! - mcycleh
//! - minstreth
//! - mhpmcounter<3-31>h
//! - mstatush

#[macro_use]
mod macros;
Expand Down Expand Up @@ -69,6 +70,7 @@ pub mod mideleg;
pub mod mie;
pub mod misa;
pub mod mstatus;
pub mod mstatush;
pub mod mtvec;

// Machine Trap Handling
Expand Down
48 changes: 48 additions & 0 deletions src/register/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,20 @@ macro_rules! read_csr_as {
};
}

macro_rules! read_csr_as_rv32 {
($register:ident, $csr_number:literal) => {
read_csr_rv32!($csr_number);

/// Reads the CSR
#[inline]
pub fn read() -> $register {
$register {
bits: unsafe { _read() },
}
}
};
}

macro_rules! read_csr_as_usize {
($csr_number:literal) => {
read_csr!($csr_number);
Expand Down Expand Up @@ -151,6 +165,23 @@ macro_rules! set {
};
}

macro_rules! set_rv32 {
($csr_number:literal) => {
/// Set the CSR
#[inline]
#[allow(unused_variables)]
unsafe fn _set(bits: usize) {
match () {
#[cfg(riscv32)]
() => core::arch::asm!(concat!("csrrs x0, ", stringify!($csr_number), ", {0}"), in(reg) bits),

#[cfg(not(riscv32))]
() => unimplemented!(),
}
}
};
}

macro_rules! clear {
($csr_number:literal) => {
/// Clear the CSR
Expand All @@ -168,6 +199,23 @@ macro_rules! clear {
};
}

macro_rules! clear_rv32 {
($csr_number:literal) => {
/// Clear the CSR
#[inline]
#[allow(unused_variables)]
unsafe fn _clear(bits: usize) {
match () {
#[cfg(riscv32)]
() => core::arch::asm!(concat!("csrrc x0, ", stringify!($csr_number), ", {0}"), in(reg) bits),

#[cfg(not(riscv32))]
() => unimplemented!(),
}
}
};
}

macro_rules! set_csr {
($(#[$attr:meta])*, $set_field:ident, $e:expr) => {
$(#[$attr])*
Expand Down
43 changes: 26 additions & 17 deletions src/register/misa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,39 +8,48 @@ pub struct Misa {
bits: NonZeroUsize,
}

/// Machine XLEN
/// Base integer ISA width
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum MXL {
pub enum XLEN {
XLEN32,
XLEN64,
XLEN128,
}

impl XLEN {
/// Converts a number into an ISA width
pub(crate) fn from(value: u8) -> Self {
match value {
1 => XLEN::XLEN32,
2 => XLEN::XLEN64,
3 => XLEN::XLEN128,
_ => unreachable!(),
}
}
}

impl Misa {
/// Returns the contents of the register as raw bits
#[inline]
pub fn bits(&self) -> usize {
self.bits.get()
}

/// Returns the machine xlen.
/// Effective xlen in M-mode (i.e., `MXLEN`).
#[inline]
pub fn mxl(&self) -> MXL {
let value = match () {
#[cfg(target_pointer_width = "32")]
() => (self.bits() >> 30) as u8,
#[cfg(target_pointer_width = "64")]
() => (self.bits() >> 62) as u8,
};
match value {
1 => MXL::XLEN32,
2 => MXL::XLEN64,
3 => MXL::XLEN128,
_ => unreachable!(),
}
pub fn mxl(&self) -> XLEN {
let value = (self.bits() >> (usize::BITS - 2)) as u8;
XLEN::from(value)
}

/// Returns true when the atomic extension is implemented.
/// Returns true when a given extension is implemented.
///
/// # Example
///
/// ``` no_run
/// let misa = unsafe { riscv::register::misa::read() };
/// assert!(misa.has_extension('A')); // panics if atomic extension is not implemented
/// ```
#[inline]
pub fn has_extension(&self, extension: char) -> bool {
let bit = extension as u8 - 65;
Expand Down
140 changes: 117 additions & 23 deletions src/register/mstatus.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
//! mstatus register

// FIXME: in 1.12 spec there will be `SBE` and `MBE` bits.
// They allows to execute supervisor in given big endian,
// they would be in a new register `mstatush` in RV32; we should implement `mstatush`
// at that time.
// FIXME: `SXL` and `UXL` bits require a structure interpreting XLEN,
// which would be the best way we implement this using Rust?
pub use super::misa::XLEN;

/// mstatus register
#[derive(Clone, Copy, Debug)]
Expand Down Expand Up @@ -53,13 +48,23 @@ pub enum SPP {
User = 0,
}

impl Mstatus {
/// User Interrupt Enable
#[inline]
pub fn uie(&self) -> bool {
self.bits & (1 << 0) != 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 {
/// Supervisor Interrupt Enable
#[inline]
pub fn sie(&self) -> bool {
Expand All @@ -72,18 +77,18 @@ impl Mstatus {
self.bits & (1 << 3) != 0
}

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

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

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

/// Machine Previous Interrupt Enable
#[inline]
pub fn mpie(&self) -> bool {
Expand Down Expand Up @@ -196,13 +201,57 @@ impl Mstatus {
self.bits & (1 << 22) != 0
}

/*
FIXME: There are MBE and SBE bits in 1.12; once Privileged Specification version 1.12
is ratified, there should be read functions of these bits as well.
*/
/// 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((self.bits >> 32) as u8 & 0x3),
}
}

/// Whether either the FS field or XS field
/// signals the presence of some dirty state
/// 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((self.bits >> 34) as u8 & 0x3),
}
}

/// 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(self.bits & (1 << 36) != 0),
}
}

/// 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(self.bits & (1 << 37) != 0),
}
}

/// 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
Expand Down Expand Up @@ -251,6 +300,15 @@ 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) {
Expand All @@ -277,3 +335,39 @@ pub unsafe fn set_fs(fs: FS) {
value |= (fs as usize) << 13;
_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),
},
}
}
Loading