Skip to content

Commit f766976

Browse files
committed
Add Mstatus helpers to allow setting fields in Mstatus
Without needing to touch the CSR. This allows multiple changes in a single register write.
1 parent a9d3e33 commit f766976

File tree

3 files changed

+153
-3
lines changed

3 files changed

+153
-3
lines changed

riscv/CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1212
- Add `Mcause::from(usize)` for use in unit tests
1313
- Add `Mstatus::from(usize)` for use in unit tests
1414
- Add `Mstatus.bits()`
15+
- Add `Mstatus::set_*` helpers to manipulate Mstatus values without touching the
16+
CSR
1517
- Export `riscv::register::macros` module macros for external use
1618

1719
### Fixed

riscv/src/register/misa.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ pub struct Misa {
1111
/// Base integer ISA width
1212
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
1313
pub enum XLEN {
14-
XLEN32,
15-
XLEN64,
16-
XLEN128,
14+
XLEN32 = 1,
15+
XLEN64 = 2,
16+
XLEN128 = 3,
1717
}
1818

1919
impl XLEN {

riscv/src/register/mstatus.rs

+148
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,15 @@ impl From<bool> for Endianness {
7272
}
7373

7474
impl Mstatus {
75+
/// Helper to insert a bitfield into Mstatus
76+
#[inline]
77+
fn bf_insert(&self, bit: usize, width: usize, val: usize) -> Self {
78+
let mask = (1 << width) - 1;
79+
Self {
80+
bits: self.bits & !(mask << bit) | (val & mask << bit),
81+
}
82+
}
83+
7584
/// Returns the contents of the register as raw bits
7685
#[inline]
7786
pub fn bits(&self) -> usize {
@@ -84,30 +93,60 @@ impl Mstatus {
8493
self.bits & (1 << 1) != 0
8594
}
8695

96+
/// Set Supervisor Interrupt Enable
97+
#[inline]
98+
pub fn set_sie(&self, sie: bool) -> Self {
99+
self.bf_insert(1, 1, sie as usize)
100+
}
101+
87102
/// Machine Interrupt Enable
88103
#[inline]
89104
pub fn mie(&self) -> bool {
90105
self.bits & (1 << 3) != 0
91106
}
92107

108+
/// Set Machine Interrupt Enable
109+
#[inline]
110+
pub fn set_mie(&self, mie: bool) -> Self {
111+
self.bf_insert(3, 1, mie as usize)
112+
}
113+
93114
/// Supervisor Previous Interrupt Enable
94115
#[inline]
95116
pub fn spie(&self) -> bool {
96117
self.bits & (1 << 5) != 0
97118
}
98119

120+
/// Supervisor Previous Interrupt Enable
121+
#[inline]
122+
pub fn set_spie(&self, spie: bool) -> Self {
123+
self.bf_insert(5, 1, spie as usize)
124+
}
125+
99126
/// U-mode non-instruction-fetch memory endianness
100127
#[inline]
101128
pub fn ube(&self) -> Endianness {
102129
Endianness::from(self.bits & (1 << 6) != 0)
103130
}
104131

132+
/// Set U-mode non-instruction-fetch memory endianness
133+
#[inline]
134+
pub fn set_ube(&self, endianness: Endianness) -> Self {
135+
self.bf_insert(6, 1, endianness as usize)
136+
}
137+
105138
/// Machine Previous Interrupt Enable
106139
#[inline]
107140
pub fn mpie(&self) -> bool {
108141
self.bits & (1 << 7) != 0
109142
}
110143

144+
/// Set Machine Previous Interrupt Enable
145+
#[inline]
146+
pub fn set_mpie(&self, mpie: bool) -> Self {
147+
self.bf_insert(7, 1, mpie as usize)
148+
}
149+
111150
/// Supervisor Previous Privilege Mode
112151
#[inline]
113152
pub fn spp(&self) -> SPP {
@@ -117,6 +156,12 @@ impl Mstatus {
117156
}
118157
}
119158

159+
/// Set Supervisor Previous Privilege Mode
160+
#[inline]
161+
pub fn set_spp(&self, spp: SPP) -> Self {
162+
self.bf_insert(8, 1, spp as usize)
163+
}
164+
120165
/// Machine Previous Privilege Mode
121166
#[inline]
122167
pub fn mpp(&self) -> MPP {
@@ -129,6 +174,12 @@ impl Mstatus {
129174
}
130175
}
131176

177+
/// Set Machine Previous Privilege Mode
178+
#[inline]
179+
pub fn set_mpp(&self, mpp: MPP) -> Self {
180+
self.bf_insert(11, 2, mpp as usize)
181+
}
182+
132183
/// Floating-point extension state
133184
///
134185
/// Encodes the status of the floating-point unit,
@@ -145,6 +196,12 @@ impl Mstatus {
145196
}
146197
}
147198

199+
/// Set Floating-point extension state
200+
#[inline]
201+
pub fn set_fs(&self, fs: FS) -> Self {
202+
self.bf_insert(13, 2, fs as usize)
203+
}
204+
148205
/// Additional extension state
149206
///
150207
/// Encodes the status of additional user-mode extensions and associated state.
@@ -160,24 +217,48 @@ impl Mstatus {
160217
}
161218
}
162219

220+
/// Set Additional extension state
221+
#[inline]
222+
pub fn set_xs(&self, xs: XS) -> Self {
223+
self.bf_insert(15, 2, xs as usize)
224+
}
225+
163226
/// Modify Memory PRiVilege
164227
#[inline]
165228
pub fn mprv(&self) -> bool {
166229
self.bits & (1 << 17) != 0
167230
}
168231

232+
/// Set Modify Memory PRiVilege
233+
#[inline]
234+
pub fn set_mprv(&self, mprv: bool) -> Self {
235+
self.bf_insert(17, 1, mprv as usize)
236+
}
237+
169238
/// Permit Supervisor User Memory access
170239
#[inline]
171240
pub fn sum(&self) -> bool {
172241
self.bits & (1 << 18) != 0
173242
}
174243

244+
/// Set Permit Supervisor User Memory access
245+
#[inline]
246+
pub fn set_sum(&self, sum: bool) -> Self {
247+
self.bf_insert(18, 1, sum as usize)
248+
}
249+
175250
/// Make eXecutable Readable
176251
#[inline]
177252
pub fn mxr(&self) -> bool {
178253
self.bits & (1 << 19) != 0
179254
}
180255

256+
/// Set Make eXecutable Readable
257+
#[inline]
258+
pub fn set_mxr(&self, mxr: bool) -> Self {
259+
self.bf_insert(19, 1, mxr as usize)
260+
}
261+
181262
/// Trap Virtual Memory
182263
///
183264
/// If this bit is set, reads or writes to `satp` CSR or execute `sfence.vma`
@@ -189,6 +270,12 @@ impl Mstatus {
189270
self.bits & (1 << 20) != 0
190271
}
191272

273+
/// Set Trap Virtual Memory
274+
#[inline]
275+
pub fn set_tvm(&self, tvm: bool) -> Self {
276+
self.bf_insert(20, 1, tvm as usize)
277+
}
278+
192279
/// Timeout Wait
193280
///
194281
/// Indicates that if WFI instruction should be intercepted.
@@ -203,6 +290,12 @@ impl Mstatus {
203290
self.bits & (1 << 21) != 0
204291
}
205292

293+
/// Set Timeout Wait
294+
#[inline]
295+
pub fn set_tw(&self, tw: bool) -> Self {
296+
self.bf_insert(21, 1, tw as usize)
297+
}
298+
206299
/// Trap SRET
207300
///
208301
/// Indicates that if SRET instruction should be trapped to raise illegal
@@ -214,6 +307,12 @@ impl Mstatus {
214307
self.bits & (1 << 22) != 0
215308
}
216309

310+
/// Set Trap SRET
311+
#[inline]
312+
pub fn set_tsr(&self, tsr: bool) -> Self {
313+
self.bf_insert(22, 1, tsr as usize)
314+
}
315+
217316
/// Effective xlen in U-mode (i.e., `UXLEN`).
218317
///
219318
/// In RISCV-32, UXL does not exist, and `UXLEN` is always [`XLEN::XLEN32`].
@@ -227,6 +326,17 @@ impl Mstatus {
227326
}
228327
}
229328

329+
/// Set Effective xlen in U-mode (i.e., `UXLEN`).
330+
#[inline]
331+
pub fn set_uxl(&self, uxl: XLEN) -> Self {
332+
#[cfg(riscv32)]
333+
{
334+
*self
335+
}
336+
#[cfg(not(riscv32))]
337+
self.bf_insert(32, 2, uxl as usize)
338+
}
339+
230340
/// Effective xlen in S-mode (i.e., `SXLEN`).
231341
///
232342
/// In RISCV-32, SXL does not exist, and SXLEN is always [`XLEN::XLEN32`].
@@ -240,6 +350,17 @@ impl Mstatus {
240350
}
241351
}
242352

