Skip to content

Commit 39f2759

Browse files
Added riscv: add DCSR (Debug Control and Status Register) support
- Implemented the dcsr CSR (0x7b0) with all fields as per RISC-V Debug Spec v0.13 - Added enums for cause and prv fields for type-safe access - Provided getters and setters for all readable/writable fields - Added unit tests for bitfields, enums, and convenience methods
1 parent 4783516 commit 39f2759

File tree

3 files changed

+213
-5
lines changed

3 files changed

+213
-5
lines changed

CHANGELOG.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
# Changelog
2-
31
## [Unreleased]
42

53
### Added

riscv/src/register.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,5 +125,5 @@ mod tests;
125125

126126
// TODO: Debug/Trace Registers (shared with Debug Mode)
127127

128-
// Debug Mode Registers
128+
// TODO: Debug Mode Registers
129129
pub mod dcsr;

riscv/src/register/dcsr.rs

Lines changed: 212 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,214 @@
11
//! dcsr register — Debug Control and Status Register (0x7b0)
2+
//!
3+
//! Provides control and status for debug mode, including cause of entry, step control, and privilege level.
24
3-
read_csr_as_usize!(0x7b0);
4-
write_csr_as_usize!(0x7b0);
5+
read_write_csr! {
6+
/// Debug Control and Status Register
7+
Dcsr: 0x7b0,
8+
mask: 0xffff_ffff,
9+
}
10+
11+
read_write_csr_field! {
12+
Dcsr,
13+
/// Previous privilege level when entering debug mode (bits 0..2)
14+
prv: [0:1],
15+
}
16+
17+
read_write_csr_field! {
18+
Dcsr,
19+
/// Single step mode (bit 2)
20+
step: 2,
21+
}
22+
23+
read_only_csr_field! {
24+
Dcsr,
25+
/// Non-maskable interrupt pending (bit 3)
26+
nmip: 3,
27+
}
28+
29+
read_write_csr_field! {
30+
Dcsr,
31+
/// Use mstatus.mprv in debug mode (bit 4)
32+
mprven: 4,
33+
}
34+
35+
read_only_csr_field! {
36+
Dcsr,
37+
/// Cause for entering debug mode (bits 6..8)
38+
cause: [6:8],
39+
}
40+
41+
read_write_csr_field! {
42+
Dcsr,
43+
/// Stop timer increment in debug mode (bit 9)
44+
stoptime: 9,
45+
}
46+
47+
read_write_csr_field! {
48+
Dcsr,
49+
/// Stop counter increment in debug mode (bit 10)
50+
stopcount: 10,
51+
}
52+
53+
read_write_csr_field! {
54+
Dcsr,
55+
/// Interrupt enable during single-step (bit 11)
56+
stepie: 11,
57+
}
58+
59+
read_write_csr_field! {
60+
Dcsr,
61+
/// EBREAK behavior in User mode (bit 12)
62+
ebreaku: 12,
63+
}
64+
65+
read_write_csr_field! {
66+
Dcsr,
67+
/// EBREAK behavior in Supervisor mode (bit 13)
68+
ebreaks: 13,
69+
}
70+
71+
read_write_csr_field! {
72+
Dcsr,
73+
/// EBREAK behavior in Machine mode (bit 15)
74+
ebreakm: 15,
75+
}
76+
77+
read_only_csr_field! {
78+
Dcsr,
79+
/// Debug version (bits 28..31)
80+
xdebugver: [28:31],
81+
}
82+
83+
/// Cause for entering debug mode
84+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
85+
pub enum DcsrCause {
86+
None = 0,
87+
Ebreak = 1,
88+
Trigger = 2,
89+
HaltRequest = 3,
90+
Step = 4,
91+
ResetHaltRequest = 5,
92+
}
93+
94+
impl DcsrCause {
95+
pub fn from_usize(val: usize) -> Result<Self, usize> {
96+
match val {
97+
0 => Ok(Self::None),
98+
1 => Ok(Self::Ebreak),
99+
2 => Ok(Self::Trigger),
100+
3 => Ok(Self::HaltRequest),
101+
4 => Ok(Self::Step),
102+
5 => Ok(Self::ResetHaltRequest),
103+
other => Err(other),
104+
}
105+
}
106+
}
107+
108+
/// Previous privilege level when entering debug mode
109+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
110+
pub enum DcsrPrv {
111+
User = 0,
112+
Supervisor = 1,
113+
Machine = 3,
114+
}
115+
116+
impl DcsrPrv {
117+
pub fn from_usize(val: usize) -> Result<Self, usize> {
118+
match val {
119+
0 => Ok(Self::User),
120+
1 => Ok(Self::Supervisor),
121+
3 => Ok(Self::Machine),
122+
other => Err(other),
123+
}
124+
}
125+
}
126+
127+
impl Dcsr {
128+
/// Returns the debug cause as an enum
129+
pub fn debug_cause(&self) -> Result<DcsrCause, usize> {
130+
DcsrCause::from_usize(self.cause())
131+
}
132+
133+
/// Returns the previous privilege level as an enum
134+
pub fn privilege_level(&self) -> Result<DcsrPrv, usize> {
135+
DcsrPrv::from_usize(self.prv())
136+
}
137+
138+
/// Sets the previous privilege level
139+
pub fn set_privilege_level(&mut self, level: DcsrPrv) {
140+
self.set_prv(level as usize);
141+
}
142+
}
143+
144+
#[cfg(test)]
145+
mod tests {
146+
use super::*;
147+
148+
#[test]
149+
fn test_dcsr_bitfields() {
150+
let mut dcsr = Dcsr::from_bits(0);
151+
152+
dcsr.set_step(true);
153+
assert!(dcsr.step());
154+
dcsr.set_mprven(true);
155+
assert!(dcsr.mprven());
156+
dcsr.set_stoptime(true);
157+
assert!(dcsr.stoptime());
158+
dcsr.set_stopcount(true);
159+
assert!(dcsr.stopcount());
160+
dcsr.set_stepie(true);
161+
assert!(dcsr.stepie());
162+
dcsr.set_ebreaku(true);
163+
assert!(dcsr.ebreaku());
164+
dcsr.set_ebreaks(true);
165+
assert!(dcsr.ebreaks());
166+
dcsr.set_ebreakm(true);
167+
assert!(dcsr.ebreakm());
168+
169+
dcsr.set_step(false);
170+
assert!(!dcsr.step());
171+
dcsr.set_mprven(false);
172+
assert!(!dcsr.mprven());
173+
dcsr.set_stoptime(false);
174+
assert!(!dcsr.stoptime());
175+
dcsr.set_stopcount(false);
176+
assert!(!dcsr.stopcount());
177+
dcsr.set_stepie(false);
178+
assert!(!dcsr.stepie());
179+
dcsr.set_ebreaku(false);
180+
assert!(!dcsr.ebreaku());
181+
dcsr.set_ebreaks(false);
182+
assert!(!dcsr.ebreaks());
183+
dcsr.set_ebreakm(false);
184+
assert!(!dcsr.ebreakm());
185+
}
186+
187+
#[test]
188+
fn test_dcsr_enums() {
189+
assert_eq!(DcsrCause::from_usize(0).unwrap(), DcsrCause::None);
190+
assert_eq!(DcsrCause::from_usize(1).unwrap(), DcsrCause::Ebreak);
191+
assert_eq!(DcsrCause::from_usize(2).unwrap(), DcsrCause::Trigger);
192+
assert_eq!(DcsrCause::from_usize(3).unwrap(), DcsrCause::HaltRequest);
193+
assert_eq!(DcsrCause::from_usize(4).unwrap(), DcsrCause::Step);
194+
assert_eq!(
195+
DcsrCause::from_usize(5).unwrap(),
196+
DcsrCause::ResetHaltRequest
197+
);
198+
assert!(DcsrCause::from_usize(6).is_err());
199+
200+
assert_eq!(DcsrPrv::from_usize(0).unwrap(), DcsrPrv::User);
201+
assert_eq!(DcsrPrv::from_usize(1).unwrap(), DcsrPrv::Supervisor);
202+
assert_eq!(DcsrPrv::from_usize(3).unwrap(), DcsrPrv::Machine);
203+
assert!(DcsrPrv::from_usize(2).is_err());
204+
}
205+
206+
#[test]
207+
fn test_dcsr_convenience_methods() {
208+
let mut dcsr = Dcsr::from_bits(0);
209+
210+
dcsr.set_privilege_level(DcsrPrv::Machine);
211+
assert_eq!(dcsr.privilege_level().unwrap(), DcsrPrv::Machine);
212+
assert_eq!(dcsr.prv(), 3);
213+
}
214+
}

0 commit comments

Comments
 (0)