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