Skip to content

Commit ee80fd4

Browse files
authored
Merge pull request #142 from rust-embedded/add-mstatush
Rework on misa and mstatus
2 parents aa56cb4 + 93c1911 commit ee80fd4

File tree

6 files changed

+246
-41
lines changed

6 files changed

+246
-41
lines changed

CHANGELOG.md

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

1010
### Added
1111

12+
- Add `read_csr_as_rv32`, `set_rv32`, and `clear_rv32` macros
13+
- Add `mstatus::uxl` and `mstatus::sxl`
14+
- Add `mstatus::ube`, `mstatus::sbe`, and `mstatus::mbe` endianness bit fields
15+
- Add `mstatush` registers (RISCV-32 only)
1216
- Add generic implementation of a PLIC peripheral
1317
- Add `asm::fence()`, a wrapper for implementing a `fence` instruction
1418
- Add `asm::fence_i()`, a wrapper for implementing a `fence.i` instruction
1519
- Add `TryFrom` implementation for `mcause::{Interrupt, Exception}` and `scause::{Interrupt, Exception}`
1620

1721
### Changed
1822

23+
- `misa::MXL` renamed to `misa::XLEN`
1924
- Removed `bit_field` dependency
2025
- CI actions updated. They now use `checkout@v3` and `dtolnay/rust-toolchain`.
2126
- `mcause::{Interrupt, Exception}` and `scause::{Interrupt, Exception}` now implement `From` trait for `usize`
@@ -25,7 +30,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
2530

2631
- Fix `scause::Exception` missing `LoadMisaligned`
2732
- Fix `scause::Exception` missing `SupervisorEnvCall`
28-
- Removed user-level interrupts from `mcause::Interrupt` and `scause::Interrupt`
33+
- Removed user-level interrupts from `mcause::Interrupt` and `scause::Interrupt`
34+
- Removed user-level interrupts from `mstatus`
2935

3036
## [v0.10.1] - 2023-01-18
3137

src/register/mod.rs renamed to src/register.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
//! - mcycleh
1010
//! - minstreth
1111
//! - mhpmcounter<3-31>h
12+
//! - mstatush
1213
1314
#[macro_use]
1415
mod macros;
@@ -69,6 +70,7 @@ pub mod mideleg;
6970
pub mod mie;
7071
pub mod misa;
7172
pub mod mstatus;
73+
pub mod mstatush;
7274
pub mod mtvec;
7375

7476
// Machine Trap Handling

src/register/macros.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,20 @@ macro_rules! read_csr_as {
5252
};
5353
}
5454

