Skip to main content

sbi_spec/binary/
counter_mask.rs

1use super::{mask_commons::has_bit, sbi_ret::SbiRegister};
2
3/// Counter index mask structure in SBI function calls for the `PMU` extension ยง11.
4#[repr(C)]
5#[derive(Debug, Copy, Clone, Eq, PartialEq)]
6pub struct CounterMask<T = usize> {
7    counter_idx_mask: T,
8    counter_idx_base: T,
9}
10
11impl<T: SbiRegister> CounterMask<T> {
12    /// Special value to ignore the `mask`, and consider all `bit`s as set.
13    pub const IGNORE_MASK: T = T::FULL_MASK;
14
15    /// Construct a [CounterMask] from mask value and base counter index.
16    #[inline]
17    pub const fn from_mask_base(counter_idx_mask: T, counter_idx_base: T) -> Self {
18        Self {
19            counter_idx_mask,
20            counter_idx_base,
21        }
22    }
23
24    /// Gets the special value for ignoring the `mask` parameter.
25    #[inline]
26    pub const fn ignore_mask(&self) -> T {
27        Self::IGNORE_MASK
28    }
29
30    /// Returns `mask` and `base` parameters from the [CounterMask].
31    #[inline]
32    pub const fn into_inner(self) -> (T, T) {
33        (self.counter_idx_mask, self.counter_idx_base)
34    }
35}
36
37// FIXME: implement for T: SbiRegister once we can implement this using const traits.
38// Ref: https://rust-lang.github.io/rust-project-goals/2024h2/const-traits.html
39impl CounterMask<usize> {
40    /// Returns whether the [CounterMask] contains the provided `counter`.
41    #[inline]
42    pub const fn has_bit(self, counter: usize) -> bool {
43        has_bit(
44            self.counter_idx_mask,
45            self.counter_idx_base,
46            Self::IGNORE_MASK,
47            counter,
48        )
49    }
50}
51
52#[cfg(test)]
53mod tests {
54    use super::*;
55
56    #[test]
57    fn rustsbi_counter_index_mask() {
58        let mask = CounterMask::from_mask_base(0b1, 400);
59        assert!(!mask.has_bit(0));
60        assert!(mask.has_bit(400));
61        assert!(!mask.has_bit(401));
62        let mask = CounterMask::from_mask_base(0b110, 500);
63        assert!(!mask.has_bit(0));
64        assert!(!mask.has_bit(500));
65        assert!(mask.has_bit(501));
66        assert!(mask.has_bit(502));
67        assert!(!mask.has_bit(500 + (usize::BITS as usize)));
68        let max_bit = 1 << (usize::BITS - 1);
69        let mask = CounterMask::from_mask_base(max_bit, 600);
70        assert!(mask.has_bit(600 + (usize::BITS as usize) - 1));
71        assert!(!mask.has_bit(600 + (usize::BITS as usize)));
72        let mask = CounterMask::from_mask_base(0b11, usize::MAX - 1);
73        assert!(!mask.has_bit(usize::MAX - 2));
74        assert!(mask.has_bit(usize::MAX - 1));
75        assert!(mask.has_bit(usize::MAX));
76        assert!(!mask.has_bit(0));
77        let mask = CounterMask::from_mask_base(0, usize::MAX);
78        let null_mask = CounterMask::from_mask_base(0, 0);
79        (0..=usize::BITS as usize).for_each(|i| {
80            assert!(mask.has_bit(i));
81            assert!(!null_mask.has_bit(i));
82        });
83        assert!(mask.has_bit(usize::MAX));
84    }
85
86    #[test]
87    fn rustsbi_counter_mask_non_usize() {
88        assert_eq!(CounterMask::<i32>::IGNORE_MASK, -1);
89        assert_eq!(CounterMask::<i64>::IGNORE_MASK, -1);
90        assert_eq!(CounterMask::<i128>::IGNORE_MASK, -1);
91        assert_eq!(CounterMask::<u32>::IGNORE_MASK, u32::MAX);
92        assert_eq!(CounterMask::<u64>::IGNORE_MASK, u64::MAX);
93        assert_eq!(CounterMask::<u128>::IGNORE_MASK, u128::MAX);
94    }
95}