Skip to content
Open
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

- 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
111 changes: 111 additions & 0 deletions riscv/src/register/mtopi.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
//! 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.interrupt_id();
//! let priority = mtopi_val.priority();
//! 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,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This mask is not correct. According to the specification, only bits 0 to 27 are used.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have fixed the bits to 0 to 27, thanks for pointing it out.

}

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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you read the documentation... It feels like it is the other way around. Higher numbers indicate lower priority. Or at least that is my understanding...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have fixed this aswell, and I again apologize for silly mistakes, I had interpreted higher = higher, while in reality according to the docs its the other way around, lower numbers means higher priority and higher means lower prority.

ipid: [0:7],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to the specification, this field is called iprio, no ipid. Can you share the documentation you are following for implementing this PR? Just to double check that I'm not missing anything.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am sorry for such silly mistakes, I had mixed iprio, and iid resulting to ipid :) I have also fixed this. The documentation I followed is this tools.cloudbear.ru/docs/riscv-aia-1.0-20230630.pdf and https://drive.google.com/file/d/1joBC2hWGEHJL4tFabjcqMpRqQNkqJ5WR/view?pli=1

}

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
}

/// Returns the interrupt priority, with higher values indicating higher priority
///
/// This value is only meaningful when `has_interrupt()` returns true.
#[inline]
pub fn priority(&self) -> usize {
self.ipid()
}

/// Returns the interrupt identifier
///
/// A value of 0 indicates no interrupt is pending. Non-zero values identify
/// specific interrupt sources as defined by the interrupt controller configuration.
#[inline]
pub fn interrupt_id(&self) -> usize {
self.iid()
}
}

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

#[test]
fn test_mtopi_fields() {
let mtopi = Mtopi::from_bits(0);

assert_eq!(mtopi.iid(), 0);
assert_eq!(mtopi.ipid(), 0);
assert!(!mtopi.has_interrupt());
assert_eq!(mtopi.priority(), 0);
assert_eq!(mtopi.interrupt_id(), 0);

// Test with some interrupt pending (IID = 11, IPID = 5)
let mtopi = Mtopi::from_bits((11 << 16) | 5);

assert_eq!(mtopi.iid(), 11);
assert_eq!(mtopi.ipid(), 5);
assert!(mtopi.has_interrupt());
assert_eq!(mtopi.priority(), 5);
assert_eq!(mtopi.interrupt_id(), 11);

// Test maximum values
let mtopi = Mtopi::from_bits((0xFFF << 16) | 0xFF);

assert_eq!(mtopi.iid(), 0xFFF);
assert_eq!(mtopi.ipid(), 0xFF);
assert!(mtopi.has_interrupt());
}

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