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

- Add `tselect`, `tdata2` and `tdata3` Sdtrig CSRs as raw `read_write_csr_as_usize!` accessors, and `tdata1` and `tcontrol` as typed CSRs with field accessors.
- Add `mireg` and `sireg` CSRs
- Add `stopei` and `vstopei` CSRs (AIA supervisor/virtual-supervisor top external
interrupt), completing the `*topei` set alongside `mtopei`.
Expand Down
7 changes: 6 additions & 1 deletion riscv/src/register.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,12 @@ pub mod vsiselect;
#[cfg(test)]
mod tests;

// TODO: Debug/Trace Registers (shared with Debug Mode)
// Debug/Trace Registers
pub mod tcontrol;
pub mod tdata1;
pub mod tdata2;
pub mod tdata3;
pub mod tselect;

// TODO: Debug Mode Registers
pub mod dcsr;
Expand Down
37 changes: 37 additions & 0 deletions riscv/src/register/tcontrol.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//! tcontrol register — Trigger Control (0x7a5)
//!
//! Global control for machine-mode triggers (Sdtrig).

read_write_csr! {
/// Trigger Control Register
Tcontrol: 0x7a5,
mask: 0x88,
}

read_write_csr_field! {
Tcontrol,
/// M-mode trigger enable (bit 3).
///
/// When a trap into M-mode is taken, `mte` is set to 0. `mret` restores it
/// from `mpte`.
mte: 3,
}

read_write_csr_field! {
Tcontrol,
/// M-mode previous trigger enable (bit 7).
mpte: 7,
}

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

#[test]
fn test_tcontrol() {
let mut tcontrol = Tcontrol::from_bits(0);

test_csr_field!(tcontrol, mte);
test_csr_field!(tcontrol, mpte);
}
}
125 changes: 125 additions & 0 deletions riscv/src/register/tdata1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
//! tdata1 register — Trigger Data 1 (0x7a1)
//!
//! First data register of the trigger selected by [`tselect`](crate::register::tselect).
//! Layout of the lower bits depends on the trigger type.

read_write_csr! {
/// Trigger Data 1 Register
Tdata1: 0x7a1,
mask: usize::MAX,
}

csr_field_enum! {
/// Trigger type encoded in `tdata1.type` (Sdtrig).
TriggerType {
default: None,
/// No trigger at this `tselect`.
None = 0,
/// Legacy SiFive address match trigger.
Legacy = 1,
/// Address/data match trigger (`mcontrol`).
Mcontrol = 2,
/// Instruction count trigger (`icount`).
Icount = 3,
/// Interrupt trigger (`itrigger`).
Itrigger = 4,
/// Exception trigger (`etrigger`).
Etrigger = 5,
/// Address/data match trigger (`mcontrol6`).
Mcontrol6 = 6,
/// Trigger source external to the trigger module (`tmexttrigger`).
Tmexttrigger = 7,
/// Custom trigger type 12.
Custom12 = 12,
/// Custom trigger type 13.
Custom13 = 13,
/// Custom trigger type 14.
Custom14 = 14,
/// Trigger disabled.
Disabled = 15,
}
}

#[cfg(target_arch = "riscv32")]
read_write_csr_field! {
Tdata1,
/// Trigger type (spec field `type`, bits XLEN-1:XLEN-4).
trigger_type,
TriggerType: [28:31],
}

#[cfg(not(target_arch = "riscv32"))]
read_write_csr_field! {
Tdata1,
/// Trigger type (spec field `type`, bits XLEN-1:XLEN-4).
trigger_type,
TriggerType: [60:63],
}

#[cfg(target_arch = "riscv32")]
read_write_csr_field! {
Tdata1,
/// Debug-mode-only write enable (bit XLEN-5).
dmode: 27,
}

#[cfg(not(target_arch = "riscv32"))]
read_write_csr_field! {
Tdata1,
/// Debug-mode-only write enable (bit XLEN-5).
dmode: 59,
}

#[cfg(target_arch = "riscv32")]
read_write_csr_field! {
Tdata1,
/// Trigger-specific data (bits XLEN-6:0).
data: [0:26],
}

#[cfg(not(target_arch = "riscv32"))]
read_write_csr_field! {
Tdata1,
/// Trigger-specific data (bits XLEN-6:0).
data: [0:58],
}

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

#[test]
fn test_tdata1() {
let mut tdata1 = Tdata1::from_bits(0);

test_csr_field!(tdata1, dmode);
test_csr_field!(
tdata1,
data: [Tdata1::DATA_SHIFT, Tdata1::DATA_SHIFT + Tdata1::DATA_WIDTH - 1],
0
);

[
TriggerType::None,
TriggerType::Legacy,
TriggerType::Mcontrol,
TriggerType::Icount,
TriggerType::Itrigger,
TriggerType::Etrigger,
TriggerType::Mcontrol6,
TriggerType::Tmexttrigger,
TriggerType::Custom12,
TriggerType::Custom13,
TriggerType::Custom14,
TriggerType::Disabled,
]
.into_iter()
.for_each(|variant| {
test_csr_field!(tdata1, trigger_type: variant);
});

tdata1 = Tdata1::from_bits(8 << Tdata1::TRIGGER_TYPE_SHIFT);
assert_eq!(tdata1.try_trigger_type(), Err(Error::InvalidVariant(8)));
}
}
21 changes: 21 additions & 0 deletions riscv/src/register/tdata2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//! tdata2 register — Trigger Data 2 (0x7a2)
//!
//! Second data register of the trigger selected by [`tselect`](crate::register::tselect). For address/data
//! match triggers this typically holds the compare value.

read_write_csr_as_usize!(0x7a2);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Added and hopefully addressed your other comments


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

#[test]
fn test_tdata2_read_write() {
for i in 0..usize::BITS {
let val = 1usize << i;
assert_eq!(unsafe { try_write(val) }, Err(Error::Unimplemented));
assert_eq!(try_read(), Err(Error::Unimplemented));
}
}
}
22 changes: 22 additions & 0 deletions riscv/src/register/tdata3.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//! tdata3 register — Trigger Data 3 (0x7a3)
//!
//! Third data register of the trigger selected by [`tselect`](crate::register::tselect).
//! Holds trigger-specific data. When [`tdata1`](crate::register::tdata1) `type` is 2, 3, 4, 5, or 6,
//! this register is interpreted as `textra32` (RV32) or `textra64` (RV64).

read_write_csr_as_usize!(0x7a3);

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

#[test]
fn test_tdata3_read_write() {
for i in 0..usize::BITS {
let val = 1usize << i;
assert_eq!(unsafe { try_write(val) }, Err(Error::Unimplemented));
assert_eq!(try_read(), Err(Error::Unimplemented));
}
}
}
22 changes: 22 additions & 0 deletions riscv/src/register/tselect.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//! tselect register — Trigger Select (0x7a0)
//!
//! Selects which trigger the `tdata1`, `tdata2` and `tdata3` registers access.
//! The register is WARL, so writing an unsupported index and reading the value
//! back is the way to discover how many triggers the hart implements.

read_write_csr_as_usize!(0x7a0);

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

#[test]
fn test_tselect_read_write() {
for i in 0..usize::BITS {
let val = 1usize << i;
assert_eq!(unsafe { try_write(val) }, Err(Error::Unimplemented));
assert_eq!(try_read(), Err(Error::Unimplemented));
}
}
}
Loading