From 9a3b72705371f2af10ab57e495e6f9bd63713369 Mon Sep 17 00:00:00 2001 From: KushalMeghani1644 Date: Thu, 30 Oct 2025 15:19:13 +0530 Subject: [PATCH 1/2] Add MTOPI CSR --- riscv/CHANGELOG.md | 7 +++ riscv/src/register.rs | 1 + riscv/src/register/macros.rs | 12 +++++ riscv/src/register/mtopi.rs | 91 ++++++++++++++++++++++++++++++++++++ 4 files changed, 111 insertions(+) create mode 100644 riscv/src/register/mtopi.rs diff --git a/riscv/CHANGELOG.md b/riscv/CHANGELOG.md index 23756a28..7d566631 100644 --- a/riscv/CHANGELOG.md +++ b/riscv/CHANGELOG.md @@ -9,9 +9,16 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Added +- Added `mtopi` CSR support for the RISC-V Advanced Interrupt Architecture extension. - Added DCSR (Debug Control and Status Register) CSR support for the RISC-V - 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. + +# Changed + +- Bump MSRV to 1.68 for latest version of syn 2.0 +- Now, `riscv::pac_enum` macro only includes trap-related code if `rt` or `rt-v-trap` features are enabled. ## [v0.15.0] - 2025-09-08 diff --git a/riscv/src/register.rs b/riscv/src/register.rs index a20328bc..72903fc6 100644 --- a/riscv/src/register.rs +++ b/riscv/src/register.rs @@ -89,6 +89,7 @@ pub mod mepc; pub mod mip; pub mod mscratch; pub mod mtinst; +pub mod mtopi; pub mod mtval; pub mod mtval2; diff --git a/riscv/src/register/macros.rs b/riscv/src/register/macros.rs index b5c9ee8e..2c4d6470 100644 --- a/riscv/src/register/macros.rs +++ b/riscv/src/register/macros.rs @@ -1041,6 +1041,18 @@ macro_rules! test_csr_field { } }}; + // test a multi-bit bitfield for read-only CSR (must come before enum pattern) + ($reg:ident, $field:ident: [$start:expr, $end:expr]) => {{ + let bits = $reg.bits(); + let exp_val = $crate::bits::bf_extract(bits, $start, $end - $start + 1); + assert_eq!($reg.$field(), exp_val); + }}; + + // test a multi-bit bitfield for read-only CSR with expected value + ($reg:ident, $field:ident: [$start:expr, $end:expr], $expected:expr) => {{ + assert_eq!($reg.$field(), $expected); + }}; + // test an enum bit field ($reg:ident, $field:ident: $var:expr) => {{ $crate::paste! { diff --git a/riscv/src/register/mtopi.rs b/riscv/src/register/mtopi.rs new file mode 100644 index 00000000..49b8ec02 --- /dev/null +++ b/riscv/src/register/mtopi.rs @@ -0,0 +1,91 @@ +//! mtopi register — Machine Top Priority Interrupt (0x7C0) +//! +//! Provides information about the highest-priority pending interrupt when AIA (Advanced Interrupt Architecture) is supported. +//! This CSR is part of the RISC-V Advanced Interrupt Architecture extension and allows software to quickly +//! identify the most important pending interrupt without scanning through multiple interrupt pending registers. +//! +//! # Usage +//! +//! ```no_run +//! use riscv::register::mtopi; +//! +//! // Read the machine top priority interrupt register +//! let mtopi_val = mtopi::read(); +//! +//! if mtopi_val.has_interrupt() { +//! let interrupt_id = mtopi_val.iid(); +//! let priority = mtopi_val.ipid(); +//! println!("Highest priority interrupt: ID={}, Priority={}", interrupt_id, priority); +//! } else { +//! println!("No interrupts pending"); +//! } +//! ``` + +read_only_csr! { + /// Machine Top Priority Interrupt Register + Mtopi: 0x7C0, + mask: 0x0FFF_00FF, +} + +read_only_csr_field! { + Mtopi, + /// Interrupt ID (bits 16..27) + /// + /// Identifies the specific interrupt source. A value of 0 indicates no interrupt is pending. + /// Non-zero values correspond to specific interrupt sources as defined by the interrupt controller. + iid: [16:27], +} + +read_only_csr_field! { + Mtopi, + /// Interrupt Priority ID (bits 0..7) + /// + /// Represents the priority level of the pending interrupt. + /// Lower numerical values indicate higher priority interrupts. + iprio: [0:7], +} + +impl Mtopi { + /// Returns true if there is a valid interrupt pending + /// + /// When this returns true, both `interrupt_id()` and `priority()` will return meaningful values. + #[inline] + pub fn is_interrupt_pending(&self) -> bool { + self.iid() != 0 + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_mtopi_fields() { + let mtopi = Mtopi::from_bits(0); + + test_csr_field!(mtopi, iid: [16, 27], 0x0); + test_csr_field!(mtopi, iprio: [0, 7], 0x0); + + let mtopi = Mtopi::from_bits((11 << 16) | 5); + test_csr_field!(mtopi, iid: [16, 27], 0xB); + test_csr_field!(mtopi, iprio: [0, 7], 0x5); + + let mtopi = Mtopi::from_bits((0xFFF << 16) | 0xFF); + test_csr_field!(mtopi, iid: [16, 27], 0xFFF); + test_csr_field!(mtopi, iprio: [0, 7], 0xFF); + + let mtopi = Mtopi::from_bits(1 << 16); + test_csr_field!(mtopi, iid: [16, 27], 0x1); + test_csr_field!(mtopi, iprio: [0, 7], 0x0); + + let mtopi = Mtopi::from_bits(1); + test_csr_field!(mtopi, iid: [16, 27], 0x0); + test_csr_field!(mtopi, iprio: [0, 7], 0x1); + } + + #[test] + fn test_mtopi_bitmask() { + let mtopi = Mtopi::from_bits(usize::MAX); + assert_eq!(mtopi.bits(), 0x0FFF_00FFusize); + } +} From 3e38720970f7fea44fc3f34154b1f551127a1fcd Mon Sep 17 00:00:00 2001 From: KushalMeghani1644 Date: Thu, 30 Oct 2025 15:43:20 +0530 Subject: [PATCH 2/2] Fix macro pattern conflicts by separating read-only CSR field tests into new test_ro_csr_field! macro --- riscv/src/register/macros.rs | 46 ++++++++++++++++++++---------------- riscv/src/register/mtopi.rs | 24 +++++++++---------- 2 files changed, 37 insertions(+), 33 deletions(-) diff --git a/riscv/src/register/macros.rs b/riscv/src/register/macros.rs index 2c4d6470..26b0e4ac 100644 --- a/riscv/src/register/macros.rs +++ b/riscv/src/register/macros.rs @@ -1041,27 +1041,6 @@ macro_rules! test_csr_field { } }}; - // test a multi-bit bitfield for read-only CSR (must come before enum pattern) - ($reg:ident, $field:ident: [$start:expr, $end:expr]) => {{ - let bits = $reg.bits(); - let exp_val = $crate::bits::bf_extract(bits, $start, $end - $start + 1); - assert_eq!($reg.$field(), exp_val); - }}; - - // test a multi-bit bitfield for read-only CSR with expected value - ($reg:ident, $field:ident: [$start:expr, $end:expr], $expected:expr) => {{ - assert_eq!($reg.$field(), $expected); - }}; - - // test an enum bit field - ($reg:ident, $field:ident: $var:expr) => {{ - $crate::paste! { - $reg.[]($var); - assert_eq!($reg.$field(), $var); - assert_eq!($reg.[](), Ok($var)); - } - }}; - // test a multi-bit bitfield ($reg:ident, $field:ident: [$start:expr, $end:expr], $reset:expr) => {{ let bits = $reg.bits(); @@ -1081,4 +1060,29 @@ macro_rules! test_csr_field { assert_eq!($reg.$field(), exp_val); } }}; + + // test an enum bit field + ($reg:ident, $field:ident: $var:expr) => {{ + $crate::paste! { + $reg.[]($var); + assert_eq!($reg.$field(), $var); + assert_eq!($reg.[](), Ok($var)); + } + }}; +} + +#[cfg(test)] +#[macro_export] +macro_rules! test_ro_csr_field { + // test a multi-bit bitfield for read-only CSR + ($reg:ident, $field:ident: [$start:expr, $end:expr]) => {{ + let bits = $reg.bits(); + let exp_val = $crate::bits::bf_extract(bits, $start, $end - $start + 1); + assert_eq!($reg.$field(), exp_val); + }}; + + // test a multi-bit bitfield for read-only CSR with expected value + ($reg:ident, $field:ident: [$start:expr, $end:expr], $expected:expr) => {{ + assert_eq!($reg.$field(), $expected); + }}; } diff --git a/riscv/src/register/mtopi.rs b/riscv/src/register/mtopi.rs index 49b8ec02..06c5b467 100644 --- a/riscv/src/register/mtopi.rs +++ b/riscv/src/register/mtopi.rs @@ -12,9 +12,9 @@ //! // Read the machine top priority interrupt register //! let mtopi_val = mtopi::read(); //! -//! if mtopi_val.has_interrupt() { +//! if mtopi_val.is_interrupt_pending() { //! let interrupt_id = mtopi_val.iid(); -//! let priority = mtopi_val.ipid(); +//! let priority = mtopi_val.iprio(); //! println!("Highest priority interrupt: ID={}, Priority={}", interrupt_id, priority); //! } else { //! println!("No interrupts pending"); @@ -63,24 +63,24 @@ mod tests { fn test_mtopi_fields() { let mtopi = Mtopi::from_bits(0); - test_csr_field!(mtopi, iid: [16, 27], 0x0); - test_csr_field!(mtopi, iprio: [0, 7], 0x0); + test_ro_csr_field!(mtopi, iid: [16, 27], 0x0); + test_ro_csr_field!(mtopi, iprio: [0, 7], 0x0); let mtopi = Mtopi::from_bits((11 << 16) | 5); - test_csr_field!(mtopi, iid: [16, 27], 0xB); - test_csr_field!(mtopi, iprio: [0, 7], 0x5); + test_ro_csr_field!(mtopi, iid: [16, 27], 0xB); + test_ro_csr_field!(mtopi, iprio: [0, 7], 0x5); let mtopi = Mtopi::from_bits((0xFFF << 16) | 0xFF); - test_csr_field!(mtopi, iid: [16, 27], 0xFFF); - test_csr_field!(mtopi, iprio: [0, 7], 0xFF); + test_ro_csr_field!(mtopi, iid: [16, 27], 0xFFF); + test_ro_csr_field!(mtopi, iprio: [0, 7], 0xFF); let mtopi = Mtopi::from_bits(1 << 16); - test_csr_field!(mtopi, iid: [16, 27], 0x1); - test_csr_field!(mtopi, iprio: [0, 7], 0x0); + test_ro_csr_field!(mtopi, iid: [16, 27], 0x1); + test_ro_csr_field!(mtopi, iprio: [0, 7], 0x0); let mtopi = Mtopi::from_bits(1); - test_csr_field!(mtopi, iid: [16, 27], 0x0); - test_csr_field!(mtopi, iprio: [0, 7], 0x1); + test_ro_csr_field!(mtopi, iid: [16, 27], 0x0); + test_ro_csr_field!(mtopi, iprio: [0, 7], 0x1); } #[test]