Skip to content

Commit b391a48

Browse files
Merge pull request #255 from rmsyn/riscv/mvendorid-csr-macro
riscv: define mvendorid CSR with macro helpers
2 parents 1da169b + 4a0bab7 commit b391a48

File tree

2 files changed

+89
-22
lines changed

2 files changed

+89
-22
lines changed

riscv/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
2828
- Use CSR helper macros to define `mstatus` register
2929
- Use CSR helper macros to define `mstatush` register
3030
- Use CSR helper macros to define `mtvec` register
31+
- Use CSR helper macros to define `mtvendorid` register
3132

3233
## [v0.12.1] - 2024-10-20
3334

riscv/src/register/mvendorid.rs

Lines changed: 88 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,100 @@
11
//! mvendorid register
22
3-
use core::num::NonZeroUsize;
3+
read_only_csr! {
4+
/// `mvendorid` register
5+
Mvendorid: 0xF11,
6+
mask: 0xffff_ffff,
7+
sentinel: 0,
8+
}
9+
10+
read_only_csr_field! {
11+
Mvendorid,
12+
/// Represents the number of continuation bytes (`0x7f`) in the JEDEC manufacturer ID.
13+
bank: [7:31],
14+
}
415

5-
/// mvendorid register
6-
#[derive(Clone, Copy, Debug)]
7-
pub struct Mvendorid {
8-
bits: NonZeroUsize,
16+
read_only_csr_field! {
17+
Mvendorid,
18+
/// Represents the final offset field in the JEDEC manufacturer ID.
19+
///
20+
/// # Note
21+
///
22+
/// The encoded value returned by `offset` does not include the odd parity bit (`0x80`).
23+
offset: [0:6],
924
}
1025

1126
impl Mvendorid {
12-
/// Returns the contents of the register as raw bits
13-
#[inline]
14-
pub fn bits(&self) -> usize {
15-
self.bits.get()
16-
}
27+
/// Represents the JEDEC manufacture continuation byte.
28+
pub const CONTINUATION: u8 = 0x7f;
1729

18-
/// Returns the JEDEC manufacturer ID
19-
#[inline]
20-
pub fn jedec_manufacturer(&self) -> usize {
21-
self.bits() >> 7
30+
/// Gets the decoded JEDEC manufacturer ID from the `mvendorid` value.
31+
///
32+
/// # Note
33+
///
34+
/// This function returns an iterator over the decoded bytes.
35+
///
36+
/// An iterator is needed because the encoding can theoretically return a max count (`0x1ff_ffff`) of continuation bytes (`0x7f`).
37+
///
38+
/// The final byte in the iterator is the `offset`, including the odd parity bit (set only if even).
39+
pub fn jedec_manufacturer(&self) -> impl Iterator<Item = u8> {
40+
const DONE: usize = usize::MAX;
41+
42+
let mut bank = self.bank();
43+
let offset = self.offset();
44+
45+
core::iter::from_fn(move || match bank {
46+
DONE => None,
47+
0 => {
48+
bank = DONE;
49+
let parity = ((1 - (offset.count_ones() % 2)) << 7) as usize;
50+
Some((parity | offset) as u8)
51+
}
52+
_ => {
53+
bank -= 1;
54+
Some(Self::CONTINUATION)
55+
}
56+
})
2257
}
2358
}
2459

25-
read_csr!(0xF11);
60+
#[cfg(test)]
61+
mod tests {
62+
use super::*;
63+
64+
#[test]
65+
fn test_mvendorid() {
66+
(0..u32::BITS)
67+
.map(|r| ((1u64 << r) - 1) as usize)
68+
.for_each(|raw| {
69+
let exp_bank = raw >> 7;
70+
let exp_offset = raw & (Mvendorid::CONTINUATION as usize);
71+
let exp_parity = ((1 - (exp_offset.count_ones() % 2)) << 7) as u8;
72+
let exp_mvendorid = Mvendorid::from_bits(raw);
2673

27-
/// Reads the CSR
28-
#[inline]
29-
pub fn read() -> Option<Mvendorid> {
30-
let r = unsafe { _read() };
31-
// When mvendorid is hardwired to zero it means that the mvendorid
32-
// csr isn't implemented.
33-
NonZeroUsize::new(r).map(|bits| Mvendorid { bits })
74+
assert_eq!(exp_mvendorid.bank(), exp_bank);
75+
assert_eq!(exp_mvendorid.offset(), exp_offset);
76+
77+
let mut jedec_iter = exp_mvendorid.jedec_manufacturer();
78+
(0..exp_bank)
79+
.for_each(|_| assert_eq!(jedec_iter.next(), Some(Mvendorid::CONTINUATION)));
80+
assert_eq!(jedec_iter.next(), Some(exp_parity | (exp_offset as u8)));
81+
assert_eq!(jedec_iter.next(), None);
82+
});
83+
84+
// ISA example used as a concrete test vector.
85+
86+
let exp_bank = 0xc;
87+
let exp_offset = 0x0a;
88+
let exp_decoded_offset = 0x8a;
89+
let raw_mvendorid = 0x60a;
90+
let exp_mvendorid = Mvendorid::from_bits(raw_mvendorid);
91+
92+
assert_eq!(exp_mvendorid.bank(), exp_bank);
93+
assert_eq!(exp_mvendorid.offset(), exp_offset);
94+
95+
let mut jedec_iter = exp_mvendorid.jedec_manufacturer();
96+
(0..exp_bank).for_each(|_| assert_eq!(jedec_iter.next(), Some(Mvendorid::CONTINUATION)));
97+
assert_eq!(jedec_iter.next(), Some(exp_decoded_offset));
98+
assert_eq!(jedec_iter.next(), None);
99+
}
34100
}

0 commit comments

Comments
 (0)