Add instructions of SB opcode format. Add helper call/ret. Add micro-op generator functions for branches. Add makro to generate helper functions.
Signed-off-by: Bastian Koppelmann <kbast...@mail.uni-paderborn.de> --- v4 -> v5: - Change int cond to TCGCond in functions gen_branch_cond, gen_branch_condi. - gen_intermediate_code_internal: Add gen_goto_tb so qemu finds new tb on singlestep and after long tbs without branch. target-tricore/helper.h | 3 + target-tricore/op_helper.c | 180 +++++++++++++++++++++++++++++++++++++++++++++ target-tricore/translate.c | 91 +++++++++++++++++++++++ 3 files changed, 274 insertions(+) diff --git a/target-tricore/helper.h b/target-tricore/helper.h index 299bd77..adf5b26 100644 --- a/target-tricore/helper.h +++ b/target-tricore/helper.h @@ -18,3 +18,6 @@ /* Arithmetic */ DEF_HELPER_3(add_ssov, i32, env, i32, i32) DEF_HELPER_3(sub_ssov, i32, env, i32, i32) +/* CSA */ +DEF_HELPER_2(call, void, env, i32) +DEF_HELPER_1(ret, void, env) diff --git a/target-tricore/op_helper.c b/target-tricore/op_helper.c index 3c83945..bdcb2c4 100644 --- a/target-tricore/op_helper.c +++ b/target-tricore/op_helper.c @@ -63,6 +63,186 @@ target_ulong helper_sub_ssov(CPUTRICOREState *env, target_ulong r1, return ret; } +/* context save area (CSA) related helpers */ + +static int cdc_increment(target_ulong *psw) +{ + if ((*psw & MASK_PSW_CDC) == 0x7f) { + return 0; + } + + (*psw)++; + /* check for overflow */ + int lo = clo32((*psw & MASK_PSW_CDC) << (32 - 7)); + int mask = (1u << (7 - lo)) - 1; + int count = *psw & mask; + if (count == 0) { + (*psw)--; + return 1; + } + return 0; +} + +static int cdc_decrement(target_ulong *psw) +{ + if ((*psw & MASK_PSW_CDC) == 0x7f) { + return 0; + } + /* check for underflow */ + int lo = clo32((*psw & MASK_PSW_CDC) << (32 - 7)); + int mask = (1u << (7 - lo)) - 1; + int count = *psw & mask; + if (count == 0) { + return 1; + } + (*psw)--; + return 0; +} + +static void save_context_upper(CPUTRICOREState *env, int ea, + target_ulong *new_FCX) +{ + *new_FCX = cpu_ldl_data(env, ea); + cpu_stl_data(env, ea, env->PCXI); + cpu_stl_data(env, ea+4, env->PSW); + cpu_stl_data(env, ea+8, env->gpr_a[10]); + cpu_stl_data(env, ea+12, env->gpr_a[11]); + cpu_stl_data(env, ea+16, env->gpr_d[8]); + cpu_stl_data(env, ea+20, env->gpr_d[9]); + cpu_stl_data(env, ea+24, env->gpr_d[10]); + cpu_stl_data(env, ea+28, env->gpr_d[11]); + cpu_stl_data(env, ea+32, env->gpr_a[12]); + cpu_stl_data(env, ea+36, env->gpr_a[13]); + cpu_stl_data(env, ea+40, env->gpr_a[14]); + cpu_stl_data(env, ea+44, env->gpr_a[15]); + cpu_stl_data(env, ea+48, env->gpr_d[12]); + cpu_stl_data(env, ea+52, env->gpr_d[13]); + cpu_stl_data(env, ea+56, env->gpr_d[14]); + cpu_stl_data(env, ea+60, env->gpr_d[15]); + +} + +static void restore_context_upper(CPUTRICOREState *env, int ea, + target_ulong *new_PCXI, target_ulong *new_PSW) +{ + *new_PCXI = cpu_ldl_data(env, ea); + *new_PSW = cpu_ldl_data(env, ea+4); + env->gpr_a[10] = cpu_ldl_data(env, ea+8); + env->gpr_a[11] = cpu_ldl_data(env, ea+12); + env->gpr_d[8] = cpu_ldl_data(env, ea+16); + env->gpr_d[9] = cpu_ldl_data(env, ea+20); + env->gpr_d[10] = cpu_ldl_data(env, ea+24); + env->gpr_d[11] = cpu_ldl_data(env, ea+28); + env->gpr_a[12] = cpu_ldl_data(env, ea+32); + env->gpr_a[13] = cpu_ldl_data(env, ea+36); + env->gpr_a[14] = cpu_ldl_data(env, ea+40); + env->gpr_a[15] = cpu_ldl_data(env, ea+44); + env->gpr_d[12] = cpu_ldl_data(env, ea+48); + env->gpr_d[13] = cpu_ldl_data(env, ea+52); + env->gpr_d[14] = cpu_ldl_data(env, ea+56); + env->gpr_d[15] = cpu_ldl_data(env, ea+60); + cpu_stl_data(env, ea, env->FCX); +} + +void helper_call(CPUTRICOREState *env, uint32_t next_pc) +{ + target_ulong tmp_FCX; + target_ulong ea; + target_ulong new_FCX; + target_ulong psw; + + psw = psw_read(env); + /* if (FCX == 0) trap(FCU); */ + if (env->FCX == 0) { + /* FCU trap */ + } + /* if (PSW.CDE) then if (cdc_increment()) then trap(CDO); */ + if (psw & MASK_PSW_CDE) { + if (cdc_increment(&psw)) { + /* CDO trap */ + } + } + /* PSW.CDE = 1;*/ + psw |= MASK_PSW_CDE; + /* tmp_FCX = FCX; */ + tmp_FCX = env->FCX; + /* EA = {FCX.FCXS, 6'b0, FCX.FCXO, 6'b0}; */ + ea = ((env->FCX & MASK_FCX_FCXS) << 12) + + ((env->FCX & MASK_FCX_FCXO) << 6); + /* new_FCX = M(EA, word); + M(EA, 16 * word) = {PCXI, PSW, A[10], A[11], D[8], D[9], D[10], D[11], + A[12], A[13], A[14], A[15], D[12], D[13], D[14], + D[15]}; */ + save_context_upper(env, ea, &new_FCX); + + /* PCXI.PCPN = ICR.CCPN; */ + env->PCXI = (env->PCXI & 0xffffff) + + ((env->ICR & MASK_ICR_CCPN) << 24); + /* PCXI.PIE = ICR.IE; */ + env->PCXI = ((env->PCXI & ~MASK_PCXI_PIE) + + ((env->ICR & MASK_ICR_IE) << 15)); + /* PCXI.UL = 1; */ + env->PCXI |= MASK_PCXI_UL; + + /* PCXI[19: 0] = FCX[19: 0]; */ + env->PCXI = (env->PCXI & 0xfff00000) + (env->FCX & 0xfffff); + /* FCX[19: 0] = new_FCX[19: 0]; */ + env->FCX = (env->FCX & 0xfff00000) + (new_FCX & 0xfffff); + /* A[11] = next_pc[31: 0]; */ + env->gpr_a[11] = next_pc; + + /* if (tmp_FCX == LCX) trap(FCD);*/ + if (tmp_FCX == env->LCX) { + /* FCD trap */ + } + psw_write(env, psw); +} + +void helper_ret(CPUTRICOREState *env) +{ + target_ulong ea; + target_ulong new_PCXI; + target_ulong new_PSW, psw; + + psw = psw_read(env); + /* if (PSW.CDE) then if (cdc_decrement()) then trap(CDU);*/ + if (env->PSW & MASK_PSW_CDE) { + if (cdc_decrement(&(env->PSW))) { + /* CDU trap */ + } + } + /* if (PCXI[19: 0] == 0) then trap(CSU); */ + if ((env->PCXI & 0xfffff) == 0) { + /* CSU trap */ + } + /* if (PCXI.UL == 0) then trap(CTYP); */ + if ((env->PCXI & MASK_PCXI_UL) == 0) { + /* CTYP trap */ + } + /* PC = {A11 [31: 1], 1’b0}; */ + env->PC = env->gpr_a[11] & 0xfffffffe; + + /* EA = {PCXI.PCXS, 6'b0, PCXI.PCXO, 6'b0}; */ + ea = ((env->PCXI & MASK_PCXI_PCXS) << 12) + + ((env->PCXI & MASK_PCXI_PCXO) << 6); + /* {new_PCXI, new_PSW, A[10], A[11], D[8], D[9], D[10], D[11], A[12], + A[13], A[14], A[15], D[12], D[13], D[14], D[15]} = M(EA, 16 * word); + M(EA, word) = FCX; */ + restore_context_upper(env, ea, &new_PCXI, &new_PSW); + /* FCX[19: 0] = PCXI[19: 0]; */ + env->FCX = (env->FCX & 0xfff00000) + (env->PCXI & 0x000fffff); + /* PCXI = new_PCXI; */ + env->PCXI = new_PCXI; + + if (tricore_feature(env, TRICORE_FEATURE_13)) { + /* PSW = new_PSW */ + psw_write(env, new_PSW); + } else { + /* PSW = {new_PSW[31:26], PSW[25:24], new_PSW[23:0]}; */ + psw_write(env, (new_PSW & ~(0x3000000)) + (psw & (0x3000000))); + } +} + 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 ad30c3d..b06f856 100644 --- a/target-tricore/translate.c +++ b/target-tricore/translate.c @@ -107,6 +107,14 @@ void tricore_cpu_dump_state(CPUState *cs, FILE *f, * Functions to generate micro-ops */ +/* Makros for generating helpers */ + +#define gen_helper_1arg(name, arg) do { \ + TCGv_i32 helper_tmp = tcg_const_i32(arg); \ + gen_helper_##name(cpu_env, helper_tmp); \ + tcg_temp_free_i32(helper_tmp); \ + } while (0) + /* Functions for load/save to/from memory */ static inline void gen_offset_ld(DisasContext *ctx, TCGv r1, TCGv r2, @@ -332,6 +340,78 @@ static inline void gen_subs(TCGv ret, TCGv r1, TCGv r2) gen_helper_sub_ssov(ret, cpu_env, r1, r2); } +/* helpers for generating program flow micro-ops */ + +static inline void gen_save_pc(target_ulong pc) +{ + tcg_gen_movi_tl(cpu_PC, pc); +} + +static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) +{ + TranslationBlock *tb; + tb = ctx->tb; + if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) && + likely(!ctx->singlestep_enabled)) { + tcg_gen_goto_tb(n); + gen_save_pc(dest); + tcg_gen_exit_tb((uintptr_t)tb + n); + } else { + gen_save_pc(dest); + if (ctx->singlestep_enabled) { + /* raise exception debug */ + } + tcg_gen_exit_tb(0); + } +} + +static inline void gen_branch_cond(DisasContext *ctx, TCGCond cond, TCGv r1, + TCGv r2, int16_t address) +{ + int jumpLabel; + jumpLabel = gen_new_label(); + tcg_gen_brcond_tl(cond, r1, r2, jumpLabel); + + gen_goto_tb(ctx, 1, ctx->next_pc); + + gen_set_label(jumpLabel); + gen_goto_tb(ctx, 0, ctx->pc + address * 2); +} + +static inline void gen_branch_condi(DisasContext *ctx, TCGCond cond, TCGv r1, + int r2, int16_t address) +{ + TCGv temp = tcg_const_i32(r2); + gen_branch_cond(ctx, cond, r1, temp, address); + tcg_temp_free(temp); +} + +static void gen_compute_branch(DisasContext *ctx, uint32_t opc, int r1, + int r2 , int32_t constant , int32_t offset) +{ + switch (opc) { +/* SB-format jumps */ + case OPC1_16_SB_J: + case OPC1_32_B_J: + gen_goto_tb(ctx, 0, ctx->pc + offset * 2); + break; + case OPC1_16_SB_CALL: + gen_helper_1arg(call, ctx->next_pc); + gen_goto_tb(ctx, 0, ctx->pc + offset * 2); + break; + case OPC1_16_SB_JZ: + gen_branch_condi(ctx, TCG_COND_EQ, cpu_gpr_d[15], 0, offset); + break; + case OPC1_16_SB_JNZ: + gen_branch_condi(ctx, TCG_COND_NE, cpu_gpr_d[15], 0, offset); + break; + default: + printf("Branch Error at %x\n", ctx->pc); + } + ctx->bstate = BS_BRANCH; +} + + /* * Functions for decoding instructions */ @@ -533,6 +613,7 @@ static void decode_16Bit_opc(CPUTRICOREState *env, DisasContext *ctx) int op1; int r1, r2; int32_t const16; + int32_t address; TCGv temp; op1 = MASK_OP_MAJOR(ctx->opcode); @@ -625,6 +706,14 @@ static void decode_16Bit_opc(CPUTRICOREState *env, DisasContext *ctx) const16 = MASK_OP_SLRO_OFF4(ctx->opcode); gen_offset_ld(ctx, cpu_gpr_d[r1], cpu_gpr_a[15], const16 * 4, MO_LESL); break; +/* SB-format */ + case OPC1_16_SB_CALL: + case OPC1_16_SB_J: + case OPC1_16_SB_JNZ: + case OPC1_16_SB_JZ: + address = MASK_OP_SB_DISP8_SEXT(ctx->opcode); + gen_compute_branch(ctx, op1, 0, 0, 0, address); + break; } } @@ -679,9 +768,11 @@ gen_intermediate_code_internal(TRICORECPU *cpu, struct TranslationBlock *tb, num_insns++; if (tcg_ctx.gen_opc_ptr >= gen_opc_end) { + gen_goto_tb(&ctx, 0, ctx.next_pc); break; } if (singlestep) { + gen_goto_tb(&ctx, 0, ctx.next_pc); break; } ctx.pc = ctx.next_pc; -- 2.0.4