ab_riscv_primitives/instructions/
utils.rs1#[cfg(test)]
4mod tests;
5
6use core::fmt;
7use core::ops::{Shl, Shr};
8
9#[derive(Default, Clone, Copy, PartialEq, Eq, Hash)]
11pub struct U24([u8; 3]);
12
13impl fmt::Debug for U24 {
14 #[inline(always)]
15 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
16 fmt::Debug::fmt(&self.to_u32(), f)
17 }
18}
19
20impl fmt::Display for U24 {
21 #[inline(always)]
22 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23 fmt::Display::fmt(&self.to_u32(), f)
24 }
25}
26
27impl fmt::LowerHex for U24 {
28 #[inline(always)]
29 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30 fmt::LowerHex::fmt(&self.to_u32(), f)
31 }
32}
33
34impl fmt::UpperHex for U24 {
35 #[inline(always)]
36 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37 fmt::UpperHex::fmt(&self.to_u32(), f)
38 }
39}
40
41const impl Shl<u8> for U24 {
42 type Output = Self;
43
44 #[inline(always)]
45 fn shl(self, rhs: u8) -> Self::Output {
46 Self::from_u32(self.to_u32().shl(rhs))
47 }
48}
49
50const impl Shr<u8> for U24 {
51 type Output = Self;
52
53 #[inline(always)]
54 fn shr(self, rhs: u8) -> Self::Output {
55 Self::from_u32(self.to_u32().shr(rhs))
56 }
57}
58
59const impl Shl<u8> for &U24 {
60 type Output = U24;
61
62 #[inline(always)]
63 fn shl(self, rhs: u8) -> Self::Output {
64 U24::from_u32(self.to_u32().shl(rhs))
65 }
66}
67
68const impl Shr<u8> for &U24 {
69 type Output = U24;
70
71 #[inline(always)]
72 fn shr(self, rhs: u8) -> Self::Output {
73 U24::from_u32(self.to_u32().shr(rhs))
74 }
75}
76
77impl From<U24> for u32 {
78 #[inline(always)]
79 fn from(v: U24) -> Self {
80 v.to_u32()
81 }
82}
83
84impl From<U24> for u64 {
85 #[inline(always)]
86 fn from(v: U24) -> Self {
87 u64::from(v.to_u32())
88 }
89}
90
91impl U24 {
92 #[inline(always)]
96 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
97 pub const fn from_u32(v: u32) -> Self {
98 let b = v.to_le_bytes();
99 debug_assert!(
100 (v << u8::BITS) >> u8::BITS == v,
101 "Input value exceeds 24 bits"
102 );
103 Self([b[0], b[1], b[2]])
104 }
105
106 #[inline(always)]
108 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
109 pub const fn to_u32(self) -> u32 {
110 let [a, b, c] = self.0;
111 u32::from_le_bytes([a, b, c, 0])
112 }
113}
114
115#[derive(Default, Clone, Copy, PartialEq, Eq, Hash)]
117pub struct I24([u8; 3]);
118
119impl fmt::Debug for I24 {
120 #[inline(always)]
121 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
122 fmt::Debug::fmt(&self.to_i32(), f)
123 }
124}
125
126impl fmt::Display for I24 {
127 #[inline(always)]
128 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
129 fmt::Display::fmt(&self.to_i32(), f)
130 }
131}
132
133impl fmt::LowerHex for I24 {
134 #[inline(always)]
135 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
136 fmt::LowerHex::fmt(&self.to_i32(), f)
137 }
138}
139
140impl fmt::UpperHex for I24 {
141 #[inline(always)]
142 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
143 fmt::UpperHex::fmt(&self.to_i32(), f)
144 }
145}
146
147const impl Shl<u8> for I24 {
148 type Output = Self;
149
150 #[inline(always)]
151 fn shl(self, rhs: u8) -> Self::Output {
152 Self::from_i32(self.to_i32().shl(rhs))
153 }
154}
155
156const impl Shr<u8> for I24 {
157 type Output = Self;
158
159 #[inline(always)]
160 fn shr(self, rhs: u8) -> Self::Output {
161 Self::from_i32(self.to_i32().shr(rhs))
162 }
163}
164
165const impl Shl<u8> for &I24 {
166 type Output = I24;
167
168 #[inline(always)]
169 fn shl(self, rhs: u8) -> Self::Output {
170 I24::from_i32(self.to_i32().shl(rhs))
171 }
172}
173
174const impl Shr<u8> for &I24 {
175 type Output = I24;
176
177 #[inline(always)]
178 fn shr(self, rhs: u8) -> Self::Output {
179 I24::from_i32(self.to_i32().shr(rhs))
180 }
181}
182
183impl From<I24> for i32 {
184 #[inline(always)]
185 fn from(v: I24) -> Self {
186 v.to_i32()
187 }
188}
189
190impl From<I24> for i64 {
191 #[inline(always)]
192 fn from(v: I24) -> Self {
193 i64::from(v.to_i32())
194 }
195}
196
197impl I24 {
198 #[inline(always)]
202 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
203 pub const fn from_i32(v: i32) -> Self {
204 let b = v.to_le_bytes();
205 debug_assert!(
206 (v << u8::BITS) >> u8::BITS == v,
207 "Input value exceeds 24 bits"
208 );
209 Self([b[0], b[1], b[2]])
210 }
211
212 #[inline(always)]
214 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
215 pub const fn to_i32(self) -> i32 {
216 let [a, b, c] = self.0;
217 i32::from_le_bytes([a, b, c, 0]) << u8::BITS >> u8::BITS
219 }
220}
221
222#[derive(Default, Clone, Copy, PartialEq, Eq, Hash)]
225pub struct I24WithZeroedBits<const LOW_ZEROED_BITS: u8>([u8; 3]);
226
227impl<const LOW_ZEROED_BITS: u8> fmt::Debug for I24WithZeroedBits<LOW_ZEROED_BITS> {
228 #[inline(always)]
229 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
230 fmt::Debug::fmt(&self.to_i32(), f)
231 }
232}
233
234impl<const LOW_ZEROED_BITS: u8> fmt::Display for I24WithZeroedBits<LOW_ZEROED_BITS> {
235 #[inline(always)]
236 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
237 fmt::Display::fmt(&self.to_i32(), f)
238 }
239}
240
241impl<const LOW_ZEROED_BITS: u8> fmt::LowerHex for I24WithZeroedBits<LOW_ZEROED_BITS> {
242 #[inline(always)]
243 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
244 fmt::LowerHex::fmt(&self.to_i32(), f)
245 }
246}
247
248impl<const LOW_ZEROED_BITS: u8> fmt::UpperHex for I24WithZeroedBits<LOW_ZEROED_BITS> {
249 #[inline(always)]
250 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
251 fmt::UpperHex::fmt(&self.to_i32(), f)
252 }
253}
254
255impl<const LOW_ZEROED_BITS: u8> From<I24WithZeroedBits<LOW_ZEROED_BITS>> for i32 {
256 #[inline(always)]
257 fn from(v: I24WithZeroedBits<LOW_ZEROED_BITS>) -> Self {
258 v.to_i32()
259 }
260}
261
262impl<const LOW_ZEROED_BITS: u8> From<I24WithZeroedBits<LOW_ZEROED_BITS>> for i64 {
263 #[inline(always)]
264 fn from(v: I24WithZeroedBits<LOW_ZEROED_BITS>) -> Self {
265 i64::from(v.to_i32())
266 }
267}
268
269impl<const LOW_ZEROED_BITS: u8> I24WithZeroedBits<LOW_ZEROED_BITS> {
270 #[inline(always)]
276 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
277 pub const fn from_i32(v_original: i32) -> Self {
278 let v = v_original >> LOW_ZEROED_BITS;
279 let b = v.to_le_bytes();
280 let return_value = Self([b[0], b[1], b[2]]);
281
282 debug_assert!(
283 return_value.to_i32() == v_original,
284 "Input has non-zero low bits"
285 );
286
287 return_value
288 }
289
290 #[inline(always)]
292 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
293 pub const fn to_i32(self) -> i32 {
294 let [a, b, c] = self.0;
295 (((i32::from_le_bytes([a, b, c, 0]) << u8::BITS >> u8::BITS) << LOW_ZEROED_BITS)
297 .cast_unsigned()
298 & (u32::MAX << LOW_ZEROED_BITS))
299 .cast_signed()
300 }
301}