diff --git a/target-cris/helper.h b/target-cris/helper.h index 9034a6157e..e4684397a0 100644 --- a/target-cris/helper.h +++ b/target-cris/helper.h @@ -14,6 +14,7 @@ DEF_HELPER_0(evaluate_flags_muls, void) DEF_HELPER_0(evaluate_flags_mulu, void) DEF_HELPER_0(evaluate_flags_mcp, void) DEF_HELPER_0(evaluate_flags_alu_4, void) +DEF_HELPER_0(evaluate_flags_sub_4, void) DEF_HELPER_0(evaluate_flags_move_4, void) DEF_HELPER_0(evaluate_flags_move_2, void) DEF_HELPER_0(evaluate_flags, void) diff --git a/target-cris/op_helper.c b/target-cris/op_helper.c index 5db4575fe5..51323a2a5c 100644 --- a/target-cris/op_helper.c +++ b/target-cris/op_helper.c @@ -245,17 +245,19 @@ void helper_rfn(void) static void evaluate_flags_writeback(uint32_t flags) { - int x; + unsigned int x, z, mask; /* Extended arithmetics, leave the z flag alone. */ x = env->cc_x; - if ((x || env->cc_op == CC_OP_ADDC) - && flags & Z_FLAG) - env->cc_mask &= ~Z_FLAG; + mask = env->cc_mask | X_FLAG; + if (x) { + z = flags & Z_FLAG; + mask = mask & ~z; + } + flags &= mask; /* all insn clear the x-flag except setf or clrf. */ - env->pregs[PR_CCS] &= ~(env->cc_mask | X_FLAG); - flags &= env->cc_mask; + env->pregs[PR_CCS] &= ~mask; env->pregs[PR_CCS] |= flags; } @@ -323,33 +325,25 @@ void helper_evaluate_flags_mcp(void) uint32_t res; uint32_t flags = 0; - src = env->cc_src; - dst = env->cc_dest; + src = env->cc_src & 0x80000000; + dst = env->cc_dest & 0x80000000; res = env->cc_result; if ((res & 0x80000000L) != 0L) { flags |= N_FLAG; - if (((src & 0x80000000L) == 0L) - && ((dst & 0x80000000L) == 0L)) - { + if (!src && !dst) flags |= V_FLAG; - } - else if (((src & 0x80000000L) != 0L) && - ((dst & 0x80000000L) != 0L)) - { + else if (src & dst) flags |= R_FLAG; - } } else { if (res == 0L) flags |= Z_FLAG; - if (((src & 0x80000000L) != 0L) - && ((dst & 0x80000000L) != 0L)) + if (src & dst) flags |= V_FLAG; - if ((dst & 0x80000000L) != 0L - || (src & 0x80000000L) != 0L) + if (dst | src) flags |= R_FLAG; } @@ -363,56 +357,61 @@ void helper_evaluate_flags_alu_4(void) uint32_t res; uint32_t flags = 0; - src = env->cc_src; - dst = env->cc_dest; - - /* Reconstruct the result. */ - switch (env->cc_op) - { - case CC_OP_SUB: - res = dst - src; - break; - case CC_OP_ADD: - res = dst + src; - break; - default: - res = env->cc_result; - break; - } - - if (env->cc_op == CC_OP_SUB || env->cc_op == CC_OP_CMP) - src = ~src; + src = env->cc_src & 0x80000000; + dst = env->cc_dest & 0x80000000; + res = env->cc_result; if ((res & 0x80000000L) != 0L) { flags |= N_FLAG; - if (((src & 0x80000000L) == 0L) - && ((dst & 0x80000000L) == 0L)) - { + if (!src && !dst) flags |= V_FLAG; - } - else if (((src & 0x80000000L) != 0L) && - ((dst & 0x80000000L) != 0L)) - { + else if (src & dst) flags |= C_FLAG; - } } else { if (res == 0L) flags |= Z_FLAG; - if (((src & 0x80000000L) != 0L) - && ((dst & 0x80000000L) != 0L)) + if (src & dst) flags |= V_FLAG; - if ((dst & 0x80000000L) != 0L - || (src & 0x80000000L) != 0L) + if (dst | src) flags |= C_FLAG; } - if (env->cc_op == CC_OP_SUB - || env->cc_op == CC_OP_CMP) { - flags ^= C_FLAG; + evaluate_flags_writeback(flags); +} + +void helper_evaluate_flags_sub_4(void) +{ + uint32_t src; + uint32_t dst; + uint32_t res; + uint32_t flags = 0; + + src = (~env->cc_src) & 0x80000000; + dst = env->cc_dest & 0x80000000; + res = env->cc_result; + + if ((res & 0x80000000L) != 0L) + { + flags |= N_FLAG; + if (!src && !dst) + flags |= V_FLAG; + else if (src & dst) + flags |= C_FLAG; } + else + { + if (res == 0L) + flags |= Z_FLAG; + if (src & dst) + flags |= V_FLAG; + if (dst | src) + flags |= C_FLAG; + } + + flags ^= C_FLAG; evaluate_flags_writeback(flags); } @@ -607,6 +606,13 @@ void helper_top_evaluate_flags(void) case CC_OP_FLAGS: /* live. */ break; + case CC_OP_SUB: + case CC_OP_CMP: + if (env->cc_size == 4) + helper_evaluate_flags_sub_4(); + else + helper_evaluate_flags(); + break; default: { switch (env->cc_size) diff --git a/target-cris/translate.c b/target-cris/translate.c index 6a8c355975..24ae03cfac 100644 --- a/target-cris/translate.c +++ b/target-cris/translate.c @@ -728,8 +728,15 @@ static void cris_evaluate_flags(DisasContext *dc) case CC_OP_FLAGS: /* live. */ break; + case CC_OP_SUB: + case CC_OP_CMP: + if (dc->cc_size == 4) + gen_helper_evaluate_flags_sub_4(); + else + gen_helper_evaluate_flags(); + + break; default: - { switch (dc->cc_size) { case 4: @@ -739,7 +746,6 @@ static void cris_evaluate_flags(DisasContext *dc) gen_helper_evaluate_flags(); break; } - } break; } if (dc->flagx_known) { @@ -821,13 +827,8 @@ static void cris_pre_alu_update_cc(DisasContext *dc, int op, /* Update cc after executing ALU op. needs the result. */ static inline void cris_update_result(DisasContext *dc, TCGv res) { - if (dc->update_cc) { - if (dc->cc_size == 4 && - (dc->cc_op == CC_OP_SUB - || dc->cc_op == CC_OP_ADD)) - return; + if (dc->update_cc) tcg_gen_mov_tl(cc_result, res); - } } /* Returns one if the write back stage should execute. */ @@ -1890,6 +1891,10 @@ static unsigned int dec_addc_r(DisasContext *dc) DIS(fprintf (logfile, "addc $r%u, $r%u\n", dc->op1, dc->op2)); cris_evaluate_flags(dc); + /* Set for this insn. */ + dc->flagx_known = 1; + dc->flags_x = X_FLAG; + cris_cc_mask(dc, CC_MASK_NZVC); cris_alu(dc, CC_OP_ADDC, cpu_R[dc->op2], cpu_R[dc->op2], cpu_R[dc->op1], 4); @@ -2615,6 +2620,11 @@ static unsigned int dec_addc_mr(DisasContext *dc) dc->op2)); cris_evaluate_flags(dc); + + /* Set for this insn. */ + dc->flagx_known = 1; + dc->flags_x = X_FLAG; + cris_alu_m_alloc_temps(t); insn_len = dec_prep_alu_m(dc, 0, 4, t[0], t[1]); cris_cc_mask(dc, CC_MASK_NZVC);