Browse Source

spec: add counter index mask type

Adds the `CounterIndexMask` type to represent `counter_idx_mask` and
`counter_idx_base` parameters from the `PMU` extension.
rmsyn 11 months ago
parent
commit
ccffd8b4e2
1 changed files with 75 additions and 0 deletions
  1. 75 0
      sbi-spec/src/binary.rs

+ 75 - 0
sbi-spec/src/binary.rs

@@ -742,6 +742,51 @@ impl HartMask {
     }
 }
 
+/// Counter index mask structure in SBI function calls for the `PMU` extension §11.
+#[repr(C)]
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+pub struct CounterMask {
+    counter_idx_mask: usize,
+    counter_idx_base: usize,
+}
+
+impl CounterMask {
+    /// Special value to ignore the `mask`, and consider all `bit`s as set.
+    pub const IGNORE_MASK: usize = usize::MAX;
+
+    /// Construct a [CounterMask] from mask value and base counter index.
+    #[inline]
+    pub const fn from_mask_base(counter_idx_mask: usize, counter_idx_base: usize) -> Self {
+        Self {
+            counter_idx_mask,
+            counter_idx_base,
+        }
+    }
+
+    /// Gets the special value for ignoring the `mask` parameter.
+    #[inline]
+    pub const fn ignore_mask(&self) -> usize {
+        Self::IGNORE_MASK
+    }
+
+    /// Returns `mask` and `base` parameters from the [CounterMask].
+    #[inline]
+    pub const fn into_inner(self) -> (usize, usize) {
+        (self.counter_idx_mask, self.counter_idx_base)
+    }
+
+    /// Returns whether the [CounterMask] contains the provided `counter`.
+    #[inline]
+    pub const fn has_bit(self, counter: usize) -> bool {
+        has_bit(
+            self.counter_idx_mask,
+            self.counter_idx_base,
+            Self::IGNORE_MASK,
+            counter,
+        )
+    }
+}
+
 /// Physical slice wrapper with type annotation.
 ///
 /// This struct wraps slices in RISC-V physical memory by low and high part of the
@@ -919,4 +964,34 @@ mod tests {
         }
         assert!(mask.has_bit(usize::MAX));
     }
+
+    #[test]
+    fn rustsbi_counter_index_mask() {
+        let mask = CounterMask::from_mask_base(0b1, 400);
+        assert!(!mask.has_bit(0));
+        assert!(mask.has_bit(400));
+        assert!(!mask.has_bit(401));
+        let mask = CounterMask::from_mask_base(0b110, 500);
+        assert!(!mask.has_bit(0));
+        assert!(!mask.has_bit(500));
+        assert!(mask.has_bit(501));
+        assert!(mask.has_bit(502));
+        assert!(!mask.has_bit(500 + (usize::BITS as usize)));
+        let max_bit = 1 << (usize::BITS - 1);
+        let mask = CounterMask::from_mask_base(max_bit, 600);
+        assert!(mask.has_bit(600 + (usize::BITS as usize) - 1));
+        assert!(!mask.has_bit(600 + (usize::BITS as usize)));
+        let mask = CounterMask::from_mask_base(0b11, usize::MAX - 1);
+        assert!(!mask.has_bit(usize::MAX - 2));
+        assert!(mask.has_bit(usize::MAX - 1));
+        assert!(mask.has_bit(usize::MAX));
+        assert!(!mask.has_bit(0));
+        let mask = CounterMask::from_mask_base(0, usize::MAX);
+        let null_mask = CounterMask::from_mask_base(0, 0);
+        (0..=usize::BITS as usize).for_each(|i| {
+            assert!(mask.has_bit(i));
+            assert!(!null_mask.has_bit(i));
+        });
+        assert!(mask.has_bit(usize::MAX));
+    }
 }