Patchwork [RFC,03/28] target-xtensa: implement disas_xtensa_insn

login
register
mail settings
Submitter Max Filippov
Date May 4, 2011, 12:59 a.m.
Message ID <1304470768-16924-3-git-send-email-jcmvbkbc@gmail.com>
Download mbox | patch
Permalink /patch/93936/
State New
Headers show

Comments

Max Filippov - May 4, 2011, 12:59 a.m.
Set up disas_xtensa_insn switch structure, mark required options on high
level groups. Implement arithmetic/bit logic/jump/call0.

Implement code generation loop with single step/breakpoint checking.

Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
---
 target-xtensa/cpu.h       |   60 +++++++
 target-xtensa/helper.c    |   27 +++-
 target-xtensa/helpers.h   |    5 +
 target-xtensa/op_helper.c |    7 +
 target-xtensa/translate.c |  374 +++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 471 insertions(+), 2 deletions(-)
 create mode 100644 target-xtensa/helpers.h
Richard Henderson - May 4, 2011, 3:39 p.m.
On 05/03/2011 05:59 PM, Max Filippov wrote:
> +static void gen_jump(DisasContext *dc, TCGv dest)
> +{
> +    tcg_gen_mov_i32(cpu_pc, dest);
> +    if (dc->singlestep_enabled) {
> +        gen_exception(EXCP_DEBUG);
> +    }
> +    tcg_gen_exit_tb(0);
> +    dc->is_jmp = DISAS_UPDATE;

You're generating useless instructions here.  The exception
is a noreturn function.  It performs a longjmp to back out
of the cpu loop.

Thus the exit_tb should be in an else here.

> +invalid_opcode:
> +    printf("INVALID(pc = %08x): %s:%d\n", dc->pc, __FILE__, __LINE__);

Don't printf.  Use the logging functions properly.


r~

Patch

diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h
index ef6881a..cf19fce 100644
--- a/target-xtensa/cpu.h
+++ b/target-xtensa/cpu.h
@@ -45,7 +45,67 @@ 
 #define TARGET_VIRT_ADDR_SPACE_BITS 32
 #define TARGET_PAGE_BITS 12
 
+enum {
+    /* Additional instructions */
+    XTENSA_OPTION_CODE_DENSITY,
+    XTENSA_OPTION_LOOP,
+    XTENSA_OPTION_EXTENDED_L32R,
+    XTENSA_OPTION_16_BIT_IMUL,
+    XTENSA_OPTION_32_BIT_IMUL,
+    XTENSA_OPTION_32_BIT_IDIV,
+    XTENSA_OPTION_MAC16,
+    XTENSA_OPTION_MISC_OP,
+    XTENSA_OPTION_COPROCESSOR,
+    XTENSA_OPTION_BOOLEAN,
+    XTENSA_OPTION_FP_COPROCESSOR,
+    XTENSA_OPTION_MP_SYNCHRO,
+    XTENSA_OPTION_CONDITIONAL_STORE,
+
+    /* Interrupts and exceptions */
+    XTENSA_OPTION_EXCEPTION,
+    XTENSA_OPTION_RELOCATABLE_VECTOR,
+    XTENSA_OPTION_UNALIGNED_EXCEPTION,
+    XTENSA_OPTION_INTERRUPT,
+    XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+    XTENSA_OPTION_TIMER_INTERRUPT,
+
+    /* Local memory */
+    XTENSA_OPTION_ICACHE,
+    XTENSA_OPTION_ICACHE_TEST,
+    XTENSA_OPTION_ICACHE_INDEX_LOCK,
+    XTENSA_OPTION_DCACHE,
+    XTENSA_OPTION_DCACHE_TEST,
+    XTENSA_OPTION_DCACHE_INDEX_LOCK,
+    XTENSA_OPTION_IRAM,
+    XTENSA_OPTION_IROM,
+    XTENSA_OPTION_DRAM,
+    XTENSA_OPTION_DROM,
+    XTENSA_OPTION_XLMI,
+    XTENSA_OPTION_HW_ALIGNMENT,
+    XTENSA_OPTION_MEMORY_ECC_PARITY,
+
+    /* Memory protection and translation */
+    XTENSA_OPTION_REGION_PROTECTION,
+    XTENSA_OPTION_REGION_TRANSLATION,
+    XTENSA_OPTION_MMU,
+
+    /* Other */
+    XTENSA_OPTION_WINDOWED_REGISTER,
+    XTENSA_OPTION_PROCESSOR_INTERFACE,
+    XTENSA_OPTION_MISC_SR,
+    XTENSA_OPTION_THREAD_POINTER,
+    XTENSA_OPTION_PROCESSOR_ID,
+    XTENSA_OPTION_DEBUG,
+    XTENSA_OPTIN_TRACE_PORT,
+};
+
+typedef struct XtensaConfig {
+    const char *name;
+    uint64_t options;
+} XtensaConfig;
+
 typedef struct CPUXtensaState {
+    const XtensaConfig *config;
     uint32_t regs[16];
     uint32_t pc;
     uint32_t sregs[256];
diff --git a/target-xtensa/helper.c b/target-xtensa/helper.c
index 6b6e17b..6f374d3 100644
--- a/target-xtensa/helper.c
+++ b/target-xtensa/helper.c
@@ -39,12 +39,32 @@  void cpu_reset(CPUXtensaState *env)
     env->pc = 0;
 }
 
+static const XtensaConfig core_config[] = {
+    {
+        .name = "sample-xtensa-core",
+        .options = -1,
+    },
+};
+
 CPUXtensaState *cpu_xtensa_init(const char *cpu_model)
 {
     static int tcg_inited;
     CPUXtensaState *env;
+    const XtensaConfig *config = NULL;
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(core_config); ++i)
+        if (strcmp(core_config[i].name, cpu_model) == 0) {
+            config = core_config + i;
+            break;
+        }
+
+    if (config == NULL) {
+        return NULL;
+    }
 
     env = qemu_mallocz(sizeof(*env));
+    env->config = config;
     cpu_exec_init(env);
 
     if (!tcg_inited) {
@@ -60,8 +80,11 @@  CPUXtensaState *cpu_xtensa_init(const char *cpu_model)
 
 void xtensa_cpu_list(FILE *f, fprintf_function cpu_fprintf)
 {
-    cpu_fprintf(f, "Available CPUs:\n"
-            "  Xtensa core\n");
+    int i;
+    cpu_fprintf(f, "Available CPUs:\n");
+    for (i = 0; i < ARRAY_SIZE(core_config); ++i) {
+        cpu_fprintf(f, "  %s\n", core_config[i].name);
+    }
 }
 
 target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
diff --git a/target-xtensa/helpers.h b/target-xtensa/helpers.h
new file mode 100644
index 0000000..c298d74
--- /dev/null
+++ b/target-xtensa/helpers.h
@@ -0,0 +1,5 @@ 
+#include "def-helper.h"
+
+DEF_HELPER_1(exception, void, i32)
+
+#include "def-helper.h"
diff --git a/target-xtensa/op_helper.c b/target-xtensa/op_helper.c
index 5a0e068..d1e620c 100644
--- a/target-xtensa/op_helper.c
+++ b/target-xtensa/op_helper.c
@@ -26,6 +26,7 @@ 
  */
 
 #include "exec.h"
+#include "helpers.h"
 
 #define MMUSUFFIX _mmu
 
@@ -49,3 +50,9 @@  void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr)
             PAGE_READ | PAGE_WRITE | PAGE_EXEC,
             mmu_idx, TARGET_PAGE_SIZE);
 }