353+
/// Set Effective xlen in S-mode (i.e., `SXLEN`).
354+
#[inline]
355+
pub fn set_sxl(&self, sxl: XLEN) -> Self {
356+
#[cfg(riscv32)]
357+
{
358+
*self
359+
}
360+
#[cfg(not(riscv32))]
361+
self.bf_insert(34, 2, sxl as usize)
362+
}
363+
243364
/// S-mode non-instruction-fetch memory endianness.
244365
///
245366
/// In RISCV-32, this field is read from the [`crate::register::mstatush`] register.
@@ -252,6 +373,17 @@ impl Mstatus {
252373
}
253374
}
254375

376+
/// Set S-mode non-instruction-fetch memory endianness
377+
#[inline]
378+
pub fn set_sbe(&self, endianness: Endianness) -> Self {
379+
#[cfg(riscv32)]
380+
{
381+
*self
382+
}
383+
#[cfg(not(riscv32))]
384+
self.bf_insert(36, 1, endianness as usize)
385+
}
386+
255387
/// M-mode non-instruction-fetch memory endianness
256388
///
257389
/// In RISCV-32, this field is read from the [`crate::register::mstatush`] register
@@ -264,11 +396,27 @@ impl Mstatus {
264396
}
265397
}
266398

399+
/// Set M-mode non-instruction-fetch memory endianness
400+
pub fn set_mbe(&self, endianness: Endianness) -> Self {
401+
#[cfg(riscv32)]
402+
{
403+
*self
404+
}
405+
#[cfg(not(riscv32))]
406+
self.bf_insert(37, 1, endianness as usize)
407+
}
408+
267409
/// Whether either the FS field or XS field signals the presence of some dirty state
268410
#[inline]
269411
pub fn sd(&self) -> bool {
270412
self.bits & (1 << (usize::BITS as usize - 1)) != 0
271413
}
414+
415+
/// Set whether either the FS field or XS field signals the presence of some dirty state
416+
#[inline]
417+
pub fn set_sd(&self, sd: bool) -> Self {
418+
self.bf_insert(usize::BITS as usize - 1, 1, sd as usize)
419+
}
272420
}
273421

274422
read_csr_as!(Mstatus, 0x300);

0 commit comments

Comments
 (0)