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