dynasm\arch\riscv/
ast.rs

1//! RISC-V registers are simple. The registers contain no size information, this is purely encoded
2//! in the target architecture and instruction
3//! we currently have three known register families.
4//! * General purpose registers, either denoted as x0-x31 or by specific names
5//! * floating point registers, denoted as f0-f31 or by specific names
6//! * vector registers, denoted as v0-v31
7use proc_macro2::Span;
8use crate::common::Jump;
9use super::riscvdata::Opdata;
10
11use std::fmt;
12
13
14/// A generic register reference. Can be either a static RegId or a dynamic register from a family
15#[derive(Debug, Clone)]
16pub enum Register {
17    Static(RegId),
18    Dynamic(RegFamily, syn::Expr)
19}
20
21/// Unique identifiers for a specific register
22#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
23pub enum RegId {
24    // regular registers
25    X0 = 0x00, X1 = 0x01, X2 = 0x02, X3 = 0x03, // zero, ra, sp, gp
26    X4 = 0x04, X5 = 0x05, X6 = 0x06, X7 = 0x07, // tp, t0, t1, t2
27    X8 = 0x08, X9 = 0x09, X10= 0x0A, X11= 0x0B, // s0, s1, a0, a1
28    X12= 0x0C, X13= 0x0D, X14= 0x0E, X15= 0x0F, // a2, a3, a4, a5
29    X16= 0x10, X17= 0x11, X18= 0x12, X19= 0x13, // a6, a7, s2, s3
30    X20= 0x14, X21= 0x15, X22= 0x16, X23= 0x17, // s4, s5, s6, s7
31    X24= 0x18, X25= 0x19, X26= 0x1A, X27= 0x1B, // s8, s9, s10,s11
32    X28= 0x1C, X29= 0x1D, X30= 0x1E, X31= 0x1F, // t3, t4, t5, t6
33
34    // floating point registers
35    F0 = 0x20, F1 = 0x21, F2 = 0x22, F3 = 0x23,
36    F4 = 0x24, F5 = 0x25, F6 = 0x26, F7 = 0x27,
37    F8 = 0x28, F9 = 0x29, F10= 0x2A, F11= 0x2B,
38    F12= 0x2C, F13= 0x2D, F14= 0x2E, F15= 0x2F,
39    F16= 0x30, F17= 0x31, F18= 0x32, F19= 0x33,
40    F20= 0x34, F21= 0x35, F22= 0x36, F23= 0x37,
41    F24= 0x38, F25= 0x39, F26= 0x3A, F27= 0x3B,
42    F28= 0x3C, F29= 0x3D, F30= 0x3E, F31= 0x3F,
43
44    // vector registers
45    V0 = 0x40, V1 = 0x41, V2 = 0x42, V3 = 0x43,
46    V4 = 0x44, V5 = 0x45, V6 = 0x46, V7 = 0x47,
47    V8 = 0x48, V9 = 0x49, V10= 0x4A, V11= 0x4B,
48    V12= 0x4C, V13= 0x4D, V14= 0x4E, V15= 0x4F,
49    V16= 0x50, V17= 0x51, V18= 0x52, V19= 0x53,
50    V20= 0x54, V21= 0x55, V22= 0x56, V23= 0x57,
51    V24= 0x58, V25= 0x59, V26= 0x5A, V27= 0x5B,
52    V28= 0x5C, V29= 0x5D, V30= 0x5E, V31= 0x5F,
53}
54
55/// Register families
56#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
57pub enum RegFamily {
58    INTEGER = 0,
59    FP = 1,
60    VECTOR = 2,
61}
62
63impl RegId {
64    /// Encode this RegId in a 5-bit value
65    pub fn code(self) -> u8 {
66        self as u8 & 0x1F
67    }
68
69    /// Returns the family of this Regid
70    pub fn family(self) -> RegFamily {
71        match self as u8 >> 5 {
72            0 => RegFamily::INTEGER,
73            1 => RegFamily::FP,
74            2 => RegFamily::VECTOR,
75            _ => unreachable!(),
76        }
77    }
78}
79
80impl fmt::Display for RegId {
81    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
82        match self.family() {
83            RegFamily::INTEGER => write!(f, "x{}", self.code()),
84            RegFamily::FP => write!(f, "f{}", self.code()),
85            RegFamily::VECTOR => write!(f, "v{}", self.code()),
86        }
87    }
88}
89
90impl Register {
91    /// Get the 5-bit code for this Register, if statically known.
92    pub fn code(&self) -> Option<u8> {
93        match self {
94            Register::Static(code) => Some(code.code()),
95            Register::Dynamic(_, _) => None
96        }
97    }
98
99    /// Returns the family that this Register is of
100    pub fn family(&self) -> RegFamily {
101        match self {
102            Register::Static(code) => code.family(),
103            Register::Dynamic(family, _) => *family
104        }
105    }
106
107    /// Returns true if this Register is dynamic
108    pub fn is_dynamic(&self) -> bool {
109        match self {
110            Register::Static(_) => false,
111            Register::Dynamic(_, _) => true
112        }
113    }
114
115    /// Returns Some(RegId) if this Register is static
116    pub fn as_id(&self) -> Option<RegId> {
117        match self {
118            Register::Static(id) => Some(*id),
119            Register::Dynamic(_, _) => None
120        }
121    }
122}
123
124
125#[derive(Debug)]
126pub enum RegListCount {
127    Static(u8),
128    Dynamic(syn::Expr),
129    Single(Register),
130    Double(Register, Register)
131}
132
133
134/// A RISC-V parsed instruction.
135/// These are fairly simple. the format is "op" [ . "opext" ]* [ arg [ , arg ]* ]
136/// where arg is
137/// * an immediate (arbitrary expression)
138/// * a label (in normal dynasm-rs style)
139/// * a register (one of the above)
140/// * a memory reference `expr? ( intreg ) `
141/// * a register list {ra [, s0 [- s_n]]}
142///
143/// this last one is somewhat problematic, as just parsing the expr will normally swallow
144/// the register reference as a call expression.
145#[derive(Debug)]
146pub enum RawArg {
147    // An immediate, or potentially an identifier
148    Immediate {
149        value: syn::Expr
150    },
151    // A label
152    JumpTarget {
153        jump: Jump
154    },
155    // A register
156    Register {
157        span: Span,
158        reg: Register
159    },
160    // A memory reference
161    Reference {
162        span: Span,
163        offset: Option<syn::Expr>,
164        base: Register,
165    },
166    // A pc-relative reference
167    LabelReference {
168        span: Span,
169        jump: Jump,
170        base: Register
171    },
172    // A register list. These only happen with a single family of instructions in the Zcmp extension
173    RegisterList {
174        span: Span,
175        first: Register, // this should always be ra
176        count: RegListCount
177    },
178}
179
180/// The result of parsing a single instruction
181#[derive(Debug)]
182pub struct ParsedInstruction {
183    pub name: String,
184    pub span: Span,
185    pub args: Vec<RawArg>
186}
187
188#[derive(Debug)]
189pub enum RegListFlat {
190    Static(u8),
191    Dynamic(syn::Expr)
192}
193
194#[derive(Debug)]
195pub enum FlatArg {
196    Immediate {
197        value: syn::Expr
198    },
199    JumpTarget {
200        jump: Jump
201    },
202    Register {
203        span: Span,
204        reg: Register
205    },
206    RegisterList {
207        span: Span,
208        count: RegListFlat
209    },
210    Default
211}
212
213/// The result of finding a match for an instruction
214#[derive(Debug)]
215pub struct MatchData {
216    pub data: &'static Opdata,
217    pub args: Vec<FlatArg>
218}