Skip to content

Commit b2f88f8

Browse files
feat: add mtopi CSR (Machine Top Priority Interrupt) register
Add support for the mtopi CSR (0x7C0) from RISC-V Advanced Interrupt Architecture (AIA). Provides read-only access to highest-priority pending interrupt information with IID and IPID fields.
1 parent 02c1edf commit b2f88f8

File tree

3 files changed

+113
-0
lines changed

3 files changed

+113
-0
lines changed

riscv/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
99

1010
### Added
1111

12+
- Added `mtopi` CSR support for the RISC-V Advanced Interrupt Architecture extension.
1213
- Added DCSR (Debug Control and Status Register) CSR support for the RISC-V
1314
- Add `miselect` CSR
1415
- Improved assembly macro handling in asm.rs

riscv/src/register.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ pub mod mepc;
8989
pub mod mip;
9090
pub mod mscratch;
9191
pub mod mtinst;
92+
pub mod mtopi;
9293
pub mod mtval;
9394
pub mod mtval2;
9495

riscv/src/register/mtopi.rs

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
//! mtopi register — Machine Top Priority Interrupt (0x7C0)
2+
//!
3+
//! Provides information about the highest-priority pending interrupt when AIA (Advanced Interrupt Architecture) is supported.
4+
//! This CSR is part of the RISC-V Advanced Interrupt Architecture extension and allows software to quickly
5+
//! identify the most important pending interrupt without scanning through multiple interrupt pending registers.
6+
//!
7+
//! # Usage
8+
//!
9+
//! ```no_run
10+
//! use riscv::register::mtopi;
11+
//!
12+
//! // Read the machine top priority interrupt register
13+
//! let mtopi_val = mtopi::read();
14+
//!
15+
//! if mtopi_val.has_interrupt() {
16+
//! let interrupt_id = mtopi_val.interrupt_id();
17+
//! let priority = mtopi_val.priority();
18+
//! println!("Highest priority interrupt: ID={}, Priority={}", interrupt_id, priority);
19+
//! } else {
20+
//! println!("No interrupts pending");
21+
//! }
22+
//! ```
23+
24+
read_only_csr! {
25+
/// Machine Top Priority Interrupt Register
26+
Mtopi: 0x7C0,
27+
mask: usize::MAX,
28+
}
29+
30+
read_only_csr_field! {
31+
Mtopi,
32+
/// Interrupt ID (bits 16..27)
33+
///
34+
/// Identifies the specific interrupt source. A value of 0 indicates no interrupt is pending.
35+
/// Non-zero values correspond to specific interrupt sources as defined by the interrupt controller.
36+
iid: [16:27],
37+
}
38+
39+
read_only_csr_field! {
40+
Mtopi,
41+
/// Interrupt Priority ID (bits 0..7)
42+
///
43+
/// Represents the priority level of the pending interrupt.
44+
/// Higher numerical values indicate higher priority interrupts.
45+
ipid: [0:7],
46+
}
47+
48+
impl Mtopi {
49+
/// Returns true if there is a valid interrupt pending
50+
///
51+
/// When this returns true, both `interrupt_id()` and `priority()` will return meaningful values.
52+
#[inline]
53+
pub fn has_interrupt(&self) -> bool {
54+
self.iid() != 0
55+
}
56+
57+
/// Returns the interrupt priority, with higher values indicating higher priority
58+
///
59+
/// This value is only meaningful when `has_interrupt()` returns true.
60+
#[inline]
61+
pub fn priority(&self) -> usize {
62+
self.ipid()
63+
}
64+
65+
/// Returns the interrupt identifier
66+
///
67+
/// A value of 0 indicates no interrupt is pending. Non-zero values identify
68+
/// specific interrupt sources as defined by the interrupt controller configuration.
69+
#[inline]
70+
pub fn interrupt_id(&self) -> usize {
71+
self.iid()
72+
}
73+
}
74+
75+
#[cfg(test)]
76+
mod tests {
77+
use super::*;
78+
79+
#[test]
80+
fn test_mtopi_fields() {
81+
let mtopi = Mtopi::from_bits(0);
82+
83+
assert_eq!(mtopi.iid(), 0);
84+
assert_eq!(mtopi.ipid(), 0);
85+
assert!(!mtopi.has_interrupt());
86+
assert_eq!(mtopi.priority(), 0);
87+
assert_eq!(mtopi.interrupt_id(), 0);
88+
89+
// Test with some interrupt pending (IID = 11, IPID = 5)
90+
let mtopi = Mtopi::from_bits((11 << 16) | 5);
91+
92+
assert_eq!(mtopi.iid(), 11);
93+
assert_eq!(mtopi.ipid(), 5);
94+
assert!(mtopi.has_interrupt());
95+
assert_eq!(mtopi.priority(), 5);
96+
assert_eq!(mtopi.interrupt_id(), 11);
97+
98+
// Test maximum values
99+
let mtopi = Mtopi::from_bits((0xFFF << 16) | 0xFF);
100+
101+
assert_eq!(mtopi.iid(), 0xFFF);
102+
assert_eq!(mtopi.ipid(), 0xFF);
103+
assert!(mtopi.has_interrupt());
104+
}
105+
106+
#[test]
107+
fn test_mtopi_bitmask() {
108+
let mtopi = Mtopi::from_bits(usize::MAX);
109+
assert_eq!(mtopi.bits(), usize::MAX);
110+
}
111+
}

0 commit comments

Comments
 (0)