Skip to content

Commit bcb0fbc

Browse files
committed
riscv: fix mstatus/sstatus helpers and field mask
1 parent 5a89b85 commit bcb0fbc

2 files changed

Lines changed: 168 additions & 27 deletions

File tree

riscv/src/register/mstatus.rs

Lines changed: 98 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@ use crate::bits::{bf_extract, bf_insert};
88
read_write_csr! {
99
/// mstatus register
1010
Mstatus: 0x300,
11-
mask: 0x8000_0000_007f_fffe,
11+
mask: 0x8000_003f_007f_ffea,
1212
}
1313

1414
#[cfg(target_arch = "riscv32")]
1515
read_write_csr! {
1616
/// mstatus register
1717
Mstatus: 0x300,
18-
mask: 0x807f_fffe,
18+
mask: 0x807f_ffea,
1919
}
2020

2121
csr_field_enum! {
@@ -153,12 +153,14 @@ read_write_csr_field! {
153153
FS: [13:14],
154154
}
155155

156-
read_write_csr_field! {
156+
read_only_csr_field! {
157157
Mstatus,
158158
/// Additional extension state
159159
///
160160
/// Encodes the status of additional user-mode extensions and associated
161-
/// state.
161+
/// state. This is a read-only field summarizing the status of all
162+
/// user-mode extensions; it is set indirectly by writing individual
163+
/// extension status CSRs.
162164
xs,
163165
XS: [15:16],
164166
}
@@ -218,16 +220,20 @@ read_write_csr_field! {
218220
}
219221

220222
#[cfg(target_arch = "riscv32")]
221-
read_write_csr_field! {
223+
read_only_csr_field! {
222224
Mstatus,
223-
/// Whether either the FS field or XS field signals the presence of some dirty state
225+
/// Whether either the FS field or XS field signals the presence of some dirty state.
226+
///
227+
/// This is a read-only bit computed by hardware as `(FS == Dirty) || (XS == Dirty) || (VS == Dirty)`.
224228
sd: 31,
225229
}
226230

227231
#[cfg(not(target_arch = "riscv32"))]
228-
read_write_csr_field! {
232+
read_only_csr_field! {
229233
Mstatus,
230-
/// Whether either the FS field or XS field signals the presence of some dirty state
234+
/// Whether either the FS field or XS field signals the presence of some dirty state.
235+
///
236+
/// This is a read-only bit computed by hardware as `(FS == Dirty) || (XS == Dirty) || (VS == Dirty)`.
231237
sd: 63,
232238
}
233239

@@ -349,7 +355,11 @@ set!(0x300);
349355
clear!(0x300);
350356

351357
set_clear_csr!(
352-
/// User Interrupt Enable
358+
/// User Interrupt Enable.
359+
///
360+
/// This helper is kept for API compatibility with legacy code that still
361+
/// targets the deprecated N-extension encoding. On systems that do not
362+
/// implement these bits, writes may be ignored by hardware.
353363
, set_uie, clear_uie, 1 << 0);
354364
set_clear_csr!(
355365
/// Supervisor Interrupt Enable
@@ -358,7 +368,11 @@ set_clear_csr!(
358368
/// Machine Interrupt Enable
359369
, set_mie, clear_mie, 1 << 3);
360370
set_csr!(
361-
/// User Previous Interrupt Enable
371+
/// User Previous Interrupt Enable.
372+
///
373+
/// This helper is kept for API compatibility with legacy code that still
374+
/// targets the deprecated N-extension encoding. On systems that do not
375+
/// implement these bits, writes may be ignored by hardware.
362376
, set_upie, 1 << 4);
363377
set_csr!(
364378
/// Supervisor Previous Interrupt Enable
@@ -466,6 +480,32 @@ pub unsafe fn set_mbe(endianness: Endianness) {
466480
}
467481
}
468482

483+
/// Set effective xlen in U-mode (i.e., `UXLEN`).
484+
///
485+
/// # Note
486+
///
487+
/// In RISCV-32, `UXL` does not exist.
488+
#[inline]
489+
#[cfg(not(target_arch = "riscv32"))]
490+
pub unsafe fn set_uxl(uxl: XLEN) {
491+
let mut value = _read();
492+
value = bf_insert(value, 32, 2, uxl as usize);
493+
_write(value);
494+
}
495+
496+
/// Set effective xlen in S-mode (i.e., `SXLEN`).
497+
///
498+
/// # Note
499+
///
500+
/// In RISCV-32, `SXL` does not exist.
501+
#[inline]
502+
#[cfg(not(target_arch = "riscv32"))]
503+
pub unsafe fn set_sxl(sxl: XLEN) {
504+
let mut value = _read();
505+
value = bf_insert(value, 34, 2, sxl as usize);
506+
_write(value);
507+
}
508+
469509
#[cfg(test)]
470510
mod test {
471511
use super::*;
@@ -491,10 +531,19 @@ mod test {
491531
test_csr_field!(mstatus, vs: VS::Clean);
492532
test_csr_field!(mstatus, vs: VS::Dirty);
493533

494-
test_csr_field!(mstatus, xs: XS::AllOff);
495-
test_csr_field!(mstatus, xs: XS::NoneDirtyOrClean);
496-
test_csr_field!(mstatus, xs: XS::NoneDirtySomeClean);
497-
test_csr_field!(mstatus, xs: XS::SomeDirty);
534+
// XS is read-only: it summarizes all user-mode extension states.
535+
[
536+
XS::AllOff,
537+
XS::NoneDirtyOrClean,
538+
XS::NoneDirtySomeClean,
539+
XS::SomeDirty,
540+
]
541+
.into_iter()
542+
.for_each(|xs| {
543+
let m = Mstatus::from_bits(xs.into_usize() << 15);
544+
assert_eq!(m.xs(), xs);
545+
assert_eq!(m.try_xs(), Ok(xs));
546+
});
498547

499548
test_csr_field!(mstatus, sie);
500549
test_csr_field!(mstatus, mie);
@@ -507,6 +556,40 @@ mod test {
507556
test_csr_field!(mstatus, tvm);
508557
test_csr_field!(mstatus, tw);
509558
test_csr_field!(mstatus, tsr);
510-
test_csr_field!(mstatus, sd);
559+
560+
// SD is read-only: hardware sets it whenever FS, VS, or XS == Dirty.
561+
assert!(!Mstatus::from_bits(0).sd());
562+
assert!(Mstatus::from_bits(usize::MAX).sd());
563+
564+
#[cfg(not(target_arch = "riscv32"))]
565+
{
566+
[XLEN::XLEN32, XLEN::XLEN64, XLEN::XLEN128]
567+
.into_iter()
568+
.for_each(|xlen| {
569+
let mut m = Mstatus::from_bits(0);
570+
m.set_uxl(xlen);
571+
assert_eq!(m.uxl(), xlen);
572+
});
573+
574+
[XLEN::XLEN32, XLEN::XLEN64, XLEN::XLEN128]
575+
.into_iter()
576+
.for_each(|xlen| {
577+
let mut m = Mstatus::from_bits(0);
578+
m.set_sxl(xlen);
579+
assert_eq!(m.sxl(), xlen);
580+
});
581+
582+
[Endianness::LittleEndian, Endianness::BigEndian]
583+
.into_iter()
584+
.for_each(|endianness| {
585+
let mut m = Mstatus::from_bits(0);
586+
m.set_sbe(endianness);
587+
assert_eq!(m.sbe(), endianness);
588+
589+
let mut m = Mstatus::from_bits(0);
590+
m.set_mbe(endianness);
591+
assert_eq!(m.mbe(), endianness);
592+
});
593+
}
511594
}
512595
}

riscv/src/register/sstatus.rs

Lines changed: 70 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
//! sstatus register
22
33
pub use super::misa::XLEN;
4-
pub use super::mstatus::{FS, XS};
4+
pub use super::mstatus::{FS, VS, XS};
55

66
#[cfg(target_arch = "riscv32")]
7-
const MASK: usize = 0x800d_e122;
7+
const MASK: usize = 0x800d_e762;
88
#[cfg(not(target_arch = "riscv32"))]
9-
const MASK: usize = 0x8000_0003_000d_e122;
9+
const MASK: usize = 0x8000_0003_000d_e762;
1010

1111
read_write_csr! {
1212
/// Supervisor Status Register
@@ -37,13 +37,26 @@ read_write_csr_field! {
3737
spie: 5,
3838
}
3939

40+
read_write_csr_field! {
41+
Sstatus,
42+
/// U-mode non-instruction-fetch memory endianness
43+
ube: 6,
44+
}
45+
4046
read_write_csr_field! {
4147
Sstatus,
4248
/// Supervisor Previous Privilege Mode
4349
spp,
4450
SPP: [8:8],
4551
}
4652

53+
read_write_csr_field! {
54+
Sstatus,
55+
/// Vector extension state
56+
vs,
57+
VS: [9:10],
58+
}
59+
4760
read_write_csr_field! {
4861
Sstatus,
4962
/// The status of the floating-point unit
@@ -80,18 +93,20 @@ read_write_csr_field! {
8093
}
8194

8295
#[cfg(target_arch = "riscv32")]
83-
read_write_csr_field! {
96+
read_only_csr_field! {
8497
Sstatus,
85-
/// Whether either the FS field or XS field
86-
/// signals the presence of some dirty state
98+
/// Whether either the FS field or XS field signals the presence of some dirty state.
99+
///
100+
/// This is a read-only bit computed by hardware as `(FS == Dirty) || (XS == Dirty) || (VS == Dirty)`.
87101
sd: 31,
88102
}
89103

90104
#[cfg(not(target_arch = "riscv32"))]
91-
read_write_csr_field! {
105+
read_only_csr_field! {
92106
Sstatus,
93-
/// Whether either the FS field or XS field
94-
/// signals the presence of some dirty state
107+
/// Whether either the FS field or XS field signals the presence of some dirty state.
108+
///
109+
/// This is a read-only bit computed by hardware as `(FS == Dirty) || (XS == Dirty) || (VS == Dirty)`.
95110
sd: 63,
96111
}
97112

@@ -110,17 +125,28 @@ set!(0x100);
110125
clear!(0x100);
111126

112127
set_clear_csr!(
113-
/// User Interrupt Enable
128+
/// User Interrupt Enable.
129+
///
130+
/// This helper is kept for API compatibility with legacy code that still
131+
/// targets the deprecated N-extension encoding. On systems that do not
132+
/// implement these bits, writes may be ignored by hardware.
114133
, set_uie, clear_uie, 1 << 0);
115134
set_clear_csr!(
116135
/// Supervisor Interrupt Enable
117136
, set_sie, clear_sie, 1 << 1);
118137
set_csr!(
119-
/// User Previous Interrupt Enable
138+
/// User Previous Interrupt Enable.
139+
///
140+
/// This helper is kept for API compatibility with legacy code that still
141+
/// targets the deprecated N-extension encoding. On systems that do not
142+
/// implement these bits, writes may be ignored by hardware.
120143
, set_upie, 1 << 4);
121144
set_csr!(
122145
/// Supervisor Previous Interrupt Enable
123146
, set_spie, 1 << 5);
147+
set_clear_csr!(
148+
/// U-mode non-instruction-fetch memory endianness
149+
, set_ube, clear_ube, 1 << 6);
124150
set_clear_csr!(
125151
/// Permit Supervisor User Memory access
126152
, set_sum, clear_sum, 1 << 18);
@@ -146,6 +172,29 @@ pub unsafe fn set_fs(fs: FS) {
146172
_write(value);
147173
}
148174

175+
/// Vector extension state
176+
#[inline]
177+
pub unsafe fn set_vs(vs: VS) {
178+
let mut value = _read();
179+
value &= !(0x3 << 9); // clear previous value
180+
value |= (vs as usize) << 9;
181+
_write(value);
182+
}
183+
184+
/// Effective xlen in U-mode (i.e., `UXLEN`)
185+
///
186+
/// # Note
187+
///
188+
/// In RISCV-32, `UXL` does not exist.
189+
#[inline]
190+
#[cfg(not(target_arch = "riscv32"))]
191+
pub unsafe fn set_uxl(uxl: XLEN) {
192+
let mut value = _read();
193+
value &= !(0x3 << 32); // clear previous value
194+
value |= (uxl as usize) << 32;
195+
_write(value);
196+
}
197+
149198
#[cfg(test)]
150199
mod tests {
151200
use super::*;
@@ -156,11 +205,18 @@ mod tests {
156205

157206
test_csr_field!(sstatus, sie);
158207
test_csr_field!(sstatus, spie);
208+
test_csr_field!(sstatus, ube);
159209

160210
[SPP::User, SPP::Supervisor].into_iter().for_each(|spp| {
161211
test_csr_field!(sstatus, spp: spp);
162212
});
163213

214+
[VS::Off, VS::Initial, VS::Clean, VS::Dirty]
215+
.into_iter()
216+
.for_each(|vs| {
217+
test_csr_field!(sstatus, vs: vs);
218+
});
219+
164220
[FS::Off, FS::Initial, FS::Clean, FS::Dirty]
165221
.into_iter()
166222
.for_each(|fs| {
@@ -189,6 +245,8 @@ mod tests {
189245
test_csr_field!(sstatus, uxl: xlen);
190246
});
191247

192-
test_csr_field!(sstatus, sd);
248+
// SD is read-only: hardware sets it whenever FS, VS, or XS == Dirty.
249+
assert!(!Sstatus::from_bits(0).sd());
250+
assert!(Sstatus::from_bits(usize::MAX).sd());
193251
}
194252
}

0 commit comments

Comments
 (0)