]>
Commit | Line | Data |
---|---|---|
55c2a12c MC |
1 | /* |
2 | * RISC-V emulation for qemu: main translation routines. | |
3 | * | |
4 | * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify it | |
7 | * under the terms and conditions of the GNU General Public License, | |
8 | * version 2 or later, as published by the Free Software Foundation. | |
9 | * | |
10 | * This program is distributed in the hope it will be useful, but WITHOUT | |
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
13 | * more details. | |
14 | * | |
15 | * You should have received a copy of the GNU General Public License along with | |
16 | * this program. If not, see <http://www.gnu.org/licenses/>. | |
17 | */ | |
18 | ||
19 | #include "qemu/osdep.h" | |
20 | #include "qemu/log.h" | |
21 | #include "cpu.h" | |
dcb32f1d | 22 | #include "tcg/tcg-op.h" |
55c2a12c MC |
23 | #include "disas/disas.h" |
24 | #include "exec/cpu_ldst.h" | |
25 | #include "exec/exec-all.h" | |
26 | #include "exec/helper-proto.h" | |
27 | #include "exec/helper-gen.h" | |
28 | ||
b2e32021 | 29 | #include "exec/translator.h" |
55c2a12c | 30 | #include "exec/log.h" |
7d7fb116 | 31 | #include "semihosting/semihost.h" |
55c2a12c MC |
32 | |
33 | #include "instmap.h" | |
75804f71 | 34 | #include "internals.h" |
55c2a12c MC |
35 | |
36 | /* global register indices */ | |
2b547084 | 37 | static TCGv cpu_gpr[32], cpu_gprh[32], cpu_pc, cpu_vl, cpu_vstart; |
55c2a12c MC |
38 | static TCGv_i64 cpu_fpr[32]; /* assume F and D extensions */ |
39 | static TCGv load_res; | |
40 | static TCGv load_val; | |
0774a7a1 | 41 | /* globals for PM CSRs */ |
0cff460d LZ |
42 | static TCGv pm_mask; |
43 | static TCGv pm_base; | |
55c2a12c MC |
44 | |
45 | #include "exec/gen-icount.h" | |
46 | ||
ecda15d1 RH |
47 | /* |
48 | * If an operation is being performed on less than TARGET_LONG_BITS, | |
49 | * it may require the inputs to be sign- or zero-extended; which will | |
50 | * depend on the exact operation being performed. | |
51 | */ | |
52 | typedef enum { | |
53 | EXT_NONE, | |
54 | EXT_SIGN, | |
55 | EXT_ZERO, | |
56 | } DisasExtend; | |
57 | ||
55c2a12c | 58 | typedef struct DisasContext { |
0114db1c EC |
59 | DisasContextBase base; |
60 | /* pc_succ_insn points to the instruction following base.pc_next */ | |
61 | target_ulong pc_succ_insn; | |
d75377bf | 62 | target_ulong priv_ver; |
a2f827ff | 63 | RISCVMXL misa_mxl_max; |
e91a7227 RH |
64 | RISCVMXL xl; |
65 | uint32_t misa_ext; | |
45b4dc8b | 66 | uint32_t opcode; |
83a71719 | 67 | uint32_t mstatus_fs; |
8e1ee1fb | 68 | uint32_t mstatus_vs; |
a88f0402 | 69 | uint32_t mstatus_hs_fs; |
8e1ee1fb | 70 | uint32_t mstatus_hs_vs; |
55c2a12c | 71 | uint32_t mem_idx; |
55c2a12c MC |
72 | /* Remember the rounding mode encoded in the previous fp instruction, |
73 | which we have already installed into env->fp_status. Or -1 for | |
74 | no previous fp instruction. Note that we exit the TB when writing | |
75 | to any system register, which includes CSR_FRM, so we do not have | |
76 | to reset this known value. */ | |
77 | int frm; | |
7667cafd | 78 | RISCVMXL ol; |
fb3f3730 | 79 | bool virt_inst_excp; |
ecda15d1 | 80 | bool virt_enabled; |
3b91323e | 81 | const RISCVCPUConfig *cfg_ptr; |
743077b3 | 82 | bool hlsx; |
2b7168fc LZ |
83 | /* vector extension */ |
84 | bool vill; | |
33f1beaf FC |
85 | /* |
86 | * Encode LMUL to lmul as follows: | |
87 | * LMUL vlmul lmul | |
88 | * 1 000 0 | |
89 | * 2 001 1 | |
90 | * 4 010 2 | |
91 | * 8 011 3 | |
92 | * - 100 - | |
93 | * 1/8 101 -3 | |
94 | * 1/4 110 -2 | |
95 | * 1/2 111 -1 | |
96 | */ | |
97 | int8_t lmul; | |
2b7168fc | 98 | uint8_t sew; |
f1eed927 | 99 | uint8_t vta; |
355d5584 | 100 | uint8_t vma; |
752614ca | 101 | bool cfg_vta_all_1s; |
f714361e | 102 | target_ulong vstart; |
2b7168fc | 103 | bool vl_eq_vlmax; |
a10b9d93 | 104 | CPUState *cs; |
ecda15d1 | 105 | TCGv zero; |
0774a7a1 | 106 | /* PointerMasking extension */ |
4208dc7e LZ |
107 | bool pm_mask_enabled; |
108 | bool pm_base_enabled; | |
2c9d7471 LZ |
109 | /* Use icount trigger for native debug */ |
110 | bool itrigger; | |
3ceeb19a RH |
111 | /* FRM is known to contain a valid value. */ |
112 | bool frm_valid; | |
62cf0245 AP |
113 | /* TCG of the current insn_start */ |
114 | TCGOp *insn_start; | |
55c2a12c MC |
115 | } DisasContext; |
116 | ||
db9f3fd6 MC |
117 | static inline bool has_ext(DisasContext *ctx, uint32_t ext) |
118 | { | |
e91a7227 | 119 | return ctx->misa_ext & ext; |
d36a86d0 RH |
120 | } |
121 | ||
5e199b6b PT |
122 | static bool always_true_p(DisasContext *ctx __attribute__((__unused__))) |
123 | { | |
124 | return true; | |
125 | } | |
126 | ||
49a7f3aa CM |
127 | static bool has_xthead_p(DisasContext *ctx __attribute__((__unused__))) |
128 | { | |
426c0491 | 129 | return ctx->cfg_ptr->ext_xtheadba || ctx->cfg_ptr->ext_xtheadbb || |
fa134585 | 130 | ctx->cfg_ptr->ext_xtheadbs || ctx->cfg_ptr->ext_xtheadcmo || |
d4d90115 | 131 | ctx->cfg_ptr->ext_xtheadcondmov || |
578086ba CM |
132 | ctx->cfg_ptr->ext_xtheadfmemidx || ctx->cfg_ptr->ext_xtheadfmv || |
133 | ctx->cfg_ptr->ext_xtheadmac || ctx->cfg_ptr->ext_xtheadmemidx || | |
134 | ctx->cfg_ptr->ext_xtheadmempair || ctx->cfg_ptr->ext_xtheadsync; | |
49a7f3aa CM |
135 | } |
136 | ||
0d429bd2 PT |
137 | #define MATERIALISE_EXT_PREDICATE(ext) \ |
138 | static bool has_ ## ext ## _p(DisasContext *ctx) \ | |
139 | { \ | |
140 | return ctx->cfg_ptr->ext_ ## ext ; \ | |
141 | } | |
142 | ||
143 | MATERIALISE_EXT_PREDICATE(XVentanaCondOps); | |
144 | ||
4fd7455b | 145 | #ifdef TARGET_RISCV32 |
905b9fcd | 146 | #define get_xl(ctx) MXL_RV32 |
4fd7455b | 147 | #elif defined(CONFIG_USER_ONLY) |
905b9fcd | 148 | #define get_xl(ctx) MXL_RV64 |
4fd7455b | 149 | #else |
905b9fcd RH |
150 | #define get_xl(ctx) ((ctx)->xl) |
151 | #endif | |
152 | ||
153 | /* The word size for this machine mode. */ | |
154 | static inline int __attribute__((unused)) get_xlen(DisasContext *ctx) | |
4fd7455b | 155 | { |
905b9fcd | 156 | return 16 << get_xl(ctx); |
4fd7455b | 157 | } |
4fd7455b | 158 | |
7667cafd RH |
159 | /* The operation length, as opposed to the xlen. */ |
160 | #ifdef TARGET_RISCV32 | |
161 | #define get_ol(ctx) MXL_RV32 | |
162 | #else | |
163 | #define get_ol(ctx) ((ctx)->ol) | |
164 | #endif | |
165 | ||
166 | static inline int get_olen(DisasContext *ctx) | |
89c88309 | 167 | { |
7667cafd | 168 | return 16 << get_ol(ctx); |
89c88309 RH |
169 | } |
170 | ||
a2f827ff FP |
171 | /* The maximum register length */ |
172 | #ifdef TARGET_RISCV32 | |
173 | #define get_xl_max(ctx) MXL_RV32 | |
174 | #else | |
175 | #define get_xl_max(ctx) ((ctx)->misa_mxl_max) | |
176 | #endif | |
177 | ||
d36a86d0 RH |
178 | /* |
179 | * RISC-V requires NaN-boxing of narrower width floating point values. | |
180 | * This applies when a 32-bit value is assigned to a 64-bit FP register. | |
181 | * For consistency and simplicity, we nanbox results even when the RVD | |
182 | * extension is not present. | |
183 | */ | |
184 | static void gen_nanbox_s(TCGv_i64 out, TCGv_i64 in) | |
185 | { | |
186 | tcg_gen_ori_i64(out, in, MAKE_64BIT_MASK(32, 32)); | |
ffe70e4d RH |
187 | } |
188 | ||
915f77b2 KC |
189 | static void gen_nanbox_h(TCGv_i64 out, TCGv_i64 in) |
190 | { | |
191 | tcg_gen_ori_i64(out, in, MAKE_64BIT_MASK(16, 48)); | |
192 | } | |
193 | ||
ffe70e4d RH |
194 | /* |
195 | * A narrow n-bit operation, where n < FLEN, checks that input operands | |
196 | * are correctly Nan-boxed, i.e., all upper FLEN - n bits are 1. | |
197 | * If so, the least-significant bits of the input are used, otherwise the | |
198 | * input value is treated as an n-bit canonical NaN (v2.2 section 9.2). | |
199 | * | |
200 | * Here, the result is always nan-boxed, even the canonical nan. | |
201 | */ | |
7b03c8e5 KC |
202 | static void gen_check_nanbox_h(TCGv_i64 out, TCGv_i64 in) |
203 | { | |
2f668fab RH |
204 | TCGv_i64 t_max = tcg_constant_i64(0xffffffffffff0000ull); |
205 | TCGv_i64 t_nan = tcg_constant_i64(0xffffffffffff7e00ull); | |
7b03c8e5 KC |
206 | |
207 | tcg_gen_movcond_i64(TCG_COND_GEU, out, in, t_max, in, t_nan); | |
7b03c8e5 KC |
208 | } |
209 | ||
ffe70e4d RH |
210 | static void gen_check_nanbox_s(TCGv_i64 out, TCGv_i64 in) |
211 | { | |
05b80ed0 RH |
212 | TCGv_i64 t_max = tcg_constant_i64(0xffffffff00000000ull); |
213 | TCGv_i64 t_nan = tcg_constant_i64(0xffffffff7fc00000ull); | |
ffe70e4d RH |
214 | |
215 | tcg_gen_movcond_i64(TCG_COND_GEU, out, in, t_max, in, t_nan); | |
db9f3fd6 MC |
216 | } |
217 | ||
a9814e3e RH |
218 | static void decode_save_opc(DisasContext *ctx) |
219 | { | |
220 | assert(ctx->insn_start != NULL); | |
221 | tcg_set_insn_start_param(ctx->insn_start, 1, ctx->opcode); | |
222 | ctx->insn_start = NULL; | |
223 | } | |
224 | ||
40f0c204 LZ |
225 | static void gen_set_pc_imm(DisasContext *ctx, target_ulong dest) |
226 | { | |
227 | if (get_xl(ctx) == MXL_RV32) { | |
228 | dest = (int32_t)dest; | |
229 | } | |
230 | tcg_gen_movi_tl(cpu_pc, dest); | |
231 | } | |
232 | ||
233 | static void gen_set_pc(DisasContext *ctx, TCGv dest) | |
234 | { | |
235 | if (get_xl(ctx) == MXL_RV32) { | |
236 | tcg_gen_ext32s_tl(cpu_pc, dest); | |
237 | } else { | |
238 | tcg_gen_mov_tl(cpu_pc, dest); | |
239 | } | |
240 | } | |
241 | ||
55c2a12c MC |
242 | static void generate_exception(DisasContext *ctx, int excp) |
243 | { | |
40f0c204 | 244 | gen_set_pc_imm(ctx, ctx->base.pc_next); |
05b80ed0 | 245 | gen_helper_raise_exception(cpu_env, tcg_constant_i32(excp)); |
0114db1c | 246 | ctx->base.is_jmp = DISAS_NORETURN; |
55c2a12c MC |
247 | } |
248 | ||
55c2a12c MC |
249 | static void gen_exception_illegal(DisasContext *ctx) |
250 | { | |
b97028b8 RH |
251 | tcg_gen_st_i32(tcg_constant_i32(ctx->opcode), cpu_env, |
252 | offsetof(CPURISCVState, bins)); | |
fb3f3730 MC |
253 | if (ctx->virt_inst_excp) { |
254 | generate_exception(ctx, RISCV_EXCP_VIRT_INSTRUCTION_FAULT); | |
255 | } else { | |
256 | generate_exception(ctx, RISCV_EXCP_ILLEGAL_INST); | |
257 | } | |
55c2a12c MC |
258 | } |
259 | ||
260 | static void gen_exception_inst_addr_mis(DisasContext *ctx) | |
261 | { | |
5dacdbae RH |
262 | tcg_gen_st_tl(cpu_pc, cpu_env, offsetof(CPURISCVState, badaddr)); |
263 | generate_exception(ctx, RISCV_EXCP_INST_ADDR_MIS); | |
55c2a12c MC |
264 | } |
265 | ||
2c9d7471 LZ |
266 | static void lookup_and_goto_ptr(DisasContext *ctx) |
267 | { | |
268 | #ifndef CONFIG_USER_ONLY | |
269 | if (ctx->itrigger) { | |
270 | gen_helper_itrigger_match(cpu_env); | |
271 | } | |
272 | #endif | |
273 | tcg_gen_lookup_and_goto_ptr(); | |
274 | } | |
275 | ||
276 | static void exit_tb(DisasContext *ctx) | |
277 | { | |
278 | #ifndef CONFIG_USER_ONLY | |
279 | if (ctx->itrigger) { | |
280 | gen_helper_itrigger_match(cpu_env); | |
281 | } | |
282 | #endif | |
283 | tcg_gen_exit_tb(NULL, 0); | |
284 | } | |
285 | ||
55c2a12c MC |
286 | static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) |
287 | { | |
2c9d7471 LZ |
288 | /* |
289 | * Under itrigger, instruction executes one by one like singlestep, | |
290 | * direct block chain benefits will be small. | |
291 | */ | |
292 | if (translator_use_goto_tb(&ctx->base, dest) && !ctx->itrigger) { | |
55c2a12c | 293 | tcg_gen_goto_tb(n); |
40f0c204 | 294 | gen_set_pc_imm(ctx, dest); |
07ea28b4 | 295 | tcg_gen_exit_tb(ctx->base.tb, n); |
55c2a12c | 296 | } else { |
40f0c204 | 297 | gen_set_pc_imm(ctx, dest); |
2c9d7471 | 298 | lookup_and_goto_ptr(ctx); |
55c2a12c MC |
299 | } |
300 | } | |
301 | ||
ecda15d1 RH |
302 | /* |
303 | * Wrappers for getting reg values. | |
304 | * | |
305 | * The $zero register does not have cpu_gpr[0] allocated -- we supply the | |
306 | * constant zero as a source, and an uninitialized sink as destination. | |
307 | * | |
308 | * Further, we may provide an extension for word operations. | |
55c2a12c | 309 | */ |
ecda15d1 | 310 | static TCGv get_gpr(DisasContext *ctx, int reg_num, DisasExtend ext) |
55c2a12c | 311 | { |
ecda15d1 RH |
312 | TCGv t; |
313 | ||
55c2a12c | 314 | if (reg_num == 0) { |
ecda15d1 | 315 | return ctx->zero; |
55c2a12c | 316 | } |
ecda15d1 | 317 | |
7667cafd RH |
318 | switch (get_ol(ctx)) { |
319 | case MXL_RV32: | |
320 | switch (ext) { | |
321 | case EXT_NONE: | |
322 | break; | |
323 | case EXT_SIGN: | |
574f3116 | 324 | t = tcg_temp_new(); |
7667cafd RH |
325 | tcg_gen_ext32s_tl(t, cpu_gpr[reg_num]); |
326 | return t; | |
327 | case EXT_ZERO: | |
574f3116 | 328 | t = tcg_temp_new(); |
7667cafd RH |
329 | tcg_gen_ext32u_tl(t, cpu_gpr[reg_num]); |
330 | return t; | |
331 | default: | |
332 | g_assert_not_reached(); | |
333 | } | |
334 | break; | |
335 | case MXL_RV64: | |
a2f827ff | 336 | case MXL_RV128: |
7667cafd RH |
337 | break; |
338 | default: | |
339 | g_assert_not_reached(); | |
ecda15d1 | 340 | } |
7667cafd | 341 | return cpu_gpr[reg_num]; |
55c2a12c MC |
342 | } |
343 | ||
a2f827ff FP |
344 | static TCGv get_gprh(DisasContext *ctx, int reg_num) |
345 | { | |
346 | assert(get_xl(ctx) == MXL_RV128); | |
347 | if (reg_num == 0) { | |
348 | return ctx->zero; | |
349 | } | |
350 | return cpu_gprh[reg_num]; | |
351 | } | |
352 | ||
191d1daf | 353 | static TCGv dest_gpr(DisasContext *ctx, int reg_num) |
ecda15d1 | 354 | { |
7667cafd | 355 | if (reg_num == 0 || get_olen(ctx) < TARGET_LONG_BITS) { |
574f3116 | 356 | return tcg_temp_new(); |
ecda15d1 RH |
357 | } |
358 | return cpu_gpr[reg_num]; | |
359 | } | |
360 | ||
a2f827ff FP |
361 | static TCGv dest_gprh(DisasContext *ctx, int reg_num) |
362 | { | |
363 | if (reg_num == 0) { | |
574f3116 | 364 | return tcg_temp_new(); |
a2f827ff FP |
365 | } |
366 | return cpu_gprh[reg_num]; | |
367 | } | |
368 | ||
ecda15d1 | 369 | static void gen_set_gpr(DisasContext *ctx, int reg_num, TCGv t) |
55c2a12c | 370 | { |
ecda15d1 | 371 | if (reg_num != 0) { |
7667cafd RH |
372 | switch (get_ol(ctx)) { |
373 | case MXL_RV32: | |
ecda15d1 | 374 | tcg_gen_ext32s_tl(cpu_gpr[reg_num], t); |
7667cafd RH |
375 | break; |
376 | case MXL_RV64: | |
a2f827ff | 377 | case MXL_RV128: |
ecda15d1 | 378 | tcg_gen_mov_tl(cpu_gpr[reg_num], t); |
7667cafd RH |
379 | break; |
380 | default: | |
381 | g_assert_not_reached(); | |
ecda15d1 | 382 | } |
a2f827ff FP |
383 | |
384 | if (get_xl_max(ctx) == MXL_RV128) { | |
385 | tcg_gen_sari_tl(cpu_gprh[reg_num], cpu_gpr[reg_num], 63); | |
386 | } | |
387 | } | |
388 | } | |
389 | ||
57c108b8 FP |
390 | static void gen_set_gpri(DisasContext *ctx, int reg_num, target_long imm) |
391 | { | |
392 | if (reg_num != 0) { | |
393 | switch (get_ol(ctx)) { | |
394 | case MXL_RV32: | |
395 | tcg_gen_movi_tl(cpu_gpr[reg_num], (int32_t)imm); | |
396 | break; | |
397 | case MXL_RV64: | |
398 | case MXL_RV128: | |
399 | tcg_gen_movi_tl(cpu_gpr[reg_num], imm); | |
400 | break; | |
401 | default: | |
402 | g_assert_not_reached(); | |
403 | } | |
404 | ||
405 | if (get_xl_max(ctx) == MXL_RV128) { | |
406 | tcg_gen_movi_tl(cpu_gprh[reg_num], -(imm < 0)); | |
407 | } | |
408 | } | |
409 | } | |
410 | ||
a2f827ff FP |
411 | static void gen_set_gpr128(DisasContext *ctx, int reg_num, TCGv rl, TCGv rh) |
412 | { | |
413 | assert(get_ol(ctx) == MXL_RV128); | |
414 | if (reg_num != 0) { | |
415 | tcg_gen_mov_tl(cpu_gpr[reg_num], rl); | |
416 | tcg_gen_mov_tl(cpu_gprh[reg_num], rh); | |
55c2a12c MC |
417 | } |
418 | } | |
419 | ||
e1a29bbd WL |
420 | static TCGv_i64 get_fpr_hs(DisasContext *ctx, int reg_num) |
421 | { | |
422 | if (!ctx->cfg_ptr->ext_zfinx) { | |
423 | return cpu_fpr[reg_num]; | |
424 | } | |
425 | ||
426 | if (reg_num == 0) { | |
427 | return tcg_constant_i64(0); | |
428 | } | |
429 | switch (get_xl(ctx)) { | |
430 | case MXL_RV32: | |
431 | #ifdef TARGET_RISCV32 | |
432 | { | |
5d509451 | 433 | TCGv_i64 t = tcg_temp_new_i64(); |
e1a29bbd WL |
434 | tcg_gen_ext_i32_i64(t, cpu_gpr[reg_num]); |
435 | return t; | |
436 | } | |
437 | #else | |
438 | /* fall through */ | |
439 | case MXL_RV64: | |
440 | return cpu_gpr[reg_num]; | |
441 | #endif | |
442 | default: | |
443 | g_assert_not_reached(); | |
444 | } | |
445 | } | |
446 | ||
026e73fa WL |
447 | static TCGv_i64 get_fpr_d(DisasContext *ctx, int reg_num) |
448 | { | |
449 | if (!ctx->cfg_ptr->ext_zfinx) { | |
450 | return cpu_fpr[reg_num]; | |
451 | } | |
452 | ||
453 | if (reg_num == 0) { | |
454 | return tcg_constant_i64(0); | |
455 | } | |
456 | switch (get_xl(ctx)) { | |
457 | case MXL_RV32: | |
458 | { | |
5d509451 | 459 | TCGv_i64 t = tcg_temp_new_i64(); |
026e73fa WL |
460 | tcg_gen_concat_tl_i64(t, cpu_gpr[reg_num], cpu_gpr[reg_num + 1]); |
461 | return t; | |
462 | } | |
463 | #ifdef TARGET_RISCV64 | |
464 | case MXL_RV64: | |
465 | return cpu_gpr[reg_num]; | |
466 | #endif | |
467 | default: | |
468 | g_assert_not_reached(); | |
469 | } | |
470 | } | |
471 | ||
e1a29bbd WL |
472 | static TCGv_i64 dest_fpr(DisasContext *ctx, int reg_num) |
473 | { | |
474 | if (!ctx->cfg_ptr->ext_zfinx) { | |
475 | return cpu_fpr[reg_num]; | |
476 | } | |
477 | ||
478 | if (reg_num == 0) { | |
5d509451 | 479 | return tcg_temp_new_i64(); |
e1a29bbd WL |
480 | } |
481 | ||
482 | switch (get_xl(ctx)) { | |
483 | case MXL_RV32: | |
5d509451 | 484 | return tcg_temp_new_i64(); |
e1a29bbd WL |
485 | #ifdef TARGET_RISCV64 |
486 | case MXL_RV64: | |
487 | return cpu_gpr[reg_num]; | |
488 | #endif | |
489 | default: | |
490 | g_assert_not_reached(); | |
491 | } | |
492 | } | |
493 | ||
494 | /* assume t is nanboxing (for normal) or sign-extended (for zfinx) */ | |
495 | static void gen_set_fpr_hs(DisasContext *ctx, int reg_num, TCGv_i64 t) | |
496 | { | |
497 | if (!ctx->cfg_ptr->ext_zfinx) { | |
498 | tcg_gen_mov_i64(cpu_fpr[reg_num], t); | |
499 | return; | |
500 | } | |
501 | if (reg_num != 0) { | |
502 | switch (get_xl(ctx)) { | |
503 | case MXL_RV32: | |
504 | #ifdef TARGET_RISCV32 | |
505 | tcg_gen_extrl_i64_i32(cpu_gpr[reg_num], t); | |
506 | break; | |
507 | #else | |
508 | /* fall through */ | |
509 | case MXL_RV64: | |
510 | tcg_gen_mov_i64(cpu_gpr[reg_num], t); | |
511 | break; | |
512 | #endif | |
513 | default: | |
514 | g_assert_not_reached(); | |
515 | } | |
516 | } | |
517 | } | |
518 | ||
026e73fa WL |
519 | static void gen_set_fpr_d(DisasContext *ctx, int reg_num, TCGv_i64 t) |
520 | { | |
521 | if (!ctx->cfg_ptr->ext_zfinx) { | |
522 | tcg_gen_mov_i64(cpu_fpr[reg_num], t); | |
523 | return; | |
524 | } | |
525 | ||
526 | if (reg_num != 0) { | |
527 | switch (get_xl(ctx)) { | |
528 | case MXL_RV32: | |
529 | #ifdef TARGET_RISCV32 | |
530 | tcg_gen_extr_i64_i32(cpu_gpr[reg_num], cpu_gpr[reg_num + 1], t); | |
531 | break; | |
532 | #else | |
533 | tcg_gen_ext32s_i64(cpu_gpr[reg_num], t); | |
534 | tcg_gen_sari_i64(cpu_gpr[reg_num + 1], t, 32); | |
535 | break; | |
536 | case MXL_RV64: | |
537 | tcg_gen_mov_i64(cpu_gpr[reg_num], t); | |
538 | break; | |
539 | #endif | |
540 | default: | |
541 | g_assert_not_reached(); | |
542 | } | |
543 | } | |
544 | } | |
545 | ||
db9f3fd6 | 546 | static void gen_jal(DisasContext *ctx, int rd, target_ulong imm) |
55c2a12c MC |
547 | { |
548 | target_ulong next_pc; | |
549 | ||
550 | /* check misaligned: */ | |
0114db1c | 551 | next_pc = ctx->base.pc_next + imm; |
db9f3fd6 | 552 | if (!has_ext(ctx, RVC)) { |
55c2a12c MC |
553 | if ((next_pc & 0x3) != 0) { |
554 | gen_exception_inst_addr_mis(ctx); | |
555 | return; | |
556 | } | |
557 | } | |
55c2a12c | 558 | |
a14db52f | 559 | gen_set_gpri(ctx, rd, ctx->pc_succ_insn); |
0114db1c EC |
560 | gen_goto_tb(ctx, 0, ctx->base.pc_next + imm); /* must use this for safety */ |
561 | ctx->base.is_jmp = DISAS_NORETURN; | |
55c2a12c MC |
562 | } |
563 | ||
4302bef9 LZ |
564 | /* Compute a canonical address from a register plus offset. */ |
565 | static TCGv get_address(DisasContext *ctx, int rs1, int imm) | |
c655df7f | 566 | { |
574f3116 | 567 | TCGv addr = tcg_temp_new(); |
4302bef9 LZ |
568 | TCGv src1 = get_gpr(ctx, rs1, EXT_NONE); |
569 | ||
570 | tcg_gen_addi_tl(addr, src1, imm); | |
4208dc7e | 571 | if (ctx->pm_mask_enabled) { |
dec19f68 | 572 | tcg_gen_andc_tl(addr, addr, pm_mask); |
4302bef9 LZ |
573 | } else if (get_xl(ctx) == MXL_RV32) { |
574 | tcg_gen_ext32u_tl(addr, addr); | |
0774a7a1 | 575 | } |
4208dc7e LZ |
576 | if (ctx->pm_base_enabled) { |
577 | tcg_gen_or_tl(addr, addr, pm_base); | |
578 | } | |
4302bef9 | 579 | return addr; |
c655df7f AB |
580 | } |
581 | ||
45f9df86 CM |
582 | /* Compute a canonical address from a register plus reg offset. */ |
583 | static TCGv get_address_indexed(DisasContext *ctx, int rs1, TCGv offs) | |
584 | { | |
574f3116 | 585 | TCGv addr = tcg_temp_new(); |
45f9df86 CM |
586 | TCGv src1 = get_gpr(ctx, rs1, EXT_NONE); |
587 | ||
588 | tcg_gen_add_tl(addr, src1, offs); | |
589 | if (ctx->pm_mask_enabled) { | |
590 | tcg_gen_andc_tl(addr, addr, pm_mask); | |
591 | } else if (get_xl(ctx) == MXL_RV32) { | |
592 | tcg_gen_ext32u_tl(addr, addr); | |
593 | } | |
594 | if (ctx->pm_base_enabled) { | |
595 | tcg_gen_or_tl(addr, addr, pm_base); | |
596 | } | |
597 | return addr; | |
598 | } | |
599 | ||
533b8f88 RH |
600 | #ifndef CONFIG_USER_ONLY |
601 | /* The states of mstatus_fs are: | |
602 | * 0 = disabled, 1 = initial, 2 = clean, 3 = dirty | |
603 | * We will have already diagnosed disabled state, | |
604 | * and need to turn initial/clean into dirty. | |
605 | */ | |
606 | static void mark_fs_dirty(DisasContext *ctx) | |
607 | { | |
608 | TCGv tmp; | |
4fd7455b | 609 | |
c163b3ba WL |
610 | if (!has_ext(ctx, RVF)) { |
611 | return; | |
612 | } | |
613 | ||
a88f0402 FC |
614 | if (ctx->mstatus_fs != MSTATUS_FS) { |
615 | /* Remember the state change for the rest of the TB. */ | |
616 | ctx->mstatus_fs = MSTATUS_FS; | |
533b8f88 | 617 | |
a88f0402 FC |
618 | tmp = tcg_temp_new(); |
619 | tcg_gen_ld_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus)); | |
b550f894 | 620 | tcg_gen_ori_tl(tmp, tmp, MSTATUS_FS); |
a88f0402 | 621 | tcg_gen_st_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus)); |
a88f0402 | 622 | } |
4fd7455b | 623 | |
a88f0402 FC |
624 | if (ctx->virt_enabled && ctx->mstatus_hs_fs != MSTATUS_FS) { |
625 | /* Remember the stage change for the rest of the TB. */ | |
626 | ctx->mstatus_hs_fs = MSTATUS_FS; | |
45b4dc8b | 627 | |
a88f0402 | 628 | tmp = tcg_temp_new(); |
45b4dc8b | 629 | tcg_gen_ld_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus_hs)); |
b550f894 | 630 | tcg_gen_ori_tl(tmp, tmp, MSTATUS_FS); |
45b4dc8b AF |
631 | tcg_gen_st_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus_hs)); |
632 | } | |
533b8f88 RH |
633 | } |
634 | #else | |
635 | static inline void mark_fs_dirty(DisasContext *ctx) { } | |
636 | #endif | |
637 | ||
8e1ee1fb FC |
638 | #ifndef CONFIG_USER_ONLY |
639 | /* The states of mstatus_vs are: | |
640 | * 0 = disabled, 1 = initial, 2 = clean, 3 = dirty | |
641 | * We will have already diagnosed disabled state, | |
642 | * and need to turn initial/clean into dirty. | |
643 | */ | |
644 | static void mark_vs_dirty(DisasContext *ctx) | |
645 | { | |
646 | TCGv tmp; | |
647 | ||
648 | if (ctx->mstatus_vs != MSTATUS_VS) { | |
649 | /* Remember the state change for the rest of the TB. */ | |
650 | ctx->mstatus_vs = MSTATUS_VS; | |
651 | ||
652 | tmp = tcg_temp_new(); | |
653 | tcg_gen_ld_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus)); | |
654 | tcg_gen_ori_tl(tmp, tmp, MSTATUS_VS); | |
655 | tcg_gen_st_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus)); | |
8e1ee1fb FC |
656 | } |
657 | ||
658 | if (ctx->virt_enabled && ctx->mstatus_hs_vs != MSTATUS_VS) { | |
659 | /* Remember the stage change for the rest of the TB. */ | |
660 | ctx->mstatus_hs_vs = MSTATUS_VS; | |
661 | ||
662 | tmp = tcg_temp_new(); | |
663 | tcg_gen_ld_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus_hs)); | |
664 | tcg_gen_ori_tl(tmp, tmp, MSTATUS_VS); | |
665 | tcg_gen_st_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus_hs)); | |
8e1ee1fb FC |
666 | } |
667 | } | |
668 | #else | |
669 | static inline void mark_vs_dirty(DisasContext *ctx) { } | |
670 | #endif | |
671 | ||
55c2a12c MC |
672 | static void gen_set_rm(DisasContext *ctx, int rm) |
673 | { | |
55c2a12c MC |
674 | if (ctx->frm == rm) { |
675 | return; | |
676 | } | |
677 | ctx->frm = rm; | |
75804f71 | 678 | |
3ceeb19a RH |
679 | if (rm == RISCV_FRM_DYN) { |
680 | /* The helper will return only if frm valid. */ | |
681 | ctx->frm_valid = true; | |
682 | } | |
75804f71 | 683 | |
a9814e3e RH |
684 | /* The helper may raise ILLEGAL_INSN -- record binv for unwind. */ |
685 | decode_save_opc(ctx); | |
05b80ed0 | 686 | gen_helper_set_rounding_mode(cpu_env, tcg_constant_i32(rm)); |
55c2a12c MC |
687 | } |
688 | ||
3ceeb19a RH |
689 | static void gen_set_rm_chkfrm(DisasContext *ctx, int rm) |
690 | { | |
691 | if (ctx->frm == rm && ctx->frm_valid) { | |
692 | return; | |
693 | } | |
694 | ctx->frm = rm; | |
695 | ctx->frm_valid = true; | |
696 | ||
697 | /* The helper may raise ILLEGAL_INSN -- record binv for unwind. */ | |
698 | decode_save_opc(ctx); | |
699 | gen_helper_set_rounding_mode_chkfrm(cpu_env, tcg_constant_i32(rm)); | |
700 | } | |
701 | ||
751538d5 LZ |
702 | static int ex_plus_1(DisasContext *ctx, int nf) |
703 | { | |
704 | return nf + 1; | |
705 | } | |
706 | ||
2a53cff4 | 707 | #define EX_SH(amount) \ |
451e4ffd | 708 | static int ex_shift_##amount(DisasContext *ctx, int imm) \ |
2a53cff4 BK |
709 | { \ |
710 | return imm << amount; \ | |
711 | } | |
3cca75a6 | 712 | EX_SH(1) |
e98d9140 BK |
713 | EX_SH(2) |
714 | EX_SH(3) | |
07b001c6 | 715 | EX_SH(4) |
2a53cff4 BK |
716 | EX_SH(12) |
717 | ||
d2e2c1e4 BK |
718 | #define REQUIRE_EXT(ctx, ext) do { \ |
719 | if (!has_ext(ctx, ext)) { \ | |
720 | return false; \ | |
721 | } \ | |
722 | } while (0) | |
7e68e6c7 | 723 | |
905b9fcd RH |
724 | #define REQUIRE_32BIT(ctx) do { \ |
725 | if (get_xl(ctx) != MXL_RV32) { \ | |
726 | return false; \ | |
727 | } \ | |
7e68e6c7 | 728 | } while (0) |
d2e2c1e4 | 729 | |
344b4a82 FP |
730 | #define REQUIRE_64BIT(ctx) do { \ |
731 | if (get_xl(ctx) != MXL_RV64) { \ | |
732 | return false; \ | |
733 | } \ | |
734 | } while (0) | |
735 | ||
736 | #define REQUIRE_128BIT(ctx) do { \ | |
737 | if (get_xl(ctx) != MXL_RV128) { \ | |
738 | return false; \ | |
739 | } \ | |
740 | } while (0) | |
741 | ||
742 | #define REQUIRE_64_OR_128BIT(ctx) do { \ | |
743 | if (get_xl(ctx) == MXL_RV32) { \ | |
744 | return false; \ | |
745 | } \ | |
daf866b6 AF |
746 | } while (0) |
747 | ||
d8e81e3c WL |
748 | #define REQUIRE_EITHER_EXT(ctx, A, B) do { \ |
749 | if (!ctx->cfg_ptr->ext_##A && \ | |
750 | !ctx->cfg_ptr->ext_##B) { \ | |
751 | return false; \ | |
752 | } \ | |
753 | } while (0) | |
754 | ||
451e4ffd | 755 | static int ex_rvc_register(DisasContext *ctx, int reg) |
e98d9140 BK |
756 | { |
757 | return 8 + reg; | |
758 | } | |
759 | ||
33632775 | 760 | static int ex_rvc_shiftli(DisasContext *ctx, int imm) |
6cafec92 RH |
761 | { |
762 | /* For RV128 a shamt of 0 means a shift by 64. */ | |
33632775 FP |
763 | if (get_ol(ctx) == MXL_RV128) { |
764 | imm = imm ? imm : 64; | |
765 | } | |
766 | return imm; | |
767 | } | |
768 | ||
769 | static int ex_rvc_shiftri(DisasContext *ctx, int imm) | |
770 | { | |
771 | /* | |
772 | * For RV128 a shamt of 0 means a shift by 64, furthermore, for right | |
773 | * shifts, the shamt is sign-extended. | |
774 | */ | |
775 | if (get_ol(ctx) == MXL_RV128) { | |
776 | imm = imm | (imm & 32) << 1; | |
777 | imm = imm ? imm : 64; | |
778 | } | |
779 | return imm; | |
6cafec92 RH |
780 | } |
781 | ||
2a53cff4 | 782 | /* Include the auto-generated decoder for 32 bit insn */ |
abff1abf | 783 | #include "decode-insn32.c.inc" |
7a50d3e2 | 784 | |
a1a3aac4 FP |
785 | static bool gen_logic_imm_fn(DisasContext *ctx, arg_i *a, |
786 | void (*func)(TCGv, TCGv, target_long)) | |
787 | { | |
788 | TCGv dest = dest_gpr(ctx, a->rd); | |
789 | TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE); | |
790 | ||
791 | func(dest, src1, a->imm); | |
792 | ||
568f247f FP |
793 | if (get_xl(ctx) == MXL_RV128) { |
794 | TCGv src1h = get_gprh(ctx, a->rs1); | |
795 | TCGv desth = dest_gprh(ctx, a->rd); | |
796 | ||
797 | func(desth, src1h, -(a->imm < 0)); | |
798 | gen_set_gpr128(ctx, a->rd, dest, desth); | |
799 | } else { | |
800 | gen_set_gpr(ctx, a->rd, dest); | |
801 | } | |
a1a3aac4 FP |
802 | |
803 | return true; | |
804 | } | |
805 | ||
806 | static bool gen_logic(DisasContext *ctx, arg_r *a, | |
807 | void (*func)(TCGv, TCGv, TCGv)) | |
808 | { | |
809 | TCGv dest = dest_gpr(ctx, a->rd); | |
810 | TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE); | |
811 | TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE); | |
812 | ||
813 | func(dest, src1, src2); | |
814 | ||
568f247f FP |
815 | if (get_xl(ctx) == MXL_RV128) { |
816 | TCGv src1h = get_gprh(ctx, a->rs1); | |
817 | TCGv src2h = get_gprh(ctx, a->rs2); | |
818 | TCGv desth = dest_gprh(ctx, a->rd); | |
819 | ||
820 | func(desth, src1h, src2h); | |
821 | gen_set_gpr128(ctx, a->rd, dest, desth); | |
822 | } else { | |
823 | gen_set_gpr(ctx, a->rd, dest); | |
824 | } | |
a1a3aac4 FP |
825 | |
826 | return true; | |
827 | } | |
828 | ||
191d1daf | 829 | static bool gen_arith_imm_fn(DisasContext *ctx, arg_i *a, DisasExtend ext, |
7fd40f86 FP |
830 | void (*func)(TCGv, TCGv, target_long), |
831 | void (*f128)(TCGv, TCGv, TCGv, TCGv, target_long)) | |
598aa116 | 832 | { |
191d1daf RH |
833 | TCGv dest = dest_gpr(ctx, a->rd); |
834 | TCGv src1 = get_gpr(ctx, a->rs1, ext); | |
598aa116 | 835 | |
7fd40f86 FP |
836 | if (get_ol(ctx) < MXL_RV128) { |
837 | func(dest, src1, a->imm); | |
838 | gen_set_gpr(ctx, a->rd, dest); | |
839 | } else { | |
840 | if (f128 == NULL) { | |
841 | return false; | |
842 | } | |
843 | ||
844 | TCGv src1h = get_gprh(ctx, a->rs1); | |
845 | TCGv desth = dest_gprh(ctx, a->rd); | |
598aa116 | 846 | |
7fd40f86 FP |
847 | f128(dest, desth, src1, src1h, a->imm); |
848 | gen_set_gpr128(ctx, a->rd, dest, desth); | |
849 | } | |
598aa116 RH |
850 | return true; |
851 | } | |
852 | ||
191d1daf | 853 | static bool gen_arith_imm_tl(DisasContext *ctx, arg_i *a, DisasExtend ext, |
7fd40f86 FP |
854 | void (*func)(TCGv, TCGv, TCGv), |
855 | void (*f128)(TCGv, TCGv, TCGv, TCGv, TCGv, TCGv)) | |
7a50d3e2 | 856 | { |
191d1daf RH |
857 | TCGv dest = dest_gpr(ctx, a->rd); |
858 | TCGv src1 = get_gpr(ctx, a->rs1, ext); | |
859 | TCGv src2 = tcg_constant_tl(a->imm); | |
7a50d3e2 | 860 | |
7fd40f86 FP |
861 | if (get_ol(ctx) < MXL_RV128) { |
862 | func(dest, src1, src2); | |
863 | gen_set_gpr(ctx, a->rd, dest); | |
864 | } else { | |
865 | if (f128 == NULL) { | |
866 | return false; | |
867 | } | |
7a50d3e2 | 868 | |
7fd40f86 FP |
869 | TCGv src1h = get_gprh(ctx, a->rs1); |
870 | TCGv src2h = tcg_constant_tl(-(a->imm < 0)); | |
871 | TCGv desth = dest_gprh(ctx, a->rd); | |
872 | ||
873 | f128(dest, desth, src1, src1h, src2, src2h); | |
874 | gen_set_gpr128(ctx, a->rd, dest, desth); | |
875 | } | |
7a50d3e2 BK |
876 | return true; |
877 | } | |
878 | ||
191d1daf | 879 | static bool gen_arith(DisasContext *ctx, arg_r *a, DisasExtend ext, |
7fd40f86 FP |
880 | void (*func)(TCGv, TCGv, TCGv), |
881 | void (*f128)(TCGv, TCGv, TCGv, TCGv, TCGv, TCGv)) | |
f2ab1728 | 882 | { |
191d1daf RH |
883 | TCGv dest = dest_gpr(ctx, a->rd); |
884 | TCGv src1 = get_gpr(ctx, a->rs1, ext); | |
885 | TCGv src2 = get_gpr(ctx, a->rs2, ext); | |
f2ab1728 | 886 | |
7fd40f86 FP |
887 | if (get_ol(ctx) < MXL_RV128) { |
888 | func(dest, src1, src2); | |
889 | gen_set_gpr(ctx, a->rd, dest); | |
890 | } else { | |
891 | if (f128 == NULL) { | |
892 | return false; | |
893 | } | |
894 | ||
895 | TCGv src1h = get_gprh(ctx, a->rs1); | |
896 | TCGv src2h = get_gprh(ctx, a->rs2); | |
897 | TCGv desth = dest_gprh(ctx, a->rd); | |
f2ab1728 | 898 | |
7fd40f86 FP |
899 | f128(dest, desth, src1, src1h, src2, src2h); |
900 | gen_set_gpr128(ctx, a->rd, dest, desth); | |
901 | } | |
f2ab1728 BK |
902 | return true; |
903 | } | |
904 | ||
80347ae9 RH |
905 | static bool gen_arith_per_ol(DisasContext *ctx, arg_r *a, DisasExtend ext, |
906 | void (*f_tl)(TCGv, TCGv, TCGv), | |
7fd40f86 FP |
907 | void (*f_32)(TCGv, TCGv, TCGv), |
908 | void (*f_128)(TCGv, TCGv, TCGv, TCGv, TCGv, TCGv)) | |
80347ae9 RH |
909 | { |
910 | int olen = get_olen(ctx); | |
911 | ||
912 | if (olen != TARGET_LONG_BITS) { | |
913 | if (olen == 32) { | |
914 | f_tl = f_32; | |
7fd40f86 | 915 | } else if (olen != 128) { |
80347ae9 RH |
916 | g_assert_not_reached(); |
917 | } | |
918 | } | |
7fd40f86 | 919 | return gen_arith(ctx, a, ext, f_tl, f_128); |
80347ae9 RH |
920 | } |
921 | ||
89c88309 | 922 | static bool gen_shift_imm_fn(DisasContext *ctx, arg_shift *a, DisasExtend ext, |
6bf4bbed FP |
923 | void (*func)(TCGv, TCGv, target_long), |
924 | void (*f128)(TCGv, TCGv, TCGv, TCGv, target_long)) | |
a10b9d93 | 925 | { |
89c88309 | 926 | TCGv dest, src1; |
7667cafd | 927 | int max_len = get_olen(ctx); |
a10b9d93 | 928 | |
89c88309 | 929 | if (a->shamt >= max_len) { |
981d3568 FC |
930 | return false; |
931 | } | |
932 | ||
89c88309 RH |
933 | dest = dest_gpr(ctx, a->rd); |
934 | src1 = get_gpr(ctx, a->rs1, ext); | |
981d3568 | 935 | |
6bf4bbed FP |
936 | if (max_len < 128) { |
937 | func(dest, src1, a->shamt); | |
938 | gen_set_gpr(ctx, a->rd, dest); | |
939 | } else { | |
940 | TCGv src1h = get_gprh(ctx, a->rs1); | |
941 | TCGv desth = dest_gprh(ctx, a->rd); | |
981d3568 | 942 | |
6bf4bbed FP |
943 | if (f128 == NULL) { |
944 | return false; | |
945 | } | |
946 | f128(dest, desth, src1, src1h, a->shamt); | |
947 | gen_set_gpr128(ctx, a->rd, dest, desth); | |
948 | } | |
981d3568 FC |
949 | return true; |
950 | } | |
951 | ||
a0245d91 RH |
952 | static bool gen_shift_imm_fn_per_ol(DisasContext *ctx, arg_shift *a, |
953 | DisasExtend ext, | |
954 | void (*f_tl)(TCGv, TCGv, target_long), | |
6bf4bbed FP |
955 | void (*f_32)(TCGv, TCGv, target_long), |
956 | void (*f_128)(TCGv, TCGv, TCGv, TCGv, | |
957 | target_long)) | |
a0245d91 RH |
958 | { |
959 | int olen = get_olen(ctx); | |
960 | if (olen != TARGET_LONG_BITS) { | |
961 | if (olen == 32) { | |
962 | f_tl = f_32; | |
6bf4bbed | 963 | } else if (olen != 128) { |
a0245d91 RH |
964 | g_assert_not_reached(); |
965 | } | |
966 | } | |
6bf4bbed | 967 | return gen_shift_imm_fn(ctx, a, ext, f_tl, f_128); |
a0245d91 RH |
968 | } |
969 | ||
89c88309 RH |
970 | static bool gen_shift_imm_tl(DisasContext *ctx, arg_shift *a, DisasExtend ext, |
971 | void (*func)(TCGv, TCGv, TCGv)) | |
23cd1777 | 972 | { |
89c88309 | 973 | TCGv dest, src1, src2; |
7667cafd | 974 | int max_len = get_olen(ctx); |
89c88309 RH |
975 | |
976 | if (a->shamt >= max_len) { | |
977 | return false; | |
978 | } | |
23cd1777 | 979 | |
89c88309 RH |
980 | dest = dest_gpr(ctx, a->rd); |
981 | src1 = get_gpr(ctx, a->rs1, ext); | |
982 | src2 = tcg_constant_tl(a->shamt); | |
23cd1777 | 983 | |
89c88309 | 984 | func(dest, src1, src2); |
23cd1777 | 985 | |
89c88309 | 986 | gen_set_gpr(ctx, a->rd, dest); |
23cd1777 FC |
987 | return true; |
988 | } | |
989 | ||
89c88309 | 990 | static bool gen_shift(DisasContext *ctx, arg_r *a, DisasExtend ext, |
6bf4bbed FP |
991 | void (*func)(TCGv, TCGv, TCGv), |
992 | void (*f128)(TCGv, TCGv, TCGv, TCGv, TCGv)) | |
981d3568 | 993 | { |
89c88309 RH |
994 | TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE); |
995 | TCGv ext2 = tcg_temp_new(); | |
6bf4bbed | 996 | int max_len = get_olen(ctx); |
981d3568 | 997 | |
6bf4bbed | 998 | tcg_gen_andi_tl(ext2, src2, max_len - 1); |
981d3568 | 999 | |
6bf4bbed FP |
1000 | TCGv dest = dest_gpr(ctx, a->rd); |
1001 | TCGv src1 = get_gpr(ctx, a->rs1, ext); | |
1002 | ||
1003 | if (max_len < 128) { | |
1004 | func(dest, src1, ext2); | |
1005 | gen_set_gpr(ctx, a->rd, dest); | |
1006 | } else { | |
1007 | TCGv src1h = get_gprh(ctx, a->rs1); | |
1008 | TCGv desth = dest_gprh(ctx, a->rd); | |
1009 | ||
1010 | if (f128 == NULL) { | |
1011 | return false; | |
1012 | } | |
1013 | f128(dest, desth, src1, src1h, ext2); | |
1014 | gen_set_gpr128(ctx, a->rd, dest, desth); | |
1015 | } | |
981d3568 FC |
1016 | return true; |
1017 | } | |
1018 | ||
a0245d91 RH |
1019 | static bool gen_shift_per_ol(DisasContext *ctx, arg_r *a, DisasExtend ext, |
1020 | void (*f_tl)(TCGv, TCGv, TCGv), | |
6bf4bbed FP |
1021 | void (*f_32)(TCGv, TCGv, TCGv), |
1022 | void (*f_128)(TCGv, TCGv, TCGv, TCGv, TCGv)) | |
a0245d91 RH |
1023 | { |
1024 | int olen = get_olen(ctx); | |
1025 | if (olen != TARGET_LONG_BITS) { | |
1026 | if (olen == 32) { | |
1027 | f_tl = f_32; | |
6bf4bbed | 1028 | } else if (olen != 128) { |
a0245d91 RH |
1029 | g_assert_not_reached(); |
1030 | } | |
1031 | } | |
6bf4bbed | 1032 | return gen_shift(ctx, a, ext, f_tl, f_128); |
a0245d91 RH |
1033 | } |
1034 | ||
60903915 RH |
1035 | static bool gen_unary(DisasContext *ctx, arg_r2 *a, DisasExtend ext, |
1036 | void (*func)(TCGv, TCGv)) | |
43824018 | 1037 | { |
60903915 RH |
1038 | TCGv dest = dest_gpr(ctx, a->rd); |
1039 | TCGv src1 = get_gpr(ctx, a->rs1, ext); | |
43824018 | 1040 | |
60903915 | 1041 | func(dest, src1); |
43824018 | 1042 | |
60903915 | 1043 | gen_set_gpr(ctx, a->rd, dest); |
43824018 KC |
1044 | return true; |
1045 | } | |
1046 | ||
fdab665f RH |
1047 | static bool gen_unary_per_ol(DisasContext *ctx, arg_r2 *a, DisasExtend ext, |
1048 | void (*f_tl)(TCGv, TCGv), | |
1049 | void (*f_32)(TCGv, TCGv)) | |
1050 | { | |
1051 | int olen = get_olen(ctx); | |
1052 | ||
1053 | if (olen != TARGET_LONG_BITS) { | |
1054 | if (olen == 32) { | |
1055 | f_tl = f_32; | |
1056 | } else { | |
1057 | g_assert_not_reached(); | |
1058 | } | |
1059 | } | |
1060 | return gen_unary(ctx, a, ext, f_tl); | |
1061 | } | |
1062 | ||
89c88309 RH |
1063 | static uint32_t opcode_at(DisasContextBase *dcbase, target_ulong pc) |
1064 | { | |
1065 | DisasContext *ctx = container_of(dcbase, DisasContext, base); | |
1066 | CPUState *cpu = ctx->cs; | |
1067 | CPURISCVState *env = cpu->env_ptr; | |
1068 | ||
1069 | return cpu_ldl_code(env, pc); | |
1070 | } | |
1071 | ||
2a53cff4 | 1072 | /* Include insn module translation function */ |
139c1837 PB |
1073 | #include "insn_trans/trans_rvi.c.inc" |
1074 | #include "insn_trans/trans_rvm.c.inc" | |
1075 | #include "insn_trans/trans_rva.c.inc" | |
1076 | #include "insn_trans/trans_rvf.c.inc" | |
1077 | #include "insn_trans/trans_rvd.c.inc" | |
1078 | #include "insn_trans/trans_rvh.c.inc" | |
1079 | #include "insn_trans/trans_rvv.c.inc" | |
43824018 | 1080 | #include "insn_trans/trans_rvb.c.inc" |
b8e1f32c | 1081 | #include "insn_trans/trans_rvzicond.c.inc" |
260b594d | 1082 | #include "insn_trans/trans_rvzawrs.c.inc" |
a939c500 | 1083 | #include "insn_trans/trans_rvzicbo.c.inc" |
915f77b2 | 1084 | #include "insn_trans/trans_rvzfh.c.inc" |
68d19b58 | 1085 | #include "insn_trans/trans_rvk.c.inc" |
139c1837 | 1086 | #include "insn_trans/trans_privileged.c.inc" |
c5d77ddd | 1087 | #include "insn_trans/trans_svinval.c.inc" |
49a7f3aa CM |
1088 | #include "decode-xthead.c.inc" |
1089 | #include "insn_trans/trans_xthead.c.inc" | |
0d429bd2 | 1090 | #include "insn_trans/trans_xventanacondops.c.inc" |
2a53cff4 | 1091 | |
59a3a1c0 | 1092 | /* Include the auto-generated decoder for 16 bit insn */ |
abff1abf | 1093 | #include "decode-insn16.c.inc" |
0d429bd2 PT |
1094 | /* Include decoders for factored-out extensions */ |
1095 | #include "decode-XVentanaCondOps.c.inc" | |
e98d9140 | 1096 | |
ef6e987b RH |
1097 | /* The specification allows for longer insns, but not supported by qemu. */ |
1098 | #define MAX_INSN_LEN 4 | |
1099 | ||
1100 | static inline int insn_len(uint16_t first_word) | |
1101 | { | |
1102 | return (first_word & 3) == 3 ? 4 : 2; | |
1103 | } | |
1104 | ||
25139bf7 | 1105 | static void decode_opc(CPURISCVState *env, DisasContext *ctx, uint16_t opcode) |
55c2a12c | 1106 | { |
5e199b6b PT |
1107 | /* |
1108 | * A table with predicate (i.e., guard) functions and decoder functions | |
1109 | * that are tested in-order until a decoder matches onto the opcode. | |
1110 | */ | |
1111 | static const struct { | |
1112 | bool (*guard_func)(DisasContext *); | |
1113 | bool (*decode_func)(DisasContext *, uint32_t); | |
1114 | } decoders[] = { | |
1115 | { always_true_p, decode_insn32 }, | |
49a7f3aa | 1116 | { has_xthead_p, decode_xthead }, |
0d429bd2 | 1117 | { has_XVentanaCondOps_p, decode_XVentanaCodeOps }, |
5e199b6b PT |
1118 | }; |
1119 | ||
fb3f3730 | 1120 | ctx->virt_inst_excp = false; |
5e199b6b | 1121 | /* Check for compressed insn */ |
ef6e987b | 1122 | if (insn_len(opcode) == 2) { |
ec2918b4 RH |
1123 | ctx->opcode = opcode; |
1124 | ctx->pc_succ_insn = ctx->base.pc_next + 2; | |
1125 | if (has_ext(ctx, RVC) && decode_insn16(ctx, opcode)) { | |
1126 | return; | |
55c2a12c MC |
1127 | } |
1128 | } else { | |
25139bf7 AB |
1129 | uint32_t opcode32 = opcode; |
1130 | opcode32 = deposit32(opcode32, 16, 16, | |
4e116893 IL |
1131 | translator_lduw(env, &ctx->base, |
1132 | ctx->base.pc_next + 2)); | |
ea7b5d5a | 1133 | ctx->opcode = opcode32; |
0114db1c | 1134 | ctx->pc_succ_insn = ctx->base.pc_next + 4; |
5e199b6b PT |
1135 | |
1136 | for (size_t i = 0; i < ARRAY_SIZE(decoders); ++i) { | |
1137 | if (decoders[i].guard_func(ctx) && | |
1138 | decoders[i].decode_func(ctx, opcode32)) { | |
1139 | return; | |
1140 | } | |
2a53cff4 | 1141 | } |
55c2a12c | 1142 | } |
5e199b6b PT |
1143 | |
1144 | gen_exception_illegal(ctx); | |
55c2a12c MC |
1145 | } |
1146 | ||
5b4f1d2d | 1147 | static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) |
55c2a12c | 1148 | { |
5b4f1d2d | 1149 | DisasContext *ctx = container_of(dcbase, DisasContext, base); |
d75377bf | 1150 | CPURISCVState *env = cs->env_ptr; |
50fba816 | 1151 | RISCVCPU *cpu = RISCV_CPU(cs); |
2b7168fc | 1152 | uint32_t tb_flags = ctx->base.tb->flags; |
55c2a12c | 1153 | |
5b4f1d2d | 1154 | ctx->pc_succ_insn = ctx->base.pc_first; |
61d56494 | 1155 | ctx->mem_idx = FIELD_EX32(tb_flags, TB_FLAGS, MEM_IDX); |
2b7168fc | 1156 | ctx->mstatus_fs = tb_flags & TB_FLAGS_MSTATUS_FS; |
8e1ee1fb | 1157 | ctx->mstatus_vs = tb_flags & TB_FLAGS_MSTATUS_VS; |
d75377bf | 1158 | ctx->priv_ver = env->priv_ver; |
45b4dc8b | 1159 | #if !defined(CONFIG_USER_ONLY) |
ae84dd0a AF |
1160 | if (riscv_has_ext(env, RVH)) { |
1161 | ctx->virt_enabled = riscv_cpu_virt_enabled(env); | |
ae84dd0a AF |
1162 | } else { |
1163 | ctx->virt_enabled = false; | |
1164 | } | |
45b4dc8b AF |
1165 | #else |
1166 | ctx->virt_enabled = false; | |
1167 | #endif | |
e91a7227 | 1168 | ctx->misa_ext = env->misa_ext; |
5b4f1d2d | 1169 | ctx->frm = -1; /* unknown rounding mode */ |
3b91323e | 1170 | ctx->cfg_ptr = &(cpu->cfg); |
a88f0402 | 1171 | ctx->mstatus_hs_fs = FIELD_EX32(tb_flags, TB_FLAGS, MSTATUS_HS_FS); |
8e1ee1fb | 1172 | ctx->mstatus_hs_vs = FIELD_EX32(tb_flags, TB_FLAGS, MSTATUS_HS_VS); |
743077b3 | 1173 | ctx->hlsx = FIELD_EX32(tb_flags, TB_FLAGS, HLSX); |
2b7168fc LZ |
1174 | ctx->vill = FIELD_EX32(tb_flags, TB_FLAGS, VILL); |
1175 | ctx->sew = FIELD_EX32(tb_flags, TB_FLAGS, SEW); | |
33f1beaf | 1176 | ctx->lmul = sextract32(FIELD_EX32(tb_flags, TB_FLAGS, LMUL), 0, 3); |
f1eed927 | 1177 | ctx->vta = FIELD_EX32(tb_flags, TB_FLAGS, VTA) && cpu->cfg.rvv_ta_all_1s; |
355d5584 | 1178 | ctx->vma = FIELD_EX32(tb_flags, TB_FLAGS, VMA) && cpu->cfg.rvv_ma_all_1s; |
752614ca | 1179 | ctx->cfg_vta_all_1s = cpu->cfg.rvv_ta_all_1s; |
f714361e | 1180 | ctx->vstart = env->vstart; |
2b7168fc | 1181 | ctx->vl_eq_vlmax = FIELD_EX32(tb_flags, TB_FLAGS, VL_EQ_VLMAX); |
a2f827ff | 1182 | ctx->misa_mxl_max = env->misa_mxl_max; |
92371bd9 | 1183 | ctx->xl = FIELD_EX32(tb_flags, TB_FLAGS, XL); |
a10b9d93 | 1184 | ctx->cs = cs; |
4208dc7e LZ |
1185 | ctx->pm_mask_enabled = FIELD_EX32(tb_flags, TB_FLAGS, PM_MASK_ENABLED); |
1186 | ctx->pm_base_enabled = FIELD_EX32(tb_flags, TB_FLAGS, PM_BASE_ENABLED); | |
2c9d7471 | 1187 | ctx->itrigger = FIELD_EX32(tb_flags, TB_FLAGS, ITRIGGER); |
ecda15d1 | 1188 | ctx->zero = tcg_constant_tl(0); |
506c6698 | 1189 | ctx->virt_inst_excp = false; |
5b4f1d2d | 1190 | } |
55c2a12c | 1191 | |
5b4f1d2d EC |
1192 | static void riscv_tr_tb_start(DisasContextBase *db, CPUState *cpu) |
1193 | { | |
1194 | } | |
55c2a12c | 1195 | |
5b4f1d2d EC |
1196 | static void riscv_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu) |
1197 | { | |
1198 | DisasContext *ctx = container_of(dcbase, DisasContext, base); | |
1199 | ||
62cf0245 AP |
1200 | tcg_gen_insn_start(ctx->base.pc_next, 0); |
1201 | ctx->insn_start = tcg_last_op(); | |
5b4f1d2d EC |
1202 | } |
1203 | ||
5b4f1d2d EC |
1204 | static void riscv_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) |
1205 | { | |
1206 | DisasContext *ctx = container_of(dcbase, DisasContext, base); | |
1207 | CPURISCVState *env = cpu->env_ptr; | |
4e116893 | 1208 | uint16_t opcode16 = translator_lduw(env, &ctx->base, ctx->base.pc_next); |
55c2a12c | 1209 | |
7667cafd | 1210 | ctx->ol = ctx->xl; |
25139bf7 | 1211 | decode_opc(env, ctx, opcode16); |
5b4f1d2d | 1212 | ctx->base.pc_next = ctx->pc_succ_insn; |
ecda15d1 | 1213 | |
00c07344 | 1214 | /* Only the first insn within a TB is allowed to cross a page boundary. */ |
5b4f1d2d | 1215 | if (ctx->base.is_jmp == DISAS_NEXT) { |
2c9d7471 | 1216 | if (ctx->itrigger || !is_same_page(&ctx->base, ctx->base.pc_next)) { |
5b4f1d2d | 1217 | ctx->base.is_jmp = DISAS_TOO_MANY; |
00c07344 RH |
1218 | } else { |
1219 | unsigned page_ofs = ctx->base.pc_next & ~TARGET_PAGE_MASK; | |
1220 | ||
1221 | if (page_ofs > TARGET_PAGE_SIZE - MAX_INSN_LEN) { | |
1222 | uint16_t next_insn = cpu_lduw_code(env, ctx->base.pc_next); | |
1223 | int len = insn_len(next_insn); | |
1224 | ||
ae9c326f | 1225 | if (!is_same_page(&ctx->base, ctx->base.pc_next + len - 1)) { |
00c07344 RH |
1226 | ctx->base.is_jmp = DISAS_TOO_MANY; |
1227 | } | |
1228 | } | |
55c2a12c | 1229 | } |
55c2a12c | 1230 | } |
5b4f1d2d EC |
1231 | } |
1232 | ||
1233 | static void riscv_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu) | |
1234 | { | |
1235 | DisasContext *ctx = container_of(dcbase, DisasContext, base); | |
1236 | ||
1237 | switch (ctx->base.is_jmp) { | |
b2e32021 | 1238 | case DISAS_TOO_MANY: |
ccf08e40 | 1239 | gen_goto_tb(ctx, 0, ctx->base.pc_next); |
55c2a12c | 1240 | break; |
b2e32021 | 1241 | case DISAS_NORETURN: |
55c2a12c | 1242 | break; |
b2e32021 EC |
1243 | default: |
1244 | g_assert_not_reached(); | |
55c2a12c | 1245 | } |
5b4f1d2d EC |
1246 | } |
1247 | ||
8eb806a7 RH |
1248 | static void riscv_tr_disas_log(const DisasContextBase *dcbase, |
1249 | CPUState *cpu, FILE *logfile) | |
5b4f1d2d | 1250 | { |
35f69039 AF |
1251 | #ifndef CONFIG_USER_ONLY |
1252 | RISCVCPU *rvcpu = RISCV_CPU(cpu); | |
1253 | CPURISCVState *env = &rvcpu->env; | |
1254 | #endif | |
1255 | ||
8eb806a7 | 1256 | fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first)); |
35f69039 | 1257 | #ifndef CONFIG_USER_ONLY |
8eb806a7 RH |
1258 | fprintf(logfile, "Priv: "TARGET_FMT_ld"; Virt: "TARGET_FMT_ld"\n", |
1259 | env->priv, env->virt); | |
35f69039 | 1260 | #endif |
8eb806a7 | 1261 | target_disas(logfile, cpu, dcbase->pc_first, dcbase->tb->size); |
5b4f1d2d EC |
1262 | } |
1263 | ||
1264 | static const TranslatorOps riscv_tr_ops = { | |
1265 | .init_disas_context = riscv_tr_init_disas_context, | |
1266 | .tb_start = riscv_tr_tb_start, | |
1267 | .insn_start = riscv_tr_insn_start, | |
5b4f1d2d EC |
1268 | .translate_insn = riscv_tr_translate_insn, |
1269 | .tb_stop = riscv_tr_tb_stop, | |
1270 | .disas_log = riscv_tr_disas_log, | |
1271 | }; | |
1272 | ||
597f9b2d | 1273 | void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns, |
306c8721 | 1274 | target_ulong pc, void *host_pc) |
5b4f1d2d EC |
1275 | { |
1276 | DisasContext ctx; | |
1277 | ||
306c8721 | 1278 | translator_loop(cs, tb, max_insns, pc, host_pc, &riscv_tr_ops, &ctx.base); |
55c2a12c MC |
1279 | } |
1280 | ||
1281 | void riscv_translate_init(void) | |
1282 | { | |
1283 | int i; | |
1284 | ||
8e034ae4 RH |
1285 | /* |
1286 | * cpu_gpr[0] is a placeholder for the zero register. Do not use it. | |
1287 | * Use the gen_set_gpr and get_gpr helper functions when accessing regs, | |
1288 | * unless you specifically block reads/writes to reg 0. | |
1289 | */ | |
55c2a12c | 1290 | cpu_gpr[0] = NULL; |
2b547084 | 1291 | cpu_gprh[0] = NULL; |
55c2a12c MC |
1292 | |
1293 | for (i = 1; i < 32; i++) { | |
1294 | cpu_gpr[i] = tcg_global_mem_new(cpu_env, | |
1295 | offsetof(CPURISCVState, gpr[i]), riscv_int_regnames[i]); | |
2b547084 FP |
1296 | cpu_gprh[i] = tcg_global_mem_new(cpu_env, |
1297 | offsetof(CPURISCVState, gprh[i]), riscv_int_regnamesh[i]); | |
55c2a12c MC |
1298 | } |
1299 | ||
1300 | for (i = 0; i < 32; i++) { | |
1301 | cpu_fpr[i] = tcg_global_mem_new_i64(cpu_env, | |
1302 | offsetof(CPURISCVState, fpr[i]), riscv_fpr_regnames[i]); | |
1303 | } | |
1304 | ||
1305 | cpu_pc = tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, pc), "pc"); | |
ad9e5aa2 | 1306 | cpu_vl = tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, vl), "vl"); |
f714361e FC |
1307 | cpu_vstart = tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, vstart), |
1308 | "vstart"); | |
55c2a12c MC |
1309 | load_res = tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, load_res), |
1310 | "load_res"); | |
1311 | load_val = tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, load_val), | |
1312 | "load_val"); | |
0774a7a1 | 1313 | /* Assign PM CSRs to tcg globals */ |
0cff460d LZ |
1314 | pm_mask = tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, cur_pmmask), |
1315 | "pmmask"); | |
1316 | pm_base = tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, cur_pmbase), | |
1317 | "pmbase"); | |
55c2a12c | 1318 | } |