xref: /openbmc/qemu/rust/common/src/bitops.rs (revision ccafa85a97e38698b798115bba6c18c849846e25)
1 // Copyright (C) 2024 Intel Corporation.
2 // Author(s): Zhao Liu <zhao1.liu@intel.com>
3 // SPDX-License-Identifier: GPL-2.0-or-later
4 
5 //! This module provides bit operation extensions to integer types.
6 
7 use std::ops::{
8     Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, DivAssign,
9     Mul, MulAssign, Not, Rem, RemAssign, Shl, ShlAssign, Shr, ShrAssign,
10 };
11 
12 /// Trait for extensions to integer types
13 pub trait IntegerExt:
14     Add<Self, Output = Self> + AddAssign<Self> +
15     BitAnd<Self, Output = Self> + BitAndAssign<Self> +
16     BitOr<Self, Output = Self> + BitOrAssign<Self> +
17     BitXor<Self, Output = Self> + BitXorAssign<Self> +
18     Copy +
19     Div<Self, Output = Self> + DivAssign<Self> +
20     Eq +
21     Mul<Self, Output = Self> + MulAssign<Self> +
22     Not<Output = Self> + Ord + PartialOrd +
23     Rem<Self, Output = Self> + RemAssign<Self> +
24     Shl<Self, Output = Self> + ShlAssign<Self> +
25     Shl<u32, Output = Self> + ShlAssign<u32> + // add more as needed
26     Shr<Self, Output = Self> + ShrAssign<Self> +
27     Shr<u32, Output = Self> + ShrAssign<u32> // add more as needed
28 {
29     const BITS: u32;
30     const MAX: Self;
31     const MIN: Self;
32     const ONE: Self;
33     const ZERO: Self;
34 
35     #[inline]
36     #[must_use]
37     fn bit(start: u32) -> Self
38     {
39         debug_assert!(start < Self::BITS);
40 
41         Self::ONE << start
42     }
43 
44     #[inline]
45     #[must_use]
46     fn mask(start: u32, length: u32) -> Self
47     {
48         /* FIXME: Implement a more elegant check with error handling support? */
49         debug_assert!(start < Self::BITS && length > 0 && length <= Self::BITS - start);
50 
51         (Self::MAX >> (Self::BITS - length)) << start
52     }
53 
54     #[inline]
55     #[must_use]
56     fn deposit<U: IntegerExt>(self, start: u32, length: u32,
57                           fieldval: U) -> Self
58         where Self: From<U>
59     {
60         debug_assert!(length <= U::BITS);
61 
62         let mask = Self::mask(start, length);
63         (self & !mask) | ((Self::from(fieldval) << start) & mask)
64     }
65 
66     #[inline]
67     #[must_use]
68     fn extract(self, start: u32, length: u32) -> Self
69     {
70         let mask = Self::mask(start, length);
71         (self & mask) >> start
72     }
73 }
74 
75 macro_rules! impl_num_ext {
76     ($type:ty) => {
77         impl IntegerExt for $type {
78             const BITS: u32 = <$type>::BITS;
79             const MAX: Self = <$type>::MAX;
80             const MIN: Self = <$type>::MIN;
81             const ONE: Self = 1;
82             const ZERO: Self = 0;
83         }
84     };
85 }
86 
87 impl_num_ext!(u8);
88 impl_num_ext!(u16);
89 impl_num_ext!(u32);
90 impl_num_ext!(u64);
91 
92 #[cfg(test)]
93 mod tests {
94     use super::*;
95 
96     #[test]
97     fn test_deposit() {
98         assert_eq!(15u32.deposit(8, 8, 1u32), 256 + 15);
99         assert_eq!(15u32.deposit(8, 1, 255u8), 256 + 15);
100     }
101 
102     #[test]
103     fn test_extract() {
104         assert_eq!(15u32.extract(2, 4), 3);
105     }
106 
107     #[test]
108     fn test_bit() {
109         assert_eq!(u8::bit(7), 128);
110         assert_eq!(u32::bit(16), 0x10000);
111     }
112 
113     #[test]
114     fn test_mask() {
115         assert_eq!(u8::mask(7, 1), 128);
116         assert_eq!(u32::mask(8, 8), 0xff00);
117     }
118 }
119