Tilegx Qemu can decode bundle, disassemble code, and generate tcg code for 1st TB block (__start). Then directly jump to __libc_start_main (2nd TB block).
In __libc_start_main, tilegx qemu continues executing, and reach to the indirectly jump statement, and jump to 3rd TB block correctly. The related test/output for 1st TB block is: The disassembly code (have compared with objdump): TB block start position: [0000000000010f60] _start y0: 00000000500bfdb4 move r52, r54 y1: 1c06400000000000 fnop y2: 0208000007600000 ld r1, r54 x0: 0000000051483000 fnop x1: 180f86c600000000 addi r12, r54, -16 x0: 00000000403f8336 andi r54, r12, -8 x1: 286af00680000000 lnk r13 y0: 00000000500bf005 move r5, r0 y1: 040046c600000000 addi r12, r54, 8 y2: 03f8000007600000 st r54, r63 y0: 00000000500bfff7 move r55, r63 y1: 0400468100000000 addi r2, r52, 8 y2: 03f8000004c00000 st r12, r63 x0: 0000000040110d86 addi r6, r54, 16 x1: 07ffffe000000000 moveli r0, -1 x0: 000000007ffff000 shl16insli r0, r0, -1 x1: 000007e180000000 moveli r3, 0 x0: 000000007ffa8000 shl16insli r0, r0, -88 x1: 3800006180000000 shl16insli r3, r3, 0 x0: 00000000500cd000 add r0, r0, r13 x1: 3877406180000000 shl16insli r3, r3, 3816 x0: 0000000010000fcc moveli r12, 0 x1: 2806686180000000 add r3, r3, r13 x0: 000000007000030c shl16insli r12, r12, 0 x1: 000007e200000000 moveli r4, 0 x0: 000000007039030c shl16insli r12, r12, 912 x1: 3800008200000000 shl16insli r4, r4, 0 x0: 00000000500cd30c add r12, r12, r13 x1: 3881808200000000 shl16insli r4, r4, 4144 x0: 00000000500cd104 add r4, r4, r13 x1: 286a718000000000 jr r12 The tcg code before optimization is: ld_i32 tmp0,env,$0xfffffffffffffff4 movi_i32 tmp1,$0x0 brcond_i32 tmp0,tmp1,ne,$0x0 mov_i64 tmp2,sp ld_i64 tmp3,env,$0x1b0 mov_i64 bp,tmp2 mov_i64 r1,tmp3 movi_i64 tmp3,$0xfffffffffffffff0 add_i64 tmp2,sp,tmp3 mov_i64 r12,tmp2 movi_i64 tmp3,$0xfffffffffffffff8 and_i64 tmp2,r12,tmp3 movi_i64 tmp3,$0x10f78 mov_i64 sp,tmp2 mov_i64 r13,tmp3 mov_i64 tmp2,r0 movi_i64 tmp4,$0x8 add_i64 tmp3,sp,tmp4 st_i64 sp,env,$0x1c0 mov_i64 r5,tmp2 mov_i64 r12,tmp3 movi_i64 tmp2,$0x0 movi_i64 tmp4,$0x8 add_i64 tmp3,bp,tmp4 st_i64 r12,env,$0x1c0 mov_i64 lr,tmp2 mov_i64 r2,tmp3 movi_i64 tmp3,$0x10 add_i64 tmp2,sp,tmp3 movi_i64 tmp3,$0xffffffffffffffff mov_i64 r6,tmp2 mov_i64 r0,tmp3 movi_i64 tmp3,$0x10 shl_i64 tmp2,r0,tmp3 movi_i64 tmp4,$0xffff or_i64 tmp3,tmp2,tmp4 movi_i64 tmp2,$0x0 mov_i64 r0,tmp3 mov_i64 r3,tmp2 movi_i64 tmp3,$0x10 shl_i64 tmp2,r0,tmp3 movi_i64 tmp4,$0xffa8 or_i64 tmp3,tmp2,tmp4 movi_i64 tmp4,$0x10 shl_i64 tmp2,r3,tmp4 mov_i64 tmp4,tmp2 mov_i64 r0,tmp3 mov_i64 r3,tmp4 add_i64 tmp2,r0,r13 movi_i64 tmp4,$0x10 shl_i64 tmp3,r3,tmp4 movi_i64 tmp5,$0xee8 or_i64 tmp4,tmp3,tmp5 mov_i64 r0,tmp2 mov_i64 r3,tmp4 movi_i64 tmp2,$0x0 add_i64 tmp3,r3,r13 mov_i64 r12,tmp2 mov_i64 r3,tmp3 movi_i64 tmp3,$0x10 shl_i64 tmp2,r12,tmp3 mov_i64 tmp3,tmp2 movi_i64 tmp2,$0x0 mov_i64 r12,tmp3 mov_i64 r4,tmp2 movi_i64 tmp3,$0x10 shl_i64 tmp2,r12,tmp3 movi_i64 tmp4,$0x390 or_i64 tmp3,tmp2,tmp4 movi_i64 tmp4,$0x10 shl_i64 tmp2,r4,tmp4 mov_i64 tmp4,tmp2 mov_i64 r12,tmp3 mov_i64 r4,tmp4 add_i64 tmp2,r12,r13 movi_i64 tmp4,$0x10 shl_i64 tmp3,r4,tmp4 movi_i64 tmp5,$0x1030 or_i64 tmp4,tmp3,tmp5 mov_i64 r12,tmp2 mov_i64 r4,tmp4 add_i64 tmp2,r4,r13 mov_i64 tmp3,r12 mov_i64 r4,tmp2 mov_i64 pc,tmp3 exit_tb $0x0 set_label $0x0 exit_tb $0x7fd21f340013 Signed-off-by: Chen Gang <gang.chen.5...@gmail.com> --- linux-user/main.c | 1 + target-tilegx/cpu-qom.h | 2 + target-tilegx/cpu.c | 4 - target-tilegx/cpu.h | 21 +- target-tilegx/translate.c | 876 +++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 885 insertions(+), 19 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index 76e5e80..ef89bfd 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -4464,6 +4464,7 @@ int main(int argc, char **argv, char **envp) env->regs[53] = regs->tp; /* TILEGX_R_TP */ env->regs[54] = regs->sp; /* TILEGX_R_SP */ env->regs[55] = regs->lr; /* TILEGX_R_LR */ + env->zero = 0; env->pc = regs->lr; } #else diff --git a/target-tilegx/cpu-qom.h b/target-tilegx/cpu-qom.h index e15a8b8..866a77d 100644 --- a/target-tilegx/cpu-qom.h +++ b/target-tilegx/cpu-qom.h @@ -69,4 +69,6 @@ static inline TilegxCPU *tilegx_env_get_cpu(CPUTLState *env) #define ENV_GET_CPU(e) CPU(tilegx_env_get_cpu(e)) +#define ENV_OFFSET offsetof(TilegxCPU, env) + #endif diff --git a/target-tilegx/cpu.c b/target-tilegx/cpu.c index 3dd66b5..a10cc24 100644 --- a/target-tilegx/cpu.c +++ b/target-tilegx/cpu.c @@ -69,10 +69,6 @@ static void tilegx_cpu_realizefn(DeviceState *dev, Error **errp) mcc->parent_realize(dev, errp); } -static void tilegx_tcg_init(void) -{ -} - static void tilegx_cpu_initfn(Object *obj) { CPUState *cs = CPU(obj); diff --git a/target-tilegx/cpu.h b/target-tilegx/cpu.h index 09a2b26..73794ab 100644 --- a/target-tilegx/cpu.h +++ b/target-tilegx/cpu.h @@ -30,16 +30,20 @@ #include "fpu/softfloat.h" /* Tilegx register alias */ -#define TILEGX_R_RE 0 /* 0 register, for function/syscall return value */ -#define TILEGX_R_NR 10 /* 10 register, for syscall number */ -#define TILEGX_R_BP 52 /* 52 register, optional frame pointer */ -#define TILEGX_R_TP 53 /* TP register, thread local storage data */ -#define TILEGX_R_SP 54 /* SP register, stack pointer */ -#define TILEGX_R_LR 55 /* LR register, may save pc, but it is not pc */ +#define TILEGX_R_RE 0 /* 0 register, for function/syscall return value */ +#define TILEGX_R_NR 10 /* 10 register, for syscall number */ +#define TILEGX_R_BP 52 /* 52 register, optional frame pointer */ +#define TILEGX_R_TP 53 /* TP register, thread local storage data */ +#define TILEGX_R_SP 54 /* SP register, stack pointer */ +#define TILEGX_R_LR 55 /* LR register, may save pc, but it is not pc */ +#define TILEGX_R_ZERO 63 /* Zero register, always zero */ +#define TILEGX_R_COUNT 56 /* Only 56 registers are really useful */ +#define TILEGX_R_NOREG 255 /* Invalid register value */ typedef struct CPUTLState { - uint64_t regs[56]; - uint64_t pc; + uint64_t regs[TILEGX_R_COUNT]; /* Common used registers by outside */ + uint64_t zero; /* Zero register */ + uint64_t pc; /* Current pc */ CPU_COMMON } CPUTLState; @@ -54,6 +58,7 @@ typedef struct CPUTLState { #include "exec/cpu-all.h" +void tilegx_tcg_init(void); int cpu_tilegx_exec(CPUTLState *s); int cpu_tilegx_signal_handler(int host_signum, void *pinfo, void *puc); diff --git a/target-tilegx/translate.c b/target-tilegx/translate.c index 5131fa7..82c751e 100644 --- a/target-tilegx/translate.c +++ b/target-tilegx/translate.c @@ -25,18 +25,880 @@ #include "exec/cpu_ldst.h" #include "exec/helper-gen.h" +#define TILEGX_BUNDLE_SIZE 8 /* Each bundle size in bytes */ +#define TILEGX_BUNDLE_INSNS 3 /* Maximized insns per bundle */ +#define TILEGX_BUNDLE_OPCS 10 /* Assume maximized opcs per bundle */ + +/* Check Bundle whether is Y type, else is X type */ +#define TILEGX_BUNDLE_TYPE_MASK 0xc000000000000000ULL +#define TILEGX_BUNDLE_TYPE_Y(bundle) ((bundle) & TILEGX_BUNDLE_TYPE_MASK) +#define TILEGX_BUNDLE_TYPE_X(bundle) (!TILEGX_BUNDLE_TYPE_Y(bundle)) + +/* Bundle pipe mask, still remain the bundle type */ +#define TILEGX_PIPE_X0(bundle) ((bundle) & 0x000000007fffffffULL) +#define TILEGX_PIPE_X1(bundle) ((bundle) & 0x3fffffff80000000ULL) +#define TILEGX_PIPE_Y0(bundle) ((bundle) & 0x00000000780fffffULL) +#define TILEGX_PIPE_Y1(bundle) ((bundle) & 0x3c07ffff80000000ULL) +#define TILEGX_PIPE_Y2(bundle) ((bundle) & 0x03f8000007f00000ULL) + +/* Code mask */ +#define TILEGX_CODE_X0(bundle) ((bundle) & 0x0000000070000000ULL) +#define TILEGX_CODE_X0_18(bundle) ((bundle) & 0x000000000ffc0000ULL) +#define TILEGX_CODE_X0_20(bundle) ((bundle) & 0x000000000ff00000ULL) +#define TILEGX_CODE_X1(bundle) ((bundle) & 0x3800000000000000ULL) +#define TILEGX_CODE_X1_49(bundle) ((bundle) & 0x07fe000000000000ULL) +#define TILEGX_CODE_X1_49_43(bundle) ((bundle) & 0x0001f80000000000ULL) +#define TILEGX_CODE_X1_51(bundle) ((bundle) & 0x07f8000000000000ULL) +#define TILEGX_CODE_X1_54(bundle) ((bundle) & 0x07c0000000000000ULL) +#define TILEGX_CODE_Y0(bundle) ((bundle) & 0x0000000078000000ULL) +#define TILEGX_CODE_Y0_E(bundle) ((bundle) & 0x00000000000c0000ULL) +#define TILEGX_CODE_Y1(bundle) ((bundle) & 0x3c00000000000000ULL) +#define TILEGX_CODE_Y1_E(bundle) ((bundle) & 0x0006000000000000ULL) +#define TILEGX_CODE_Y2(bundle) ((bundle) & 0x0200000004000000ULL) +/* No Y2_E */ + +/* (F)Nop operation, only have effect within their own pipe */ +#define TILEGX_OPCX0_FNOP 0x0000000051483000ULL +#define TILEGX_OPCX0_NOP 0x0000000051485000ULL +#define TILEGX_OPCX1_FNOP 0x286a300000000000ULL +#define TILEGX_OPCX1_NOP 0x286b080000000000ULL +#define TILEGX_OPCY0_FNOP 0x00000000300c3000ULL +#define TILEGX_OPCY0_NOP 0x00000000300c5000ULL +#define TILEGX_OPCY1_FNOP 0x1c06400000000000ULL +#define TILEGX_OPCY1_NOP 0x1c06780000000000ULL +/* No Y2 (F)NOP */ + +/* Data width mask */ +#define TILEGX_DATA_REGISTER 0x3f /* Register data width mask */ +#define TILEGX_DATA_IMM6 0x3f /* Imm6 data width mask */ +#define TILEGX_DATA_IMM8 0xff /* Imm8 data width mask */ +#define TILEGX_DATA_IMM11 0x7ff /* Imm11 data width mask */ +#define TILEGX_DATA_IMM16 0xffff /* Imm16 data width mask */ + +#define TILEGX_GEN_CHK_BEGIN(x) \ + if ((x) == TILEGX_R_ZERO) { +#define TILEGX_GEN_CHK_END(x) \ + return 0; \ + } \ + if ((x) >= TILEGX_R_COUNT) { \ + return -1; \ + } + +#define TILEGX_GEN_CHK_SIMPLE(x) \ + TILEGX_GEN_CHK_BEGIN(x) \ + TILEGX_GEN_CHK_END(x) + +#define TILEGX_GEN_SAVE_PREP(rdst) \ + dc->tmp_regcur->idx = rdst; \ + dc->tmp_regcur->val = tcg_temp_new_i64(); + +#define TILEGX_GEN_SAVE_TMP_1(func, rdst, x1) \ + TILEGX_GEN_SAVE_PREP(rdst) \ + func(dc->tmp_regcur->val, x1); + +#define TILEGX_GEN_SAVE_TMP_2(func, rdst, x1, x2) \ + TILEGX_GEN_SAVE_PREP(rdst) \ + func(dc->tmp_regcur->val, x1, x2); + +static TCGv_ptr cpu_env; +static TCGv_i64 cpu_pc; +static TCGv_i64 cpu_regs[TILEGX_R_COUNT]; + +static const char *reg_names[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", + "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", + "r32", "r33", "r34", "r35", "r36", "r37", "r38", "r39", + "r40", "r41", "r42", "r43", "r44", "r45", "r46", "r47", + "r48", "r49", "r50", "r51", "bp", "tp", "sp", "lr" +}; + +#include "exec/gen-icount.h" + +/* This is the state at translation time. */ +struct DisasContext { + uint64_t pc; /* Current pc */ + unsigned int cpustate_changed; /* Whether cpu state changed */ + + struct { + unsigned char idx; /* index */ + TCGv val; /* value */ + } *tmp_regcur, /* Current temporary registers */ + tmp_regs[TILEGX_BUNDLE_INSNS]; /* All temporary registers */ + + struct { + TCGCond cond; /* Branch condition */ + TCGv dest; /* pc jump destination, if will jump */ + TCGv val1; /* Firt value for condition comparing */ + TCGv val2; /* Second value for condition comparing */ + } jmp; /* Jump object, only once in each TB block */ +}; + +void tilegx_tcg_init(void) +{ + int i; + + cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env"); + cpu_pc = tcg_global_mem_new_i64(TCG_AREG0, offsetof(CPUTLState, pc), "pc"); + for (i = 0; i < TILEGX_R_COUNT; i++) { + cpu_regs[i] = tcg_global_mem_new_i64(TCG_AREG0, + offsetof(CPUTLState, regs[i]), + reg_names[i]); + } +} + +static int gen_move(struct DisasContext *dc, + unsigned char rdst, unsigned char rsrc) +{ + qemu_log("move r%d, r%d", rdst, rsrc); + TILEGX_GEN_CHK_SIMPLE(rdst); + TILEGX_GEN_CHK_BEGIN(rsrc); + TILEGX_GEN_SAVE_TMP_1(tcg_gen_movi_i64, rdst, 0); + TILEGX_GEN_CHK_END(rsrc); + + TILEGX_GEN_SAVE_TMP_1(tcg_gen_mov_i64, rdst, cpu_regs[rsrc]); + return 0; +} + +static int gen_move_imm(struct DisasContext *dc, + unsigned char rdst, int64_t imm) +{ + TILEGX_GEN_CHK_SIMPLE(rdst); + TILEGX_GEN_SAVE_TMP_1(tcg_gen_movi_i64, rdst, imm); + return 0; +} + +static int gen_moveli(struct DisasContext *dc, unsigned char rdst, short im16) +{ + qemu_log("moveli r%d, %d", rdst, im16); + return gen_move_imm(dc, rdst, (int64_t)im16); +} + +static int gen_movei(struct DisasContext *dc, unsigned char rdst, char im8) +{ + qemu_log("movei r%d, %d", rdst, im8); + return gen_move_imm(dc, rdst, (int64_t)im8); +} + +static int gen_ld(struct DisasContext *dc, + unsigned char rdst, unsigned char rsrc) +{ + qemu_log("ld r%d, r%d", rdst, rsrc); + TILEGX_GEN_CHK_SIMPLE(rdst); + TILEGX_GEN_CHK_BEGIN(rsrc); + TILEGX_GEN_SAVE_TMP_2(tcg_gen_ld_i64, rdst, cpu_env, 0); + TILEGX_GEN_CHK_END(rsrc); + + TILEGX_GEN_SAVE_TMP_2(tcg_gen_ld_i64, rdst, cpu_env, + offsetof(CPUTLState, regs[rsrc])); + return 0; +} + +static int gen_st(struct DisasContext *dc, + unsigned char rdst, unsigned char rsrc) +{ + qemu_log("st r%d, r%d", rdst, rsrc); + TILEGX_GEN_CHK_SIMPLE(rdst); + TILEGX_GEN_CHK_BEGIN(rsrc); + tcg_gen_st_i64(cpu_regs[rdst], cpu_env, offsetof(CPUTLState, zero)); + TILEGX_GEN_CHK_END(rsrc); + + tcg_gen_st_i64(cpu_regs[rdst], cpu_env, offsetof(CPUTLState, regs[rsrc])); + return 0; +} + +static int gen_addimm(struct DisasContext *dc, + unsigned char rdst, unsigned char rsrc, int64_t imm) +{ + TILEGX_GEN_CHK_SIMPLE(rdst); + TILEGX_GEN_CHK_BEGIN(rsrc); + TILEGX_GEN_SAVE_TMP_1(tcg_gen_movi_i64, rdst, imm); + TILEGX_GEN_CHK_END(rsrc); + + TILEGX_GEN_SAVE_TMP_2(tcg_gen_addi_i64, rdst, cpu_regs[rsrc], imm); + return 0; +} + +static int gen_addi(struct DisasContext *dc, + unsigned char rdst, unsigned char rsrc, char im8) +{ + qemu_log("addi r%d, r%d, %d", rdst, rsrc, im8); + return gen_addimm(dc, rdst, rsrc, (int64_t)im8); +} + +static int gen_addli(struct DisasContext *dc, + unsigned char rdst, unsigned char rsrc, short im16) +{ + qemu_log("addli r%d, r%d, %d", rdst, rsrc, im16); + return gen_addimm(dc, rdst, rsrc, (int64_t)im16); +} + +static int gen_add(struct DisasContext *dc, + unsigned char rdst, unsigned char rsrc, unsigned char rsrcb) +{ + qemu_log("add r%d, r%d, r%d", rdst, rsrc, rsrcb); + TILEGX_GEN_CHK_SIMPLE(rdst); + TILEGX_GEN_CHK_BEGIN(rsrc); + TILEGX_GEN_CHK_BEGIN(rsrcb); + TILEGX_GEN_SAVE_TMP_1(tcg_gen_movi_i64, rdst, 0); + TILEGX_GEN_CHK_END(rsrcb); + TILEGX_GEN_SAVE_TMP_1(tcg_gen_mov_i64, rdst, cpu_regs[rsrcb]); + TILEGX_GEN_CHK_END(rsrc); + + TILEGX_GEN_CHK_BEGIN(rsrcb); + TILEGX_GEN_SAVE_TMP_1(tcg_gen_mov_i64, rdst, cpu_regs[rsrc]); + TILEGX_GEN_CHK_END(rsrcb); + + TILEGX_GEN_SAVE_TMP_2(tcg_gen_add_i64, rdst, + cpu_regs[rsrc], cpu_regs[rsrcb]); + return 0; +} + +static int gen_andimm(struct DisasContext *dc, + unsigned char rdst, unsigned char rsrc, int64_t imm) +{ + TILEGX_GEN_CHK_SIMPLE(rdst); + TILEGX_GEN_CHK_BEGIN(rsrc); + TILEGX_GEN_SAVE_TMP_1(tcg_gen_movi_i64, rdst, 0); + TILEGX_GEN_CHK_END(rsrc); + + TILEGX_GEN_SAVE_TMP_2(tcg_gen_andi_i64, rdst, + cpu_regs[rsrc], (uint64_t)imm); + return 0; +} + +static int gen_andi(struct DisasContext *dc, + unsigned char rdst, unsigned char rsrc, char im8) +{ + qemu_log("andi r%d, r%d, %d", rdst, rsrc, im8); + return gen_andimm(dc, rdst, rsrc, (int64_t)im8); +} + +static int gen_lnk(struct DisasContext *dc, unsigned char rdst) +{ + qemu_log("lnk r%d", rdst); + TILEGX_GEN_CHK_SIMPLE(rdst); + TILEGX_GEN_SAVE_TMP_1(tcg_gen_movi_i64, rdst, dc->pc + TILEGX_BUNDLE_SIZE); + return 0; +} + +static int gen_shl16insli(struct DisasContext *dc, + unsigned char rdst, unsigned char rsrc, short im16) +{ + int64_t imm; + TCGv_i64 tmp; + + qemu_log("shl16insli r%d, r%d, %d", rdst, rsrc, im16); + TILEGX_GEN_CHK_SIMPLE(rdst); + + imm = (int64_t)im16 & 0x000000000000ffffLL; + + TILEGX_GEN_CHK_BEGIN(rsrc); + TILEGX_GEN_SAVE_TMP_1(tcg_gen_movi_i64, rdst, imm); + TILEGX_GEN_CHK_END(rsrc); + + tmp = tcg_temp_new_i64(); + tcg_gen_shli_i64(tmp, cpu_regs[rsrc], 16); + TILEGX_GEN_SAVE_TMP_2(tcg_gen_ori_i64, rdst, tmp, imm); + tcg_temp_free_i64(tmp); + return 0; +} + +static int gen_jr(struct DisasContext *dc, unsigned char rsrc) +{ + qemu_log("jr r%d", rsrc); + TILEGX_GEN_CHK_SIMPLE(rsrc); + + dc->jmp.dest = tcg_temp_new_i64(); + + dc->jmp.cond = TCG_COND_ALWAYS; + tcg_gen_mov_i64(dc->jmp.dest, cpu_regs[rsrc]); + return 0; +} + +static int gen_beqz(struct DisasContext *dc, unsigned char rsrc, int off) +{ + qemu_log("beqz r%d, %d", rsrc, off); + TILEGX_GEN_CHK_SIMPLE(rsrc); + + dc->jmp.dest = tcg_temp_new_i64(); + dc->jmp.val1 = tcg_temp_new_i64(); + dc->jmp.val2 = tcg_temp_new_i64(); + + dc->jmp.cond = TCG_COND_EQ; + tcg_gen_movi_i64(dc->jmp.dest, dc->pc + (int64_t)off * TILEGX_BUNDLE_SIZE); + tcg_gen_mov_i64(dc->jmp.val1, cpu_regs[rsrc]); + tcg_gen_movi_i64(dc->jmp.val2, 0); + + return 0; +} + +static int translate_x0_bundle(struct DisasContext *dc, uint64_t bundle) +{ + unsigned char rdst, rsrc, rsrcb; + char im8; + short im16; + + qemu_log("\nx0: %16.16lx\t", bundle); + if (bundle == TILEGX_OPCX0_FNOP) { + qemu_log("fnop"); + return 0; + } + + if (bundle == TILEGX_OPCX0_NOP) { + qemu_log("nop"); + return 0; + } + + switch (TILEGX_CODE_X0(bundle)) { + case 0x0000000010000000ULL: + rdst = (unsigned char)(bundle & TILEGX_DATA_REGISTER); + rsrc = (unsigned char)((bundle >> 6) & TILEGX_DATA_REGISTER); + im16 = (short)((bundle >> 12) & TILEGX_DATA_IMM16); + if (rsrc == 0x3f) { + /* moveli Dest, Imm16 */ + if (gen_moveli(dc, rdst, im16)) { + /* FIXME: raise an exception for invalid instruction */ + return -1; + } + } else { + /* addli Dest, SrcA, Imm16 */ + if (gen_addli(dc, rdst, rsrc, im16)) { + /* FIXME: raise an exception for invalid instruction */ + return -1; + } + } + break; + + case 0x0000000040000000ULL: + switch (TILEGX_CODE_X0_20(bundle)) { + /* andi Dest, SrcA, Imm8 */ + case 0x0000000000300000ULL: + rdst = (unsigned char)(bundle & TILEGX_DATA_REGISTER); + rsrc = (unsigned char)((bundle >> 6) & TILEGX_DATA_REGISTER); + im8 = (char)((bundle >> 12) & TILEGX_DATA_IMM8); + if (gen_andi(dc, rdst, rsrc, im8)) { + /* FIXME: raise an exception for invalid instruction */ + return -1; + } + break; + + /* addi Dest, SrcA, Imm8 */ + case 0x0000000000100000ULL: + rdst = (unsigned char)(bundle & TILEGX_DATA_REGISTER); + rsrc = (unsigned char)((bundle >> 6) & TILEGX_DATA_REGISTER); + im8 = (char)((bundle >> 12) & TILEGX_DATA_IMM8); + if (gen_addi(dc, rdst, rsrc, im8)) { + /* FIXME: raise an exception for invalid instruction */ + return -1; + } + break; + + default: + /* FIXME: raise an exception for invalid instruction */ + qemu_log("20 bundle value: %16.16llx", TILEGX_CODE_X0_20(bundle)); + return -1; + } + break; + + case 0x0000000050000000ULL: + switch (TILEGX_CODE_X0_18(bundle)) { + /* add Dest, SrcA, SrcB */ + case 0x00000000000c0000ULL: + rdst = (unsigned char)(bundle & TILEGX_DATA_REGISTER); + rsrc = (unsigned char)((bundle >> 6) & TILEGX_DATA_REGISTER); + rsrcb = (unsigned char)((bundle >> 12) & TILEGX_DATA_REGISTER); + if (gen_add(dc, rdst, rsrc, rsrcb)) { + /* FIXME: raise an exception for invalid instruction */ + return -1; + } + break; + + case 0x0000000001040000ULL: + rdst = (unsigned char)(bundle & TILEGX_DATA_REGISTER); + rsrc = (unsigned char)((bundle >> 6) & TILEGX_DATA_REGISTER); + rsrcb = (unsigned char)((bundle >> 12) & TILEGX_DATA_REGISTER); + /* move Dest, Src */ + if (rsrcb == 0x3f) { + if (gen_move(dc, rdst, rsrc)) { + /* FIXME: raise an exception for invalid instruction */ + return -1; + } + } else { + qemu_log("invalid rsrcb, not 0x3f for move in x0"); + } + break; + + default: + /* FIXME: raise an exception for invalid instruction */ + qemu_log("18 bundle value: %16.16llx", TILEGX_CODE_X0_18(bundle)); + return -1; + } + break; + + /* shl16insli Dest, SrcA, Imm16 */ + case 0x0000000070000000ULL: + rdst = (unsigned char)(bundle & TILEGX_DATA_REGISTER); + rsrc = (unsigned char)((bundle >> 6) & TILEGX_DATA_REGISTER); + im16 = (short)((bundle >> 12) & TILEGX_DATA_IMM16); + if (gen_shl16insli(dc, rdst, rsrc, im16)) { + /* FIXME: raise an exception for invalid instruction */ + return -1; + } + break; + + default: + /* FIXME: raise an exception for invalid instruction */ + qemu_log("bundle value: %16.16llx", TILEGX_CODE_X0(bundle)); + return -1; + } + + return 0; +} + +static int translate_x1_bundle(struct DisasContext *dc, uint64_t bundle) +{ + unsigned char rdst, rsrc, rsrcb; + char im8; + short im16; + struct { + int v :17; + } off17; + + qemu_log("\nx1: %16.16lx\t", bundle); + if (bundle == TILEGX_OPCX1_FNOP) { + qemu_log("fnop"); + return 0; + } + + if (bundle == TILEGX_OPCX1_NOP) { + qemu_log("nop"); + return 0; + } + + switch (TILEGX_CODE_X1(bundle)) { + case 0x0000000000000000ULL: + rdst = (unsigned char)((bundle >> 31) & TILEGX_DATA_REGISTER); + rsrc = (unsigned char)((bundle >> 37) & TILEGX_DATA_REGISTER); + im16 = (short)((bundle >> 43) & TILEGX_DATA_IMM16); + if (rsrc == 0x3f) { + /* moveli Dest, Imm16 */ + if (gen_moveli(dc, rdst, im16)) { + /* FIXME: raise an exception for invalid instruction */ + return -1; + } + } else { + /* addli Dest, SrcA, Imm16 */ + if (gen_addli(dc, rdst, rsrc, im16)) { + /* FIXME: raise an exception for invalid instruction */ + return -1; + } + } + break; + + case 0x1000000000000000ULL: + switch (TILEGX_CODE_X1_54(bundle)) { + /* beqz Src, Broff */ + case 0x0440000000000000ULL: + off17.v = (int)((bundle >> 31) & TILEGX_DATA_IMM6); + rsrc = (unsigned char)((bundle >> 37) & TILEGX_DATA_REGISTER); + off17.v |= (int)((bundle >> 37) & (TILEGX_DATA_IMM11 << 6)); + if (gen_beqz(dc, rsrc, (int)off17.v)) { + /* FIXME: raise an exception for invalid instruction */ + return -1; + } + break; + + default: + /* FIXME: raise an exception for invalid instruction */ + qemu_log("54 bundle value: %llx", TILEGX_CODE_X1_51(bundle)); + return -1; + } + break; + + case 0x1800000000000000ULL: + switch (TILEGX_CODE_X1_51(bundle)) { + /* addi Dest, SrcA, Imm8 */ + case 0x0008000000000000ULL: + rdst = (unsigned char)((bundle >> 31) & TILEGX_DATA_REGISTER); + rsrc = (unsigned char)((bundle >> 37) & TILEGX_DATA_REGISTER); + im8 = (char)((bundle >> 43) & TILEGX_DATA_IMM8); + if (rsrc == 0x3f) { + if (gen_movei(dc, rdst, im8)) { + /* FIXME: raise an exception for invalid instruction */ + return -1; + } + } else { + if (gen_addi(dc, rdst, rsrc, im8)) { + /* FIXME: raise an exception for invalid instruction */ + return -1; + } + } + break; + default: + /* FIXME: raise an exception for invalid instruction */ + qemu_log("51 bundle value: %llx", TILEGX_CODE_X1_51(bundle)); + return -1; + } + break; + + case 0x2800000000000000ULL: + switch (TILEGX_CODE_X1_49(bundle)) { + /* add Dest, SrcA, SrcB */ + case 0x0006000000000000ULL: + rdst = (unsigned char)((bundle >> 31) & TILEGX_DATA_REGISTER); + rsrc = (unsigned char)((bundle >> 37) & TILEGX_DATA_REGISTER); + rsrcb = (unsigned char)((bundle >> 43) & TILEGX_DATA_REGISTER); + if (gen_add(dc, rdst, rsrc, rsrcb)) { + /* FIXME: raise an exception for invalid instruction */ + return -1; + } + break; + + /* store Dest, Src */ + case 0x0062000000000000ULL: + rdst = (unsigned char)((bundle >> 37) & TILEGX_DATA_REGISTER); + rsrc = (unsigned char)((bundle >> 43) & TILEGX_DATA_REGISTER); + if (gen_st(dc, rdst, rsrc)) { + /* FIXME: raise an exception for invalid instruction */ + return -1; + } + break; + + case 0x006a000000000000ULL: + switch (TILEGX_CODE_X1_49_43(bundle)) { + /* lnk Dest */ + case 0x0000f00000000000ULL: + rdst = (unsigned char)((bundle >> 31) & TILEGX_DATA_REGISTER); + if (gen_lnk(dc, rdst)) { + /* FIXME: raise an exception for invalid instruction */ + return -1; + } + break; + + /* jr SrcA */ + case 0x0000700000000000ULL: + rsrc = (unsigned char)((bundle >> 37) & TILEGX_DATA_REGISTER); + if (gen_jr(dc, rsrc)) { + /* FIXME: raise an exception for invalid instruction */ + return -1; + } + break; + + default: + /* FIXME: raise an exception for invalid instruction */ + qemu_log("49_43 bundle value: %16.16llx", + TILEGX_CODE_X1_49_43(bundle)); + return -1; + } + break; + default: + /* FIXME: raise an exception for invalid instruction */ + qemu_log("49 bundle value: %16.16llx", TILEGX_CODE_X1_49(bundle)); + return -1; + } + break; + + /* shl16insli Dest, SrcA, Imm16 */ + case 0x3800000000000000ULL: + rdst = (unsigned char)((bundle >> 31) & TILEGX_DATA_REGISTER); + rsrc = (unsigned char)((bundle >> 37) & TILEGX_DATA_REGISTER); + im16 = (short)((bundle >> 43) & TILEGX_DATA_IMM16); + if (gen_shl16insli(dc, rdst, rsrc, im16)) { + /* FIXME: raise an exception for invalid instruction */ + return -1; + } + break; + + default: + /* FIXME: raise an exception for invalid instruction */ + qemu_log("bundle value: %16.16llx", TILEGX_CODE_X1(bundle)); + return -1; + } + + return 0; +} + +static int translate_y0_bundle(struct DisasContext *dc, uint64_t bundle) +{ + unsigned char rsrc, rdst; + char im8; + + qemu_log("\ny0: %16.16lx\t", bundle); + if (bundle == TILEGX_OPCY0_FNOP) { + qemu_log("fnop"); + return 0; + } + + if (bundle == TILEGX_OPCY0_NOP) { + qemu_log("nop"); + return 0; + } + + switch (TILEGX_CODE_Y0(bundle)) { + /* addi Dest, SrcA, Imm8 */ + case 0x0000000000000000ULL: + rdst = (unsigned char)(bundle & TILEGX_DATA_REGISTER); + rsrc = (unsigned char)((bundle >> 6) & TILEGX_DATA_REGISTER); + im8 = (char)((bundle >> 12) & TILEGX_DATA_IMM8); + if (gen_addi(dc, rdst, rsrc, im8)) { + /* FIXME: raise an exception for invalid instruction */ + return -1; + } + break; + + case 0x0000000050000000ULL: + switch (TILEGX_CODE_Y0_E(bundle)) { + /* move Dest, SrcA */ + case 0x0000000000080000ULL: + rdst = (unsigned char)(bundle & TILEGX_DATA_REGISTER); + rsrc = (unsigned char)((bundle >> 6) & TILEGX_DATA_REGISTER); + if (gen_move(dc, rdst, rsrc)) { + /* FIXME: raise an exception for invalid instruction */ + return -1; + } + break; + + default: + /* FIXME: raise an exception for invalid instruction */ + return -1; + } + break; + + default: + /* FIXME: raise an exception for invalid instruction */ + qemu_log("bundle value: %16.16llx", TILEGX_CODE_Y0(bundle)); + return -1; + } + + return 0; +} + +static int translate_y1_bundle(struct DisasContext *dc, uint64_t bundle) +{ + unsigned char rdst, rsrc, rsrcb; + char im8; + + qemu_log("\ny1: %16.16lx\t", bundle); + if (bundle == TILEGX_OPCY1_FNOP) { + qemu_log("fnop"); + return 0; + } + + if (bundle == TILEGX_OPCY1_NOP) { + qemu_log("nop"); + return 0; + } + + switch (TILEGX_CODE_Y1(bundle)) { + /* addi Dest, SrcA, Imm8 */ + case 0x0400000000000000ULL: + rdst = (unsigned char)((bundle >> 31) & TILEGX_DATA_REGISTER); + rsrc = (unsigned char)((bundle >> 37) & TILEGX_DATA_REGISTER); + im8 = (char)((bundle >> 43) & TILEGX_DATA_IMM8); + if (gen_addi(dc, rdst, rsrc, im8)) { + /* FIXME: raise an exception for invalid instruction */ + return -1; + } + break; + + case 0x2c00000000000000ULL: + switch(TILEGX_CODE_Y1_E(bundle)) { + case 0x0004000000000000ULL: + rdst = (unsigned char)((bundle >> 31) & TILEGX_DATA_REGISTER); + rsrc = (unsigned char)((bundle >> 37) & TILEGX_DATA_REGISTER); + rsrcb = (unsigned char)((bundle >> 43) & TILEGX_DATA_REGISTER); + /* move Dest, Src */ + if (rsrcb == 0x3f) { + if (gen_move(dc, rdst, rsrc)) { + /* FIXME: raise an exception for invalid instruction */ + return -1; + } + } else { + qemu_log("invalid rsrcb, not 0x3f for move in y1"); + } + break; + + default: + /* FIXME: raise an exception for invalid instruction */ + qemu_log("y1 E bundle value: %16.16llx", TILEGX_CODE_Y1_E(bundle)); + break; + } + break; + + default: + /* FIXME: raise an exception for invalid instruction */ + qemu_log("bundle value: %16.16llx", TILEGX_CODE_Y1(bundle)); + return -1; + } + + return 0; +} + +static int translate_y2_bundle(struct DisasContext *dc, uint64_t bundle, + uint64_t mode) +{ + unsigned char rsrc, rdst; + + qemu_log("\ny2: %16.16lx\t", bundle); + switch (TILEGX_CODE_Y2(bundle)) { + case 0x0200000004000000ULL: + switch (mode) { + /* ld Dest, Src */ + case 0x8000000000000000ULL: + rdst = (unsigned char)((bundle >> 51) & TILEGX_DATA_REGISTER); + rsrc = (unsigned char)((bundle >> 20) & TILEGX_DATA_REGISTER); + if (gen_ld(dc, rdst, rsrc)) { + /* FIXME: raise an exception for invalid instruction */ + return -1; + } + break; + /* st Dest, Src */ + case 0xc000000000000000ULL: + rdst = (unsigned char)((bundle >> 20) & TILEGX_DATA_REGISTER); + rsrc = (unsigned char)((bundle >> 51) & TILEGX_DATA_REGISTER); + if (gen_st(dc, rdst, rsrc)) { + /* FIXME: raise an exception for invalid instruction */ + return -1; + } + break; + default: + /* FIXME: raise an exception for invalid instruction */ + qemu_log("bundle value: %16.16llx, mode: %16.16lx", + TILEGX_CODE_Y2(bundle), mode); + return -1; + } + break; + + default: + /* FIXME: raise an exception for invalid instruction */ + qemu_log("bundle value: %16.16llx", TILEGX_CODE_Y2(bundle)); + return -1; + } + + return 0; +} + +static int translate_one_bundle(struct DisasContext *dc, uint64_t bundle) +{ + int i, ret = 0; + TCGv tmp; + + for (i = 0; i < TILEGX_BUNDLE_INSNS; i++) { + dc->tmp_regs[i].idx = TILEGX_R_NOREG; + TCGV_UNUSED_I64(dc->tmp_regs[i].val); + } + + /* For can regress completely, it must be y0 -> y1 -> y2, or x0 -> x1. */ + if (TILEGX_BUNDLE_TYPE_Y(bundle)) { + dc->tmp_regcur = dc->tmp_regs + 0; + ret = translate_y0_bundle(dc, TILEGX_PIPE_Y0(bundle)); + if (ret) { + goto err; + } + dc->tmp_regcur = dc->tmp_regs + 1; + ret = translate_y1_bundle(dc, TILEGX_PIPE_Y1(bundle)); + if (ret) { + goto err; + } + dc->tmp_regcur = dc->tmp_regs + 2; + ret = translate_y2_bundle(dc, TILEGX_PIPE_Y2(bundle), + bundle & TILEGX_BUNDLE_TYPE_MASK); + if (ret) { + goto err; + } + } else { + dc->tmp_regcur = dc->tmp_regs + 0; + ret = translate_x0_bundle(dc, TILEGX_PIPE_X0(bundle)); + if (ret) { + goto err; + } + dc->tmp_regcur = dc->tmp_regs + 1; + ret = translate_x1_bundle(dc, TILEGX_PIPE_X1(bundle)); + if (ret) { + goto err; + } + } + + for (i = 0; i < TILEGX_BUNDLE_INSNS; i++) { + if (dc->tmp_regs[i].idx == TILEGX_R_NOREG) { + continue; + } + tcg_gen_mov_i64(cpu_regs[dc->tmp_regs[i].idx], dc->tmp_regs[i].val); + tcg_temp_free_i64(dc->tmp_regs[i].val); + } + + if (dc->jmp.cond != TCG_COND_NEVER) { + if (dc->jmp.cond == TCG_COND_ALWAYS) { + tcg_gen_mov_i64(cpu_pc, dc->jmp.dest); + } else { + tmp = tcg_const_i64(dc->pc + TILEGX_BUNDLE_SIZE); + tcg_gen_movcond_i64(dc->jmp.cond, cpu_pc, + dc->jmp.val1, dc->jmp.val2, + dc->jmp.dest, tmp); + tcg_temp_free_i64(dc->jmp.val1); + tcg_temp_free_i64(dc->jmp.val2); + tcg_temp_free_i64(tmp); + } + tcg_temp_free_i64(dc->jmp.dest); + tcg_gen_exit_tb(0); + } + +err: + return ret; +} + static inline void gen_intermediate_code_internal(TilegxCPU *cpu, TranslationBlock *tb, bool search_pc) { - /* - * FIXME: after load elf64 tilegx binary successfully, it will quit, at - * present, and will implement the related features next. - */ - fprintf(stderr, "\nLoad elf64 tilegx successfully\n"); - fprintf(stderr, "reach code start position: [" TARGET_FMT_lx "] %s\n\n", + int ret = 0; + struct DisasContext ctx; + struct DisasContext *dc = &ctx; + + CPUTLState *env = &cpu->env; + uint64_t pc_start = tb->pc; + uint64_t next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE; + int num_insns = 0; + int max_insns = tb->cflags & CF_COUNT_MASK; + + /* FIXME: do not consider about search_pc firstly. */ + qemu_log("TB block start position: [" TARGET_FMT_lx "] %s\n\n", tb->pc, lookup_symbol(tb->pc)); - exit(0); + + dc->pc = pc_start; + dc->cpustate_changed = 0; + dc->jmp.cond = TCG_COND_NEVER; + TCGV_UNUSED_I64(dc->jmp.dest); + TCGV_UNUSED_I64(dc->jmp.val1); + TCGV_UNUSED_I64(dc->jmp.val2); + + if (!max_insns) { + max_insns = CF_COUNT_MASK; + } + + gen_tb_start(tb); + do { + ret = translate_one_bundle(dc, cpu_ldq_data(env, dc->pc)); + if (ret) { + goto err; + } + num_insns++; + dc->pc += TILEGX_BUNDLE_SIZE; + } while (tcg_op_buf_count() <= OPC_MAX_SIZE - TILEGX_BUNDLE_OPCS + && num_insns <= max_insns - TILEGX_BUNDLE_INSNS + && dc->pc <= next_page_start - TILEGX_BUNDLE_SIZE + && dc->jmp.cond == TCG_COND_NEVER + && !dc->cpustate_changed); + gen_tb_end(tb, num_insns); + + tb->size = dc->pc - pc_start; + tb->icount = num_insns; + + return; +err: + exit(-1); } void gen_intermediate_code(CPUTLState *env, struct TranslationBlock *tb) -- 1.9.3