Skip to content
Open
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
1 change: 1 addition & 0 deletions riscv/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
3 changes: 3 additions & 0 deletions riscv/src/register.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
160 changes: 160 additions & 0 deletions riscv/src/register/mvien.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
//! 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<I: InterruptNumber>(&self, interrupt: I) -> Result<bool> {
let n = interrupt.number();
if Self::is_valid_interrupt(n) {
Ok(bf_extract(self.bits, n, 1) != 0)
} else {
Err(Error::InvalidVariant(n))
}
}

/// Enable a specific core interrupt source.
///
/// Returns `Error` if the interrupt number is invalid.
#[inline]
pub fn enable<I: InterruptNumber>(&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<I: InterruptNumber>(&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<Self> {
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_eq!(m.is_enabled(int), Ok(false));

assert!(m.enable(int).is_ok());
assert_eq!(m.is_enabled(int), Ok(true));

assert!(m.disable(int).is_ok());
assert_eq!(m.is_enabled(int), Ok(false));
});
}
}
122 changes: 122 additions & 0 deletions riscv/src/register/mvienh.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
//! 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<I: InterruptNumber>(&self, interrupt: I) -> Result<bool> {
let n = interrupt.number();

if Self::is_valid_interrupt(n) {
Ok(bf_extract(self.bits, Self::shift_interrupt(n), 1) != 0)
} else {
Err(Error::InvalidVariant(n))
}
}

/// Enable a specific core interrupt source.
#[inline]
pub fn enable<I: InterruptNumber>(&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<I: InterruptNumber>(&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<Self> {
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_eq!(m.is_enabled(int), Ok(false));

assert!(m.enable(int).is_ok());
assert_eq!(m.is_enabled(int), Ok(true));

assert!(m.disable(int).is_ok());
assert_eq!(m.is_enabled(int), Ok(false));
});
}
}
2 changes: 1 addition & 1 deletion typos.toml
Original file line number Diff line number Diff line change
@@ -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]"]
Loading