Skip to content

Commit 447c907

Browse files
Merge pull request #413 from JurajSadel/upstream/sdtrig-stubs
riscv: add Sdtrig CSRs as raw usize accessors
2 parents 6f5e501 + af1ada0 commit 447c907

7 files changed

Lines changed: 235 additions & 2 deletions

File tree

riscv/CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
99

1010
### Added
1111

12+
- 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.
1213
- Add `read_bits`/`try_read_bits` and `write_bits`/`try_write_bits` to the modules generated by `read_csr_as_usize!` and `write_csr_as_usize!`, as aliases of `read`/`write` so that a generated CSR module offers the same raw accessors no matter which macro defined it.
1314
- Add `read_bits`/`try_read_bits` and `write_bits`/`try_write_bits` to the CSR modules generated by `read_write_csr!` `read_only_csr!` and `write_only_csr!`.
1415
- Add atomic topei read-clear operations
15-
- Add `mireg` CSR
16+
- Add `mireg` and `sireg` CSRs
1617
- Add `stopei` and `vstopei` CSRs (AIA supervisor/virtual-supervisor top external
1718
interrupt), completing the `*topei` set alongside `mtopei`.
1819
- Auto-generate `<FIELD>_SHIFT`, `<FIELD>_WIDTH`, and `<FIELD>_MASK` associated

riscv/src/register.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,12 @@ pub mod vsiselect;
140140
#[cfg(test)]
141141
mod tests;
142142

143-
// TODO: Debug/Trace Registers (shared with Debug Mode)
143+
// Debug/Trace Registers
144+
pub mod tcontrol;
145+
pub mod tdata1;
146+
pub mod tdata2;
147+
pub mod tdata3;
148+
pub mod tselect;
144149

145150
// TODO: Debug Mode Registers
146151
pub mod dcsr;

riscv/src/register/tcontrol.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
//! tcontrol register — Trigger Control (0x7a5)
2+
//!
3+
//! Global control for machine-mode triggers (Sdtrig).
4+
5+
read_write_csr! {
6+
/// Trigger Control Register
7+
Tcontrol: 0x7a5,
8+
mask: 0x88,
9+
}
10+
11+
read_write_csr_field! {
12+
Tcontrol,
13+
/// M-mode trigger enable (bit 3).
14+
///
15+
/// When a trap into M-mode is taken, `mte` is set to 0. `mret` restores it
16+
/// from `mpte`.
17+
mte: 3,
18+
}
19+
20+
read_write_csr_field! {
21+
Tcontrol,
22+
/// M-mode previous trigger enable (bit 7).
23+
mpte: 7,
24+
}
25+
26+
#[cfg(test)]
27+
mod tests {
28+
use super::*;
29+
30+
#[test]
31+
fn test_tcontrol() {
32+
let mut tcontrol = Tcontrol::from_bits(0);
33+
34+
test_csr_field!(tcontrol, mte);
35+
test_csr_field!(tcontrol, mpte);
36+
}
37+
}