+
+void HELPER(exception)(uint32_t excp)
+{
+    env->exception_index = excp;
+    cpu_loop_exit();
+}
diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c
index c47feab..16efcfd 100644
--- a/target-xtensa/translate.c
+++ b/target-xtensa/translate.c
@@ -36,17 +36,391 @@ 
 #include "tcg-op.h"
 #include "qemu-log.h"
 
+#include "helpers.h"
+#define GEN_HELPER 1
+#include "helpers.h"
+
+typedef struct DisasContext {
+    const XtensaConfig *config;
+    TranslationBlock *tb;
+    uint32_t pc;
+    int is_jmp;
+    int singlestep_enabled;
+} DisasContext;
+
+static TCGv_ptr cpu_env;
+static TCGv_i32 cpu_pc;
+static TCGv_i32 cpu_R[16];
+
+#include "gen-icount.h"
 
 void xtensa_translate_init(void)
 {
+    static const char * const regnames[] = {
+        "ar0", "ar1", "ar2", "ar3",
+        "ar4", "ar5", "ar6", "ar7",
+        "ar8", "ar9", "ar10", "ar11",
+        "ar12", "ar13", "ar14", "ar15",
+    };
+    int i;
+
+    cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
+    cpu_pc = tcg_global_mem_new_i32(TCG_AREG0,
+            offsetof(CPUState, pc), "pc");
+
+    for (i = 0; i < 16; i++) {
+        cpu_R[i] = tcg_global_mem_new_i32(TCG_AREG0,
+                offsetof(CPUState, regs[i]),
+                regnames[i]);
+    }
+}
+
+static void gen_exception(int excp)
+{
+    TCGv_i32 tmp = tcg_const_i32(excp);
+    gen_helper_exception(tmp);
+    tcg_temp_free(tmp);
+}
+
+static void gen_jump(DisasContext *dc, TCGv dest)
+{
+    tcg_gen_mov_i32(cpu_pc, dest);
+    if (dc->singlestep_enabled) {
+        gen_exception(EXCP_DEBUG);
+    }
+    tcg_gen_exit_tb(0);
+    dc->is_jmp = DISAS_UPDATE;
+}
+
+static void gen_jumpi(DisasContext *dc, uint32_t dest)
+{
+    TCGv_i32 tmp = tcg_const_i32(dest);
+    gen_jump(dc, tmp);
+    tcg_temp_free(tmp);
+}
+
+static void disas_xtensa_insn(DisasContext *dc)
+{
+#define HAS_OPTION(opt) do { \
+        if (!(dc->config->options & (((uint64_t)1) << (opt)))) { \
+            goto invalid_opcode; \
+        } \
+    } while (0)
+
+#define _OP0 (((_b0) & 0xf0) >> 4)
+#define _OP1 (((_b2) & 0xf0) >> 4)
+#define _OP2 ((_b2) & 0xf)
+#define RRR_R ((_b1) & 0xf)
+#define RRR_S (((_b1) & 0xf0) >> 4)
+#define RRR_T ((_b0) & 0xf)
+
+#define RRRN_R RRR_R
+#define RRRN_S RRR_S
+#define RRRN_T RRR_T
+
+#define RI16_IMM16 (((_b1) << 8) | (_b2))
+
+#define CALL_N (((_b0) & 0xc) >> 2)
+#define CALL_OFFSET ((((_b0) & 0x3) << 16) | ((_b1) << 8) | (_b2))
+#define CALL_OFFSET_SE (((_b0 & 0x2) ? 0xfffc0000 : 0) | CALL_OFFSET)
+
+    uint8_t _b0 = ldub_code(dc->pc);
+    uint8_t _b1 = ldub_code(dc->pc + 1);
+    uint8_t _b2 = ldub_code(dc->pc + 2);
+
+    switch (_OP0) {
+    case 0: /*QRST*/
+        switch (_OP1) {
+        case 0: /*RST0*/
+            switch (_OP2) {
+            case 0: /*ST0*/
+                if ((RRR_R & 0xc) == 0x8) {
+                    HAS_OPTION(XTENSA_OPTION_BOOLEAN);
+                }
+
+                switch (RRR_R) {
+                case 0: /*SNM0*/
+                    break;
+
+                case 1: /*MOVSPw*/
+                    HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
+                    break;
+
+                case 2: /*SYNC*/
+                    break;
+
+                case 3:
+                    break;
+
+                }
+                break;
+
+            case 1: /*AND*/
+                tcg_gen_and_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]);
+                break;
+
+            case 2: /*OR*/
+                tcg_gen_or_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]);
+                break;
+
+            case 3: /*XOR*/
+                tcg_gen_xor_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]);
+                break;
+
+            case 4: /*ST1*/
+                break;
+
+            case 5: /*TLB*/
+                break;
+
+            case 6: /*RT0*/
+                break;
+
+            case 7: /*reserved*/
+                break;
+
+            case 8: /*ADD*/
+                tcg_gen_add_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]);
+                break;
+
+            case 9: /*ADD**/
+            case 10:
+            case 11:
+                {
+                    TCGv_i32 tmp = tcg_temp_new_i32();
+                    tcg_gen_shli_i32(tmp, cpu_R[RRR_S], _OP2 - 8);
+                    tcg_gen_add_i32(cpu_R[RRR_R], tmp, cpu_R[RRR_T]);
+                    tcg_temp_free(tmp);
+                }
+                break;
+
+            case 12: /*SUB*/
+                tcg_gen_sub_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]);
+                break;
+
+            case 13: /*SUB**/
+            case 14:
+            case 15:
+                {
+                    TCGv_i32 tmp = tcg_temp_new_i32();
+                    tcg_gen_shli_i32(tmp, cpu_R[RRR_S], _OP2 - 12);
+                    tcg_gen_sub_i32(cpu_R[RRR_R], tmp, cpu_R[RRR_T]);
+                    tcg_temp_free(tmp);
+                }
+                break;
+            }
+            break;
+
+        case 1: /*RST1*/
+            break;
+
+        case 2: /*RST2*/
+            break;
+
+        case 3: /*RST3*/
+            break;
+
+        case 4: /*EXTUI*/
+        case 5:
+            break;
+
+        case 6: /*CUST0*/
+            break;
+
+        case 7: /*CUST1*/
+            break;
+
+        case 8: /*LSCXp*/
+            HAS_OPTION(XTENSA_OPTION_COPROCESSOR);
+            break;
+
+        case 9: /*LSC4*/
+            break;
+
+        case 10: /*FP0*/
+            HAS_OPTION(XTENSA_OPTION_FP_COPROCESSOR);
+            break;
+
+        case 11: /*FP1*/
+            HAS_OPTION(XTENSA_OPTION_FP_COPROCESSOR);
+            break;
+
+        default: /*reserved*/
+            break;
+        }
+        break;
+
+    case 1: /*L32R*/
+        {
+            TCGv_i32 tmp = tcg_const_i32(
+                    (0xfffc0000 | (RI16_IMM16 << 2)) +
+                    ((dc->pc + 3) & ~3));
+
+            /* no ext L32R */
+
+            tcg_gen_qemu_ld32u(cpu_R[RRR_T], tmp, 0);
+            tcg_temp_free(tmp);
+        }
+        break;
+
+    case 2: /*LSAI*/
+        break;
+
+    case 3: /*LSCIp*/
+        HAS_OPTION(XTENSA_OPTION_COPROCESSOR);
+        break;
+
+    case 4: /*MAC16d*/
+        HAS_OPTION(XTENSA_OPTION_MAC16);
+        break;
+
+    case 5: /*CALLN*/
+        switch (CALL_N) {
+        case 0: /*CALL0*/
+            tcg_gen_movi_i32(cpu_R[0], dc->pc + 3);
+            gen_jumpi(dc, (dc->pc & ~3) + (CALL_OFFSET_SE << 2) + 4);
+            break;
+
+        case 1: /*CALL4w*/
+        case 2: /*CALL8w*/
+        case 3: /*CALL12w*/
+            HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
+            break;
+        }
+        break;
+
+    case 6: /*SI*/
+        switch (CALL_N) {
+        case 0: /*J*/
+            gen_jumpi(dc, dc->pc + 4 + CALL_OFFSET_SE);
+            break;
+
+        }
+        break;
+
+    case 7: /*B*/
+        break;
+
+    case 8: /*L32I.Nn*/
+        break;
+
+    case 9: /*S32I.Nn*/
+        break;
+
+    case 10: /*ADD.Nn*/
+        break;
+
+    case 11: /*ADDI.Nn*/
+        break;
+
+    case 12: /*ST2n*/
+        break;
+
+    case 13: /*ST3n*/
+        break;
+
+    default: /*reserved*/
+        break;
+    }
+
+    if (_OP0 >= 8) {
+        dc->pc += 2;
+        HAS_OPTION(XTENSA_OPTION_CODE_DENSITY);
+    } else {
+        dc->pc += 3;
+    }
+    return;
+
+invalid_opcode:
+    printf("INVALID(pc = %08x): %s:%d\n", dc->pc, __FILE__, __LINE__);
+    dc->pc += (_OP0 >= 8) ? 2 : 3;
+#undef HAS_OPTION
+}
+
+static void check_breakpoint(CPUState *env, DisasContext *dc)
+{
+    CPUBreakpoint *bp;
+
+    if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
+        QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
+            if (bp->pc == dc->pc) {
+                tcg_gen_movi_i32(cpu_pc, dc->pc);
+                gen_exception(EXCP_DEBUG);
+                dc->is_jmp = DISAS_UPDATE;
+             }
+        }
+    }
+}
+
+static void gen_intermediate_code_internal(
+        CPUState *env, TranslationBlock *tb, int search_pc)
+{
+    DisasContext dc;
+    int insn_count = 0;
+    int j, lj = -1;
+    uint16_t *gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
+    int max_insns = tb->cflags & CF_COUNT_MASK;
+
+    if (max_insns == 0) {
+        max_insns = CF_COUNT_MASK;
+    }
+
+    dc.config = env->config;
+    dc.singlestep_enabled = env->singlestep_enabled;
+    dc.tb = tb;
+    dc.pc = env->pc;
+    dc.is_jmp = DISAS_NEXT;
+
+    gen_icount_start();
+
+    do {
+        check_breakpoint(env, &dc);
+
+        if (search_pc) {
+            j = gen_opc_ptr - gen_opc_buf;
+            if (lj < j) {
+                lj++;
+                while (lj < j) {
+                    gen_opc_instr_start[lj++] = 0;
+                }
+            }
+            gen_opc_pc[lj] = dc.pc;
+            gen_opc_instr_start[lj] = 1;
+            gen_opc_icount[lj] = insn_count;
+        }
+
+        if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP))) {
+            tcg_gen_debug_insn_start(dc.pc);
+        }
+
+        disas_xtensa_insn(&dc);
+        ++insn_count;
+        if (env->singlestep_enabled) {
+            tcg_gen_movi_i32(cpu_pc, dc.pc);
+            gen_exception(EXCP_DEBUG);
+            break;
+        }
+    } while (dc.is_jmp == DISAS_NEXT &&
+            insn_count < max_insns &&
+            gen_opc_ptr < gen_opc_end);
+
+    if (dc.is_jmp == DISAS_NEXT) {
+        tcg_gen_movi_i32(cpu_pc, dc.pc);
+        tcg_gen_exit_tb(0);
+    }
+    gen_icount_end(tb, insn_count);
+    *gen_opc_ptr = INDEX_op_end;
+
 }
 
 void gen_intermediate_code(CPUState *env, TranslationBlock *tb)
 {
+    gen_intermediate_code_internal(env, tb, 0);
 }
 
 void gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb)
 {
+    gen_intermediate_code_internal(env, tb, 1);
 }
 
 void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,