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 @@ -9,6 +9,7 @@ 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
Expand Down
1 change: 1 addition & 0 deletions riscv/src/register.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
13 changes: 13 additions & 0 deletions riscv/src/register/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1041,6 +1041,19 @@ macro_rules! test_csr_field {
}
}};

// test a multi-bit bitfield for read-only CSR (must come before enum pattern)
($reg:ident, $field:ident: [$start:literal, $end:literal]) => {{
let bits = $reg.bits();

let shift = $end - $start + 1;
let mask = (1usize << shift) - 1;

let exp_val = (bits >> $start) & mask;

// Test field extraction matches expected value
assert_eq!($reg.$field(), exp_val);
}};

// test an enum bit field
($reg:ident, $field:ident: $var:expr) => {{
$crate::paste! {
Expand Down
102 changes: 102 additions & 0 deletions riscv/src/register/mtopi.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
//! 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: usize::MAX,
}

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.
/// Higher numerical values indicate higher priority interrupts.
ipid: [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 has_interrupt(&self) -> bool {
self.iid() != 0
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_mtopi_fields() {
// Test using helper macros as requested - follows mcounteren.rs pattern
let mut mtopi = Mtopi::from_bits(0);

// Test iid field [16:27] - using test helper macro
test_csr_field!(mtopi, iid: [16, 27]);
// Test ipid field [0:7] - using test helper macro
test_csr_field!(mtopi, ipid: [0, 7]);

// Test helper methods
assert!(!mtopi.has_interrupt());

// Test with some interrupt pending (IID = 11, IPID = 5)
mtopi = Mtopi::from_bits((11 << 16) | 5);
test_csr_field!(mtopi, iid: [16, 27]);
test_csr_field!(mtopi, ipid: [0, 7]);
assert!(mtopi.has_interrupt());

// Test maximum values for each field
mtopi = Mtopi::from_bits((0xFFF << 16) | 0xFF);
test_csr_field!(mtopi, iid: [16, 27]);
test_csr_field!(mtopi, ipid: [0, 7]);
assert!(mtopi.has_interrupt());

// Test field boundaries
mtopi = Mtopi::from_bits(1 << 16);
test_csr_field!(mtopi, iid: [16, 27]);
test_csr_field!(mtopi, ipid: [0, 7]);

mtopi = Mtopi::from_bits(1);
test_csr_field!(mtopi, iid: [16, 27]);
test_csr_field!(mtopi, ipid: [0, 7]);
}

#[test]
fn test_mtopi_bitmask() {
let mtopi = Mtopi::from_bits(usize::MAX);
assert_eq!(mtopi.bits(), usize::MAX);
}
}
Loading