diff options
-rw-r--r-- | target-tricore/helper.h | 4 | ||||
-rw-r--r-- | target-tricore/op_helper.c | 45 | ||||
-rw-r--r-- | target-tricore/translate.c | 303 |
3 files changed, 352 insertions, 0 deletions
diff --git a/target-tricore/helper.h b/target-tricore/helper.h index 7b7d74b32c..fbabbd5c69 100644 --- a/target-tricore/helper.h +++ b/target-tricore/helper.h @@ -23,3 +23,7 @@ DEF_HELPER_2(call, void, env, i32) DEF_HELPER_1(ret, void, env) DEF_HELPER_2(bisr, void, env, i32) DEF_HELPER_1(rfe, void, env) +DEF_HELPER_2(ldlcx, void, env, i32) +DEF_HELPER_2(lducx, void, env, i32) +DEF_HELPER_2(stlcx, void, env, i32) +DEF_HELPER_2(stucx, void, env, i32) diff --git a/target-tricore/op_helper.c b/target-tricore/op_helper.c index f2a5cbccf3..94b5d8e12e 100644 --- a/target-tricore/op_helper.c +++ b/target-tricore/op_helper.c @@ -175,6 +175,27 @@ static void restore_context_upper(CPUTriCoreState *env, int ea, env->gpr_d[15] = cpu_ldl_data(env, ea+60); } +static void restore_context_lower(CPUTriCoreState *env, int ea, + target_ulong *ra, target_ulong *pcxi) +{ + *pcxi = cpu_ldl_data(env, ea); + *ra = cpu_ldl_data(env, ea+4); + env->gpr_a[2] = cpu_ldl_data(env, ea+8); + env->gpr_a[3] = cpu_ldl_data(env, ea+12); + env->gpr_d[0] = cpu_ldl_data(env, ea+16); + env->gpr_d[1] = cpu_ldl_data(env, ea+20); + env->gpr_d[2] = cpu_ldl_data(env, ea+24); + env->gpr_d[3] = cpu_ldl_data(env, ea+28); + env->gpr_a[4] = cpu_ldl_data(env, ea+32); + env->gpr_a[5] = cpu_ldl_data(env, ea+36); + env->gpr_a[6] = cpu_ldl_data(env, ea+40); + env->gpr_a[7] = cpu_ldl_data(env, ea+44); + env->gpr_d[4] = cpu_ldl_data(env, ea+48); + env->gpr_d[5] = cpu_ldl_data(env, ea+52); + env->gpr_d[6] = cpu_ldl_data(env, ea+56); + env->gpr_d[7] = cpu_ldl_data(env, ea+60); +} + void helper_call(CPUTriCoreState *env, uint32_t next_pc) { target_ulong tmp_FCX; @@ -356,6 +377,30 @@ void helper_rfe(CPUTriCoreState *env) psw_write(env, new_PSW); } +void helper_ldlcx(CPUTriCoreState *env, uint32_t ea) +{ + uint32_t dummy; + /* insn doesn't load PCXI and RA */ + restore_context_lower(env, ea, &dummy, &dummy); +} + +void helper_lducx(CPUTriCoreState *env, uint32_t ea) +{ + uint32_t dummy; + /* insn doesn't load PCXI and PSW */ + restore_context_upper(env, ea, &dummy, &dummy); +} + +void helper_stlcx(CPUTriCoreState *env, uint32_t ea) +{ + save_context_lower(env, ea); +} + +void helper_stucx(CPUTriCoreState *env, uint32_t ea) +{ + save_context_upper(env, ea); +} + static inline void QEMU_NORETURN do_raise_exception_err(CPUTriCoreState *env, uint32_t exception, int error_code, diff --git a/target-tricore/translate.c b/target-tricore/translate.c index 4f654deb65..fc89a4357a 100644 --- a/target-tricore/translate.c +++ b/target-tricore/translate.c @@ -115,6 +115,8 @@ void tricore_cpu_dump_state(CPUState *cs, FILE *f, tcg_temp_free_i32(helper_tmp); \ } while (0) +#define EA_ABS_FORMAT(con) (((con & 0x3C000) << 14) + (con & 0x3FFF)) + /* Functions for load/save to/from memory */ static inline void gen_offset_ld(DisasContext *ctx, TCGv r1, TCGv r2, @@ -135,6 +137,62 @@ static inline void gen_offset_st(DisasContext *ctx, TCGv r1, TCGv r2, tcg_temp_free(temp); } +static void gen_st_2regs_64(TCGv rh, TCGv rl, TCGv address, DisasContext *ctx) +{ + TCGv_i64 temp = tcg_temp_new_i64(); + + tcg_gen_concat_i32_i64(temp, rl, rh); + tcg_gen_qemu_st_i64(temp, address, ctx->mem_idx, MO_LEQ); + + tcg_temp_free_i64(temp); +} + +static void gen_ld_2regs_64(TCGv rh, TCGv rl, TCGv address, DisasContext *ctx) +{ + TCGv_i64 temp = tcg_temp_new_i64(); + + tcg_gen_qemu_ld_i64(temp, address, ctx->mem_idx, MO_LEQ); + /* write back to two 32 bit regs */ + tcg_gen_extr_i64_i32(rl, rh, temp); + + tcg_temp_free_i64(temp); +} + +/* M(EA, word) = (M(EA, word) & ~E[a][63:32]) | (E[a][31:0] & E[a][63:32]); */ +static void gen_ldmst(DisasContext *ctx, int ereg, TCGv ea) +{ + TCGv temp = tcg_temp_new(); + TCGv temp2 = tcg_temp_new(); + + /* temp = (M(EA, word) */ + tcg_gen_qemu_ld_tl(temp, ea, ctx->mem_idx, MO_LEUL); + /* temp = temp & ~E[a][63:32]) */ + tcg_gen_andc_tl(temp, temp, cpu_gpr_d[ereg+1]); + /* temp2 = (E[a][31:0] & E[a][63:32]); */ + tcg_gen_and_tl(temp2, cpu_gpr_d[ereg], cpu_gpr_d[ereg+1]); + /* temp = temp | temp2; */ + tcg_gen_or_tl(temp, temp, temp2); + /* M(EA, word) = temp; */ + tcg_gen_qemu_st_tl(temp, ea, ctx->mem_idx, MO_LEUL); + + tcg_temp_free(temp); + tcg_temp_free(temp2); +} + +/* tmp = M(EA, word); + M(EA, word) = D[a]; + D[a] = tmp[31:0];*/ +static void gen_swap(DisasContext *ctx, int reg, TCGv ea) +{ + TCGv temp = tcg_temp_new(); + + tcg_gen_qemu_ld_tl(temp, ea, ctx->mem_idx, MO_LEUL); + tcg_gen_qemu_st_tl(cpu_gpr_d[reg], ea, ctx->mem_idx, MO_LEUL); + tcg_gen_mov_tl(cpu_gpr_d[reg], temp); + + tcg_temp_free(temp); +} + /* Functions for arithmetic instructions */ static inline void gen_add_d(TCGv ret, TCGv r1, TCGv r2) @@ -1099,8 +1157,253 @@ static void decode_16Bit_opc(CPUTriCoreState *env, DisasContext *ctx) } } +/* + * 32 bit instructions + */ + +/* ABS-format */ +static void decode_abs_ldw(CPUTriCoreState *env, DisasContext *ctx) +{ + int32_t op2; + int32_t r1; + uint32_t address; + TCGv temp; + + r1 = MASK_OP_ABS_S1D(ctx->opcode); + address = MASK_OP_ABS_OFF18(ctx->opcode); + op2 = MASK_OP_ABS_OP2(ctx->opcode); + + temp = tcg_const_i32(EA_ABS_FORMAT(address)); + + switch (op2) { + case OPC2_32_ABS_LD_A: + tcg_gen_qemu_ld_tl(cpu_gpr_a[r1], temp, ctx->mem_idx, MO_LESL); + break; + case OPC2_32_ABS_LD_D: + gen_ld_2regs_64(cpu_gpr_d[r1+1], cpu_gpr_d[r1], temp, ctx); + break; + case OPC2_32_ABS_LD_DA: + gen_ld_2regs_64(cpu_gpr_a[r1+1], cpu_gpr_a[r1], temp, ctx); + break; + case OPC2_32_ABS_LD_W: + tcg_gen_qemu_ld_tl(cpu_gpr_d[r1], temp, ctx->mem_idx, MO_LESL); + break; + } + + tcg_temp_free(temp); +} + +static void decode_abs_ldb(CPUTriCoreState *env, DisasContext *ctx) +{ + int32_t op2; + int32_t r1; + uint32_t address; + TCGv temp; + + r1 = MASK_OP_ABS_S1D(ctx->opcode); + address = MASK_OP_ABS_OFF18(ctx->opcode); + op2 = MASK_OP_ABS_OP2(ctx->opcode); + + temp = tcg_const_i32(EA_ABS_FORMAT(address)); + + switch (op2) { + case OPC2_32_ABS_LD_B: + tcg_gen_qemu_ld_tl(cpu_gpr_d[r1], temp, ctx->mem_idx, MO_SB); + break; + case OPC2_32_ABS_LD_BU: + tcg_gen_qemu_ld_tl(cpu_gpr_d[r1], temp, ctx->mem_idx, MO_UB); + break; + case OPC2_32_ABS_LD_H: + tcg_gen_qemu_ld_tl(cpu_gpr_d[r1], temp, ctx->mem_idx, MO_LESW); + break; + case OPC2_32_ABS_LD_HU: + tcg_gen_qemu_ld_tl(cpu_gpr_d[r1], temp, ctx->mem_idx, MO_LEUW); + break; + } + + tcg_temp_free(temp); +} + +static void decode_abs_ldst_swap(CPUTriCoreState *env, DisasContext *ctx) +{ + int32_t op2; + int32_t r1; + uint32_t address; + TCGv temp; + + r1 = MASK_OP_ABS_S1D(ctx->opcode); + address = MASK_OP_ABS_OFF18(ctx->opcode); + op2 = MASK_OP_ABS_OP2(ctx->opcode); + + temp = tcg_const_i32(EA_ABS_FORMAT(address)); + + switch (op2) { + case OPC2_32_ABS_LDMST: + gen_ldmst(ctx, r1, temp); + break; + case OPC2_32_ABS_SWAP_W: + gen_swap(ctx, r1, temp); + break; + } + + tcg_temp_free(temp); +} + +static void decode_abs_ldst_context(CPUTriCoreState *env, DisasContext *ctx) +{ + uint32_t op2; + int32_t off18; + + off18 = MASK_OP_ABS_OFF18(ctx->opcode); + op2 = MASK_OP_ABS_OP2(ctx->opcode); + + switch (op2) { + case OPC2_32_ABS_LDLCX: + gen_helper_1arg(ldlcx, EA_ABS_FORMAT(off18)); + break; + case OPC2_32_ABS_LDUCX: + gen_helper_1arg(lducx, EA_ABS_FORMAT(off18)); + break; + case OPC2_32_ABS_STLCX: + gen_helper_1arg(stlcx, EA_ABS_FORMAT(off18)); + break; + case OPC2_32_ABS_STUCX: + gen_helper_1arg(stucx, EA_ABS_FORMAT(off18)); + break; + } +} + +static void decode_abs_store(CPUTriCoreState *env, DisasContext *ctx) +{ + int32_t op2; + int32_t r1; + uint32_t address; + TCGv temp; + + r1 = MASK_OP_ABS_S1D(ctx->opcode); + address = MASK_OP_ABS_OFF18(ctx->opcode); + op2 = MASK_OP_ABS_OP2(ctx->opcode); + + temp = tcg_const_i32(EA_ABS_FORMAT(address)); + + switch (op2) { + case OPC2_32_ABS_ST_A: + tcg_gen_qemu_st_tl(cpu_gpr_a[r1], temp, ctx->mem_idx, MO_LESL); + break; + case OPC2_32_ABS_ST_D: + gen_st_2regs_64(cpu_gpr_d[r1+1], cpu_gpr_d[r1], temp, ctx); + break; + case OPC2_32_ABS_ST_DA: + gen_st_2regs_64(cpu_gpr_a[r1+1], cpu_gpr_a[r1], temp, ctx); + break; + case OPC2_32_ABS_ST_W: + tcg_gen_qemu_st_tl(cpu_gpr_d[r1], temp, ctx->mem_idx, MO_LESL); + break; + + } + tcg_temp_free(temp); +} + +static void decode_abs_storeb_h(CPUTriCoreState *env, DisasContext *ctx) +{ + int32_t op2; + int32_t r1; + uint32_t address; + TCGv temp; + + r1 = MASK_OP_ABS_S1D(ctx->opcode); + address = MASK_OP_ABS_OFF18(ctx->opcode); + op2 = MASK_OP_ABS_OP2(ctx->opcode); + + temp = tcg_const_i32(EA_ABS_FORMAT(address)); + + switch (op2) { + case OPC2_32_ABS_ST_B: + tcg_gen_qemu_st_tl(cpu_gpr_d[r1], temp, ctx->mem_idx, MO_UB); + break; + case OPC2_32_ABS_ST_H: + tcg_gen_qemu_st_tl(cpu_gpr_d[r1], temp, ctx->mem_idx, MO_LEUW); + break; + } + tcg_temp_free(temp); +} + static void decode_32Bit_opc(CPUTriCoreState *env, DisasContext *ctx) { + int op1; + int32_t r1; + int32_t address; + int8_t b; + int32_t bpos; + TCGv temp, temp2; + + op1 = MASK_OP_MAJOR(ctx->opcode); + + switch (op1) { +/* ABS-format */ + case OPCM_32_ABS_LDW: + decode_abs_ldw(env, ctx); + break; + case OPCM_32_ABS_LDB: + decode_abs_ldb(env, ctx); + break; + case OPCM_32_ABS_LDMST_SWAP: + decode_abs_ldst_swap(env, ctx); + break; + case OPCM_32_ABS_LDST_CONTEXT: + decode_abs_ldst_context(env, ctx); + break; + case OPCM_32_ABS_STORE: + decode_abs_store(env, ctx); + break; + case OPCM_32_ABS_STOREB_H: + decode_abs_storeb_h(env, ctx); + break; + case OPC1_32_ABS_STOREQ: + address = MASK_OP_ABS_OFF18(ctx->opcode); + r1 = MASK_OP_ABS_S1D(ctx->opcode); + temp = tcg_const_i32(EA_ABS_FORMAT(address)); + temp2 = tcg_temp_new(); + + tcg_gen_shri_tl(temp2, cpu_gpr_d[r1], 16); + tcg_gen_qemu_st_tl(temp2, temp, ctx->mem_idx, MO_LEUW); + + tcg_temp_free(temp2); + tcg_temp_free(temp); + break; + case OPC1_32_ABS_LD_Q: + address = MASK_OP_ABS_OFF18(ctx->opcode); + r1 = MASK_OP_ABS_S1D(ctx->opcode); + temp = tcg_const_i32(EA_ABS_FORMAT(address)); + + tcg_gen_qemu_ld_tl(cpu_gpr_d[r1], temp, ctx->mem_idx, MO_LEUW); + tcg_gen_shli_tl(cpu_gpr_d[r1], cpu_gpr_d[r1], 16); + + tcg_temp_free(temp); + break; + case OPC1_32_ABS_LEA: + address = MASK_OP_ABS_OFF18(ctx->opcode); + r1 = MASK_OP_ABS_S1D(ctx->opcode); + tcg_gen_movi_tl(cpu_gpr_a[r1], EA_ABS_FORMAT(address)); + break; +/* ABSB-format */ + case OPC1_32_ABSB_ST_T: + address = MASK_OP_ABS_OFF18(ctx->opcode); + b = MASK_OP_ABSB_B(ctx->opcode); + bpos = MASK_OP_ABSB_BPOS(ctx->opcode); + + temp = tcg_const_i32(EA_ABS_FORMAT(address)); + temp2 = tcg_temp_new(); + + tcg_gen_qemu_ld_tl(temp2, temp, ctx->mem_idx, MO_UB); + tcg_gen_andi_tl(temp2, temp2, ~(0x1u << bpos)); + tcg_gen_ori_tl(temp2, temp2, (b << bpos)); + tcg_gen_qemu_st_tl(temp2, temp, ctx->mem_idx, MO_UB); + + tcg_temp_free(temp); + tcg_temp_free(temp2); + break; + } } static void decode_opc(CPUTriCoreState *env, DisasContext *ctx, int *is_branch) |