xref: /openbmc/qemu/target/riscv/translate.c (revision b550f894)
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"
22 #include "tcg/tcg-op.h"
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 
29 #include "exec/translator.h"
30 #include "exec/log.h"
31 
32 #include "instmap.h"
33 
34 /* global register indices */
35 static TCGv cpu_gpr[32], cpu_pc, cpu_vl;
36 static TCGv_i64 cpu_fpr[32]; /* assume F and D extensions */
37 static TCGv load_res;
38 static TCGv load_val;
39 
40 #include "exec/gen-icount.h"
41 
42 /*
43  * If an operation is being performed on less than TARGET_LONG_BITS,
44  * it may require the inputs to be sign- or zero-extended; which will
45  * depend on the exact operation being performed.
46  */
47 typedef enum {
48     EXT_NONE,
49     EXT_SIGN,
50     EXT_ZERO,
51 } DisasExtend;
52 
53 typedef struct DisasContext {
54     DisasContextBase base;
55     /* pc_succ_insn points to the instruction following base.pc_next */
56     target_ulong pc_succ_insn;
57     target_ulong priv_ver;
58     RISCVMXL xl;
59     uint32_t misa_ext;
60     uint32_t opcode;
61     uint32_t mstatus_fs;
62     uint32_t mstatus_hs_fs;
63     uint32_t mem_idx;
64     /* Remember the rounding mode encoded in the previous fp instruction,
65        which we have already installed into env->fp_status.  Or -1 for
66        no previous fp instruction.  Note that we exit the TB when writing
67        to any system register, which includes CSR_FRM, so we do not have
68        to reset this known value.  */
69     int frm;
70     RISCVMXL ol;
71     bool virt_enabled;
72     bool ext_ifencei;
73     bool hlsx;
74     /* vector extension */
75     bool vill;
76     uint8_t lmul;
77     uint8_t sew;
78     uint16_t vlen;
79     uint16_t mlen;
80     bool vl_eq_vlmax;
81     uint8_t ntemp;
82     CPUState *cs;
83     TCGv zero;
84     /* Space for 3 operands plus 1 extra for address computation. */
85     TCGv temp[4];
86 } DisasContext;
87 
88 static inline bool has_ext(DisasContext *ctx, uint32_t ext)
89 {
90     return ctx->misa_ext & ext;
91 }
92 
93 #ifdef TARGET_RISCV32
94 #define get_xl(ctx)    MXL_RV32
95 #elif defined(CONFIG_USER_ONLY)
96 #define get_xl(ctx)    MXL_RV64
97 #else
98 #define get_xl(ctx)    ((ctx)->xl)
99 #endif
100 
101 /* The word size for this machine mode. */
102 static inline int __attribute__((unused)) get_xlen(DisasContext *ctx)
103 {
104     return 16 << get_xl(ctx);
105 }
106 
107 /* The operation length, as opposed to the xlen. */
108 #ifdef TARGET_RISCV32
109 #define get_ol(ctx)    MXL_RV32
110 #else
111 #define get_ol(ctx)    ((ctx)->ol)
112 #endif
113 
114 static inline int get_olen(DisasContext *ctx)
115 {
116     return 16 << get_ol(ctx);
117 }
118 
119 /*
120  * RISC-V requires NaN-boxing of narrower width floating point values.
121  * This applies when a 32-bit value is assigned to a 64-bit FP register.
122  * For consistency and simplicity, we nanbox results even when the RVD
123  * extension is not present.
124  */
125 static void gen_nanbox_s(TCGv_i64 out, TCGv_i64 in)
126 {
127     tcg_gen_ori_i64(out, in, MAKE_64BIT_MASK(32, 32));
128 }
129 
130 /*
131  * A narrow n-bit operation, where n < FLEN, checks that input operands
132  * are correctly Nan-boxed, i.e., all upper FLEN - n bits are 1.
133  * If so, the least-significant bits of the input are used, otherwise the
134  * input value is treated as an n-bit canonical NaN (v2.2 section 9.2).
135  *
136  * Here, the result is always nan-boxed, even the canonical nan.
137  */
138 static void gen_check_nanbox_s(TCGv_i64 out, TCGv_i64 in)
139 {
140     TCGv_i64 t_max = tcg_constant_i64(0xffffffff00000000ull);
141     TCGv_i64 t_nan = tcg_constant_i64(0xffffffff7fc00000ull);
142 
143     tcg_gen_movcond_i64(TCG_COND_GEU, out, in, t_max, in, t_nan);
144 }
145 
146 static void generate_exception(DisasContext *ctx, int excp)
147 {
148     tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next);
149     gen_helper_raise_exception(cpu_env, tcg_constant_i32(excp));
150     ctx->base.is_jmp = DISAS_NORETURN;
151 }
152 
153 static void generate_exception_mtval(DisasContext *ctx, int excp)
154 {
155     tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next);
156     tcg_gen_st_tl(cpu_pc, cpu_env, offsetof(CPURISCVState, badaddr));
157     gen_helper_raise_exception(cpu_env, tcg_constant_i32(excp));
158     ctx->base.is_jmp = DISAS_NORETURN;
159 }
160 
161 static void gen_exception_illegal(DisasContext *ctx)
162 {
163     generate_exception(ctx, RISCV_EXCP_ILLEGAL_INST);
164 }
165 
166 static void gen_exception_inst_addr_mis(DisasContext *ctx)
167 {
168     generate_exception_mtval(ctx, RISCV_EXCP_INST_ADDR_MIS);
169 }
170 
171 static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
172 {
173     if (translator_use_goto_tb(&ctx->base, dest)) {
174         tcg_gen_goto_tb(n);
175         tcg_gen_movi_tl(cpu_pc, dest);
176         tcg_gen_exit_tb(ctx->base.tb, n);
177     } else {
178         tcg_gen_movi_tl(cpu_pc, dest);
179         tcg_gen_lookup_and_goto_ptr();
180     }
181 }
182 
183 /*
184  * Wrappers for getting reg values.
185  *
186  * The $zero register does not have cpu_gpr[0] allocated -- we supply the
187  * constant zero as a source, and an uninitialized sink as destination.
188  *
189  * Further, we may provide an extension for word operations.
190  */
191 static TCGv temp_new(DisasContext *ctx)
192 {
193     assert(ctx->ntemp < ARRAY_SIZE(ctx->temp));
194     return ctx->temp[ctx->ntemp++] = tcg_temp_new();
195 }
196 
197 static TCGv get_gpr(DisasContext *ctx, int reg_num, DisasExtend ext)
198 {
199     TCGv t;
200 
201     if (reg_num == 0) {
202         return ctx->zero;
203     }
204 
205     switch (get_ol(ctx)) {
206     case MXL_RV32:
207         switch (ext) {
208         case EXT_NONE:
209             break;
210         case EXT_SIGN:
211             t = temp_new(ctx);
212             tcg_gen_ext32s_tl(t, cpu_gpr[reg_num]);
213             return t;
214         case EXT_ZERO:
215             t = temp_new(ctx);
216             tcg_gen_ext32u_tl(t, cpu_gpr[reg_num]);
217             return t;
218         default:
219             g_assert_not_reached();
220         }
221         break;
222     case MXL_RV64:
223         break;
224     default:
225         g_assert_not_reached();
226     }
227     return cpu_gpr[reg_num];
228 }
229 
230 static TCGv dest_gpr(DisasContext *ctx, int reg_num)
231 {
232     if (reg_num == 0 || get_olen(ctx) < TARGET_LONG_BITS) {
233         return temp_new(ctx);
234     }
235     return cpu_gpr[reg_num];
236 }
237 
238 static void gen_set_gpr(DisasContext *ctx, int reg_num, TCGv t)
239 {
240     if (reg_num != 0) {
241         switch (get_ol(ctx)) {
242         case MXL_RV32:
243             tcg_gen_ext32s_tl(cpu_gpr[reg_num], t);
244             break;
245         case MXL_RV64:
246             tcg_gen_mov_tl(cpu_gpr[reg_num], t);
247             break;
248         default:
249             g_assert_not_reached();
250         }
251     }
252 }
253 
254 static void gen_jal(DisasContext *ctx, int rd, target_ulong imm)
255 {
256     target_ulong next_pc;
257 
258     /* check misaligned: */
259     next_pc = ctx->base.pc_next + imm;
260     if (!has_ext(ctx, RVC)) {
261         if ((next_pc & 0x3) != 0) {
262             gen_exception_inst_addr_mis(ctx);
263             return;
264         }
265     }
266     if (rd != 0) {
267         tcg_gen_movi_tl(cpu_gpr[rd], ctx->pc_succ_insn);
268     }
269 
270     gen_goto_tb(ctx, 0, ctx->base.pc_next + imm); /* must use this for safety */
271     ctx->base.is_jmp = DISAS_NORETURN;
272 }
273 
274 #ifndef CONFIG_USER_ONLY
275 /* The states of mstatus_fs are:
276  * 0 = disabled, 1 = initial, 2 = clean, 3 = dirty
277  * We will have already diagnosed disabled state,
278  * and need to turn initial/clean into dirty.
279  */
280 static void mark_fs_dirty(DisasContext *ctx)
281 {
282     TCGv tmp;
283 
284     if (ctx->mstatus_fs != MSTATUS_FS) {
285         /* Remember the state change for the rest of the TB. */
286         ctx->mstatus_fs = MSTATUS_FS;
287 
288         tmp = tcg_temp_new();
289         tcg_gen_ld_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus));
290         tcg_gen_ori_tl(tmp, tmp, MSTATUS_FS);
291         tcg_gen_st_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus));
292         tcg_temp_free(tmp);
293     }
294 
295     if (ctx->virt_enabled && ctx->mstatus_hs_fs != MSTATUS_FS) {
296         /* Remember the stage change for the rest of the TB. */
297         ctx->mstatus_hs_fs = MSTATUS_FS;
298 
299         tmp = tcg_temp_new();
300         tcg_gen_ld_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus_hs));
301         tcg_gen_ori_tl(tmp, tmp, MSTATUS_FS);
302         tcg_gen_st_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus_hs));
303         tcg_temp_free(tmp);
304     }
305 }
306 #else
307 static inline void mark_fs_dirty(DisasContext *ctx) { }
308 #endif
309 
310 static void gen_set_rm(DisasContext *ctx, int rm)
311 {
312     if (ctx->frm == rm) {
313         return;
314     }
315     ctx->frm = rm;
316     gen_helper_set_rounding_mode(cpu_env, tcg_constant_i32(rm));
317 }
318 
319 static int ex_plus_1(DisasContext *ctx, int nf)
320 {
321     return nf + 1;
322 }
323 
324 #define EX_SH(amount) \
325     static int ex_shift_##amount(DisasContext *ctx, int imm) \
326     {                                         \
327         return imm << amount;                 \
328     }
329 EX_SH(1)
330 EX_SH(2)
331 EX_SH(3)
332 EX_SH(4)
333 EX_SH(12)
334 
335 #define REQUIRE_EXT(ctx, ext) do { \
336     if (!has_ext(ctx, ext)) {      \
337         return false;              \
338     }                              \
339 } while (0)
340 
341 #define REQUIRE_32BIT(ctx) do {    \
342     if (get_xl(ctx) != MXL_RV32) { \
343         return false;              \
344     }                              \
345 } while (0)
346 
347 #define REQUIRE_64BIT(ctx) do {    \
348     if (get_xl(ctx) < MXL_RV64) {  \
349         return false;              \
350     }                              \
351 } while (0)
352 
353 static int ex_rvc_register(DisasContext *ctx, int reg)
354 {
355     return 8 + reg;
356 }
357 
358 static int ex_rvc_shifti(DisasContext *ctx, int imm)
359 {
360     /* For RV128 a shamt of 0 means a shift by 64. */
361     return imm ? imm : 64;
362 }
363 
364 /* Include the auto-generated decoder for 32 bit insn */
365 #include "decode-insn32.c.inc"
366 
367 static bool gen_arith_imm_fn(DisasContext *ctx, arg_i *a, DisasExtend ext,
368                              void (*func)(TCGv, TCGv, target_long))
369 {
370     TCGv dest = dest_gpr(ctx, a->rd);
371     TCGv src1 = get_gpr(ctx, a->rs1, ext);
372 
373     func(dest, src1, a->imm);
374 
375     gen_set_gpr(ctx, a->rd, dest);
376     return true;
377 }
378 
379 static bool gen_arith_imm_tl(DisasContext *ctx, arg_i *a, DisasExtend ext,
380                              void (*func)(TCGv, TCGv, TCGv))
381 {
382     TCGv dest = dest_gpr(ctx, a->rd);
383     TCGv src1 = get_gpr(ctx, a->rs1, ext);
384     TCGv src2 = tcg_constant_tl(a->imm);
385 
386     func(dest, src1, src2);
387 
388     gen_set_gpr(ctx, a->rd, dest);
389     return true;
390 }
391 
392 static bool gen_arith(DisasContext *ctx, arg_r *a, DisasExtend ext,
393                       void (*func)(TCGv, TCGv, TCGv))
394 {
395     TCGv dest = dest_gpr(ctx, a->rd);
396     TCGv src1 = get_gpr(ctx, a->rs1, ext);
397     TCGv src2 = get_gpr(ctx, a->rs2, ext);
398 
399     func(dest, src1, src2);
400 
401     gen_set_gpr(ctx, a->rd, dest);
402     return true;
403 }
404 
405 static bool gen_arith_per_ol(DisasContext *ctx, arg_r *a, DisasExtend ext,
406                              void (*f_tl)(TCGv, TCGv, TCGv),
407                              void (*f_32)(TCGv, TCGv, TCGv))
408 {
409     int olen = get_olen(ctx);
410 
411     if (olen != TARGET_LONG_BITS) {
412         if (olen == 32) {
413             f_tl = f_32;
414         } else {
415             g_assert_not_reached();
416         }
417     }
418     return gen_arith(ctx, a, ext, f_tl);
419 }
420 
421 static bool gen_shift_imm_fn(DisasContext *ctx, arg_shift *a, DisasExtend ext,
422                              void (*func)(TCGv, TCGv, target_long))
423 {
424     TCGv dest, src1;
425     int max_len = get_olen(ctx);
426 
427     if (a->shamt >= max_len) {
428         return false;
429     }
430 
431     dest = dest_gpr(ctx, a->rd);
432     src1 = get_gpr(ctx, a->rs1, ext);
433 
434     func(dest, src1, a->shamt);
435 
436     gen_set_gpr(ctx, a->rd, dest);
437     return true;
438 }
439 
440 static bool gen_shift_imm_fn_per_ol(DisasContext *ctx, arg_shift *a,
441                                     DisasExtend ext,
442                                     void (*f_tl)(TCGv, TCGv, target_long),
443                                     void (*f_32)(TCGv, TCGv, target_long))
444 {
445     int olen = get_olen(ctx);
446     if (olen != TARGET_LONG_BITS) {
447         if (olen == 32) {
448             f_tl = f_32;
449         } else {
450             g_assert_not_reached();
451         }
452     }
453     return gen_shift_imm_fn(ctx, a, ext, f_tl);
454 }
455 
456 static bool gen_shift_imm_tl(DisasContext *ctx, arg_shift *a, DisasExtend ext,
457                              void (*func)(TCGv, TCGv, TCGv))
458 {
459     TCGv dest, src1, src2;
460     int max_len = get_olen(ctx);
461 
462     if (a->shamt >= max_len) {
463         return false;
464     }
465 
466     dest = dest_gpr(ctx, a->rd);
467     src1 = get_gpr(ctx, a->rs1, ext);
468     src2 = tcg_constant_tl(a->shamt);
469 
470     func(dest, src1, src2);
471 
472     gen_set_gpr(ctx, a->rd, dest);
473     return true;
474 }
475 
476 static bool gen_shift(DisasContext *ctx, arg_r *a, DisasExtend ext,
477                       void (*func)(TCGv, TCGv, TCGv))
478 {
479     TCGv dest = dest_gpr(ctx, a->rd);
480     TCGv src1 = get_gpr(ctx, a->rs1, ext);
481     TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE);
482     TCGv ext2 = tcg_temp_new();
483 
484     tcg_gen_andi_tl(ext2, src2, get_olen(ctx) - 1);
485     func(dest, src1, ext2);
486 
487     gen_set_gpr(ctx, a->rd, dest);
488     tcg_temp_free(ext2);
489     return true;
490 }
491 
492 static bool gen_shift_per_ol(DisasContext *ctx, arg_r *a, DisasExtend ext,
493                              void (*f_tl)(TCGv, TCGv, TCGv),
494                              void (*f_32)(TCGv, TCGv, TCGv))
495 {
496     int olen = get_olen(ctx);
497     if (olen != TARGET_LONG_BITS) {
498         if (olen == 32) {
499             f_tl = f_32;
500         } else {
501             g_assert_not_reached();
502         }
503     }
504     return gen_shift(ctx, a, ext, f_tl);
505 }
506 
507 static bool gen_unary(DisasContext *ctx, arg_r2 *a, DisasExtend ext,
508                       void (*func)(TCGv, TCGv))
509 {
510     TCGv dest = dest_gpr(ctx, a->rd);
511     TCGv src1 = get_gpr(ctx, a->rs1, ext);
512 
513     func(dest, src1);
514 
515     gen_set_gpr(ctx, a->rd, dest);
516     return true;
517 }
518 
519 static bool gen_unary_per_ol(DisasContext *ctx, arg_r2 *a, DisasExtend ext,
520                              void (*f_tl)(TCGv, TCGv),
521                              void (*f_32)(TCGv, TCGv))
522 {
523     int olen = get_olen(ctx);
524 
525     if (olen != TARGET_LONG_BITS) {
526         if (olen == 32) {
527             f_tl = f_32;
528         } else {
529             g_assert_not_reached();
530         }
531     }
532     return gen_unary(ctx, a, ext, f_tl);
533 }
534 
535 static uint32_t opcode_at(DisasContextBase *dcbase, target_ulong pc)
536 {
537     DisasContext *ctx = container_of(dcbase, DisasContext, base);
538     CPUState *cpu = ctx->cs;
539     CPURISCVState *env = cpu->env_ptr;
540 
541     return cpu_ldl_code(env, pc);
542 }
543 
544 /* Include insn module translation function */
545 #include "insn_trans/trans_rvi.c.inc"
546 #include "insn_trans/trans_rvm.c.inc"
547 #include "insn_trans/trans_rva.c.inc"
548 #include "insn_trans/trans_rvf.c.inc"
549 #include "insn_trans/trans_rvd.c.inc"
550 #include "insn_trans/trans_rvh.c.inc"
551 #include "insn_trans/trans_rvv.c.inc"
552 #include "insn_trans/trans_rvb.c.inc"
553 #include "insn_trans/trans_privileged.c.inc"
554 
555 /* Include the auto-generated decoder for 16 bit insn */
556 #include "decode-insn16.c.inc"
557 
558 static void decode_opc(CPURISCVState *env, DisasContext *ctx, uint16_t opcode)
559 {
560     /* check for compressed insn */
561     if (extract16(opcode, 0, 2) != 3) {
562         if (!has_ext(ctx, RVC)) {
563             gen_exception_illegal(ctx);
564         } else {
565             ctx->pc_succ_insn = ctx->base.pc_next + 2;
566             if (!decode_insn16(ctx, opcode)) {
567                 gen_exception_illegal(ctx);
568             }
569         }
570     } else {
571         uint32_t opcode32 = opcode;
572         opcode32 = deposit32(opcode32, 16, 16,
573                              translator_lduw(env, &ctx->base,
574                                              ctx->base.pc_next + 2));
575         ctx->pc_succ_insn = ctx->base.pc_next + 4;
576         if (!decode_insn32(ctx, opcode32)) {
577             gen_exception_illegal(ctx);
578         }
579     }
580 }
581 
582 static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
583 {
584     DisasContext *ctx = container_of(dcbase, DisasContext, base);
585     CPURISCVState *env = cs->env_ptr;
586     RISCVCPU *cpu = RISCV_CPU(cs);
587     uint32_t tb_flags = ctx->base.tb->flags;
588 
589     ctx->pc_succ_insn = ctx->base.pc_first;
590     ctx->mem_idx = FIELD_EX32(tb_flags, TB_FLAGS, MEM_IDX);
591     ctx->mstatus_fs = tb_flags & TB_FLAGS_MSTATUS_FS;
592     ctx->priv_ver = env->priv_ver;
593 #if !defined(CONFIG_USER_ONLY)
594     if (riscv_has_ext(env, RVH)) {
595         ctx->virt_enabled = riscv_cpu_virt_enabled(env);
596     } else {
597         ctx->virt_enabled = false;
598     }
599 #else
600     ctx->virt_enabled = false;
601 #endif
602     ctx->misa_ext = env->misa_ext;
603     ctx->frm = -1;  /* unknown rounding mode */
604     ctx->ext_ifencei = cpu->cfg.ext_ifencei;
605     ctx->vlen = cpu->cfg.vlen;
606     ctx->mstatus_hs_fs = FIELD_EX32(tb_flags, TB_FLAGS, MSTATUS_HS_FS);
607     ctx->hlsx = FIELD_EX32(tb_flags, TB_FLAGS, HLSX);
608     ctx->vill = FIELD_EX32(tb_flags, TB_FLAGS, VILL);
609     ctx->sew = FIELD_EX32(tb_flags, TB_FLAGS, SEW);
610     ctx->lmul = FIELD_EX32(tb_flags, TB_FLAGS, LMUL);
611     ctx->mlen = 1 << (ctx->sew  + 3 - ctx->lmul);
612     ctx->vl_eq_vlmax = FIELD_EX32(tb_flags, TB_FLAGS, VL_EQ_VLMAX);
613     ctx->xl = FIELD_EX32(tb_flags, TB_FLAGS, XL);
614     ctx->cs = cs;
615     ctx->ntemp = 0;
616     memset(ctx->temp, 0, sizeof(ctx->temp));
617 
618     ctx->zero = tcg_constant_tl(0);
619 }
620 
621 static void riscv_tr_tb_start(DisasContextBase *db, CPUState *cpu)
622 {
623 }
624 
625 static void riscv_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu)
626 {
627     DisasContext *ctx = container_of(dcbase, DisasContext, base);
628 
629     tcg_gen_insn_start(ctx->base.pc_next);
630 }
631 
632 static void riscv_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
633 {
634     DisasContext *ctx = container_of(dcbase, DisasContext, base);
635     CPURISCVState *env = cpu->env_ptr;
636     uint16_t opcode16 = translator_lduw(env, &ctx->base, ctx->base.pc_next);
637 
638     ctx->ol = ctx->xl;
639     decode_opc(env, ctx, opcode16);
640     ctx->base.pc_next = ctx->pc_succ_insn;
641 
642     for (int i = ctx->ntemp - 1; i >= 0; --i) {
643         tcg_temp_free(ctx->temp[i]);
644         ctx->temp[i] = NULL;
645     }
646     ctx->ntemp = 0;
647 
648     if (ctx->base.is_jmp == DISAS_NEXT) {
649         target_ulong page_start;
650 
651         page_start = ctx->base.pc_first & TARGET_PAGE_MASK;
652         if (ctx->base.pc_next - page_start >= TARGET_PAGE_SIZE) {
653             ctx->base.is_jmp = DISAS_TOO_MANY;
654         }
655     }
656 }
657 
658 static void riscv_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
659 {
660     DisasContext *ctx = container_of(dcbase, DisasContext, base);
661 
662     switch (ctx->base.is_jmp) {
663     case DISAS_TOO_MANY:
664         gen_goto_tb(ctx, 0, ctx->base.pc_next);
665         break;
666     case DISAS_NORETURN:
667         break;
668     default:
669         g_assert_not_reached();
670     }
671 }
672 
673 static void riscv_tr_disas_log(const DisasContextBase *dcbase, CPUState *cpu)
674 {
675 #ifndef CONFIG_USER_ONLY
676     RISCVCPU *rvcpu = RISCV_CPU(cpu);
677     CPURISCVState *env = &rvcpu->env;
678 #endif
679 
680     qemu_log("IN: %s\n", lookup_symbol(dcbase->pc_first));
681 #ifndef CONFIG_USER_ONLY
682     qemu_log("Priv: "TARGET_FMT_ld"; Virt: "TARGET_FMT_ld"\n", env->priv, env->virt);
683 #endif
684     log_target_disas(cpu, dcbase->pc_first, dcbase->tb->size);
685 }
686 
687 static const TranslatorOps riscv_tr_ops = {
688     .init_disas_context = riscv_tr_init_disas_context,
689     .tb_start           = riscv_tr_tb_start,
690     .insn_start         = riscv_tr_insn_start,
691     .translate_insn     = riscv_tr_translate_insn,
692     .tb_stop            = riscv_tr_tb_stop,
693     .disas_log          = riscv_tr_disas_log,
694 };
695 
696 void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns)
697 {
698     DisasContext ctx;
699 
700     translator_loop(&riscv_tr_ops, &ctx.base, cs, tb, max_insns);
701 }
702 
703 void riscv_translate_init(void)
704 {
705     int i;
706 
707     /*
708      * cpu_gpr[0] is a placeholder for the zero register. Do not use it.
709      * Use the gen_set_gpr and get_gpr helper functions when accessing regs,
710      * unless you specifically block reads/writes to reg 0.
711      */
712     cpu_gpr[0] = NULL;
713 
714     for (i = 1; i < 32; i++) {
715         cpu_gpr[i] = tcg_global_mem_new(cpu_env,
716             offsetof(CPURISCVState, gpr[i]), riscv_int_regnames[i]);
717     }
718 
719     for (i = 0; i < 32; i++) {
720         cpu_fpr[i] = tcg_global_mem_new_i64(cpu_env,
721             offsetof(CPURISCVState, fpr[i]), riscv_fpr_regnames[i]);
722     }
723 
724     cpu_pc = tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, pc), "pc");
725     cpu_vl = tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, vl), "vl");
726     load_res = tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, load_res),
727                              "load_res");
728     load_val = tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, load_val),
729                              "load_val");
730 }
731