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