xref: /openbmc/qemu/target/riscv/translate.c (revision c655df7f)
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 /*
275  * Temp stub: generates address adjustment for PointerMasking
276  */
277 static TCGv gen_pm_adjust_address(DisasContext *s, TCGv src)
278 {
279     return src;
280 }
281 
282 #ifndef CONFIG_USER_ONLY
283 /* The states of mstatus_fs are:
284  * 0 = disabled, 1 = initial, 2 = clean, 3 = dirty
285  * We will have already diagnosed disabled state,
286  * and need to turn initial/clean into dirty.
287  */
288 static void mark_fs_dirty(DisasContext *ctx)
289 {
290     TCGv tmp;
291 
292     if (ctx->mstatus_fs != MSTATUS_FS) {
293         /* Remember the state change for the rest of the TB. */
294         ctx->mstatus_fs = MSTATUS_FS;
295 
296         tmp = tcg_temp_new();
297         tcg_gen_ld_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus));
298         tcg_gen_ori_tl(tmp, tmp, MSTATUS_FS);
299         tcg_gen_st_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus));
300         tcg_temp_free(tmp);
301     }
302 
303     if (ctx->virt_enabled && ctx->mstatus_hs_fs != MSTATUS_FS) {
304         /* Remember the stage change for the rest of the TB. */
305         ctx->mstatus_hs_fs = MSTATUS_FS;
306 
307         tmp = tcg_temp_new();
308         tcg_gen_ld_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus_hs));
309         tcg_gen_ori_tl(tmp, tmp, MSTATUS_FS);
310         tcg_gen_st_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus_hs));
311         tcg_temp_free(tmp);
312     }
313 }
314 #else
315 static inline void mark_fs_dirty(DisasContext *ctx) { }
316 #endif
317 
318 static void gen_set_rm(DisasContext *ctx, int rm)
319 {
320     if (ctx->frm == rm) {
321         return;
322     }
323     ctx->frm = rm;
324     gen_helper_set_rounding_mode(cpu_env, tcg_constant_i32(rm));
325 }
326 
327 static int ex_plus_1(DisasContext *ctx, int nf)
328 {
329     return nf + 1;
330 }
331 
332 #define EX_SH(amount) \
333     static int ex_shift_##amount(DisasContext *ctx, int imm) \
334     {                                         \
335         return imm << amount;                 \
336     }
337 EX_SH(1)
338 EX_SH(2)
339 EX_SH(3)
340 EX_SH(4)
341 EX_SH(12)
342 
343 #define REQUIRE_EXT(ctx, ext) do { \
344     if (!has_ext(ctx, ext)) {      \
345         return false;              \
346     }                              \
347 } while (0)
348 
349 #define REQUIRE_32BIT(ctx) do {    \
350     if (get_xl(ctx) != MXL_RV32) { \
351         return false;              \
352     }                              \
353 } while (0)
354 
355 #define REQUIRE_64BIT(ctx) do {    \
356     if (get_xl(ctx) < MXL_RV64) {  \
357         return false;              \
358     }                              \
359 } while (0)
360 
361 static int ex_rvc_register(DisasContext *ctx, int reg)
362 {
363     return 8 + reg;
364 }
365 
366 static int ex_rvc_shifti(DisasContext *ctx, int imm)
367 {
368     /* For RV128 a shamt of 0 means a shift by 64. */
369     return imm ? imm : 64;
370 }
371 
372 /* Include the auto-generated decoder for 32 bit insn */
373 #include "decode-insn32.c.inc"
374 
375 static bool gen_arith_imm_fn(DisasContext *ctx, arg_i *a, DisasExtend ext,
376                              void (*func)(TCGv, TCGv, target_long))
377 {
378     TCGv dest = dest_gpr(ctx, a->rd);
379     TCGv src1 = get_gpr(ctx, a->rs1, ext);
380 
381     func(dest, src1, a->imm);
382 
383     gen_set_gpr(ctx, a->rd, dest);
384     return true;
385 }
386 
387 static bool gen_arith_imm_tl(DisasContext *ctx, arg_i *a, DisasExtend ext,
388                              void (*func)(TCGv, TCGv, TCGv))
389 {
390     TCGv dest = dest_gpr(ctx, a->rd);
391     TCGv src1 = get_gpr(ctx, a->rs1, ext);
392     TCGv src2 = tcg_constant_tl(a->imm);
393 
394     func(dest, src1, src2);
395 
396     gen_set_gpr(ctx, a->rd, dest);
397     return true;
398 }
399 
400 static bool gen_arith(DisasContext *ctx, arg_r *a, DisasExtend ext,
401                       void (*func)(TCGv, TCGv, TCGv))
402 {
403     TCGv dest = dest_gpr(ctx, a->rd);
404     TCGv src1 = get_gpr(ctx, a->rs1, ext);
405     TCGv src2 = get_gpr(ctx, a->rs2, ext);
406 
407     func(dest, src1, src2);
408 
409     gen_set_gpr(ctx, a->rd, dest);
410     return true;
411 }
412 
413 static bool gen_arith_per_ol(DisasContext *ctx, arg_r *a, DisasExtend ext,
414                              void (*f_tl)(TCGv, TCGv, TCGv),
415                              void (*f_32)(TCGv, TCGv, TCGv))
416 {
417     int olen = get_olen(ctx);
418 
419     if (olen != TARGET_LONG_BITS) {
420         if (olen == 32) {
421             f_tl = f_32;
422         } else {
423             g_assert_not_reached();
424         }
425     }
426     return gen_arith(ctx, a, ext, f_tl);
427 }
428 
429 static bool gen_shift_imm_fn(DisasContext *ctx, arg_shift *a, DisasExtend ext,
430                              void (*func)(TCGv, TCGv, target_long))
431 {
432     TCGv dest, src1;
433     int max_len = get_olen(ctx);
434 
435     if (a->shamt >= max_len) {
436         return false;
437     }
438 
439     dest = dest_gpr(ctx, a->rd);
440     src1 = get_gpr(ctx, a->rs1, ext);
441 
442     func(dest, src1, a->shamt);
443 
444     gen_set_gpr(ctx, a->rd, dest);
445     return true;
446 }
447 
448 static bool gen_shift_imm_fn_per_ol(DisasContext *ctx, arg_shift *a,
449                                     DisasExtend ext,
450                                     void (*f_tl)(TCGv, TCGv, target_long),
451                                     void (*f_32)(TCGv, TCGv, target_long))
452 {
453     int olen = get_olen(ctx);
454     if (olen != TARGET_LONG_BITS) {
455         if (olen == 32) {
456             f_tl = f_32;
457         } else {
458             g_assert_not_reached();
459         }
460     }
461     return gen_shift_imm_fn(ctx, a, ext, f_tl);
462 }
463 
464 static bool gen_shift_imm_tl(DisasContext *ctx, arg_shift *a, DisasExtend ext,
465                              void (*func)(TCGv, TCGv, TCGv))
466 {
467     TCGv dest, src1, src2;
468     int max_len = get_olen(ctx);
469 
470     if (a->shamt >= max_len) {
471         return false;
472     }
473 
474     dest = dest_gpr(ctx, a->rd);
475     src1 = get_gpr(ctx, a->rs1, ext);
476     src2 = tcg_constant_tl(a->shamt);
477 
478     func(dest, src1, src2);
479 
480     gen_set_gpr(ctx, a->rd, dest);
481     return true;
482 }
483 
484 static bool gen_shift(DisasContext *ctx, arg_r *a, DisasExtend ext,
485                       void (*func)(TCGv, TCGv, TCGv))
486 {
487     TCGv dest = dest_gpr(ctx, a->rd);
488     TCGv src1 = get_gpr(ctx, a->rs1, ext);
489     TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE);
490     TCGv ext2 = tcg_temp_new();
491 
492     tcg_gen_andi_tl(ext2, src2, get_olen(ctx) - 1);
493     func(dest, src1, ext2);
494 
495     gen_set_gpr(ctx, a->rd, dest);
496     tcg_temp_free(ext2);
497     return true;
498 }
499 
500 static bool gen_shift_per_ol(DisasContext *ctx, arg_r *a, DisasExtend ext,
501                              void (*f_tl)(TCGv, TCGv, TCGv),
502                              void (*f_32)(TCGv, TCGv, TCGv))
503 {
504     int olen = get_olen(ctx);
505     if (olen != TARGET_LONG_BITS) {
506         if (olen == 32) {
507             f_tl = f_32;
508         } else {
509             g_assert_not_reached();
510         }
511     }
512     return gen_shift(ctx, a, ext, f_tl);
513 }
514 
515 static bool gen_unary(DisasContext *ctx, arg_r2 *a, DisasExtend ext,
516                       void (*func)(TCGv, TCGv))
517 {
518     TCGv dest = dest_gpr(ctx, a->rd);
519     TCGv src1 = get_gpr(ctx, a->rs1, ext);
520 
521     func(dest, src1);
522 
523     gen_set_gpr(ctx, a->rd, dest);
524     return true;
525 }
526 
527 static bool gen_unary_per_ol(DisasContext *ctx, arg_r2 *a, DisasExtend ext,
528                              void (*f_tl)(TCGv, TCGv),
529                              void (*f_32)(TCGv, TCGv))
530 {
531     int olen = get_olen(ctx);
532 
533     if (olen != TARGET_LONG_BITS) {
534         if (olen == 32) {
535             f_tl = f_32;
536         } else {
537             g_assert_not_reached();
538         }
539     }
540     return gen_unary(ctx, a, ext, f_tl);
541 }
542 
543 static uint32_t opcode_at(DisasContextBase *dcbase, target_ulong pc)
544 {
545     DisasContext *ctx = container_of(dcbase, DisasContext, base);
546     CPUState *cpu = ctx->cs;
547     CPURISCVState *env = cpu->env_ptr;
548 
549     return cpu_ldl_code(env, pc);
550 }
551 
552 /* Include insn module translation function */
553 #include "insn_trans/trans_rvi.c.inc"
554 #include "insn_trans/trans_rvm.c.inc"
555 #include "insn_trans/trans_rva.c.inc"
556 #include "insn_trans/trans_rvf.c.inc"
557 #include "insn_trans/trans_rvd.c.inc"
558 #include "insn_trans/trans_rvh.c.inc"
559 #include "insn_trans/trans_rvv.c.inc"
560 #include "insn_trans/trans_rvb.c.inc"
561 #include "insn_trans/trans_privileged.c.inc"
562 
563 /* Include the auto-generated decoder for 16 bit insn */
564 #include "decode-insn16.c.inc"
565 
566 static void decode_opc(CPURISCVState *env, DisasContext *ctx, uint16_t opcode)
567 {
568     /* check for compressed insn */
569     if (extract16(opcode, 0, 2) != 3) {
570         if (!has_ext(ctx, RVC)) {
571             gen_exception_illegal(ctx);
572         } else {
573             ctx->pc_succ_insn = ctx->base.pc_next + 2;
574             if (!decode_insn16(ctx, opcode)) {
575                 gen_exception_illegal(ctx);
576             }
577         }
578     } else {
579         uint32_t opcode32 = opcode;
580         opcode32 = deposit32(opcode32, 16, 16,
581                              translator_lduw(env, &ctx->base,
582                                              ctx->base.pc_next + 2));
583         ctx->pc_succ_insn = ctx->base.pc_next + 4;
584         if (!decode_insn32(ctx, opcode32)) {
585             gen_exception_illegal(ctx);
586         }
587     }
588 }
589 
590 static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
591 {
592     DisasContext *ctx = container_of(dcbase, DisasContext, base);
593     CPURISCVState *env = cs->env_ptr;
594     RISCVCPU *cpu = RISCV_CPU(cs);
595     uint32_t tb_flags = ctx->base.tb->flags;
596 
597     ctx->pc_succ_insn = ctx->base.pc_first;
598     ctx->mem_idx = FIELD_EX32(tb_flags, TB_FLAGS, MEM_IDX);
599     ctx->mstatus_fs = tb_flags & TB_FLAGS_MSTATUS_FS;
600     ctx->priv_ver = env->priv_ver;
601 #if !defined(CONFIG_USER_ONLY)
602     if (riscv_has_ext(env, RVH)) {
603         ctx->virt_enabled = riscv_cpu_virt_enabled(env);
604     } else {
605         ctx->virt_enabled = false;
606     }
607 #else
608     ctx->virt_enabled = false;
609 #endif
610     ctx->misa_ext = env->misa_ext;
611     ctx->frm = -1;  /* unknown rounding mode */
612     ctx->ext_ifencei = cpu->cfg.ext_ifencei;
613     ctx->vlen = cpu->cfg.vlen;
614     ctx->mstatus_hs_fs = FIELD_EX32(tb_flags, TB_FLAGS, MSTATUS_HS_FS);
615     ctx->hlsx = FIELD_EX32(tb_flags, TB_FLAGS, HLSX);
616     ctx->vill = FIELD_EX32(tb_flags, TB_FLAGS, VILL);
617     ctx->sew = FIELD_EX32(tb_flags, TB_FLAGS, SEW);
618     ctx->lmul = FIELD_EX32(tb_flags, TB_FLAGS, LMUL);
619     ctx->mlen = 1 << (ctx->sew  + 3 - ctx->lmul);
620     ctx->vl_eq_vlmax = FIELD_EX32(tb_flags, TB_FLAGS, VL_EQ_VLMAX);
621     ctx->xl = FIELD_EX32(tb_flags, TB_FLAGS, XL);
622     ctx->cs = cs;
623     ctx->ntemp = 0;
624     memset(ctx->temp, 0, sizeof(ctx->temp));
625 
626     ctx->zero = tcg_constant_tl(0);
627 }
628 
629 static void riscv_tr_tb_start(DisasContextBase *db, CPUState *cpu)
630 {
631 }
632 
633 static void riscv_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu)
634 {
635     DisasContext *ctx = container_of(dcbase, DisasContext, base);
636 
637     tcg_gen_insn_start(ctx->base.pc_next);
638 }
639 
640 static void riscv_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
641 {
642     DisasContext *ctx = container_of(dcbase, DisasContext, base);
643     CPURISCVState *env = cpu->env_ptr;
644     uint16_t opcode16 = translator_lduw(env, &ctx->base, ctx->base.pc_next);
645 
646     ctx->ol = ctx->xl;
647     decode_opc(env, ctx, opcode16);
648     ctx->base.pc_next = ctx->pc_succ_insn;
649 
650     for (int i = ctx->ntemp - 1; i >= 0; --i) {
651         tcg_temp_free(ctx->temp[i]);
652         ctx->temp[i] = NULL;
653     }
654     ctx->ntemp = 0;
655 
656     if (ctx->base.is_jmp == DISAS_NEXT) {
657         target_ulong page_start;
658 
659         page_start = ctx->base.pc_first & TARGET_PAGE_MASK;
660         if (ctx->base.pc_next - page_start >= TARGET_PAGE_SIZE) {
661             ctx->base.is_jmp = DISAS_TOO_MANY;
662         }
663     }
664 }
665 
666 static void riscv_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
667 {
668     DisasContext *ctx = container_of(dcbase, DisasContext, base);
669 
670     switch (ctx->base.is_jmp) {
671     case DISAS_TOO_MANY:
672         gen_goto_tb(ctx, 0, ctx->base.pc_next);
673         break;
674     case DISAS_NORETURN:
675         break;
676     default:
677         g_assert_not_reached();
678     }
679 }
680 
681 static void riscv_tr_disas_log(const DisasContextBase *dcbase, CPUState *cpu)
682 {
683 #ifndef CONFIG_USER_ONLY
684     RISCVCPU *rvcpu = RISCV_CPU(cpu);
685     CPURISCVState *env = &rvcpu->env;
686 #endif
687 
688     qemu_log("IN: %s\n", lookup_symbol(dcbase->pc_first));
689 #ifndef CONFIG_USER_ONLY
690     qemu_log("Priv: "TARGET_FMT_ld"; Virt: "TARGET_FMT_ld"\n", env->priv, env->virt);
691 #endif
692     log_target_disas(cpu, dcbase->pc_first, dcbase->tb->size);
693 }
694 
695 static const TranslatorOps riscv_tr_ops = {
696     .init_disas_context = riscv_tr_init_disas_context,
697     .tb_start           = riscv_tr_tb_start,
698     .insn_start         = riscv_tr_insn_start,
699     .translate_insn     = riscv_tr_translate_insn,
700     .tb_stop            = riscv_tr_tb_stop,
701     .disas_log          = riscv_tr_disas_log,
702 };
703 
704 void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns)
705 {
706     DisasContext ctx;
707 
708     translator_loop(&riscv_tr_ops, &ctx.base, cs, tb, max_insns);
709 }
710 
711 void riscv_translate_init(void)
712 {
713     int i;
714 
715     /*
716      * cpu_gpr[0] is a placeholder for the zero register. Do not use it.
717      * Use the gen_set_gpr and get_gpr helper functions when accessing regs,
718      * unless you specifically block reads/writes to reg 0.
719      */
720     cpu_gpr[0] = NULL;
721 
722     for (i = 1; i < 32; i++) {
723         cpu_gpr[i] = tcg_global_mem_new(cpu_env,
724             offsetof(CPURISCVState, gpr[i]), riscv_int_regnames[i]);
725     }
726 
727     for (i = 0; i < 32; i++) {
728         cpu_fpr[i] = tcg_global_mem_new_i64(cpu_env,
729             offsetof(CPURISCVState, fpr[i]), riscv_fpr_regnames[i]);
730     }
731 
732     cpu_pc = tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, pc), "pc");
733     cpu_vl = tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, vl), "vl");
734     load_res = tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, load_res),
735                              "load_res");
736     load_val = tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, load_val),
737                              "load_val");
738 }
739