Skip to main content

ab_riscv_primitives/registers/
general_purpose.rs

1//! RISC-V general purpose registers
2
3#[cfg(test)]
4mod tests;
5
6use crate::registers::general_purpose::private::PhantomRegister;
7use core::fmt;
8use core::hint::unreachable_unchecked;
9use core::marker::Destruct;
10use core::ops::{
11    Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not, Shl, Shr,
12    Sub, SubAssign,
13};
14
15mod private {
16    use core::marker::PhantomData;
17
18    #[derive(Debug, Clone, Copy)]
19    pub struct PhantomRegister<Type>(PhantomData<Type>);
20}
21
22/// Register type.
23///
24/// `u32` for RV32 and `u64` for RV64.
25pub const trait RegType
26where
27    Self: [const] Default
28        + [const] From<bool>
29        + [const] From<u8>
30        + [const] From<u16>
31        + [const] From<u32>
32        + [const] Eq
33        + [const] Ord
34        + [const] Add<Output = Self>
35        + [const] AddAssign
36        + [const] Sub<Output = Self>
37        + [const] SubAssign
38        + [const] BitAnd<Output = Self>
39        + [const] BitAndAssign
40        + [const] BitOr<Output = Self>
41        + [const] BitOrAssign
42        + [const] BitXor<Output = Self>
43        + [const] BitXorAssign
44        + [const] Not<Output = Self>
45        + [const] Shl<u8, Output = Self>
46        + [const] Shl<u16, Output = Self>
47        + [const] Shl<u32, Output = Self>
48        + [const] Shl<i32, Output = Self>
49        + [const] Shr<u8, Output = Self>
50        + [const] Shr<u16, Output = Self>
51        + [const] Shr<u32, Output = Self>
52        + [const] Shr<i32, Output = Self>
53        + fmt::Display
54        + fmt::LowerHex
55        + fmt::UpperHex
56        + fmt::Debug
57        + Copy
58        + Send
59        + Sync
60        + Sized
61        + 'static,
62{
63    /// The size of this type in bits
64    const BITS: u8;
65
66    /// Convert to `u64`
67    fn as_u64(&self) -> u64;
68}
69
70impl const RegType for u32 {
71    const BITS: u8 = u32::BITS as u8;
72
73    #[inline(always)]
74    fn as_u64(&self) -> u64 {
75        u64::from(*self)
76    }
77}
78
79impl const RegType for u64 {
80    const BITS: u8 = u64::BITS as u8;
81
82    #[inline(always)]
83    fn as_u64(&self) -> u64 {
84        *self
85    }
86}
87
88/// GPR (General Purpose Register)
89pub const trait Register:
90    fmt::Display + fmt::Debug + [const] Eq + [const] Destruct + Copy + Send + Sync + Sized + 'static
91{
92    /// Whether this is RVE variant with the number of general purpose registers reduced to 16
93    /// XLEN
94    const XLEN: u8 = Self::Type::BITS;
95    /// Zero register
96    const ZERO: Self;
97    /// Stack pointer register
98    const SP: Self;
99    /// Return address register
100    const RA: Self;
101    /// Function argument register a0
102    const A0: Self;
103    /// Function argument register a1
104    const A1: Self;
105    /// Register type.
106    ///
107    /// `u32` for RV32 and `u64` for RV64.
108    type Type: [const] RegType;
109
110    /// Create a register from its bit representation
111    fn from_bits(bits: u8) -> Option<Self>;
112}
113
114/// RISC-V general purpose register for RV32E/RV64E.
115///
116/// Use `Type = u32` for RV32E and `Type = u64` for RV64E.
117#[derive(Clone, Copy)]
118#[repr(u8)]
119pub enum EReg<Type> {
120    /// Always zero: `x0`
121    Zero = 0,
122    /// Return address: `x1`
123    Ra = 1,
124    /// Stack pointer: `x2`
125    Sp = 2,
126    /// Global pointer: `x3`
127    Gp = 3,
128    /// Thread pointer: `x4`
129    Tp = 4,
130    /// Temporary/alternate return address: `x5`
131    T0 = 5,
132    /// Temporary: `x6`
133    T1 = 6,
134    /// Temporary: `x7`
135    T2 = 7,
136    /// Saved register/frame pointer: `x8`
137    S0 = 8,
138    /// Saved register: `x9`
139    S1 = 9,
140    /// Function argument/return value: `x10`
141    A0 = 10,
142    /// Function argument/return value: `x11`
143    A1 = 11,
144    /// Function argument: `x12`
145    A2 = 12,
146    /// Function argument: `x13`
147    A3 = 13,
148    /// Function argument: `x14`
149    A4 = 14,
150    /// Function argument: `x15`
151    A5 = 15,
152    /// Phantom register that is never constructed and is only used due to type system limitations
153    #[doc(hidden)]
154    Phantom(PhantomRegister<Type>),
155}
156
157impl<Type> fmt::Display for EReg<Type> {
158    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
159        match self {
160            Self::Zero => write!(f, "zero"),
161            Self::Ra => write!(f, "ra"),
162            Self::Sp => write!(f, "sp"),
163            Self::Gp => write!(f, "gp"),
164            Self::Tp => write!(f, "tp"),
165            Self::T0 => write!(f, "t0"),
166            Self::T1 => write!(f, "t1"),
167            Self::T2 => write!(f, "t2"),
168            Self::S0 => write!(f, "s0"),
169            Self::S1 => write!(f, "s1"),
170            Self::A0 => write!(f, "a0"),
171            Self::A1 => write!(f, "a1"),
172            Self::A2 => write!(f, "a2"),
173            Self::A3 => write!(f, "a3"),
174            Self::A4 => write!(f, "a4"),
175            Self::A5 => write!(f, "a5"),
176            Self::Phantom(_) => {
177                // SAFETY: Phantom register is never constructed
178                unsafe { unreachable_unchecked() }
179            }
180        }
181    }
182}
183
184impl<Type> fmt::Debug for EReg<Type> {
185    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
186        fmt::Display::fmt(self, f)
187    }
188}
189
190impl<Type> const PartialEq for EReg<Type> {
191    #[inline(always)]
192    fn eq(&self, other: &Self) -> bool {
193        // This is quite ugly, but there doesn't seem to be a much better way with `Phantom` variant
194        matches!(
195            (self, other),
196            (Self::Zero, Self::Zero)
197                | (Self::Ra, Self::Ra)
198                | (Self::Sp, Self::Sp)
199                | (Self::Gp, Self::Gp)
200                | (Self::Tp, Self::Tp)
201                | (Self::T0, Self::T0)
202                | (Self::T1, Self::T1)
203                | (Self::T2, Self::T2)
204                | (Self::S0, Self::S0)
205                | (Self::S1, Self::S1)
206                | (Self::A0, Self::A0)
207                | (Self::A1, Self::A1)
208                | (Self::A2, Self::A2)
209                | (Self::A3, Self::A3)
210                | (Self::A4, Self::A4)
211                | (Self::A5, Self::A5)
212                | (Self::Phantom(_), Self::Phantom(_))
213        )
214    }
215}
216
217impl<Type> const Eq for EReg<Type> {}
218
219impl const Register for EReg<u32> {
220    const ZERO: Self = Self::Zero;
221    const SP: Self = Self::Sp;
222    const RA: Self = Self::Ra;
223    const A0: Self = Self::A0;
224    const A1: Self = Self::A1;
225    type Type = u32;
226
227    #[inline(always)]
228    fn from_bits(bits: u8) -> Option<Self> {
229        match bits {
230            0 => Some(Self::Zero),
231            1 => Some(Self::Ra),
232            2 => Some(Self::Sp),
233            3 => Some(Self::Gp),
234            4 => Some(Self::Tp),
235            5 => Some(Self::T0),
236            6 => Some(Self::T1),
237            7 => Some(Self::T2),
238            8 => Some(Self::S0),
239            9 => Some(Self::S1),
240            10 => Some(Self::A0),
241            11 => Some(Self::A1),
242            12 => Some(Self::A2),
243            13 => Some(Self::A3),
244            14 => Some(Self::A4),
245            15 => Some(Self::A5),
246            _ => None,
247        }
248    }
249}
250
251impl const Register for EReg<u64> {
252    const ZERO: Self = Self::Zero;
253    const SP: Self = Self::Sp;
254    const RA: Self = Self::Ra;
255    const A0: Self = Self::A0;
256    const A1: Self = Self::A1;
257    type Type = u64;
258
259    #[inline(always)]
260    fn from_bits(bits: u8) -> Option<Self> {
261        match bits {
262            0 => Some(Self::Zero),
263            1 => Some(Self::Ra),
264            2 => Some(Self::Sp),
265            3 => Some(Self::Gp),
266            4 => Some(Self::Tp),
267            5 => Some(Self::T0),
268            6 => Some(Self::T1),
269            7 => Some(Self::T2),
270            8 => Some(Self::S0),
271            9 => Some(Self::S1),
272            10 => Some(Self::A0),
273            11 => Some(Self::A1),
274            12 => Some(Self::A2),
275            13 => Some(Self::A3),
276            14 => Some(Self::A4),
277            15 => Some(Self::A5),
278            _ => None,
279        }
280    }
281}
282
283/// RISC-V general purpose register for RV32I/RV64I.
284///
285/// Use `Type = u32` for RV32I and `Type = u64` for RV64I.
286#[derive(Clone, Copy)]
287#[repr(u8)]
288pub enum Reg<Type> {
289    /// Always zero: `x0`
290    Zero = 0,
291    /// Return address: `x1`
292    Ra = 1,
293    /// Stack pointer: `x2`
294    Sp = 2,
295    /// Global pointer: `x3`
296    Gp = 3,
297    /// Thread pointer: `x4`
298    Tp = 4,
299    /// Temporary/alternate return address: `x5`
300    T0 = 5,
301    /// Temporary: `x6`
302    T1 = 6,
303    /// Temporary: `x7`
304    T2 = 7,
305    /// Saved register/frame pointer: `x8`
306    S0 = 8,
307    /// Saved register: `x9`
308    S1 = 9,
309    /// Function argument/return value: `x10`
310    A0 = 10,
311    /// Function argument/return value: `x11`
312    A1 = 11,
313    /// Function argument: `x12`
314    A2 = 12,
315    /// Function argument: `x13`
316    A3 = 13,
317    /// Function argument: `x14`
318    A4 = 14,
319    /// Function argument: `x15`
320    A5 = 15,
321    /// Function argument: `x16`
322    A6 = 16,
323    /// Function argument: `x17`
324    A7 = 17,
325    /// Saved register: `x18`
326    S2 = 18,
327    /// Saved register: `x19`
328    S3 = 19,
329    /// Saved register: `x20`
330    S4 = 20,
331    /// Saved register: `x21`
332    S5 = 21,
333    /// Saved register: `x22`
334    S6 = 22,
335    /// Saved register: `x23`
336    S7 = 23,
337    /// Saved register: `x24`
338    S8 = 24,
339    /// Saved register: `x25`
340    S9 = 25,
341    /// Saved register: `x26`
342    S10 = 26,
343    /// Saved register: `x27`
344    S11 = 27,
345    /// Temporary: `x28`
346    T3 = 28,
347    /// Temporary: `x29`
348    T4 = 29,
349    /// Temporary: `x30`
350    T5 = 30,
351    /// Temporary: `x31`
352    T6 = 31,
353    /// Phantom register that is never constructed and is only used due to type system limitations
354    #[doc(hidden)]
355    Phantom(PhantomRegister<Type>),
356}
357
358impl<Type> const From<EReg<u64>> for Reg<Type> {
359    #[inline(always)]
360    fn from(reg: EReg<u64>) -> Self {
361        match reg {
362            EReg::Zero => Self::Zero,
363            EReg::Ra => Self::Ra,
364            EReg::Sp => Self::Sp,
365            EReg::Gp => Self::Gp,
366            EReg::Tp => Self::Tp,
367            EReg::T0 => Self::T0,
368            EReg::T1 => Self::T1,
369            EReg::T2 => Self::T2,
370            EReg::S0 => Self::S0,
371            EReg::S1 => Self::S1,
372            EReg::A0 => Self::A0,
373            EReg::A1 => Self::A1,
374            EReg::A2 => Self::A2,
375            EReg::A3 => Self::A3,
376            EReg::A4 => Self::A4,
377            EReg::A5 => Self::A5,
378            EReg::Phantom(_) => {
379                // SAFETY: Phantom register is never constructed
380                unsafe { unreachable_unchecked() }
381            }
382        }
383    }
384}
385
386impl<Type> fmt::Display for Reg<Type> {
387    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
388        match self {
389            Self::Zero => write!(f, "zero"),
390            Self::Ra => write!(f, "ra"),
391            Self::Sp => write!(f, "sp"),
392            Self::Gp => write!(f, "gp"),
393            Self::Tp => write!(f, "tp"),
394            Self::T0 => write!(f, "t0"),
395            Self::T1 => write!(f, "t1"),
396            Self::T2 => write!(f, "t2"),
397            Self::S0 => write!(f, "s0"),
398            Self::S1 => write!(f, "s1"),
399            Self::A0 => write!(f, "a0"),
400            Self::A1 => write!(f, "a1"),
401            Self::A2 => write!(f, "a2"),
402            Self::A3 => write!(f, "a3"),
403            Self::A4 => write!(f, "a4"),
404            Self::A5 => write!(f, "a5"),
405            Self::A6 => write!(f, "a6"),
406            Self::A7 => write!(f, "a7"),
407            Self::S2 => write!(f, "s2"),
408            Self::S3 => write!(f, "s3"),
409            Self::S4 => write!(f, "s4"),
410            Self::S5 => write!(f, "s5"),
411            Self::S6 => write!(f, "s6"),
412            Self::S7 => write!(f, "s7"),
413            Self::S8 => write!(f, "s8"),
414            Self::S9 => write!(f, "s9"),
415            Self::S10 => write!(f, "s10"),
416            Self::S11 => write!(f, "s11"),
417            Self::T3 => write!(f, "t3"),
418            Self::T4 => write!(f, "t4"),
419            Self::T5 => write!(f, "t5"),
420            Self::T6 => write!(f, "t6"),
421            Self::Phantom(_) => {
422                // SAFETY: Phantom register is never constructed
423                unsafe { unreachable_unchecked() }
424            }
425        }
426    }
427}
428
429impl<Type> fmt::Debug for Reg<Type> {
430    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
431        fmt::Display::fmt(self, f)
432    }
433}
434
435impl<Type> const PartialEq for Reg<Type> {
436    #[inline(always)]
437    fn eq(&self, other: &Self) -> bool {
438        // This is quite ugly, but there doesn't seem to be a much better way with `Phantom` variant
439        matches!(
440            (self, other),
441            (Self::Zero, Self::Zero)
442                | (Self::Ra, Self::Ra)
443                | (Self::Sp, Self::Sp)
444                | (Self::Gp, Self::Gp)
445                | (Self::Tp, Self::Tp)
446                | (Self::T0, Self::T0)
447                | (Self::T1, Self::T1)
448                | (Self::T2, Self::T2)
449                | (Self::S0, Self::S0)
450                | (Self::S1, Self::S1)
451                | (Self::A0, Self::A0)
452                | (Self::A1, Self::A1)
453                | (Self::A2, Self::A2)
454                | (Self::A3, Self::A3)
455                | (Self::A4, Self::A4)
456                | (Self::A5, Self::A5)
457                | (Self::A6, Self::A6)
458                | (Self::A7, Self::A7)
459                | (Self::S2, Self::S2)
460                | (Self::S3, Self::S3)
461                | (Self::S4, Self::S4)
462                | (Self::S5, Self::S5)
463                | (Self::S6, Self::S6)
464                | (Self::S7, Self::S7)
465                | (Self::S8, Self::S8)
466                | (Self::S9, Self::S9)
467                | (Self::S10, Self::S10)
468                | (Self::S11, Self::S11)
469                | (Self::T3, Self::T3)
470                | (Self::T4, Self::T4)
471                | (Self::T5, Self::T5)
472                | (Self::T6, Self::T6)
473                | (Self::Phantom(_), Self::Phantom(_))
474        )
475    }
476}
477
478impl<Type> const Eq for Reg<Type> {}
479
480impl const Register for Reg<u32> {
481    const ZERO: Self = Self::Zero;
482    const SP: Self = Self::Sp;
483    const RA: Self = Self::Ra;
484    const A0: Self = Self::A0;
485    const A1: Self = Self::A1;
486    type Type = u32;
487
488    #[inline(always)]
489    fn from_bits(bits: u8) -> Option<Self> {
490        match bits {
491            0 => Some(Self::Zero),
492            1 => Some(Self::Ra),
493            2 => Some(Self::Sp),
494            3 => Some(Self::Gp),
495            4 => Some(Self::Tp),
496            5 => Some(Self::T0),
497            6 => Some(Self::T1),
498            7 => Some(Self::T2),
499            8 => Some(Self::S0),
500            9 => Some(Self::S1),
501            10 => Some(Self::A0),
502            11 => Some(Self::A1),
503            12 => Some(Self::A2),
504            13 => Some(Self::A3),
505            14 => Some(Self::A4),
506            15 => Some(Self::A5),
507            16 => Some(Self::A6),
508            17 => Some(Self::A7),
509            18 => Some(Self::S2),
510            19 => Some(Self::S3),
511            20 => Some(Self::S4),
512            21 => Some(Self::S5),
513            22 => Some(Self::S6),
514            23 => Some(Self::S7),
515            24 => Some(Self::S8),
516            25 => Some(Self::S9),
517            26 => Some(Self::S10),
518            27 => Some(Self::S11),
519            28 => Some(Self::T3),
520            29 => Some(Self::T4),
521            30 => Some(Self::T5),
522            31 => Some(Self::T6),
523            _ => None,
524        }
525    }
526}
527
528impl const Register for Reg<u64> {
529    const ZERO: Self = Self::Zero;
530    const SP: Self = Self::Sp;
531    const RA: Self = Self::Ra;
532    const A0: Self = Self::A0;
533    const A1: Self = Self::A1;
534    type Type = u64;
535
536    #[inline(always)]
537    fn from_bits(bits: u8) -> Option<Self> {
538        match bits {
539            0 => Some(Self::Zero),
540            1 => Some(Self::Ra),
541            2 => Some(Self::Sp),
542            3 => Some(Self::Gp),
543            4 => Some(Self::Tp),
544            5 => Some(Self::T0),
545            6 => Some(Self::T1),
546            7 => Some(Self::T2),
547            8 => Some(Self::S0),
548            9 => Some(Self::S1),
549            10 => Some(Self::A0),
550            11 => Some(Self::A1),
551            12 => Some(Self::A2),
552            13 => Some(Self::A3),
553            14 => Some(Self::A4),
554            15 => Some(Self::A5),
555            16 => Some(Self::A6),
556            17 => Some(Self::A7),
557            18 => Some(Self::S2),
558            19 => Some(Self::S3),
559            20 => Some(Self::S4),
560            21 => Some(Self::S5),
561            22 => Some(Self::S6),
562            23 => Some(Self::S7),
563            24 => Some(Self::S8),
564            25 => Some(Self::S9),
565            26 => Some(Self::S10),
566            27 => Some(Self::S11),
567            28 => Some(Self::T3),
568            29 => Some(Self::T4),
569            30 => Some(Self::T5),
570            31 => Some(Self::T6),
571            _ => None,
572        }
573    }
574}