From 012aa79db4a388a3b6263ec3f85f9d255d9f7c40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rom=C3=A1n=20C=C3=A1rdenas?= Date: Fri, 3 Nov 2023 12:41:02 +0100 Subject: [PATCH] HAL implementations --- .github/workflows/clippy.yml | 2 +- Cargo.toml | 5 ++ examples/e310x.rs | 165 +++++++++++++++++++++++++++++++++++ src/aclint.rs | 26 ++---- src/aclint/mswi.rs | 27 ++++++ src/aclint/mtimer.rs | 35 +++++++- src/aclint/sswi.rs | 27 ++++++ src/hal.rs | 5 ++ src/hal/aclint.rs | 47 ++++++++++ src/hal_async.rs | 5 ++ src/hal_async/aclint.rs | 82 +++++++++++++++++ src/lib.rs | 3 + src/macros.rs | 59 ++++++++++++- src/plic.rs | 31 ++----- 14 files changed, 473 insertions(+), 46 deletions(-) create mode 100644 examples/e310x.rs create mode 100644 src/hal.rs create mode 100644 src/hal/aclint.rs create mode 100644 src/hal_async.rs create mode 100644 src/hal_async/aclint.rs diff --git a/.github/workflows/clippy.yml b/.github/workflows/clippy.yml index c8c92a6..272ec79 100644 --- a/.github/workflows/clippy.yml +++ b/.github/workflows/clippy.yml @@ -37,4 +37,4 @@ jobs: runs-on: ubuntu-latest if: always() steps: - - run: jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}' \ No newline at end of file + - run: jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}' diff --git a/Cargo.toml b/Cargo.toml index d6a2f93..0509281 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,8 +6,13 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +embedded-hal = "1.0.0-rc.1" +embedded-hal-async = { version = "1.0.0-rc.1", optional = true } riscv = { git = "/~https://github.com/rust-embedded/riscv", branch = "master" } +[features] +hal-async = ["embedded-hal-async"] + [package.metadata.docs.rs] default-target = "riscv64imac-unknown-none-elf" targets = [ diff --git a/examples/e310x.rs b/examples/e310x.rs new file mode 100644 index 0000000..df21cf1 --- /dev/null +++ b/examples/e310x.rs @@ -0,0 +1,165 @@ +use riscv_peripheral::{ + aclint::HartIdNumber, + plic::{ContextNumber, InterruptNumber, PriorityNumber}, +}; + +#[repr(u16)] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum HartId { + H0 = 0, +} + +unsafe impl HartIdNumber for HartId { + const MAX_HART_ID_NUMBER: u16 = 0; + + #[inline] + fn number(self) -> u16 { + self as _ + } + + #[inline] + fn from_number(number: u16) -> Result { + if number > Self::MAX_HART_ID_NUMBER { + Err(number) + } else { + // SAFETY: valid context number + Ok(unsafe { core::mem::transmute(number) }) + } + } +} + +unsafe impl ContextNumber for HartId { + const MAX_CONTEXT_NUMBER: u16 = 0; + + #[inline] + fn number(self) -> u16 { + self as _ + } + + #[inline] + fn from_number(number: u16) -> Result { + if number > Self::MAX_CONTEXT_NUMBER { + Err(number) + } else { + // SAFETY: valid context number + Ok(unsafe { core::mem::transmute(number) }) + } + } +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[repr(u16)] +pub enum Interrupt { + WATCHDOG = 1, + RTC = 2, + UART0 = 3, + UART1 = 4, + QSPI0 = 5, + QSPI1 = 6, + QSPI2 = 7, + GPIO0 = 8, + GPIO1 = 9, + GPIO2 = 10, + GPIO3 = 11, + GPIO4 = 12, + GPIO5 = 13, + GPIO6 = 14, + GPIO7 = 15, + GPIO8 = 16, + GPIO9 = 17, + GPIO10 = 18, + GPIO11 = 19, + GPIO12 = 20, + GPIO13 = 21, + GPIO14 = 22, + GPIO15 = 23, + GPIO16 = 24, + GPIO17 = 25, + GPIO18 = 26, + GPIO19 = 27, + GPIO20 = 28, + GPIO21 = 29, + GPIO22 = 30, + GPIO23 = 31, + GPIO24 = 32, + GPIO25 = 33, + GPIO26 = 34, + GPIO27 = 35, + GPIO28 = 36, + GPIO29 = 37, + GPIO30 = 38, + GPIO31 = 39, + PWM0CMP0 = 40, + PWM0CMP1 = 41, + PWM0CMP2 = 42, + PWM0CMP3 = 43, + PWM1CMP0 = 44, + PWM1CMP1 = 45, + PWM1CMP2 = 46, + PWM1CMP3 = 47, + PWM2CMP0 = 48, + PWM2CMP1 = 49, + PWM2CMP2 = 50, + PWM2CMP3 = 51, + I2C0 = 52, +} + +unsafe impl InterruptNumber for Interrupt { + const MAX_INTERRUPT_NUMBER: u16 = 52; + + #[inline] + fn number(self) -> u16 { + self as _ + } + + #[inline] + fn from_number(number: u16) -> Result { + if number == 0 || number > Self::MAX_INTERRUPT_NUMBER { + Err(number) + } else { + // SAFETY: valid interrupt number + Ok(unsafe { core::mem::transmute(number) }) + } + } +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[repr(u8)] +pub enum Priority { + P0 = 0, + P1 = 1, + P2 = 2, + P3 = 3, + P4 = 4, + P5 = 5, + P6 = 6, + P7 = 7, +} + +unsafe impl PriorityNumber for Priority { + const MAX_PRIORITY_NUMBER: u8 = 7; + + #[inline] + fn number(self) -> u8 { + self as _ + } + + #[inline] + fn from_number(number: u8) -> Result { + if number > Self::MAX_PRIORITY_NUMBER { + Err(number) + } else { + // SAFETY: valid priority number + Ok(unsafe { core::mem::transmute(number) }) + } + } +} + +riscv_peripheral::clint_codegen!( + base 0x0200_0000, + freq 32_768, + mtimecmps [mtimecmp0=(HartId::H0,"`H0`")], + msips [msip0=(HartId::H0,"`H0`")], +); + +fn main() {} diff --git a/src/aclint.rs b/src/aclint.rs index e29ed73..c19b644 100644 --- a/src/aclint.rs +++ b/src/aclint.rs @@ -136,6 +136,7 @@ pub(crate) mod test { crate::clint_codegen!( base 0x0200_0000, mtimecmps [mtimecmp0=(HartId::H0,"`H0`"), mtimecmp1=(HartId::H1,"`H1`"), mtimecmp2=(HartId::H2,"`H2`")], + msips [msip0=(HartId::H0,"`H0`"), msip1=(HartId::H1,"`H1`"), msip2=(HartId::H2,"`H2`")], ); let mswi = CLINT::mswi(); @@ -150,25 +151,16 @@ pub(crate) mod test { let mtimecmp2 = mtimer.mtimecmp(HartId::H2); assert_eq!(mtimecmp0.get_ptr() as usize, 0x0200_4000); - assert_eq!(mtimecmp1.get_ptr() as usize, 0x0200_4000 + 1 * 8); // 8 bytes per register + assert_eq!(mtimecmp1.get_ptr() as usize, 0x0200_4000 + 8); // 8 bytes per register assert_eq!(mtimecmp2.get_ptr() as usize, 0x0200_4000 + 2 * 8); - // Check that the mtimecmpX functions are equivalent to the mtimer.mtimecmp(X) function. - let mtimecmp0 = CLINT::mtimecmp0(); - let mtimecmp1 = CLINT::mtimecmp1(); - let mtimecmp2 = CLINT::mtimecmp2(); + assert_eq!(CLINT::mtime(), mtimer.mtime); + assert_eq!(CLINT::mtimecmp0(), mtimer.mtimecmp(HartId::H0)); + assert_eq!(CLINT::mtimecmp1(), mtimer.mtimecmp(HartId::H1)); + assert_eq!(CLINT::mtimecmp2(), mtimer.mtimecmp(HartId::H2)); - assert_eq!( - mtimecmp0.get_ptr() as usize, - mtimer.mtimecmp(HartId::H0).get_ptr() as usize - ); - assert_eq!( - mtimecmp1.get_ptr() as usize, - mtimer.mtimecmp(HartId::H1).get_ptr() as usize - ); - assert_eq!( - mtimecmp2.get_ptr() as usize, - mtimer.mtimecmp(HartId::H2).get_ptr() as usize - ); + assert_eq!(CLINT::msip0(), mswi.msip(HartId::H0)); + assert_eq!(CLINT::msip1(), mswi.msip(HartId::H1)); + assert_eq!(CLINT::msip2(), mswi.msip(HartId::H2)); } } diff --git a/src/aclint/mswi.rs b/src/aclint/mswi.rs index fd66314..3af4af7 100644 --- a/src/aclint/mswi.rs +++ b/src/aclint/mswi.rs @@ -58,3 +58,30 @@ impl MSIP { self.register.write(0); } } + +#[cfg(test)] +mod test { + use super::super::test::HartId; + use super::*; + + #[test] + fn test_mswi() { + // slice to emulate the interrupt pendings register + let raw_reg = [0u32; HartId::MAX_HART_ID_NUMBER as usize + 1]; + // SAFETY: valid memory address + let mswi = unsafe { MSWI::new(raw_reg.as_ptr() as _) }; + + for i in 0..=HartId::MAX_HART_ID_NUMBER { + let hart_id = HartId::from_number(i).unwrap(); + let msip = mswi.msip(hart_id); + assert!(!msip.is_pending()); + assert_eq!(raw_reg[i as usize], 0); + msip.pend(); + assert!(msip.is_pending()); + assert_ne!(raw_reg[i as usize], 0); + msip.unpend(); + assert!(!msip.is_pending()); + assert_eq!(raw_reg[i as usize], 0); + } + } +} diff --git a/src/aclint/mtimer.rs b/src/aclint/mtimer.rs index 5deb79b..7144567 100644 --- a/src/aclint/mtimer.rs +++ b/src/aclint/mtimer.rs @@ -18,7 +18,7 @@ impl MTIMER { /// /// # Safety /// - /// The base address must point to a valid `MTIMER` peripheral. + /// The base addresses must point to valid `MTIMECMP` and `MTIME` peripherals. #[inline] pub const unsafe fn new(mtimecmp: usize, mtime: usize) -> Self { Self { @@ -44,3 +44,36 @@ safe_peripheral!(MTIMECMP, u64, RW); // MTIME register. safe_peripheral!(MTIME, u64, RW); + +#[cfg(test)] +mod test { + use super::super::test::HartId; + use super::*; + + #[test] + fn check_mtimer() { + // slice to emulate the mtimecmp registers + let raw_mtimecmp = [0u64; HartId::MAX_HART_ID_NUMBER as usize + 1]; + let raw_mtime = 0u64; + // SAFETY: valid memory addresses + let mtimer = + unsafe { MTIMER::new(raw_mtimecmp.as_ptr() as _, &raw_mtime as *const u64 as _) }; + + assert_eq!( + mtimer.mtimecmp(HartId::H0).get_ptr() as usize, + raw_mtimecmp.as_ptr() as usize + ); + assert_eq!(mtimer.mtimecmp(HartId::H1).get_ptr() as usize, unsafe { + raw_mtimecmp.as_ptr().offset(1) + } + as usize); + assert_eq!(mtimer.mtimecmp(HartId::H2).get_ptr() as usize, unsafe { + raw_mtimecmp.as_ptr().offset(2) + } + as usize); + assert_eq!( + mtimer.mtime.get_ptr() as usize, + &raw_mtime as *const u64 as _ + ); + } +} diff --git a/src/aclint/sswi.rs b/src/aclint/sswi.rs index e31c6cf..51072d6 100644 --- a/src/aclint/sswi.rs +++ b/src/aclint/sswi.rs @@ -89,3 +89,30 @@ impl SETSSIP { self.register.write(0); } } + +#[cfg(test)] +mod test { + use super::super::test::HartId; + use super::*; + + #[test] + fn test_sswi() { + // slice to emulate the interrupt pendings register + let raw_reg = [0u32; HartId::MAX_HART_ID_NUMBER as usize + 1]; + // SAFETY: valid memory address + let mswi = unsafe { SSWI::new(raw_reg.as_ptr() as _) }; + + for i in 0..=HartId::MAX_HART_ID_NUMBER { + let hart_id = HartId::from_number(i).unwrap(); + let setssip = mswi.setssip(hart_id); + assert!(!setssip.is_pending()); + assert_eq!(raw_reg[i as usize], 0); + setssip.pend(); + assert!(setssip.is_pending()); + assert_ne!(raw_reg[i as usize], 0); + setssip.unpend(); + assert!(!setssip.is_pending()); + assert_eq!(raw_reg[i as usize], 0); + } + } +} diff --git a/src/hal.rs b/src/hal.rs new file mode 100644 index 0000000..8d16ffe --- /dev/null +++ b/src/hal.rs @@ -0,0 +1,5 @@ +//! trait implementations for embedded-hal + +pub use embedded_hal::*; // re-export embedded-hal to allow macros to use it + +pub mod aclint; // ACLINT and CLINT peripherals diff --git a/src/hal/aclint.rs b/src/hal/aclint.rs new file mode 100644 index 0000000..d448b55 --- /dev/null +++ b/src/hal/aclint.rs @@ -0,0 +1,47 @@ +//! Delay trait implementation for (A)CLINT peripherals + +use crate::aclint::mtimer::MTIME; +pub use crate::hal::delay::DelayUs; + +/// Delay implementation for (A)CLINT peripherals. +pub struct Delay { + mtime: MTIME, + freq: usize, +} + +impl Delay { + /// Creates a new `Delay` instance. + #[inline] + pub const fn new(mtime: MTIME, freq: usize) -> Self { + Self { mtime, freq } + } + + /// Returns the frequency of the `MTIME` register. + #[inline] + pub const fn get_freq(&self) -> usize { + self.freq + } + + /// Sets the frequency of the `MTIME` register. + #[inline] + pub fn set_freq(&mut self, freq: usize) { + self.freq = freq; + } + + /// Returns the `MTIME` register. + #[inline] + pub const fn get_mtime(&self) -> MTIME { + self.mtime + } +} + +impl DelayUs for Delay { + #[inline] + fn delay_us(&mut self, us: u32) { + let time_from = self.mtime.read(); + let time_to = time_from.wrapping_add(us as u64 * self.freq as u64 / 1_000_000); + + while time_to < self.mtime.read() {} // wait for overflow + while time_to > self.mtime.read() {} // wait for time to pass + } +} diff --git a/src/hal_async.rs b/src/hal_async.rs new file mode 100644 index 0000000..5cd093c --- /dev/null +++ b/src/hal_async.rs @@ -0,0 +1,5 @@ +//! async trait implementations for embedded-hal + +pub use embedded_hal_async::*; // re-export embedded-hal-async to allow macros to use it + +pub mod aclint; // ACLINT and CLINT peripherals diff --git a/src/hal_async/aclint.rs b/src/hal_async/aclint.rs new file mode 100644 index 0000000..25c18d0 --- /dev/null +++ b/src/hal_async/aclint.rs @@ -0,0 +1,82 @@ +//! Asynchronous delay implementation for the (A)CLINT peripheral. + +use crate::aclint::mtimer::MTIME; +pub use crate::hal::aclint::Delay; +pub use crate::hal_async::delay::DelayUs; +use core::{ + cmp::Ordering, + future::Future, + pin::Pin, + task::{Context, Poll}, +}; + +enum DelayAsyncState { + WaitOverflow(u64), + Wait(u64), + Ready, +} + +struct FSMDelay { + mtime: MTIME, + state: DelayAsyncState, +} + +impl FSMDelay { + pub fn new(n_ticks: u64, mtime: MTIME) -> Self { + let t_from = mtime.read(); + let t_to = t_from.wrapping_add(n_ticks); + + let state = match t_to.cmp(&t_from) { + Ordering::Less => DelayAsyncState::WaitOverflow(t_to), + Ordering::Greater => DelayAsyncState::Wait(t_to), + Ordering::Equal => DelayAsyncState::Ready, + }; + + Self { mtime, state } + } +} + +impl Future for FSMDelay { + type Output = (); + + fn poll(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll { + match self.state { + DelayAsyncState::WaitOverflow(t_to) => match t_to.cmp(&self.mtime.read()) { + Ordering::Less => Poll::Pending, + Ordering::Greater => { + self.state = DelayAsyncState::Wait(t_to); + Poll::Pending + } + Ordering::Equal => { + self.state = DelayAsyncState::Ready; + Poll::Ready(()) + } + }, + DelayAsyncState::Wait(t_to) => { + if self.mtime.read() < t_to { + Poll::Pending + } else { + self.state = DelayAsyncState::Ready; + Poll::Ready(()) + } + } + DelayAsyncState::Ready => Poll::Ready(()), + } + } +} + +impl DelayUs for Delay { + #[inline] + async fn delay_us(&mut self, us: u32) { + let n_ticks = us as u64 * self.get_freq() as u64 / 1_000_000; + let state = FSMDelay::new(n_ticks, self.get_mtime()); + state.await; + } + + #[inline] + async fn delay_ms(&mut self, ms: u32) { + let n_ticks = ms as u64 * self.get_freq() as u64 / 1_000; + let state = FSMDelay::new(n_ticks, self.get_mtime()); + state.await; + } +} diff --git a/src/lib.rs b/src/lib.rs index 2a6a6c7..8bfd17b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,6 +6,9 @@ pub use riscv; // re-export riscv crate to allow macros to use it pub mod common; // common definitions for all peripherals +pub mod hal; // trait implementations for embedded-hal +#[cfg(feature = "hal-async")] +pub mod hal_async; // async trait implementations for embedded-hal pub mod macros; // macros for easing the definition of peripherals in PACs pub mod aclint; // ACLINT and CLINT peripherals diff --git a/src/macros.rs b/src/macros.rs index 39a4d58..38571dc 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -3,10 +3,12 @@ /// Macro to create interfaces to CLINT peripherals in PACs. /// The resulting struct will be named `CLINT`, and will provide safe access to the CLINT registers. /// -/// This macro expects 2 different argument types: +/// This macro expects 4 different argument types: /// /// - Base address (**MANDATORY**): base address of the CLINT peripheral of the target. +/// - Frequency (**OPTIONAL**): clock frequency (in Hz) of the `MTIME` register. It enables the `delay` method of the `CLINT` struct. /// - Per-HART mtimecmp registers (**OPTIONAL**): a list of `mtimecmp` registers for easing access to per-HART mtimecmp regs. +/// - Per-HART msip registers (**OPTIONAL**): a list of `msip` registers for easing access to per-HART msip regs. /// /// Check the examples below for more details about the usage and syntax of this macro. /// @@ -17,10 +19,11 @@ /// ``` /// use riscv_peripheral::clint_codegen; /// -/// clint_codegen!(base 0x0200_0000,); // do not forget the ending comma! +/// clint_codegen!(base 0x0200_0000, freq 32_768,); // do not forget the ending comma! /// /// let mswi = CLINT::mswi(); // MSWI peripheral /// let mtimer = CLINT::mtimer(); // MTIMER peripheral +/// let delay = CLINT::delay(); // For the `embedded_hal::delay::DelayUs` and `embedded_hal_async::delay::DelayUs` traits /// ``` /// /// ## Base address and per-HART mtimecmp registers @@ -49,7 +52,8 @@ /// /// clint_codegen!( /// base 0x0200_0000, -/// mtimecmps [mtimecmp0 = (HartId::H0, "`H0`"), mtimecmp1 = (HartId::H1, "`H1`"), mtimecmp2 = (HartId::H2, "`H2`")], // do not forget the ending comma! +/// mtimecmps [mtimecmp0 = (HartId::H0, "`H0`"), mtimecmp1 = (HartId::H1, "`H1`"), mtimecmp2 = (HartId::H2, "`H2`")], +/// msips [msip0=(HartId::H0,"`H0`"), msip1=(HartId::H1,"`H1`"), msip2=(HartId::H2,"`H2`")], // do not forget the ending comma! /// ); /// /// let mswi = CLINT::mswi(); // MSWI peripheral @@ -58,6 +62,10 @@ /// let mtimecmp0 = CLINT::mtimecmp0(); // mtimecmp register for HART 0 /// let mtimecmp1 = CLINT::mtimecmp1(); // mtimecmp register for HART 1 /// let mtimecmp2 = CLINT::mtimecmp2(); // mtimecmp register for HART 2 +/// +/// let msip0 = CLINT::msip0(); // msip register for HART 0 +/// let msip1 = CLINT::msip1(); // msip register for HART 1 +/// let msip2 = CLINT::msip2(); // msip register for HART 2 /// ``` #[macro_export] macro_rules! clint_codegen { @@ -67,6 +75,7 @@ macro_rules! clint_codegen { }; (base $addr:literal, $($tail:tt)*) => { /// CLINT peripheral + #[allow(clippy::upper_case_acronyms)] #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub struct CLINT; @@ -175,13 +184,54 @@ macro_rules! clint_codegen { pub const fn mtimer() -> $crate::aclint::mtimer::MTIMER { $crate::aclint::CLINT::::mtimer() } + + /// Returns the `MTIME` register of the `MTIMER` peripheral. + #[inline] + pub const fn mtime() -> $crate::aclint::mtimer::MTIME { + Self::mtimer().mtime + } + } + $crate::clint_codegen!($($tail)*); + }; + (freq $freq:literal, $($tail:tt)*) => { + impl CLINT { + /// Returns the frequency of the `MTIME` register. + #[inline] + pub const fn freq() -> usize { + $freq + } + + /// Delay implementation for CLINT peripherals. + /// + /// # Note + /// + /// You must export the `riscv_peripheral::hal::delay::DelayUs` trait in order to use delay methods. + /// You must export the `riscv_peripheral::hal_async::delay::DelayUs` trait in order to use async delay methods. + #[inline] + pub const fn delay() -> $crate::hal::aclint::Delay { + $crate::hal::aclint::Delay::new(Self::mtime(), Self::freq()) + } + } + $crate::clint_codegen!($($tail)*); + }; + (msips [$($fn:ident = ($hart:expr , $shart:expr)),+], $($tail:tt)*) => { + impl CLINT { + $( + #[doc = "Returns the `msip` register for HART "] + #[doc = $shart] + #[doc = "."] + #[inline] + pub fn $fn() -> $crate::aclint::mswi::MSIP { + Self::mswi().msip($hart) + } + )* } $crate::clint_codegen!($($tail)*); }; (mtimecmps [$($fn:ident = ($hart:expr , $shart:expr)),+], $($tail:tt)*) => { impl CLINT { $( - #[doc = "Returns the `mtimecmp` peripheral HART "] + #[doc = "Returns the `mtimecmp` register for HART "] #[doc = $shart] #[doc = "."] #[inline] @@ -203,6 +253,7 @@ macro_rules! plic_codegen { }; (base $addr:literal, $($tail:tt)*) => { /// PLIC peripheral + #[allow(clippy::upper_case_acronyms)] #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub struct PLIC; diff --git a/src/plic.rs b/src/plic.rs index cf64395..3185a77 100644 --- a/src/plic.rs +++ b/src/plic.rs @@ -361,38 +361,23 @@ pub(crate) mod test { for i in 0..=Context::MAX_CONTEXT_NUMBER { let context = Context::from_number(i).unwrap(); + let i = i as usize; + let ctx = PLIC::ctx(context); - assert_eq!( - ctx.enables().address(), - 0x0C00_0000 + 0x2000 + i as usize * 0x80 - ); + assert_eq!(ctx.enables().address(), 0x0C00_0000 + 0x2000 + i * 0x80); assert_eq!( ctx.threshold().get_ptr() as usize, - 0x0C00_0000 + 0x20_0000 + i as usize * 0x1000 + 0x0C00_0000 + 0x20_0000 + i * 0x1000 ); assert_eq!( ctx.claim().get_ptr() as usize, - 0x0C00_0000 + 0x20_0004 + i as usize * 0x1000 + 0x0C00_0000 + 0x20_0004 + i * 0x1000 ); } - let ctx0 = PLIC::ctx0(); - let ctx_0_ = PLIC::ctx(Context::C0); - assert_eq!(ctx0.enables().address(), ctx_0_.enables().address()); - assert_eq!(ctx0.threshold().get_ptr(), ctx_0_.threshold().get_ptr()); - assert_eq!(ctx0.claim().get_ptr(), ctx_0_.claim().get_ptr()); - - let ctx1 = PLIC::ctx1(); - let ctx_1_ = PLIC::ctx(Context::C1); - assert_eq!(ctx1.enables().address(), ctx_1_.enables().address()); - assert_eq!(ctx1.threshold().get_ptr(), ctx_1_.threshold().get_ptr()); - assert_eq!(ctx1.claim().get_ptr(), ctx_1_.claim().get_ptr()); - - let ctx2 = PLIC::ctx2(); - let ctx_2_ = PLIC::ctx(Context::C2); - assert_eq!(ctx2.enables().address(), ctx_2_.enables().address()); - assert_eq!(ctx2.threshold().get_ptr(), ctx_2_.threshold().get_ptr()); - assert_eq!(ctx2.claim().get_ptr(), ctx_2_.claim().get_ptr()); + assert_eq!(PLIC::ctx0(), PLIC::ctx(Context::C0)); + assert_eq!(PLIC::ctx1(), PLIC::ctx(Context::C1)); + assert_eq!(PLIC::ctx2(), PLIC::ctx(Context::C2)); } }