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