55+
macro_rules! read_csr_as_rv32 {
56+
($register:ident, $csr_number:literal) => {
57+
read_csr_rv32!($csr_number);
58+
59+
/// Reads the CSR
60+
#[inline]
61+
pub fn read() -> $register {
62+
$register {
63+
bits: unsafe { _read() },
64+
}
65+
}
66+
};
67+
}
68+
5569
macro_rules! read_csr_as_usize {
5670
($csr_number:literal) => {
5771
read_csr!($csr_number);
@@ -151,6 +165,23 @@ macro_rules! set {
151165
};
152166
}
153167

168+
macro_rules! set_rv32 {
169+
($csr_number:literal) => {
170+
/// Set the CSR
171+
#[inline]
172+
#[allow(unused_variables)]
173+
unsafe fn _set(bits: usize) {
174+
match () {
175+
#[cfg(riscv32)]
176+
() => core::arch::asm!(concat!("csrrs x0, ", stringify!($csr_number), ", {0}"), in(reg) bits),
177+
178+
#[cfg(not(riscv32))]
179+
() => unimplemented!(),
180+
}
181+
}
182+
};
183+
}
184+
154185
macro_rules! clear {
155186
($csr_number:literal) => {
156187
/// Clear the CSR
@@ -168,6 +199,23 @@ macro_rules! clear {
168199
};
169200
}
170201

202+
macro_rules! clear_rv32 {
203+
($csr_number:literal) => {
204+
/// Clear the CSR
205+
#[inline]
206+
#[allow(unused_variables)]
207+
unsafe fn _clear(bits: usize) {
208+
match () {
209+
#[cfg(riscv32)]
210+
() => core::arch::asm!(concat!("csrrc x0, ", stringify!($csr_number), ", {0}"), in(reg) bits),
211+
212+
#[cfg(not(riscv32))]
213+
() => unimplemented!(),
214+
}
215+
}
216+
};
217+
}
218+
171219
macro_rules! set_csr {
172220
($(#[$attr:meta])*, $set_field:ident, $e:expr) => {
173221
$(#[$attr])*

src/register/misa.rs

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,39 +8,48 @@ pub struct Misa {
88
bits: NonZeroUsize,
99
}
1010

11-
/// Machine XLEN
11+
/// Base integer ISA width
1212
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
13-
pub enum MXL {
13+
pub enum XLEN {
1414
XLEN32,
1515
XLEN64,
1616
XLEN128,
1717
}
1818

19+
impl XLEN {
20+
/// Converts a number into an ISA width
21+
pub(crate) fn from(value: u8) -> Self {
22+
match value {
23+
1 => XLEN::XLEN32,
24+
2 => XLEN::XLEN64,
25+
3 => XLEN::XLEN128,
26+
_ => unreachable!(),
27+
}
28+
}
29+
}
30+
1931
impl Misa {
2032
/// Returns the contents of the register as raw bits
2133
#[inline]
2234
pub fn bits(&self) -> usize {
2335
self.bits.get()
2436
}
2537

26-
/// Returns the machine xlen.
38+
/// Effective xlen in M-mode (i.e., `MXLEN`).
2739
#[inline]
28-
pub fn mxl(&self) -> MXL {
29-
let value = match () {
30-
#[cfg(target_pointer_width = "32")]
31-
() => (self.bits() >> 30) as u8,
32-
#[cfg(target_pointer_width = "64")]
33-
() => (self.bits() >> 62) as u8,
34-
};
35-
match value {
36-
1 => MXL::XLEN32,
37-
2 => MXL::XLEN64,
38-
3 => MXL::XLEN128,
39-
_ => unreachable!(),
40-
}
40+
pub fn mxl(&self) -> XLEN {
41+
let value = (self.bits() >> (usize::BITS - 2)) as u8;
42+
XLEN::from(value)
4143
}
4244

43-
/// Returns true when the atomic extension is implemented.
45+
/// Returns true when a given extension is implemented.
46+
///
47+
/// # Example
48+
///
49+
/// ``` no_run
50+
/// let misa = unsafe { riscv::register::misa::read() };
51+
/// assert!(misa.has_extension('A')); // panics if atomic extension is not implemented
52+
/// ```
4453
#[inline]
4554
pub fn has_extension(&self, extension: char) -> bool {
4655
let bit = extension as u8 - 65;

src/register/mstatus.rs

Lines changed: 117 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,6 @@
11
//! mstatus register
22
3-
// FIXME: in 1.12 spec there will be `SBE` and `MBE` bits.
4-
// They allows to execute supervisor in given big endian,
5-
// they would be in a new register `mstatush` in RV32; we should implement `mstatush`
6-
// at that time.
7-
// FIXME: `SXL` and `UXL` bits require a structure interpreting XLEN,
8-
// which would be the best way we implement this using Rust?
3+
pub use super::misa::XLEN;
94

105
/// mstatus register
116
#[derive(Clone, Copy, Debug)]
@@ -53,13 +48,23 @@ pub enum SPP {
5348
User = 0,
5449
}
5550

56-
impl Mstatus {
57-
/// User Interrupt Enable
58-
#[inline]
59-
pub fn uie(&self) -> bool {
60-
self.bits & (1 << 0) != 0
51+
/// Non-instruction-fetch memory endianness
52+
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
53+
pub enum Endianness {
54+
BigEndian = 1,
55+
LittleEndian = 0,
56+
}
57+
58+
impl From<bool> for Endianness {
59+
fn from(value: bool) -> Self {
60+
match value {
61+
true => Self::BigEndian,
62+
false => Self::LittleEndian,
63+
}
6164
}
65+
}
6266

67+
impl Mstatus {
6368
/// Supervisor Interrupt Enable
6469
#[inline]
6570
pub fn sie(&self) -> bool {
@@ -72,18 +77,18 @@ impl Mstatus {
7277
self.bits & (1 << 3) != 0
7378
}
7479

75-
/// User Previous Interrupt Enable
76-
#[inline]
77-
pub fn upie(&self) -> bool {
78-
self.bits & (1 << 4) != 0
79-
}
80-
8180
/// Supervisor Previous Interrupt Enable
8281
#[inline]
8382
pub fn spie(&self) -> bool {
8483
self.bits & (1 << 5) != 0
8584
}
8685

86+
/// U-mode non-instruction-fetch memory endianness
87+
#[inline]
88+
pub fn ube(&self) -> Endianness {
89+
Endianness::from(self.bits & (1 << 6) != 0)
90+
}
91+
8792
/// Machine Previous Interrupt Enable
8893
#[inline]
8994
pub fn mpie(&self) -> bool {
@@ -196,13 +201,57 @@ impl Mstatus {
196201
self.bits & (1 << 22) != 0
197202
}
198203

199-
/*
200-
FIXME: There are MBE and SBE bits in 1.12; once Privileged Specification version 1.12
201-
is ratified, there should be read functions of these bits as well.
202-
*/
204+
/// Effective xlen in U-mode (i.e., `UXLEN`).
205+
///
206+
/// In RISCV-32, UXL does not exist, and `UXLEN` is always [`XLEN::XLEN32`].
207+
#[inline]
208+
pub fn uxl(&self) -> XLEN {
209+
match () {
210+
#[cfg(riscv32)]
211+
() => XLEN::XLEN32,
212+
#[cfg(not(riscv32))]
213+
() => XLEN::from((self.bits >> 32) as u8 & 0x3),
214+
}
215+
}
203216

204-
/// Whether either the FS field or XS field
205-
/// signals the presence of some dirty state
217+
/// Effective xlen in S-mode (i.e., `SXLEN`).
218+
///
219+
/// In RISCV-32, SXL does not exist, and SXLEN is always [`XLEN::XLEN32`].
220+
#[inline]
221+
pub fn sxl(&self) -> XLEN {
222+
match () {
223+
#[cfg(riscv32)]
224+
() => XLEN::XLEN32,
225+
#[cfg(not(riscv32))]
226+
() => XLEN::from((self.bits >> 34) as u8 & 0x3),
227+
}
228+
}
229+
230+
/// S-mode non-instruction-fetch memory endianness.
231+
///
232+
/// In RISCV-32, this field is read from the [`crate::register::mstatush`] register.
233+
pub fn sbe(&self) -> Endianness {
234+
match () {
235+
#[cfg(riscv32)]
236+
() => super::mstatush::read().sbe(),
237+
#[cfg(not(riscv32))]
238+
() => Endianness::from(self.bits & (1 << 36) != 0),
239+
}
240+
}
241+
242+
/// M-mode non-instruction-fetch memory endianness
243+
///
244+
/// In RISCV-32, this field is read from the [`crate::register::mstatush`] register
245+
pub fn mbe(&self) -> Endianness {
246+
match () {
247+
#[cfg(riscv32)]
248+
() => super::mstatush::read().mbe(),
249+
#[cfg(not(riscv32))]
250+
() => Endianness::from(self.bits & (1 << 37) != 0),
251+
}
252+
}
253+
254+
/// Whether either the FS field or XS field signals the presence of some dirty state
206255
#[inline]
207256
pub fn sd(&self) -> bool {
208257
self.bits & (1 << (usize::BITS as usize - 1)) != 0
@@ -251,6 +300,15 @@ set_clear_csr!(
251300
/// Trap SRET
252301
, set_tsr, clear_tsr, 1 << 22);
253302

303+
/// Set U-mode non-instruction-fetch memory endianness
304+
#[inline]
305+
pub unsafe fn set_ube(endianness: Endianness) {
306+
match endianness {
307+
Endianness::BigEndian => _set(1 << 6),
308+
Endianness::LittleEndian => _clear(1 << 6),
309+
}
310+
}
311+
254312
/// Supervisor Previous Privilege Mode
255313
#[inline]
256314
pub unsafe fn set_spp(spp: SPP) {
@@ -277,3 +335,39 @@ pub unsafe fn set_fs(fs: FS) {
277335
value |= (fs as usize) << 13;
278336
_write(value);
279337
}
338+
339+
/// Set S-mode non-instruction-fetch memory endianness
340+
///
341+
/// # Note
342+
///
343+
/// In RISCV-32, this function calls [`crate::register::mstatush::set_sbe`]
344+
#[inline]
345+
pub unsafe fn set_sbe(endianness: Endianness) {
346+
match () {
347+
#[cfg(riscv32)]
348+
() => super::mstatush::set_sbe(endianness),
349+
#[cfg(not(riscv32))]
350+
() => match endianness {
351+
Endianness::BigEndian => _set(1 << 36),
352+
Endianness::LittleEndian => _clear(1 << 36),
353+
},
354+
}
355+
}
356+
357+
/// Set M-mode non-instruction-fetch memory endianness
358+
///
359+
/// # Note
360+
///
361+
/// In RISCV-32, this function calls [`crate::register::mstatush::set_mbe`]
362+
#[inline]
363+
pub unsafe fn set_mbe(endianness: Endianness) {
364+
match () {
365+
#[cfg(riscv32)]
366+
() => super::mstatush::set_mbe(endianness),
367+
#[cfg(not(riscv32))]
368+
() => match endianness {
369+
Endianness::BigEndian => _set(1 << 37),
370+
Endianness::LittleEndian => _clear(1 << 37),
371+
},
372+
}
373+
}

0 commit comments

Comments
 (0)