Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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

- Add Mtopi
- 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
8 changes: 8 additions & 0 deletions riscv/src/register/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1070,3 +1070,11 @@ macro_rules! test_csr_field {
}
}};
}

#[cfg(test)]
#[macro_export]
macro_rules! test_ro_csr_field {
($reg:ident, $field:ident: [$start:expr, $end:expr], $expected:expr) => {{
assert_eq!($reg.$field(), $expected);
}};
}
91 changes: 91 additions & 0 deletions riscv/src/register/mtopi.rs
Original file line number Diff line number Diff line change
@@ -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.is_interrupt_pending() {
//! let interrupt_id = mtopi_val.iid();
//! let priority = mtopi_val.iprio();
//! 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_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_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_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_ro_csr_field!(mtopi, iid: [16, 27], 0x1);
test_ro_csr_field!(mtopi, iprio: [0, 7], 0x0);

let mtopi = Mtopi::from_bits(1);
test_ro_csr_field!(mtopi, iid: [16, 27], 0x0);
test_ro_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);
}
}