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
41impl const 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
50impl const 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
59impl const 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
68impl const 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 pub const fn from_u32(v: u32) -> Self {
97 let b = v.to_le_bytes();
98 debug_assert!(
99 (v << u8::BITS) >> u8::BITS == v,
100 "Input value exceeds 24 bits"
101 );
102 Self([b[0], b[1], b[2]])
103 }
104
105 #[inline(always)]
107 pub const fn to_u32(self) -> u32 {
108 let [a, b, c] = self.0;
109 u32::from_le_bytes([a, b, c, 0])
110 }
111}
112
113#[derive(Default, Clone, Copy, PartialEq, Eq, Hash)]
115pub struct I24([u8; 3]);
116
117impl fmt::Debug for I24 {
118 #[inline(always)]
119 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
120 fmt::Debug::fmt(&self.to_i32(), f)
121 }
122}
123
124impl fmt::Display for I24 {
125 #[inline(always)]
126 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
127 fmt::Display::fmt(&self.to_i32(), f)
128 }
129}
130
131impl fmt::LowerHex for I24 {
132 #[inline(always)]
133 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
134 fmt::LowerHex::fmt(&self.to_i32(), f)
135 }
136}
137
138impl fmt::UpperHex for I24 {
139 #[inline(always)]
140 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
141 fmt::UpperHex::fmt(&self.to_i32(), f)
142 }
143}
144
145impl const Shl<u8> for I24 {
146 type Output = Self;
147
148 #[inline(always)]
149 fn shl(self, rhs: u8) -> Self::Output {
150 Self::from_i32(self.to_i32().shl(rhs))
151 }
152}
153
154impl const Shr<u8> for I24 {
155 type Output = Self;
156
157 #[inline(always)]
158 fn shr(self, rhs: u8) -> Self::Output {
159 Self::from_i32(self.to_i32().shr(rhs))
160 }
161}
162
163impl const Shl<u8> for &I24 {
164 type Output = I24;
165
166 #[inline(always)]
167 fn shl(self, rhs: u8) -> Self::Output {
168 I24::from_i32(self.to_i32().shl(rhs))
169 }
170}
171
172impl const Shr<u8> for &I24 {
173 type Output = I24;
174
175 #[inline(always)]
176 fn shr(self, rhs: u8) -> Self::Output {
177 I24::from_i32(self.to_i32().shr(rhs))
178 }
179}
180
181impl From<I24> for i32 {
182 #[inline(always)]
183 fn from(v: I24) -> Self {
184 v.to_i32()
185 }
186}
187
188impl From<I24> for i64 {
189 #[inline(always)]
190 fn from(v: I24) -> Self {
191 i64::from(v.to_i32())
192 }
193}
194
195impl I24 {
196 #[inline(always)]
200 pub const fn from_i32(v: i32) -> Self {
201 let b = v.to_le_bytes();
202 debug_assert!(
203 (v << u8::BITS) >> u8::BITS == v,
204 "Input value exceeds 24 bits"
205 );
206 Self([b[0], b[1], b[2]])
207 }
208
209 #[inline(always)]
211 pub const fn to_i32(self) -> i32 {
212 let [a, b, c] = self.0;
213 i32::from_le_bytes([a, b, c, 0]) << u8::BITS >> u8::BITS
215 }
216}
217
218#[derive(Default, Clone, Copy, PartialEq, Eq, Hash)]
221pub struct I24WithZeroedBits<const LOW_ZEROED_BITS: u8>([u8; 3]);
222
223impl<const LOW_ZEROED_BITS: u8> fmt::Debug for I24WithZeroedBits<LOW_ZEROED_BITS> {
224 #[inline(always)]
225 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
226 fmt::Debug::fmt(&self.to_i32(), f)
227 }
228}
229
230impl<const LOW_ZEROED_BITS: u8> fmt::Display for I24WithZeroedBits<LOW_ZEROED_BITS> {
231 #[inline(always)]
232 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
233 fmt::Display::fmt(&self.to_i32(), f)
234 }
235}
236
237impl<const LOW_ZEROED_BITS: u8> fmt::LowerHex for I24WithZeroedBits<LOW_ZEROED_BITS> {
238 #[inline(always)]
239 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
240 fmt::LowerHex::fmt(&self.to_i32(), f)
241 }
242}
243
244impl<const LOW_ZEROED_BITS: u8> fmt::UpperHex for I24WithZeroedBits<LOW_ZEROED_BITS> {
245 #[inline(always)]
246 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
247 fmt::UpperHex::fmt(&self.to_i32(), f)
248 }
249}
250
251impl<const LOW_ZEROED_BITS: u8> From<I24WithZeroedBits<LOW_ZEROED_BITS>> for i32 {
252 #[inline(always)]
253 fn from(v: I24WithZeroedBits<LOW_ZEROED_BITS>) -> Self {
254 v.to_i32()
255 }
256}
257
258impl<const LOW_ZEROED_BITS: u8> From<I24WithZeroedBits<LOW_ZEROED_BITS>> for i64 {
259 #[inline(always)]
260 fn from(v: I24WithZeroedBits<LOW_ZEROED_BITS>) -> Self {
261 i64::from(v.to_i32())
262 }
263}
264
265impl<const LOW_ZEROED_BITS: u8> I24WithZeroedBits<LOW_ZEROED_BITS> {
266 #[inline(always)]
272 pub const fn from_i32(v_original: i32) -> Self {
273 let v = v_original >> LOW_ZEROED_BITS;
274 let b = v.to_le_bytes();
275 let return_value = Self([b[0], b[1], b[2]]);
276
277 debug_assert!(
278 return_value.to_i32() == v_original,
279 "Input has non-zero low bits"
280 );
281
282 return_value
283 }
284
285 #[inline(always)]
287 pub const fn to_i32(self) -> i32 {
288 let [a, b, c] = self.0;
289 (((i32::from_le_bytes([a, b, c, 0]) << u8::BITS >> u8::BITS) << LOW_ZEROED_BITS)
291 .cast_unsigned()
292 & (u32::MAX << LOW_ZEROED_BITS))
293 .cast_signed()
294 }
295}