riscv/src/register/tdata1.rs

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
//! tdata1 register — Trigger Data 1 (0x7a1)
2+
//!
3+
//! First data register of the trigger selected by [`tselect`](crate::register::tselect).
4+
//! Layout of the lower bits depends on the trigger type.
5+
6+
read_write_csr! {
7+
/// Trigger Data 1 Register
8+
Tdata1: 0x7a1,
9+
mask: usize::MAX,
10+
}
11+
12+
csr_field_enum! {
13+
/// Trigger type encoded in `tdata1.type` (Sdtrig).
14+
TriggerType {
15+
default: None,
16+
/// No trigger at this `tselect`.
17+
None = 0,
18+
/// Legacy SiFive address match trigger.
19+
Legacy = 1,
20+
/// Address/data match trigger (`mcontrol`).
21+
Mcontrol = 2,
22+
/// Instruction count trigger (`icount`).
23+
Icount = 3,
24+
/// Interrupt trigger (`itrigger`).
25+
Itrigger = 4,
26+
/// Exception trigger (`etrigger`).
27+
Etrigger = 5,
28+
/// Address/data match trigger (`mcontrol6`).
29+
Mcontrol6 = 6,
30+
/// Trigger source external to the trigger module (`tmexttrigger`).
31+
Tmexttrigger = 7,
32+
/// Custom trigger type 12.
33+
Custom12 = 12,
34+
/// Custom trigger type 13.
35+
Custom13 = 13,
36+
/// Custom trigger type 14.
37+
Custom14 = 14,
38+
/// Trigger disabled.
39+
Disabled = 15,
40+
}
41+
}
42+
43+
#[cfg(target_arch = "riscv32")]
44+
read_write_csr_field! {
45+
Tdata1,
46+
/// Trigger type (spec field `type`, bits XLEN-1:XLEN-4).
47+
trigger_type,
48+
TriggerType: [28:31],
49+
}
50+
51+
#[cfg(not(target_arch = "riscv32"))]
52+
read_write_csr_field! {
53+
Tdata1,
54+
/// Trigger type (spec field `type`, bits XLEN-1:XLEN-4).
55+
trigger_type,
56+
TriggerType: [60:63],
57+
}
58+
59+
#[cfg(target_arch = "riscv32")]
60+
read_write_csr_field! {
61+
Tdata1,
62+
/// Debug-mode-only write enable (bit XLEN-5).
63+
dmode: 27,
64+
}
65+
66+
#[cfg(not(target_arch = "riscv32"))]
67+
read_write_csr_field! {
68+
Tdata1,
69+
/// Debug-mode-only write enable (bit XLEN-5).
70+
dmode: 59,
71+
}
72+
73+
#[cfg(target_arch = "riscv32")]
74+
read_write_csr_field! {
75+
Tdata1,
76+
/// Trigger-specific data (bits XLEN-6:0).
77+
data: [0:26],
78+
}
79+
80+
#[cfg(not(target_arch = "riscv32"))]
81+
read_write_csr_field! {
82+
Tdata1,
83+
/// Trigger-specific data (bits XLEN-6:0).
84+
data: [0:58],
85+
}
86+
87+
#[cfg(test)]
88+
mod tests {
89+
use super::*;
90+
use crate::result::Error;
91+
92+
#[test]
93+
fn test_tdata1() {
94+
let mut tdata1 = Tdata1::from_bits(0);
95+
96+
test_csr_field!(tdata1, dmode);
97+
test_csr_field!(
98+
tdata1,
99+
data: [Tdata1::DATA_SHIFT, Tdata1::DATA_SHIFT + Tdata1::DATA_WIDTH - 1],
100+
0
101+
);
102+
103+
[
104+
TriggerType::None,
105+
TriggerType::Legacy,
106+
TriggerType::Mcontrol,
107+
TriggerType::Icount,
108+
TriggerType::Itrigger,
109+
TriggerType::Etrigger,
110+
TriggerType::Mcontrol6,
111+
TriggerType::Tmexttrigger,
112+
TriggerType::Custom12,
113+
TriggerType::Custom13,
114+
TriggerType::Custom14,
115+
TriggerType::Disabled,
116+
]
117+
.into_iter()
118+
.for_each(|variant| {
119+
test_csr_field!(tdata1, trigger_type: variant);
120+
});
121+
122+
tdata1 = Tdata1::from_bits(8 << Tdata1::TRIGGER_TYPE_SHIFT);
123+
assert_eq!(tdata1.try_trigger_type(), Err(Error::InvalidVariant(8)));
124+
}
125+
}

riscv/src/register/tdata2.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//! tdata2 register — Trigger Data 2 (0x7a2)
2+
//!
3+
//! Second data register of the trigger selected by [`tselect`](crate::register::tselect). For address/data
4+
//! match triggers this typically holds the compare value.
5+
6+
read_write_csr_as_usize!(0x7a2);
7+
8+
#[cfg(test)]
9+
mod tests {
10+
use super::*;
11+
use crate::result::Error;
12+
13+
#[test]
14+
fn test_tdata2_read_write() {
15+
for i in 0..usize::BITS {
16+
let val = 1usize << i;
17+
assert_eq!(unsafe { try_write(val) }, Err(Error::Unimplemented));
18+
assert_eq!(try_read(), Err(Error::Unimplemented));
19+
}
20+
}
21+
}

riscv/src/register/tdata3.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//! tdata3 register — Trigger Data 3 (0x7a3)
2+
//!
3+
//! Third data register of the trigger selected by [`tselect`](crate::register::tselect).
4+
//! Holds trigger-specific data. When [`tdata1`](crate::register::tdata1) `type` is 2, 3, 4, 5, or 6,
5+
//! this register is interpreted as `textra32` (RV32) or `textra64` (RV64).
6+
7+
read_write_csr_as_usize!(0x7a3);
8+
9+
#[cfg(test)]
10+
mod tests {
11+
use super::*;
12+
use crate::result::Error;
13+
14+
#[test]
15+
fn test_tdata3_read_write() {
16+
for i in 0..usize::BITS {
17+
let val = 1usize << i;
18+
assert_eq!(unsafe { try_write(val) }, Err(Error::Unimplemented));
19+
assert_eq!(try_read(), Err(Error::Unimplemented));
20+
}
21+
}
22+
}

riscv/src/register/tselect.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//! tselect register — Trigger Select (0x7a0)
2+
//!
3+
//! Selects which trigger the `tdata1`, `tdata2` and `tdata3` registers access.
4+
//! The register is WARL, so writing an unsupported index and reading the value
5+
//! back is the way to discover how many triggers the hart implements.
6+
7+
read_write_csr_as_usize!(0x7a0);
8+
9+
#[cfg(test)]
10+
mod tests {
11+
use super::*;
12+
use crate::result::Error;
13+
14+
#[test]
15+
fn test_tselect_read_write() {
16+
for i in 0..usize::BITS {
17+
let val = 1usize << i;
18+
assert_eq!(unsafe { try_write(val) }, Err(Error::Unimplemented));
19+
assert_eq!(try_read(), Err(Error::Unimplemented));
20+
}
21+
}
22+
}

0 commit comments

Comments
 (0)