diff --git a/riscv/CHANGELOG.md b/riscv/CHANGELOG.md index 07d20828..15eec1cb 100644 --- a/riscv/CHANGELOG.md +++ b/riscv/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Add `miselect` CSR - Improved assembly macro handling in asm.rs - New `rt` and `rt-v-trap` features to opt-in `riscv-rt`-related code in `riscv::pac_enum` macro. +- Add `mvien` + `mvienh` CSR # Changed diff --git a/riscv/src/register.rs b/riscv/src/register.rs index a20328bc..64c3b483 100644 --- a/riscv/src/register.rs +++ b/riscv/src/register.rs @@ -91,6 +91,9 @@ pub mod mscratch; pub mod mtinst; pub mod mtval; pub mod mtval2; +pub mod mvien; +#[cfg(any(test, target_arch = "riscv32"))] +pub mod mvienh; // Machine Protection and Translation mod pmpcfgx; diff --git a/riscv/src/register/mvien.rs b/riscv/src/register/mvien.rs new file mode 100644 index 00000000..af162063 --- /dev/null +++ b/riscv/src/register/mvien.rs @@ -0,0 +1,157 @@ +//! mvien register + +use crate::bits::{bf_extract, bf_insert}; +use riscv_pac::result::{Error, Result}; +use riscv_pac::InterruptNumber; + +#[cfg(target_arch = "riscv32")] +const MASK: usize = 0xffff_e222; +#[cfg(not(target_arch = "riscv32"))] +const MASK: usize = 0xffff_ffff_ffff_e222; + +read_write_csr! { + /// `mvien` register + Mvien: 0x308, + mask: MASK, +} + +read_write_csr_field! { + Mvien, + /// Alias of `mie.SSIE` + ssoft: 1, +} + +read_write_csr_field! { + Mvien, + /// Alias of `mie.STIE` + stimer: 5, +} + +read_write_csr_field! { + Mvien, + /// Alias of `mie.SEIE` + sext: 9, +} + +impl Mvien { + /// Represents the minimum interrupt of the unlabelled virtual interrupt range. + pub const MIN_INTERRUPT: usize = 13; + /// Represents the maximum interrupt of the unlabelled virtual interrupt range. + #[cfg(target_arch = "riscv32")] + pub const MAX_INTERRUPT: usize = 31; + /// Represents the maximum interrupt of the unlabelled virtual interrupt range. + #[cfg(not(target_arch = "riscv32"))] + pub const MAX_INTERRUPT: usize = 63; + + /// Gets whether the interrupt number is a valid virtual interrupt. + #[inline] + pub const fn is_valid_interrupt(int: usize) -> bool { + matches!(int, 1 | 5 | 9 | Self::MIN_INTERRUPT..=Self::MAX_INTERRUPT) + } + + /// Check if a specific core interrupt source is enabled. + /// + /// Returns `Error` if the interrupt number is invalid. + #[inline] + pub fn is_enabled(&self, interrupt: I) -> bool { + let n = interrupt.number(); + + Self::is_valid_interrupt(n) && bf_extract(self.bits, n, 1) != 0 + } + + /// Enable a specific core interrupt source. + /// + /// Returns `Error` if the interrupt number is invalid. + #[inline] + pub fn enable(&mut self, interrupt: I) -> Result<()> { + let n = interrupt.number(); + + if Self::is_valid_interrupt(n) { + self.bits = bf_insert(self.bits, n, 1, 1); + Ok(()) + } else { + Err(Error::InvalidVariant(n)) + } + } + + /// Disable a specific core interrupt source. + /// + /// Returns `Error` if the interrupt number is invalid. + #[inline] + pub fn disable(&mut self, interrupt: I) -> Result<()> { + let n = interrupt.number(); + + if Self::is_valid_interrupt(n) { + self.bits = bf_insert(self.bits, n, 1, 0); + Ok(()) + } else { + Err(Error::InvalidVariant(n)) + } + } +} + +set!(0x308); +clear!(0x308); + +set_clear_csr!( + /// Supervisor Software Interrupt Enable + , set_ssoft, clear_ssoft, 1 << 1); +set_clear_csr!( + /// Supervisor Timer Interrupt Enable + , set_stimer, clear_stimer, 1 << 5); +set_clear_csr!( + /// Supervisor External Interrupt Enable + , set_sext, clear_sext, 1 << 9); + +read_composite_csr!(super::mvienh::read().bits(), read().bits()); + +#[cfg(test)] +mod tests { + use super::*; + + /// Represents a custom set of virtual interrupts. + /// + /// NOTE: a real implementation may want to enumerate the valid virtual interrupt variants. + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + pub struct VirtualInterrupt(usize); + + /// SAFETY: `VirtualInterrupt` represents the virtual RISC-V interrupts + unsafe impl InterruptNumber for VirtualInterrupt { + const MAX_INTERRUPT_NUMBER: usize = Mvien::MAX_INTERRUPT; + + #[inline] + fn number(self) -> usize { + self.0 + } + + #[inline] + fn from_number(value: usize) -> Result { + if Mvien::is_valid_interrupt(value) { + Ok(Self(value)) + } else { + Err(Error::InvalidVariant(value)) + } + } + } + + #[test] + fn test_mvien() { + let mut m = Mvien::from_bits(0); + + test_csr_field!(m, ssoft); + test_csr_field!(m, stimer); + test_csr_field!(m, sext); + + (0..=VirtualInterrupt::MAX_INTERRUPT_NUMBER) + .filter_map(|n| VirtualInterrupt::from_number(n).ok()) + .for_each(|int| { + assert!(!m.is_enabled(int)); + + assert!(m.enable(int).is_ok()); + assert!(m.is_enabled(int)); + + assert!(m.disable(int).is_ok()); + assert!(!m.is_enabled(int)); + }); + } +} diff --git a/riscv/src/register/mvienh.rs b/riscv/src/register/mvienh.rs new file mode 100644 index 00000000..9ec5438f --- /dev/null +++ b/riscv/src/register/mvienh.rs @@ -0,0 +1,118 @@ +//! mvienh register + +use crate::bits::{bf_extract, bf_insert}; +use riscv_pac::result::{Error, Result}; +use riscv_pac::InterruptNumber; + +read_write_csr! { + /// `mvienh` register + Mvienh: 0x318, + mask: 0xffff_ffff, +} + +set!(0x318); +clear!(0x318); + +impl Mvienh { + /// Represents the value to shift interrupt numbers to their relative value. + pub const INTERRUPT_SHIFT: usize = 32; + /// Represents the minimum interrupt of the unlabelled virtual interrupt range. + pub const MIN_INTERRUPT: usize = 32; + /// Represents the maximum interrupt of the unlabelled virtual interrupt range. + pub const MAX_INTERRUPT: usize = 63; + + /// Gets whether the interrupt number is a valid virtual interrupt. + #[inline] + pub const fn is_valid_interrupt(int: usize) -> bool { + matches!(int, Self::MIN_INTERRUPT..=Self::MAX_INTERRUPT) + } + + /// Shifts the high-order interrupt number bits down to their relative value. + #[inline] + pub const fn shift_interrupt(int: usize) -> usize { + int.saturating_sub(Self::INTERRUPT_SHIFT) + } + + /// Check if a specific core interrupt source is enabled. + /// + /// Returns `Error` if the interrupt number is invalid. + #[inline] + pub fn is_enabled(&self, interrupt: I) -> bool { + let n = interrupt.number(); + + Self::is_valid_interrupt(n) && bf_extract(self.bits, Self::shift_interrupt(n), 1) != 0 + } + + /// Enable a specific core interrupt source. + #[inline] + pub fn enable(&mut self, interrupt: I) -> Result<()> { + let n = interrupt.number(); + + if Self::is_valid_interrupt(n) { + self.bits = bf_insert(self.bits, Self::shift_interrupt(n), 1, 1); + Ok(()) + } else { + Err(Error::InvalidVariant(n)) + } + } + + /// Disable a specific core interrupt source. + #[inline] + pub fn disable(&mut self, interrupt: I) -> Result<()> { + let n = interrupt.number(); + + if Self::is_valid_interrupt(n) { + self.bits = bf_insert(self.bits, Self::shift_interrupt(n), 1, 0); + Ok(()) + } else { + Err(Error::InvalidVariant(n)) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + /// Represents a custom set of virtual interrupts. + /// + /// NOTE: a real implementation may want to enumerate the valid virtual interrupt variants. + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + pub struct VirtualInterrupt(usize); + + /// SAFETY: `VirtualInterrupt` represents the virtual RISC-V interrupts + unsafe impl InterruptNumber for VirtualInterrupt { + const MAX_INTERRUPT_NUMBER: usize = Mvienh::MAX_INTERRUPT; + + #[inline] + fn number(self) -> usize { + self.0 + } + + #[inline] + fn from_number(value: usize) -> Result { + if Mvienh::is_valid_interrupt(value) { + Ok(Self(value)) + } else { + Err(Error::InvalidVariant(value)) + } + } + } + + #[test] + fn test_mvienh() { + let mut m = Mvienh::from_bits(0); + + (Mvienh::MIN_INTERRUPT..=Mvienh::MAX_INTERRUPT) + .filter_map(|n| VirtualInterrupt::from_number(n).ok()) + .for_each(|int| { + assert!(!m.is_enabled(int)); + + assert!(m.enable(int).is_ok()); + assert!(m.is_enabled(int)); + + assert!(m.disable(int).is_ok()); + assert!(!m.is_enabled(int)); + }); + } +} diff --git a/typos.toml b/typos.toml index a5674cea..a4a8e72e 100644 --- a/typos.toml +++ b/typos.toml @@ -1,2 +1,2 @@ [default] -extend-ignore-re = ["[Ss][Ii][Ee]", "[Ss][Xx][Ll]", "[.]?useed[.,:]?"] +extend-ignore-re = ["[Ss][Ii][Ee]", "[Ss][Xx][Ll]", "[.]?useed[.,:]?", "[Ss][Tt][Ii][Pp]"]