#![no_std]
pub mod geilen;
pub mod peripheral;
pub mod register;
use core::num::NonZeroU16;
use riscv::InterruptNumber;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[repr(transparent)]
pub struct Iid {
number: NonZeroU16,
}
impl Iid {
pub const SSOFT: Iid = Iid::new(1).unwrap();
pub const MSOFT: Iid = Iid::new(3).unwrap();
pub const STIMER: Iid = Iid::new(5).unwrap();
pub const MTIMER: Iid = Iid::new(7).unwrap();
pub const SEXT: Iid = Iid::new(9).unwrap();
pub const MEXT: Iid = Iid::new(11).unwrap();
#[inline]
pub const fn new(number: u16) -> Option<Iid> {
const IID_MAX: u16 = 2047;
match number {
1..=IID_MAX => match NonZeroU16::new(number) {
Some(nz) => Some(Iid { number: nz }),
None => None, },
_ => None,
}
}
#[inline]
pub const fn number(self) -> u16 {
self.number.get()
}
}
impl From<riscv::interrupt::Interrupt> for Iid {
#[inline]
fn from(value: riscv::interrupt::Interrupt) -> Self {
assert!(value.number() <= u16::MAX as usize && value.number() != 0);
Iid::new(value.number() as u16).unwrap()
}
}
impl TryFrom<Iid> for riscv::interrupt::Interrupt {
type Error = ();
#[inline]
fn try_from(value: Iid) -> Result<Self, Self::Error> {
use riscv::interrupt::Interrupt;
match value {
Iid::SSOFT => Ok(Interrupt::SupervisorSoft),
Iid::MSOFT => Ok(Interrupt::MachineSoft),
Iid::STIMER => Ok(Interrupt::SupervisorTimer),
Iid::MTIMER => Ok(Interrupt::MachineTimer),
Iid::SEXT => Ok(Interrupt::SupervisorExternal),
Iid::MEXT => Ok(Interrupt::MachineExternal),
_ => Err(()),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn iid_new_bounds() {
assert!(Iid::new(0).is_none());
assert!(Iid::new(1).is_some());
assert!(Iid::new(2047).is_some());
assert!(Iid::new(2048).is_none());
}
#[test]
fn iid_consts() {
assert_eq!(Iid::SSOFT.number(), 1);
assert_eq!(Iid::MSOFT.number(), 3);
assert_eq!(Iid::STIMER.number(), 5);
assert_eq!(Iid::MTIMER.number(), 7);
assert_eq!(Iid::SEXT.number(), 9);
assert_eq!(Iid::MEXT.number(), 11);
}
#[test]
fn iid_usage_match_if() {
let iid = Iid::MEXT;
if iid == Iid::MTIMER {
unreachable!()
} else if iid == Iid::MSOFT {
unreachable!()
} else if iid == Iid::MEXT {
assert!(true)
} else {
unreachable!()
}
match iid {
Iid::MTIMER => unreachable!(),
Iid::MSOFT => unreachable!(),
Iid::MEXT => assert!(true),
_ => unreachable!(),
}
let iid = Some(Iid::MSOFT);
match iid {
Some(Iid::MTIMER) => unreachable!(),
Some(Iid::MSOFT) => assert!(true),
Some(Iid::MEXT) => unreachable!(),
Some(_) | None => unreachable!(),
}
}
#[test]
fn iid_convert_riscv_crate() {
use riscv::interrupt::Interrupt;
let irqs = [
(Interrupt::SupervisorExternal, Iid::SEXT),
(Interrupt::MachineExternal, Iid::MEXT),
(Interrupt::SupervisorSoft, Iid::SSOFT),
(Interrupt::MachineSoft, Iid::MSOFT),
(Interrupt::SupervisorTimer, Iid::STIMER),
(Interrupt::MachineTimer, Iid::MTIMER),
];
for (riscv_irq, aia_iid) in irqs {
assert_eq!(aia_iid, Iid::from(riscv_irq));
assert_eq!(aia_iid, riscv_irq.into());
assert_eq!(aia_iid.try_into(), Ok(riscv_irq));
assert_eq!(Interrupt::try_from(aia_iid), Ok(riscv_irq));
}
}
}