1 | //===-- RISCVInstructions.h -----------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #ifndef LLDB_SOURCE_PLUGINS_INSTRUCTION_RISCV_RISCVINSTRUCTION_H |
10 | #define LLDB_SOURCE_PLUGINS_INSTRUCTION_RISCV_RISCVINSTRUCTION_H |
11 | |
12 | #include <cstdint> |
13 | #include <optional> |
14 | #include <variant> |
15 | |
16 | #include "llvm/ADT/APFloat.h" |
17 | |
18 | namespace lldb_private { |
19 | |
20 | class EmulateInstructionRISCV; |
21 | |
22 | struct Rd { |
23 | uint32_t rd; |
24 | bool Write(EmulateInstructionRISCV &emulator, uint64_t value); |
25 | bool WriteAPFloat(EmulateInstructionRISCV &emulator, llvm::APFloat value); |
26 | }; |
27 | |
28 | struct Rs { |
29 | uint32_t rs; |
30 | std::optional<uint64_t> Read(EmulateInstructionRISCV &emulator); |
31 | std::optional<int32_t> ReadI32(EmulateInstructionRISCV &emulator); |
32 | std::optional<int64_t> ReadI64(EmulateInstructionRISCV &emulator); |
33 | std::optional<uint32_t> ReadU32(EmulateInstructionRISCV &emulator); |
34 | std::optional<llvm::APFloat> ReadAPFloat(EmulateInstructionRISCV &emulator, |
35 | bool isDouble); |
36 | }; |
37 | |
38 | #define DERIVE_EQ(NAME) \ |
39 | bool operator==(const NAME &r) const { \ |
40 | return std::memcmp(this, &r, sizeof(NAME)) == 0; \ |
41 | } |
42 | |
43 | #define I_TYPE_INST(NAME) \ |
44 | struct NAME { \ |
45 | Rd rd; \ |
46 | Rs rs1; \ |
47 | uint32_t imm; \ |
48 | DERIVE_EQ(NAME); \ |
49 | } |
50 | #define S_TYPE_INST(NAME) \ |
51 | struct NAME { \ |
52 | Rs rs1; \ |
53 | Rs rs2; \ |
54 | uint32_t imm; \ |
55 | DERIVE_EQ(NAME); \ |
56 | } |
57 | #define U_TYPE_INST(NAME) \ |
58 | struct NAME { \ |
59 | Rd rd; \ |
60 | uint32_t imm; \ |
61 | DERIVE_EQ(NAME); \ |
62 | } |
63 | /// The memory layout are the same in our code. |
64 | #define J_TYPE_INST(NAME) U_TYPE_INST(NAME) |
65 | #define R_TYPE_INST(NAME) \ |
66 | struct NAME { \ |
67 | Rd rd; \ |
68 | Rs rs1; \ |
69 | Rs rs2; \ |
70 | DERIVE_EQ(NAME); \ |
71 | } |
72 | #define R_SHAMT_TYPE_INST(NAME) \ |
73 | struct NAME { \ |
74 | Rd rd; \ |
75 | Rs rs1; \ |
76 | uint32_t shamt; \ |
77 | DERIVE_EQ(NAME); \ |
78 | } |
79 | #define R_RS1_TYPE_INST(NAME) \ |
80 | struct NAME { \ |
81 | Rd rd; \ |
82 | Rs rs1; \ |
83 | DERIVE_EQ(NAME); \ |
84 | } |
85 | #define R4_TYPE_INST(NAME) \ |
86 | struct NAME { \ |
87 | Rd rd; \ |
88 | Rs rs1; \ |
89 | Rs rs2; \ |
90 | Rs rs3; \ |
91 | int32_t rm; \ |
92 | DERIVE_EQ(NAME); \ |
93 | } |
94 | /// The `inst` fields are used for debugging. |
95 | #define INVALID_INST(NAME) \ |
96 | struct NAME { \ |
97 | uint32_t inst; \ |
98 | DERIVE_EQ(NAME); \ |
99 | } |
100 | |
101 | // RV32I instructions (The base integer ISA) |
102 | struct B { |
103 | Rs rs1; |
104 | Rs rs2; |
105 | uint32_t imm; |
106 | uint32_t funct3; |
107 | DERIVE_EQ(B); |
108 | }; |
109 | U_TYPE_INST(LUI); |
110 | U_TYPE_INST(AUIPC); |
111 | J_TYPE_INST(JAL); |
112 | I_TYPE_INST(JALR); |
113 | I_TYPE_INST(LB); |
114 | I_TYPE_INST(LH); |
115 | I_TYPE_INST(LW); |
116 | I_TYPE_INST(LBU); |
117 | I_TYPE_INST(LHU); |
118 | S_TYPE_INST(SB); |
119 | S_TYPE_INST(SH); |
120 | S_TYPE_INST(SW); |
121 | I_TYPE_INST(ADDI); |
122 | I_TYPE_INST(SLTI); |
123 | I_TYPE_INST(SLTIU); |
124 | I_TYPE_INST(XORI); |
125 | I_TYPE_INST(ORI); |
126 | I_TYPE_INST(ANDI); |
127 | R_TYPE_INST(ADD); |
128 | R_TYPE_INST(SUB); |
129 | R_TYPE_INST(SLL); |
130 | R_TYPE_INST(SLT); |
131 | R_TYPE_INST(SLTU); |
132 | R_TYPE_INST(XOR); |
133 | R_TYPE_INST(SRL); |
134 | R_TYPE_INST(SRA); |
135 | R_TYPE_INST(OR); |
136 | R_TYPE_INST(AND); |
137 | |
138 | // RV64I inst (The base integer ISA) |
139 | I_TYPE_INST(LWU); |
140 | I_TYPE_INST(LD); |
141 | S_TYPE_INST(SD); |
142 | R_SHAMT_TYPE_INST(SLLI); |
143 | R_SHAMT_TYPE_INST(SRLI); |
144 | R_SHAMT_TYPE_INST(SRAI); |
145 | I_TYPE_INST(ADDIW); |
146 | R_SHAMT_TYPE_INST(SLLIW); |
147 | R_SHAMT_TYPE_INST(SRLIW); |
148 | R_SHAMT_TYPE_INST(SRAIW); |
149 | R_TYPE_INST(ADDW); |
150 | R_TYPE_INST(SUBW); |
151 | R_TYPE_INST(SLLW); |
152 | R_TYPE_INST(SRLW); |
153 | R_TYPE_INST(SRAW); |
154 | |
155 | // RV32M inst (The standard integer multiplication and division extension) |
156 | R_TYPE_INST(MUL); |
157 | R_TYPE_INST(MULH); |
158 | R_TYPE_INST(MULHSU); |
159 | R_TYPE_INST(MULHU); |
160 | R_TYPE_INST(DIV); |
161 | R_TYPE_INST(DIVU); |
162 | R_TYPE_INST(REM); |
163 | R_TYPE_INST(REMU); |
164 | |
165 | // RV64M inst (The standard integer multiplication and division extension) |
166 | R_TYPE_INST(MULW); |
167 | R_TYPE_INST(DIVW); |
168 | R_TYPE_INST(DIVUW); |
169 | R_TYPE_INST(REMW); |
170 | R_TYPE_INST(REMUW); |
171 | |
172 | // RV32A inst (The standard atomic instruction extension) |
173 | R_RS1_TYPE_INST(LR_W); |
174 | R_TYPE_INST(SC_W); |
175 | R_TYPE_INST(AMOSWAP_W); |
176 | R_TYPE_INST(AMOADD_W); |
177 | R_TYPE_INST(AMOXOR_W); |
178 | R_TYPE_INST(AMOAND_W); |
179 | R_TYPE_INST(AMOOR_W); |
180 | R_TYPE_INST(AMOMIN_W); |
181 | R_TYPE_INST(AMOMAX_W); |
182 | R_TYPE_INST(AMOMINU_W); |
183 | R_TYPE_INST(AMOMAXU_W); |
184 | |
185 | // RV64A inst (The standard atomic instruction extension) |
186 | R_RS1_TYPE_INST(LR_D); |
187 | R_TYPE_INST(SC_D); |
188 | R_TYPE_INST(AMOSWAP_D); |
189 | R_TYPE_INST(AMOADD_D); |
190 | R_TYPE_INST(AMOXOR_D); |
191 | R_TYPE_INST(AMOAND_D); |
192 | R_TYPE_INST(AMOOR_D); |
193 | R_TYPE_INST(AMOMIN_D); |
194 | R_TYPE_INST(AMOMAX_D); |
195 | R_TYPE_INST(AMOMINU_D); |
196 | R_TYPE_INST(AMOMAXU_D); |
197 | |
198 | // RV32F inst (The standard single-precision floating-point extension) |
199 | I_TYPE_INST(FLW); |
200 | S_TYPE_INST(FSW); |
201 | R4_TYPE_INST(FMADD_S); |
202 | R4_TYPE_INST(FMSUB_S); |
203 | R4_TYPE_INST(FNMADD_S); |
204 | R4_TYPE_INST(FNMSUB_S); |
205 | R_TYPE_INST(FADD_S); |
206 | R_TYPE_INST(FSUB_S); |
207 | R_TYPE_INST(FMUL_S); |
208 | R_TYPE_INST(FDIV_S); |
209 | I_TYPE_INST(FSQRT_S); |
210 | R_TYPE_INST(FSGNJ_S); |
211 | R_TYPE_INST(FSGNJN_S); |
212 | R_TYPE_INST(FSGNJX_S); |
213 | R_TYPE_INST(FMIN_S); |
214 | R_TYPE_INST(FMAX_S); |
215 | I_TYPE_INST(FCVT_W_S); |
216 | I_TYPE_INST(FCVT_WU_S); |
217 | I_TYPE_INST(FMV_X_W); |
218 | R_TYPE_INST(FEQ_S); |
219 | R_TYPE_INST(FLT_S); |
220 | R_TYPE_INST(FLE_S); |
221 | I_TYPE_INST(FCLASS_S); |
222 | I_TYPE_INST(FCVT_S_W); |
223 | I_TYPE_INST(FCVT_S_WU); |
224 | I_TYPE_INST(FMV_W_X); |
225 | |
226 | // RV64F inst (The standard single-precision floating-point extension) |
227 | I_TYPE_INST(FCVT_L_S); |
228 | I_TYPE_INST(FCVT_LU_S); |
229 | I_TYPE_INST(FCVT_S_L); |
230 | I_TYPE_INST(FCVT_S_LU); |
231 | |
232 | // RV32D inst (Extension for Double-Precision Floating-Point) |
233 | I_TYPE_INST(FLD); |
234 | S_TYPE_INST(FSD); |
235 | R4_TYPE_INST(FMADD_D); |
236 | R4_TYPE_INST(FMSUB_D); |
237 | R4_TYPE_INST(FNMSUB_D); |
238 | R4_TYPE_INST(FNMADD_D); |
239 | R_TYPE_INST(FADD_D); |
240 | R_TYPE_INST(FSUB_D); |
241 | R_TYPE_INST(FMUL_D); |
242 | R_TYPE_INST(FDIV_D); |
243 | I_TYPE_INST(FSQRT_D); |
244 | R_TYPE_INST(FSGNJ_D); |
245 | R_TYPE_INST(FSGNJN_D); |
246 | R_TYPE_INST(FSGNJX_D); |
247 | R_TYPE_INST(FMIN_D); |
248 | R_TYPE_INST(FMAX_D); |
249 | I_TYPE_INST(FCVT_S_D); |
250 | I_TYPE_INST(FCVT_D_S); |
251 | R_TYPE_INST(FEQ_D); |
252 | R_TYPE_INST(FLT_D); |
253 | R_TYPE_INST(FLE_D); |
254 | I_TYPE_INST(FCLASS_D); |
255 | I_TYPE_INST(FCVT_W_D); |
256 | I_TYPE_INST(FCVT_WU_D); |
257 | I_TYPE_INST(FCVT_D_W); |
258 | I_TYPE_INST(FCVT_D_WU); |
259 | |
260 | // RV64D inst (Extension for Double-Precision Floating-Point) |
261 | I_TYPE_INST(FCVT_L_D); |
262 | I_TYPE_INST(FCVT_LU_D); |
263 | I_TYPE_INST(FMV_X_D); |
264 | I_TYPE_INST(FCVT_D_L); |
265 | I_TYPE_INST(FCVT_D_LU); |
266 | I_TYPE_INST(FMV_D_X); |
267 | |
268 | /// Invalid and reserved instructions, the `inst` fields are used for debugging. |
269 | INVALID_INST(INVALID); |
270 | INVALID_INST(RESERVED); |
271 | INVALID_INST(EBREAK); |
272 | INVALID_INST(HINT); |
273 | INVALID_INST(NOP); |
274 | |
275 | using RISCVInst = std::variant< |
276 | LUI, AUIPC, JAL, JALR, B, LB, LH, LW, LBU, LHU, SB, SH, SW, ADDI, SLTI, |
277 | SLTIU, XORI, ORI, ANDI, ADD, SUB, SLL, SLT, SLTU, XOR, SRL, SRA, OR, AND, |
278 | LWU, LD, SD, SLLI, SRLI, SRAI, ADDIW, SLLIW, SRLIW, SRAIW, ADDW, SUBW, SLLW, |
279 | SRLW, SRAW, MUL, MULH, MULHSU, MULHU, DIV, DIVU, REM, REMU, MULW, DIVW, |
280 | DIVUW, REMW, REMUW, LR_W, SC_W, AMOSWAP_W, AMOADD_W, AMOXOR_W, AMOAND_W, |
281 | AMOOR_W, AMOMIN_W, AMOMAX_W, AMOMINU_W, AMOMAXU_W, LR_D, SC_D, AMOSWAP_D, |
282 | AMOADD_D, AMOXOR_D, AMOAND_D, AMOOR_D, AMOMIN_D, AMOMAX_D, AMOMINU_D, |
283 | AMOMAXU_D, FLW, FSW, FMADD_S, FMSUB_S, FNMADD_S, FNMSUB_S, FADD_S, FSUB_S, |
284 | FMUL_S, FDIV_S, FSQRT_S, FSGNJ_S, FSGNJN_S, FSGNJX_S, FMIN_S, FMAX_S, |
285 | FCVT_W_S, FCVT_WU_S, FMV_X_W, FEQ_S, FLT_S, FLE_S, FCLASS_S, FCVT_S_W, |
286 | FCVT_S_WU, FMV_W_X, FCVT_L_S, FCVT_LU_S, FCVT_S_L, FCVT_S_LU, FLD, FSD, |
287 | FMADD_D, FMSUB_D, FNMSUB_D, FNMADD_D, FADD_D, FSUB_D, FMUL_D, FDIV_D, |
288 | FSQRT_D, FSGNJ_D, FSGNJN_D, FSGNJX_D, FMIN_D, FMAX_D, FCVT_S_D, FCVT_D_S, |
289 | FEQ_D, FLT_D, FLE_D, FCLASS_D, FCVT_W_D, FCVT_WU_D, FCVT_D_W, FCVT_D_WU, |
290 | FCVT_L_D, FCVT_LU_D, FMV_X_D, FCVT_D_L, FCVT_D_LU, FMV_D_X, INVALID, EBREAK, |
291 | RESERVED, HINT, NOP>; |
292 | |
293 | constexpr uint8_t RV32 = 1; |
294 | constexpr uint8_t RV64 = 2; |
295 | constexpr uint8_t RV128 = 4; |
296 | |
297 | struct InstrPattern { |
298 | const char *name; |
299 | /// Bit mask to check the type of a instruction (B-Type, I-Type, J-Type, etc.) |
300 | uint32_t type_mask; |
301 | /// Characteristic value after bitwise-and with type_mask. |
302 | uint32_t eigen; |
303 | RISCVInst (*decode)(uint32_t inst); |
304 | /// If not specified, the inst will be supported by all RV versions. |
305 | uint8_t inst_type = RV32 | RV64 | RV128; |
306 | }; |
307 | |
308 | struct DecodeResult { |
309 | RISCVInst decoded; |
310 | uint32_t inst; |
311 | bool is_rvc; |
312 | InstrPattern pattern; |
313 | }; |
314 | |
315 | constexpr uint32_t DecodeRD(uint32_t inst) { return (inst & 0xF80) >> 7; } |
316 | constexpr uint32_t DecodeRS1(uint32_t inst) { return (inst & 0xF8000) >> 15; } |
317 | constexpr uint32_t DecodeRS2(uint32_t inst) { return (inst & 0x1F00000) >> 20; } |
318 | constexpr uint32_t DecodeRS3(uint32_t inst) { |
319 | return (inst & 0xF0000000) >> 27; |
320 | } |
321 | constexpr uint32_t DecodeFunct3(uint32_t inst) { return (inst & 0x7000) >> 12; } |
322 | constexpr uint32_t DecodeFunct2(uint32_t inst) { |
323 | return (inst & 0xE000000) >> 25; |
324 | } |
325 | constexpr uint32_t DecodeFunct7(uint32_t inst) { |
326 | return (inst & 0xFE000000) >> 25; |
327 | } |
328 | |
329 | constexpr int32_t DecodeRM(uint32_t inst) { return DecodeFunct3(inst); } |
330 | |
331 | /// RISC-V spec: The upper bits of a valid NaN-boxed value must be all 1s. |
332 | constexpr uint64_t NanBoxing(uint64_t val) { |
333 | return val | 0xFFFF'FFFF'0000'0000; |
334 | } |
335 | constexpr uint32_t NanUnBoxing(uint64_t val) { |
336 | return val & (~0xFFFF'FFFF'0000'0000); |
337 | } |
338 | |
339 | #undef R_TYPE_INST |
340 | #undef R_SHAMT_TYPE_INST |
341 | #undef R_RS1_TYPE_INST |
342 | #undef R4_TYPE_INST |
343 | #undef I_TYPE_INST |
344 | #undef S_TYPE_INST |
345 | #undef B_TYPE_INST |
346 | #undef U_TYPE_INST |
347 | #undef J_TYPE_INST |
348 | #undef INVALID_INST |
349 | #undef DERIVE_EQ |
350 | |
351 | } // namespace lldb_private |
352 | #endif // LLDB_SOURCE_PLUGINS_INSTRUCTION_RISCV_RISCVINSTRUCTION_H |
353 | |