use crate::{
bits::{bf_extract, bf_insert},
result::{Error, Result},
InterruptNumber,
};
read_write_csr! {
Mvienh: 0x318,
mask: 0xffff_ffff,
}
set!(0x318);
clear!(0x318);
impl Mvienh {
pub const INTERRUPT_SHIFT: usize = 32;
pub const MIN_INTERRUPT: usize = 32;
pub const MAX_INTERRUPT: usize = 63;
#[inline]
pub const fn is_valid_interrupt(int: usize) -> bool {
matches!(int, Self::MIN_INTERRUPT..=Self::MAX_INTERRUPT)
}
#[inline]
pub const fn shift_interrupt(int: usize) -> usize {
int.saturating_sub(Self::INTERRUPT_SHIFT)
}
#[inline]
pub fn is_enabled<I: InterruptNumber>(&self, interrupt: I) -> bool {
let n = interrupt.number();
Self::is_valid_interrupt(n) && bf_extract(self.bits, Self::shift_interrupt(n), 1) != 0
}
#[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))
}
}
#[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::*;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct VirtualInterrupt(usize);
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!(!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));
});
}
}