diff options
Diffstat (limited to 'target-cris/translate.c')
-rw-r--r-- | target-cris/translate.c | 287 |
1 files changed, 219 insertions, 68 deletions
diff --git a/target-cris/translate.c b/target-cris/translate.c index fffc98d37e..854878ebf5 100644 --- a/target-cris/translate.c +++ b/target-cris/translate.c @@ -223,9 +223,9 @@ static inline void t_gen_mov_preg_TN(int r, TCGv tn) } } -static inline void t_gen_mov_TN_im(TCGv tn, int32_t val) +static inline void t_gen_raise_exception(uint32_t index) { - tcg_gen_movi_tl(tn, val); + tcg_gen_helper_0_1(helper_raise_exception, tcg_const_tl(index)); } static void t_gen_lsl(TCGv d, TCGv a, TCGv b) @@ -375,6 +375,62 @@ static void t_gen_lz_i32(TCGv d, TCGv x) tcg_gen_discard_i32(n); } +static void t_gen_btst(TCGv d, TCGv s) +{ + TCGv sbit; + TCGv bset; + int l1; + + /* des ref: + The N flag is set according to the selected bit in the dest reg. + The Z flag is set if the selected bit and all bits to the right are + zero. + The X flag is cleared. + Other flags are left untouched. + The destination reg is not affected. + + unsigned int fz, sbit, bset, mask, masked_t0; + + sbit = T1 & 31; + bset = !!(T0 & (1 << sbit)); + mask = sbit == 31 ? -1 : (1 << (sbit + 1)) - 1; + masked_t0 = T0 & mask; + fz = !(masked_t0 | bset); + + // Clear the X, N and Z flags. + T0 = env->pregs[PR_CCS] & ~(X_FLAG | N_FLAG | Z_FLAG); + // Set the N and Z flags accordingly. + T0 |= (bset << 3) | (fz << 2); + */ + + l1 = gen_new_label(); + sbit = tcg_temp_new(TCG_TYPE_TL); + bset = tcg_temp_new(TCG_TYPE_TL); + + /* Compute bset and sbit. */ + tcg_gen_andi_tl(sbit, s, 31); + tcg_gen_shl_tl(s, tcg_const_tl(1), sbit); + tcg_gen_and_tl(bset, d, s); + tcg_gen_shr_tl(bset, bset, sbit); + /* Displace to N_FLAG. */ + tcg_gen_shli_tl(bset, bset, 3); + + tcg_gen_shl_tl(sbit, tcg_const_tl(2), sbit); + tcg_gen_subi_tl(sbit, sbit, 1); + tcg_gen_and_tl(sbit, d, sbit); + + tcg_gen_andi_tl(d, cpu_PR[PR_CCS], ~(X_FLAG | N_FLAG | Z_FLAG)); + /* or in the N_FLAG. */ + tcg_gen_or_tl(d, d, bset); + tcg_gen_brcond_tl(TCG_COND_NE, sbit, tcg_const_tl(0), l1); + /* or in the Z_FLAG. */ + tcg_gen_ori_tl(d, d, Z_FLAG); + gen_set_label(l1); + + tcg_gen_discard_tl(sbit); + tcg_gen_discard_tl(bset); +} + static void t_gen_cris_dstep(TCGv d, TCGv s) { int l1; @@ -738,7 +794,7 @@ static void crisv32_alu_op(DisasContext *dc, int op, int rd, int size) t_gen_lz_i32(cpu_T[0], cpu_T[1]); break; case CC_OP_BTST: - gen_op_btst_T0_T1(); + t_gen_btst(cpu_T[0], cpu_T[1]); writeback = 0; break; case CC_OP_MULS: @@ -846,83 +902,172 @@ static void gen_tst_cc (DisasContext *dc, int cond) int arith_opt; /* TODO: optimize more condition codes. */ + + /* + * If the flags are live, we've gotta look into the bits of CCS. + * Otherwise, if we just did an arithmetic operation we try to + * evaluate the condition code faster. + * + * When this function is done, T0 should be non-zero if the condition + * code is true. + */ arith_opt = arith_cc(dc) && !dc->flags_live; switch (cond) { case CC_EQ: - if (arith_opt) - gen_op_tst_cc_eq_fast (); + if (arith_opt) { + /* If cc_result is zero, T0 should be + non-zero otherwise T0 should be zero. */ + int l1; + l1 = gen_new_label(); + tcg_gen_movi_tl(cpu_T[0], 0); + tcg_gen_brcond_tl(TCG_COND_NE, cc_result, + tcg_const_tl(0), l1); + tcg_gen_movi_tl(cpu_T[0], 1); + gen_set_label(l1); + } else { cris_evaluate_flags(dc); - gen_op_tst_cc_eq (); + tcg_gen_andi_tl(cpu_T[0], + cpu_PR[PR_CCS], Z_FLAG); } break; case CC_NE: if (arith_opt) - gen_op_tst_cc_ne_fast (); + tcg_gen_mov_tl(cpu_T[0], cc_result); else { cris_evaluate_flags(dc); - gen_op_tst_cc_ne (); + tcg_gen_xori_tl(cpu_T[0], cpu_PR[PR_CCS], + Z_FLAG); + tcg_gen_andi_tl(cpu_T[0], cpu_T[0], Z_FLAG); } break; case CC_CS: cris_evaluate_flags(dc); - gen_op_tst_cc_cs (); + tcg_gen_andi_tl(cpu_T[0], cpu_PR[PR_CCS], C_FLAG); break; case CC_CC: cris_evaluate_flags(dc); - gen_op_tst_cc_cc (); + tcg_gen_xori_tl(cpu_T[0], cpu_PR[PR_CCS], + C_FLAG); + tcg_gen_andi_tl(cpu_T[0], cpu_T[0], C_FLAG); break; case CC_VS: cris_evaluate_flags(dc); - gen_op_tst_cc_vs (); + tcg_gen_andi_tl(cpu_T[0], cpu_PR[PR_CCS], V_FLAG); break; case CC_VC: cris_evaluate_flags(dc); - gen_op_tst_cc_vc (); + tcg_gen_xori_tl(cpu_T[0], cpu_PR[PR_CCS], + V_FLAG); + tcg_gen_andi_tl(cpu_T[0], cpu_T[0], V_FLAG); break; case CC_PL: if (arith_opt) - gen_op_tst_cc_pl_fast (); + tcg_gen_shli_tl(cpu_T[0], cc_result, 31); else { cris_evaluate_flags(dc); - gen_op_tst_cc_pl (); + tcg_gen_xori_tl(cpu_T[0], cpu_PR[PR_CCS], + N_FLAG); + tcg_gen_andi_tl(cpu_T[0], cpu_T[0], N_FLAG); } break; case CC_MI: - if (arith_opt) - gen_op_tst_cc_mi_fast (); + if (arith_opt) { + tcg_gen_shli_tl(cpu_T[0], cc_result, 31); + tcg_gen_xori_tl(cpu_T[0], cpu_T[0], 1); + } else { cris_evaluate_flags(dc); - gen_op_tst_cc_mi (); + tcg_gen_andi_tl(cpu_T[0], cpu_PR[PR_CCS], + N_FLAG); } break; case CC_LS: cris_evaluate_flags(dc); - gen_op_tst_cc_ls (); + tcg_gen_andi_tl(cpu_T[0], cpu_PR[PR_CCS], + C_FLAG | Z_FLAG); break; case CC_HI: cris_evaluate_flags(dc); - gen_op_tst_cc_hi (); + { + TCGv tmp; + + tmp = tcg_temp_new(TCG_TYPE_TL); + tcg_gen_xori_tl(tmp, cpu_PR[PR_CCS], + C_FLAG | Z_FLAG); + /* Overlay the C flag on top of the Z. */ + tcg_gen_shli_tl(cpu_T[0], tmp, 2); + tcg_gen_and_tl(cpu_T[0], tmp, cpu_T[0]); + tcg_gen_andi_tl(cpu_T[0], cpu_T[0], Z_FLAG); + + tcg_gen_discard_tl(tmp); + } break; case CC_GE: cris_evaluate_flags(dc); - gen_op_tst_cc_ge (); + /* Overlay the V flag on top of the N. */ + tcg_gen_shli_tl(cpu_T[0], cpu_PR[PR_CCS], 2); + tcg_gen_xor_tl(cpu_T[0], + cpu_PR[PR_CCS], cpu_T[0]); + tcg_gen_andi_tl(cpu_T[0], cpu_T[0], N_FLAG); + tcg_gen_xori_tl(cpu_T[0], cpu_T[0], N_FLAG); break; case CC_LT: cris_evaluate_flags(dc); - gen_op_tst_cc_lt (); + /* Overlay the V flag on top of the N. */ + tcg_gen_shli_tl(cpu_T[0], cpu_PR[PR_CCS], 2); + tcg_gen_xor_tl(cpu_T[0], + cpu_PR[PR_CCS], cpu_T[0]); + tcg_gen_andi_tl(cpu_T[0], cpu_T[0], N_FLAG); break; case CC_GT: cris_evaluate_flags(dc); - gen_op_tst_cc_gt (); + { + TCGv n, z; + + n = tcg_temp_new(TCG_TYPE_TL); + z = tcg_temp_new(TCG_TYPE_TL); + + /* To avoid a shift we overlay everything on + the V flag. */ + tcg_gen_shri_tl(n, cpu_PR[PR_CCS], 2); + tcg_gen_shri_tl(z, cpu_PR[PR_CCS], 1); + /* invert Z. */ + tcg_gen_xori_tl(z, z, 2); + + tcg_gen_xor_tl(n, n, cpu_PR[PR_CCS]); + tcg_gen_xori_tl(n, n, 2); + tcg_gen_and_tl(cpu_T[0], z, n); + tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 2); + + tcg_gen_discard_tl(n); + tcg_gen_discard_tl(z); + } break; case CC_LE: cris_evaluate_flags(dc); - gen_op_tst_cc_le (); + { + TCGv n, z; + + n = tcg_temp_new(TCG_TYPE_TL); + z = tcg_temp_new(TCG_TYPE_TL); + + /* To avoid a shift we overlay everything on + the V flag. */ + tcg_gen_shri_tl(n, cpu_PR[PR_CCS], 2); + tcg_gen_shri_tl(z, cpu_PR[PR_CCS], 1); + + tcg_gen_xor_tl(n, n, cpu_PR[PR_CCS]); + tcg_gen_or_tl(cpu_T[0], z, n); + tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 2); + + tcg_gen_discard_tl(n); + tcg_gen_discard_tl(z); + } break; case CC_P: cris_evaluate_flags(dc); - gen_op_tst_cc_p (); + tcg_gen_andi_tl(cpu_T[0], cpu_PR[PR_CCS], P_FLAG); break; case CC_A: cris_evaluate_flags(dc); @@ -944,7 +1089,7 @@ static void cris_prepare_cc_branch (DisasContext *dc, int offset, int cond) if (cond != CC_A) { gen_tst_cc (dc, cond); - gen_op_evaluate_bcc (); + t_gen_mov_env_TN(btaken, cpu_T[0]); } tcg_gen_movi_tl(env_btarget, dc->delayed_pc); } @@ -1225,7 +1370,7 @@ static unsigned int dec_subq(DisasContext *dc) cris_cc_mask(dc, CC_MASK_NZVC); /* Fetch register operand, */ t_gen_mov_TN_reg(cpu_T[0], dc->op2); - t_gen_mov_TN_im(cpu_T[1], dc->op1); + tcg_gen_movi_tl(cpu_T[1], dc->op1); crisv32_alu_op(dc, CC_OP_SUB, dc->op2, 4); return 2; } @@ -1238,7 +1383,7 @@ static unsigned int dec_cmpq(DisasContext *dc) DIS(fprintf (logfile, "cmpq %d, $r%d\n", imm, dc->op2)); cris_cc_mask(dc, CC_MASK_NZVC); t_gen_mov_TN_reg(cpu_T[0], dc->op2); - t_gen_mov_TN_im(cpu_T[1], imm); + tcg_gen_movi_tl(cpu_T[1], imm); crisv32_alu_op(dc, CC_OP_CMP, dc->op2, 4); return 2; } @@ -1251,7 +1396,7 @@ static unsigned int dec_andq(DisasContext *dc) DIS(fprintf (logfile, "andq %d, $r%d\n", imm, dc->op2)); cris_cc_mask(dc, CC_MASK_NZ); t_gen_mov_TN_reg(cpu_T[0], dc->op2); - t_gen_mov_TN_im(cpu_T[1], imm); + tcg_gen_movi_tl(cpu_T[1], imm); crisv32_alu_op(dc, CC_OP_AND, dc->op2, 4); return 2; } @@ -1263,7 +1408,7 @@ static unsigned int dec_orq(DisasContext *dc) DIS(fprintf (logfile, "orq %d, $r%d\n", imm, dc->op2)); cris_cc_mask(dc, CC_MASK_NZ); t_gen_mov_TN_reg(cpu_T[0], dc->op2); - t_gen_mov_TN_im(cpu_T[1], imm); + tcg_gen_movi_tl(cpu_T[1], imm); crisv32_alu_op(dc, CC_OP_OR, dc->op2, 4); return 2; } @@ -1272,10 +1417,9 @@ static unsigned int dec_btstq(DisasContext *dc) dc->op1 = EXTRACT_FIELD(dc->ir, 0, 4); DIS(fprintf (logfile, "btstq %u, $r%d\n", dc->op1, dc->op2)); - cris_evaluate_flags(dc); cris_cc_mask(dc, CC_MASK_NZ); t_gen_mov_TN_reg(cpu_T[0], dc->op2); - t_gen_mov_TN_im(cpu_T[1], dc->op1); + tcg_gen_movi_tl(cpu_T[1], dc->op1); crisv32_alu_op(dc, CC_OP_BTST, dc->op2, 4); cris_update_cc_op(dc, CC_OP_FLAGS, 4); @@ -1289,7 +1433,7 @@ static unsigned int dec_asrq(DisasContext *dc) DIS(fprintf (logfile, "asrq %u, $r%d\n", dc->op1, dc->op2)); cris_cc_mask(dc, CC_MASK_NZ); t_gen_mov_TN_reg(cpu_T[0], dc->op2); - t_gen_mov_TN_im(cpu_T[1], dc->op1); + tcg_gen_movi_tl(cpu_T[1], dc->op1); crisv32_alu_op(dc, CC_OP_ASR, dc->op2, 4); return 2; } @@ -1300,7 +1444,7 @@ static unsigned int dec_lslq(DisasContext *dc) cris_cc_mask(dc, CC_MASK_NZ); t_gen_mov_TN_reg(cpu_T[0], dc->op2); - t_gen_mov_TN_im(cpu_T[1], dc->op1); + tcg_gen_movi_tl(cpu_T[1], dc->op1); crisv32_alu_op(dc, CC_OP_LSL, dc->op2, 4); return 2; } @@ -1311,7 +1455,7 @@ static unsigned int dec_lsrq(DisasContext *dc) cris_cc_mask(dc, CC_MASK_NZ); t_gen_mov_TN_reg(cpu_T[0], dc->op2); - t_gen_mov_TN_im(cpu_T[1], dc->op1); + tcg_gen_movi_tl(cpu_T[1], dc->op1); crisv32_alu_op(dc, CC_OP_LSR, dc->op2, 4); return 2; } @@ -1338,14 +1482,20 @@ static unsigned int dec_scc_r(DisasContext *dc) if (cond != CC_A) { + int l1; + gen_tst_cc (dc, cond); - tcg_gen_mov_tl(cpu_T[1], cpu_T[0]); + + l1 = gen_new_label(); + tcg_gen_movi_tl(cpu_R[dc->op1], 0); + tcg_gen_brcond_tl(TCG_COND_EQ, cpu_T[0], tcg_const_tl(0), l1); + tcg_gen_movi_tl(cpu_R[dc->op1], 1); + gen_set_label(l1); } else - tcg_gen_movi_tl(cpu_T[1], 1); + tcg_gen_movi_tl(cpu_R[dc->op1], 1); cris_cc_mask(dc, 0); - crisv32_alu_op(dc, CC_OP_MOVE, dc->op1, 4); return 2; } @@ -1624,7 +1774,6 @@ static unsigned int dec_btst_r(DisasContext *dc) { DIS(fprintf (logfile, "btst $r%u, $r%u\n", dc->op1, dc->op2)); - cris_evaluate_flags(dc); cris_cc_mask(dc, CC_MASK_NZ); dec_prep_alu_r(dc, dc->op1, dc->op2, 4, 0); crisv32_alu_op(dc, CC_OP_BTST, dc->op2, 4); @@ -1772,10 +1921,18 @@ static unsigned int dec_setclrf(DisasContext *dc) cris_update_cc_op(dc, CC_OP_FLAGS, 4); tcg_gen_movi_tl(cc_op, dc->cc_op); - if (set) - gen_op_setf(flags); + if (set) { + if (!dc->user && (flags & U_FLAG)) { + /* Enter user mode. */ + t_gen_mov_env_TN(ksp, cpu_R[R_SP]); + tcg_gen_mov_tl(cpu_R[R_SP], cpu_PR[PR_USP]); + dc->is_jmp = DISAS_UPDATE; + } + tcg_gen_ori_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], flags); + } else - gen_op_clrf(flags); + tcg_gen_andi_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], ~flags); + dc->flags_live = 1; dc->clear_x = 0; return 2; @@ -1785,28 +1942,19 @@ static unsigned int dec_move_rs(DisasContext *dc) { DIS(fprintf (logfile, "move $r%u, $s%u\n", dc->op1, dc->op2)); cris_cc_mask(dc, 0); - t_gen_mov_TN_reg(cpu_T[0], dc->op1); - gen_op_movl_sreg_T0(dc->op2); - -#if !defined(CONFIG_USER_ONLY) - if (dc->op2 == 6) - gen_op_movl_tlb_hi_T0(); - else if (dc->op2 == 5) { /* srs is checked at runtime. */ - tcg_gen_helper_0_1(helper_tlb_update, cpu_T[0]); - gen_op_movl_tlb_lo_T0(); - } -#endif + tcg_gen_helper_0_2(helper_movl_sreg_reg, + tcg_const_tl(dc->op2), tcg_const_tl(dc->op1)); return 2; } static unsigned int dec_move_sr(DisasContext *dc) { DIS(fprintf (logfile, "move $s%u, $r%u\n", dc->op2, dc->op1)); cris_cc_mask(dc, 0); - gen_op_movl_T0_sreg(dc->op2); - tcg_gen_mov_tl(cpu_T[1], cpu_T[0]); - crisv32_alu_op(dc, CC_OP_MOVE, dc->op1, 4); + tcg_gen_helper_0_2(helper_movl_reg_sreg, + tcg_const_tl(dc->op1), tcg_const_tl(dc->op2)); return 2; } + static unsigned int dec_move_rp(DisasContext *dc) { DIS(fprintf (logfile, "move $r%u, $p%u\n", dc->op1, dc->op2)); @@ -2024,9 +2172,11 @@ static unsigned int dec_test_m(DisasContext *dc) dc->op1, dc->postinc ? "+]" : "]", dc->op2)); + cris_evaluate_flags(dc); + insn_len = dec_prep_alu_m(dc, 0, memsize); cris_cc_mask(dc, CC_MASK_NZ); - gen_op_clrf(3); + tcg_gen_andi_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], ~3); tcg_gen_mov_tl(cpu_T[0], cpu_T[1]); tcg_gen_movi_tl(cpu_T[1], 0); @@ -2444,10 +2594,6 @@ static unsigned int dec_rfe_etc(DisasContext *dc) case 2: /* rfe. */ cris_evaluate_flags(dc); - gen_op_ccs_rshift(); - /* FIXME: don't set the P-FLAG if R is set. */ - tcg_gen_ori_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], P_FLAG); - /* Debug helper. */ tcg_gen_helper_0_0(helper_rfe); dc->is_jmp = DISAS_UPDATE; break; @@ -2460,7 +2606,9 @@ static unsigned int dec_rfe_etc(DisasContext *dc) tcg_gen_movi_tl(cpu_T[0], dc->pc); t_gen_mov_env_TN(pc, cpu_T[0]); /* Breaks start at 16 in the exception vector. */ - gen_op_break_im(dc->op1 + 16); + t_gen_mov_env_TN(trap_vector, + tcg_const_tl(dc->op1 + 16)); + t_gen_raise_exception(EXCP_BREAK); dc->is_jmp = DISAS_UPDATE; break; default: @@ -2642,7 +2790,7 @@ static void check_breakpoint(CPUState *env, DisasContext *dc) cris_evaluate_flags (dc); tcg_gen_movi_tl(cpu_T[0], dc->pc); t_gen_mov_env_TN(pc, cpu_T[0]); - gen_op_debug(); + t_gen_raise_exception(EXCP_DEBUG); dc->is_jmp = DISAS_UPDATE; } } @@ -2689,13 +2837,14 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, - "search=%d pc=%x ccs=%x pid=%x usp=%x\n" + "search=%d pc=%x ccs=%x pid=%x usp=%x dbg=%x %x %x\n" "%x.%x.%x.%x\n" "%x.%x.%x.%x\n" "%x.%x.%x.%x\n" "%x.%x.%x.%x\n", search_pc, env->pc, env->pregs[PR_CCS], env->pregs[PR_PID], env->pregs[PR_USP], + env->debug1, env->debug2, env->debug3, env->regs[0], env->regs[1], env->regs[2], env->regs[3], env->regs[4], env->regs[5], env->regs[6], env->regs[7], env->regs[8], env->regs[9], @@ -2733,7 +2882,6 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, dc->clear_x = 1; insn_len = cris_decoder(dc); - STATS(gen_op_exec_insn()); dc->ppc = dc->pc; dc->pc += insn_len; if (dc->clear_x) @@ -2778,7 +2926,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, cris_evaluate_flags (dc); done: if (__builtin_expect(env->singlestep_enabled, 0)) { - gen_op_debug(); + t_gen_raise_exception(EXCP_DEBUG); } else { switch(dc->is_jmp) { case DISAS_NEXT: @@ -2933,13 +3081,16 @@ CPUCRISState *cpu_cris_init (const char *cpu_model) pregnames[i]); } - TCG_HELPER(helper_tlb_update); - TCG_HELPER(helper_tlb_flush); - TCG_HELPER(helper_rfe); + TCG_HELPER(helper_raise_exception); TCG_HELPER(helper_store); TCG_HELPER(helper_dump); TCG_HELPER(helper_dummy); + TCG_HELPER(helper_tlb_flush); + TCG_HELPER(helper_movl_sreg_reg); + TCG_HELPER(helper_movl_reg_sreg); + TCG_HELPER(helper_rfe); + TCG_HELPER(helper_evaluate_flags_muls); TCG_HELPER(helper_evaluate_flags_mulu); TCG_HELPER(helper_evaluate_flags_mcp); |