cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

translate.c (18790B)


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