Add tcg and cpu model initialization Add gen_intermediate_code function, dummy decode_opc Add exception helpers necessary for gen_intermediate_code
Signed-off-by: Sagar Karandikar <sag...@eecs.berkeley.edu> --- target-riscv/helper.h | 4 + target-riscv/op_helper.c | 26 +++++ target-riscv/translate.c | 244 ++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 273 insertions(+), 1 deletion(-) diff --git a/target-riscv/helper.h b/target-riscv/helper.h index e69de29..0461118 100644 --- a/target-riscv/helper.h +++ b/target-riscv/helper.h @@ -0,0 +1,4 @@ +/* Exceptions */ +DEF_HELPER_2(raise_exception, noreturn, env, i32) +DEF_HELPER_1(raise_exception_debug, noreturn, env) +DEF_HELPER_3(raise_exception_mbadaddr, noreturn, env, i32, tl) diff --git a/target-riscv/op_helper.c b/target-riscv/op_helper.c index c77a520..fd1ef3c 100644 --- a/target-riscv/op_helper.c +++ b/target-riscv/op_helper.c @@ -24,6 +24,32 @@ #include "qemu/host-utils.h" #include "exec/helper-proto.h" +/* Exceptions processing helpers */ +static inline void QEMU_NORETURN do_raise_exception_err(CPURISCVState *env, + uint32_t exception, uintptr_t pc) +{ + CPUState *cs = CPU(riscv_env_get_cpu(env)); + qemu_log_mask(CPU_LOG_INT, "%s: %d\n", __func__, exception); + cs->exception_index = exception; + cpu_loop_exit_restore(cs, pc); +} + +void helper_raise_exception(CPURISCVState *env, uint32_t exception) +{ + do_raise_exception_err(env, exception, 0); +} + +void helper_raise_exception_debug(CPURISCVState *env) +{ + do_raise_exception_err(env, EXCP_DEBUG, 0); +} + +void helper_raise_exception_mbadaddr(CPURISCVState *env, uint32_t exception, + target_ulong bad_pc) { + env->badaddr = bad_pc; + do_raise_exception_err(env, exception, 0); +} + #ifndef CONFIG_USER_ONLY void riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr, MMUAccessType access_type, int mmu_idx, diff --git a/target-riscv/translate.c b/target-riscv/translate.c index b50c662..8413c39 100644 --- a/target-riscv/translate.c +++ b/target-riscv/translate.c @@ -27,6 +27,35 @@ #include "exec/helper-proto.h" #include "exec/helper-gen.h" +#define RISCV_DEBUG_DISAS 0 + +/* global register indices */ +static TCGv_ptr cpu_env; +static TCGv cpu_gpr[32], cpu_PC; +static TCGv_i64 cpu_fpr[32]; /* assume F and D extensions */ +static TCGv load_res; + +#include "exec/gen-icount.h" + +typedef struct DisasContext { + struct TranslationBlock *tb; + target_ulong pc; + uint32_t opcode; + int singlestep_enabled; + int mem_idx; + int bstate; +} DisasContext; + +static inline void kill_unknown(DisasContext *ctx, int excp); + +enum { + BS_NONE = 0, /* When seen outside of translation while loop, indicates + need to exit tb due to end of page. */ + BS_STOP = 1, /* Need to exit tb for syscall, sret, etc. */ + BS_BRANCH = 2, /* Need to exit tb for branch, jal, etc. */ +}; + + static const char * const regnames[] = { "zero", "ra ", "sp ", "gp ", "tp ", "t0 ", "t1 ", "t2 ", "s0 ", "s1 ", "a0 ", "a1 ", "a2 ", "a3 ", "a4 ", "a5 ", @@ -41,8 +70,160 @@ static const char * const fpr_regnames[] = { "fs8", "fs9", "fs10", "fs11", "ft8", "ft9", "ft10", "ft11" }; +static inline void generate_exception(DisasContext *ctx, int excp) +{ + tcg_gen_movi_tl(cpu_PC, ctx->pc); + TCGv_i32 helper_tmp = tcg_const_i32(excp); + gen_helper_raise_exception(cpu_env, helper_tmp); + tcg_temp_free_i32(helper_tmp); +} + +static inline void generate_exception_mbadaddr(DisasContext *ctx, int excp) +{ + tcg_gen_movi_tl(cpu_PC, ctx->pc); + TCGv_i32 helper_tmp = tcg_const_i32(excp); + gen_helper_raise_exception_mbadaddr(cpu_env, helper_tmp, cpu_PC); + tcg_temp_free_i32(helper_tmp); +} + +/* unknown instruction */ +static inline void kill_unknown(DisasContext *ctx, int excp) +{ + generate_exception(ctx, excp); + ctx->bstate = BS_STOP; +} + +static inline bool use_goto_tb(DisasContext *ctx, target_ulong dest) +{ + if (unlikely(ctx->singlestep_enabled)) { + return false; + } + +#ifndef CONFIG_USER_ONLY + return (ctx->tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK); +#else + return true; +#endif +} + +static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) +{ + if (use_goto_tb(ctx, dest)) { + /* chaining is only allowed when the jump is to the same page */ + tcg_gen_goto_tb(n); + tcg_gen_movi_tl(cpu_PC, dest); + tcg_gen_exit_tb((uintptr_t)ctx->tb + n); + } else { + tcg_gen_movi_tl(cpu_PC, dest); + if (ctx->singlestep_enabled) { + gen_helper_raise_exception_debug(cpu_env); + } + tcg_gen_exit_tb(0); + } +} + +static void decode_opc(CPURISCVState *env, DisasContext *ctx) +{ +} + void gen_intermediate_code(CPURISCVState *env, TranslationBlock *tb) { + RISCVCPU *cpu = riscv_env_get_cpu(env); + CPUState *cs = CPU(cpu); + DisasContext ctx; + target_ulong pc_start; + target_ulong next_page_start; + int num_insns; + int max_insns; + pc_start = tb->pc; + next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE; + ctx.pc = pc_start; + + /* once we have GDB, the rest of the translate.c implementation should be + ready for singlestep */ + ctx.singlestep_enabled = cs->singlestep_enabled; + + ctx.tb = tb; + ctx.bstate = BS_NONE; + + ctx.mem_idx = cpu_mmu_index(env, false); + num_insns = 0; + max_insns = tb->cflags & CF_COUNT_MASK; + if (max_insns == 0) { + max_insns = CF_COUNT_MASK; + } + if (max_insns > TCG_MAX_INSNS) { + max_insns = TCG_MAX_INSNS; + } + gen_tb_start(tb); + + while (ctx.bstate == BS_NONE) { + tcg_gen_insn_start(ctx.pc); + num_insns++; + + if (unlikely(cpu_breakpoint_test(cs, ctx.pc, BP_ANY))) { + tcg_gen_movi_tl(cpu_PC, ctx.pc); + ctx.bstate = BS_BRANCH; + gen_helper_raise_exception_debug(cpu_env); + /* The address covered by the breakpoint must be included in + [tb->pc, tb->pc + tb->size) in order to for it to be + properly cleared -- thus we increment the PC here so that + the logic setting tb->size below does the right thing. */ + ctx.pc += 4; + goto done_generating; + } + + if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) { + gen_io_start(); + } + + ctx.opcode = cpu_ldl_code(env, ctx.pc); + decode_opc(env, &ctx); + ctx.pc += 4; + + if (cs->singlestep_enabled) { + break; + } + if (ctx.pc >= next_page_start) { + break; + } + if (tcg_op_buf_full()) { + break; + } + if (num_insns >= max_insns) { + break; + } + if (singlestep) { + break; + } + + } + if (tb->cflags & CF_LAST_IO) { + gen_io_end(); + } + if (cs->singlestep_enabled && ctx.bstate != BS_BRANCH) { + if (ctx.bstate == BS_NONE) { + tcg_gen_movi_tl(cpu_PC, ctx.pc); + } + gen_helper_raise_exception_debug(cpu_env); + } else { + switch (ctx.bstate) { + case BS_STOP: + gen_goto_tb(&ctx, 0, ctx.pc); + break; + case BS_NONE: /* handle end of page - DO NOT CHAIN. See gen_goto_tb. */ + tcg_gen_movi_tl(cpu_PC, ctx.pc); + tcg_gen_exit_tb(0); + break; + case BS_BRANCH: /* ops using BS_BRANCH generate own exit seq */ + default: + break; + } + } +done_generating: + gen_tb_end(tb, num_insns); + tb->size = ctx.pc - pc_start; + tb->icount = num_insns; } void riscv_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, @@ -78,6 +259,34 @@ void riscv_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, void riscv_tcg_init(void) { + int i; + static int inited; + + /* Initialize various static tables. */ + if (inited) { + return; + } + + cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env"); + + /* WARNING: cpu_gpr[0] is not allocated ON PURPOSE. Do not use it. */ + /* Use the gen_set_gpr and gen_get_gpr helper functions when accessing */ + /* registers, unless you specifically block reads/writes to reg 0 */ + TCGV_UNUSED(cpu_gpr[0]); + for (i = 1; i < 32; i++) { + cpu_gpr[i] = tcg_global_mem_new(cpu_env, + offsetof(CPURISCVState, gpr[i]), regnames[i]); + } + + for (i = 0; i < 32; i++) { + cpu_fpr[i] = tcg_global_mem_new_i64(cpu_env, + offsetof(CPURISCVState, fpr[i]), fpr_regnames[i]); + } + + cpu_PC = tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, PC), "PC"); + load_res = tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, load_res), + "load_res"); + inited = 1; } #define MCPUID_RV64I (2L << (TARGET_LONG_BITS - 2)) @@ -111,6 +320,17 @@ static const riscv_def_t riscv_defs[] = { }, }; +static const riscv_def_t *cpu_riscv_find_by_name(const char *name) +{ + int i; + for (i = 0; i < ARRAY_SIZE(riscv_defs); i++) { + if (strcasecmp(name, riscv_defs[i].name) == 0) { + return &riscv_defs[i]; + } + } + return NULL; +} + void riscv_cpu_list(FILE *f, fprintf_function cpu_fprintf) { int i; @@ -121,7 +341,29 @@ void riscv_cpu_list(FILE *f, fprintf_function cpu_fprintf) RISCVCPU *cpu_riscv_init(const char *cpu_model) { - return NULL; + RISCVCPU *cpu; + CPURISCVState *env; + const riscv_def_t *def; + + def = cpu_riscv_find_by_name(cpu_model); + if (!def) { + return NULL; + } + cpu = RISCV_CPU(object_new(TYPE_RISCV_CPU)); + env = &cpu->env; + env->cpu_model = def; + + memset(env->csr, 0, 4096 * sizeof(target_ulong)); + env->priv = PRV_M; + + /* set mcpuid from def */ + env->csr[CSR_MISA] = def->init_misa_reg; + object_property_set_bool(OBJECT(cpu), true, "realized", NULL); + + /* fpu flags: */ + set_default_nan_mode(1, &env->fp_status); + + return cpu; } void restore_state_to_opc(CPURISCVState *env, TranslationBlock *tb, -- 2.9.3