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


Reply via email to