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