浏览代码

Merge pull request #71 from rmsyn/binary/bitmask

spec: convert `BitVector` to a helper function, add counter index mask
Luo Jia / Zhouqi Jiang 11 月之前
父节点
当前提交
387003b3cf
共有 1 个文件被更改,包括 127 次插入37 次删除
  1. 127 37
      sbi-spec/src/binary.rs

+ 127 - 37
sbi-spec/src/binary.rs

@@ -673,58 +673,118 @@ impl SbiRet {
     }
 }
 
+/// Check if the implementation contains the provided `bit`.
+///
+/// ## Parameters
+///
+/// - `mask`: bitmask defining the range of bits.
+/// - `base`: the starting bit index. (default: `0`)
+/// - `ignore`: if `base` is equal to this value, ignore the `mask` parameter, and consider all `bit`s set.
+/// - `bit`: the bit index to check for membership in the `mask`.
+pub(crate) const fn has_bit(mask: usize, base: usize, ignore: usize, bit: usize) -> bool {
+    if base == ignore {
+        // ignore the `mask`, consider all `bit`s as set.
+        true
+    } else if bit < base {
+        // invalid index, under minimum range.
+        false
+    } else if (bit - base) >= usize::BITS as usize {
+        // invalid index, over max range.
+        false
+    } else {
+        // index is in range, check if it is set in the mask.
+        mask & (1 << (bit - base)) != 0
+    }
+}
+
 /// Hart mask structure in SBI function calls.
-#[derive(Debug, Copy, Clone)]
+#[repr(C)]
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
 pub struct HartMask {
-    inner: BitVector,
+    hart_mask: usize,
+    hart_mask_base: usize,
 }
 
 impl HartMask {
-    /// Construct a hart mask from mask value and base hart id.
-    #[inline]
-    pub const fn from_mask_base(hart_mask: usize, hart_mask_base: usize) -> HartMask {
-        HartMask {
-            inner: BitVector {
-                hart_mask,
-                hart_mask_base,
-            },
+    /// Special value to ignore the `mask`, and consider all `bit`s as set.
+    pub const IGNORE_MASK: usize = usize::MAX;
+
+    /// Construct a [HartMask] from mask value and base hart id.
+    #[inline]
+    pub const fn from_mask_base(hart_mask: usize, hart_mask_base: usize) -> Self {
+        Self {
+            hart_mask,
+            hart_mask_base,
         }
     }
 
-    /// Returns `hart_mask` and `hart_mask_base` parameters from the hart mask structure.
+    /// 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 [HartMask].
     #[inline]
     pub const fn into_inner(self) -> (usize, usize) {
-        (self.inner.hart_mask, self.inner.hart_mask_base)
+        (self.hart_mask, self.hart_mask_base)
     }
 
-    /// Check if the `hart_id` is included in this hart mask structure.
+    /// Returns whether the [HartMask] contains the provided `hart_id`.
     #[inline]
-    pub const fn has_bit(&self, hart_id: usize) -> bool {
-        let BitVector {
-            hart_mask,
-            hart_mask_base,
-        } = self.inner;
-        if hart_mask_base == usize::MAX {
-            // If `hart_mask_base` equals `usize::MAX`, that means `hart_mask` is ignored
-            // and all available harts must be considered.
-            return true;
-        }
-        let Some(idx) = hart_id.checked_sub(hart_mask_base) else {
-            // hart_id < hart_mask_base, not in current mask range
-            return false;
-        };
-        if idx >= usize::BITS as usize {
-            // hart_idx >= hart_mask_base + XLEN, not in current mask range
-            return false;
-        }
-        hart_mask & (1 << idx) != 0
+    pub const fn has_bit(self, hart_id: usize) -> bool {
+        has_bit(
+            self.hart_mask,
+            self.hart_mask_base,
+            Self::IGNORE_MASK,
+            hart_id,
+        )
     }
 }
 
-#[derive(Debug, Copy, Clone)]
-struct BitVector {
-    hart_mask: usize,
-    hart_mask_base: usize,
+/// 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.
@@ -873,7 +933,7 @@ impl<T> Copy for SharedPtr<T> {}
 
 #[cfg(test)]
 mod tests {
-    use super::HartMask;
+    use super::*;
 
     #[test]
     fn rustsbi_hart_mask() {
@@ -904,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));
+    }
 }