X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=target-cris%2Fop_helper.c;h=79bff386633ab9c56dea1a01a91dfd81a22effb4;hb=34daffa04886444dafd4a6951167225e824003d0;hp=148c1e08ff675ad126916e447cb91de6206a4a29;hpb=6913ba56807e5a5275bd839550e8a951d2ef63af;p=qemu.git diff --git a/target-cris/op_helper.c b/target-cris/op_helper.c index 148c1e08f..79bff3866 100644 --- a/target-cris/op_helper.c +++ b/target-cris/op_helper.c @@ -15,101 +15,100 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * License along with this library; if not, see . */ -#include -#include "exec.h" +#include "cpu.h" #include "mmu.h" #include "helper.h" +#include "qemu/host-utils.h" +//#define CRIS_OP_HELPER_DEBUG + + +#ifdef CRIS_OP_HELPER_DEBUG +#define D(x) x +#define D_LOG(...) qemu_log(__VA__ARGS__) +#else #define D(x) +#define D_LOG(...) do { } while (0) +#endif #if !defined(CONFIG_USER_ONLY) +#include "exec/softmmu_exec.h" #define MMUSUFFIX _mmu #define SHIFT 0 -#include "softmmu_template.h" +#include "exec/softmmu_template.h" #define SHIFT 1 -#include "softmmu_template.h" +#include "exec/softmmu_template.h" #define SHIFT 2 -#include "softmmu_template.h" +#include "exec/softmmu_template.h" #define SHIFT 3 -#include "softmmu_template.h" +#include "exec/softmmu_template.h" /* Try to fill the TLB and return an exception if error. If retaddr is NULL, it means that the function was called in C code (i.e. not from generated code or from helper.c) */ -/* XXX: fix it to restore all registers */ -void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) +void tlb_fill(CPUCRISState *env, target_ulong addr, int is_write, int mmu_idx, + uintptr_t retaddr) { - TranslationBlock *tb; - CPUState *saved_env; - unsigned long pc; int ret; - /* XXX: hack to restore env in all cases, even if not called from - generated code */ - saved_env = env; - env = cpu_single_env; - - D(fprintf(logfile, "%s pc=%x tpc=%x ra=%x\n", __func__, - env->pc, env->debug1, retaddr)); - ret = cpu_cris_handle_mmu_fault(env, addr, is_write, mmu_idx, 1); - if (__builtin_expect(ret, 0)) { + D_LOG("%s pc=%x tpc=%x ra=%p\n", __func__, + env->pc, env->debug1, (void *)retaddr); + ret = cpu_cris_handle_mmu_fault(env, addr, is_write, mmu_idx); + if (unlikely(ret)) { if (retaddr) { /* now we have a real cpu fault */ - pc = (unsigned long)retaddr; - tb = tb_find_pc(pc); - if (tb) { - /* the PC is inside the translated code. It means that we have - a virtual CPU fault */ - cpu_restore_state(tb, env, pc, NULL); - + if (cpu_restore_state(env, retaddr)) { /* Evaluate flags after retranslation. */ - helper_top_evaluate_flags(); + helper_top_evaluate_flags(env); } } - cpu_loop_exit(); + cpu_loop_exit(env); } - env = saved_env; } #endif -void helper_raise_exception(uint32_t index) +void helper_raise_exception(CPUCRISState *env, uint32_t index) { env->exception_index = index; - cpu_loop_exit(); + cpu_loop_exit(env); } -void helper_tlb_flush_pid(uint32_t pid) +void helper_tlb_flush_pid(CPUCRISState *env, uint32_t pid) { #if !defined(CONFIG_USER_ONLY) - cris_mmu_flush_pid(env, pid); + pid &= 0xff; + if (pid != (env->pregs[PR_PID] & 0xff)) + cris_mmu_flush_pid(env, env->pregs[PR_PID]); #endif } -void helper_dump(uint32_t a0, uint32_t a1, uint32_t a2) +void helper_spc_write(CPUCRISState *env, uint32_t new_spc) { - (fprintf(logfile, "%s: a0=%x a1=%x\n", __func__, a0, a1)); +#if !defined(CONFIG_USER_ONLY) + tlb_flush_page(env, env->pregs[PR_SPC]); + tlb_flush_page(env, new_spc); +#endif } -void helper_dummy(void) +void helper_dump(uint32_t a0, uint32_t a1, uint32_t a2) { - + qemu_log("%s: a0=%x a1=%x\n", __func__, a0, a1); } /* Used by the tlb decoder. */ #define EXTRACT_FIELD(src, start, end) \ (((src) >> start) & ((1 << (end - start + 1)) - 1)) -void helper_movl_sreg_reg (uint32_t sreg, uint32_t reg) +void helper_movl_sreg_reg(CPUCRISState *env, uint32_t sreg, uint32_t reg) { uint32_t srs; srs = env->pregs[PR_SRS]; @@ -149,16 +148,17 @@ void helper_movl_sreg_reg (uint32_t sreg, uint32_t reg) env->tlbsets[srs - 1][set][idx].lo = lo; env->tlbsets[srs - 1][set][idx].hi = hi; - D(fprintf(logfile, - "tlb flush vaddr=%x v=%d pc=%x\n", - vaddr, tlb_v, env->pc)); - tlb_flush_page(env, vaddr); + D_LOG("tlb flush vaddr=%x v=%d pc=%x\n", + vaddr, tlb_v, env->pc); + if (tlb_v) { + tlb_flush_page(env, vaddr); + } } } #endif } -void helper_movl_reg_sreg (uint32_t reg, uint32_t sreg) +void helper_movl_reg_sreg(CPUCRISState *env, uint32_t reg, uint32_t sreg) { uint32_t srs; env->pregs[PR_SRS] &= 3; @@ -184,10 +184,9 @@ void helper_movl_reg_sreg (uint32_t reg, uint32_t sreg) } #endif env->regs[reg] = env->sregs[srs][sreg]; - RETURN(); } -static void cris_ccs_rshift(CPUState *env) +static void cris_ccs_rshift(CPUCRISState *env) { uint32_t ccs; @@ -204,14 +203,14 @@ static void cris_ccs_rshift(CPUState *env) env->pregs[PR_CCS] = ccs; } -void helper_rfe(void) +void helper_rfe(CPUCRISState *env) { int rflag = env->pregs[PR_CCS] & R_FLAG; - D(fprintf(logfile, "rfe: erp=%x pid=%x ccs=%x btarget=%x\n", + D_LOG("rfe: erp=%x pid=%x ccs=%x btarget=%x\n", env->pregs[PR_ERP], env->pregs[PR_PID], env->pregs[PR_CCS], - env->btarget)); + env->btarget); cris_ccs_rshift(env); @@ -220,14 +219,14 @@ void helper_rfe(void) env->pregs[PR_CCS] |= P_FLAG; } -void helper_rfn(void) +void helper_rfn(CPUCRISState *env) { int rflag = env->pregs[PR_CCS] & R_FLAG; - D(fprintf(logfile, "rfn: erp=%x pid=%x ccs=%x btarget=%x\n", + D_LOG("rfn: erp=%x pid=%x ccs=%x btarget=%x\n", env->pregs[PR_ERP], env->pregs[PR_PID], env->pregs[PR_CCS], - env->btarget)); + env->btarget); cris_ccs_rshift(env); @@ -235,59 +234,72 @@ void helper_rfn(void) if (!rflag) env->pregs[PR_CCS] |= P_FLAG; - /* Always set the M flag. */ - env->pregs[PR_CCS] |= M_FLAG; + /* Always set the M flag. */ + env->pregs[PR_CCS] |= M_FLAG_V32; } -void helper_store(uint32_t a0) +uint32_t helper_lz(uint32_t t0) { - if (env->pregs[PR_CCS] & P_FLAG ) - { - cpu_abort(env, "cond_store_failed! pc=%x a0=%x\n", - env->pc, a0); - } + return clz32(t0); } -void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec, - int is_asi) +uint32_t helper_btst(CPUCRISState *env, uint32_t t0, uint32_t t1, uint32_t ccs) { - D(printf("%s addr=%x w=%d ex=%d asi=%d\n", - __func__, addr, is_write, is_exec, is_asi)); + /* FIXME: clean this up. */ + + /* 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. */ + ccs = ccs & ~(X_FLAG | N_FLAG | Z_FLAG); + if (env->pregs[PR_VR] < 32) + ccs &= ~(V_FLAG | C_FLAG); + /* Set the N and Z flags accordingly. */ + ccs |= (bset << 3) | (fz << 2); + return ccs; } -static void evaluate_flags_writeback(uint32_t flags) +static inline uint32_t evaluate_flags_writeback(CPUCRISState *env, + uint32_t flags, uint32_t ccs) { - 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] |= flags; + ccs &= ~mask; + ccs |= flags; + return ccs; } -void helper_evaluate_flags_muls(void) +uint32_t helper_evaluate_flags_muls(CPUCRISState *env, + uint32_t ccs, uint32_t res, uint32_t mof) { - uint32_t src; - uint32_t dst; - uint32_t res; uint32_t flags = 0; int64_t tmp; - int32_t mof; int dneg; - src = env->cc_src; - dst = env->cc_dest; - res = env->cc_result; - dneg = ((int32_t)res) < 0; - mof = env->pregs[PR_MOF]; tmp = mof; tmp <<= 32; tmp |= res; @@ -298,23 +310,15 @@ void helper_evaluate_flags_muls(void) if ((dneg && mof != -1) || (!dneg && mof != 0)) flags |= V_FLAG; - evaluate_flags_writeback(flags); + return evaluate_flags_writeback(env, flags, ccs); } -void helper_evaluate_flags_mulu(void) +uint32_t helper_evaluate_flags_mulu(CPUCRISState *env, + uint32_t ccs, uint32_t res, uint32_t mof) { - uint32_t src; - uint32_t dst; - uint32_t res; uint32_t flags = 0; uint64_t tmp; - uint32_t mof; - - src = env->cc_src; - dst = env->cc_dest; - res = env->cc_result; - mof = env->pregs[PR_MOF]; tmp = mof; tmp <<= 32; tmp |= res; @@ -325,147 +329,127 @@ void helper_evaluate_flags_mulu(void) if (mof) flags |= V_FLAG; - evaluate_flags_writeback(flags); + return evaluate_flags_writeback(env, flags, ccs); } -void helper_evaluate_flags_mcp(void) +uint32_t helper_evaluate_flags_mcp(CPUCRISState *env, uint32_t ccs, + uint32_t src, uint32_t dst, uint32_t res) { - uint32_t src; - uint32_t dst; - uint32_t res; uint32_t flags = 0; - src = env->cc_src; - dst = env->cc_dest; - res = env->cc_result; + src = src & 0x80000000; + dst = dst & 0x80000000; 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; } - evaluate_flags_writeback(flags); + return evaluate_flags_writeback(env, flags, ccs); } -void helper_evaluate_flags_alu_4(void) +uint32_t helper_evaluate_flags_alu_4(CPUCRISState *env, uint32_t ccs, + uint32_t src, uint32_t dst, uint32_t res) { - uint32_t src; - uint32_t dst; - uint32_t res; uint32_t flags = 0; - src = env->cc_src; - dst = env->cc_dest; + src = src & 0x80000000; + dst = dst & 0x80000000; - /* Reconstruct the result. */ - switch (env->cc_op) + if ((res & 0x80000000L) != 0L) { - case CC_OP_SUB: - res = dst - src; - break; - case CC_OP_ADD: - res = dst + src; - break; - default: - res = env->cc_result; - break; + 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; } - if (env->cc_op == CC_OP_SUB || env->cc_op == CC_OP_CMP) - src = ~src; + return evaluate_flags_writeback(env, flags, ccs); +} + +uint32_t helper_evaluate_flags_sub_4(CPUCRISState *env, uint32_t ccs, + uint32_t src, uint32_t dst, uint32_t res) +{ + uint32_t flags = 0; + + src = (~src) & 0x80000000; + dst = dst & 0x80000000; 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); + flags ^= C_FLAG; + return evaluate_flags_writeback(env, flags, ccs); } -void helper_evaluate_flags_move_4 (void) +uint32_t helper_evaluate_flags_move_4(CPUCRISState *env, + uint32_t ccs, uint32_t res) { - uint32_t res; uint32_t flags = 0; - res = env->cc_result; - if ((int32_t)res < 0) flags |= N_FLAG; else if (res == 0L) flags |= Z_FLAG; - evaluate_flags_writeback(flags); + return evaluate_flags_writeback(env, flags, ccs); } -void helper_evaluate_flags_move_2 (void) +uint32_t helper_evaluate_flags_move_2(CPUCRISState *env, + uint32_t ccs, uint32_t res) { - uint32_t src; uint32_t flags = 0; - uint16_t res; - - src = env->cc_src; - res = env->cc_result; if ((int16_t)res < 0L) flags |= N_FLAG; else if (res == 0) flags |= Z_FLAG; - evaluate_flags_writeback(flags); + return evaluate_flags_writeback(env, flags, ccs); } /* TODO: This is expensive. We could split things up and only evaluate part of CCR on a need to know basis. For now, we simply re-evaluate everything. */ -void helper_evaluate_flags (void) +void helper_evaluate_flags(CPUCRISState *env) { - uint32_t src; - uint32_t dst; - uint32_t res; + uint32_t src, dst, res; uint32_t flags = 0; src = env->cc_src; @@ -576,25 +560,31 @@ void helper_evaluate_flags (void) break; } - if (env->cc_op == CC_OP_SUB - || env->cc_op == CC_OP_CMP) { + if (env->cc_op == CC_OP_SUB || env->cc_op == CC_OP_CMP) flags ^= C_FLAG; - } - evaluate_flags_writeback(flags); + + env->pregs[PR_CCS] = evaluate_flags_writeback(env, flags, + env->pregs[PR_CCS]); } -void helper_top_evaluate_flags(void) +void helper_top_evaluate_flags(CPUCRISState *env) { switch (env->cc_op) { case CC_OP_MCP: - helper_evaluate_flags_mcp(); + env->pregs[PR_CCS] = helper_evaluate_flags_mcp(env, + env->pregs[PR_CCS], env->cc_src, + env->cc_dest, env->cc_result); break; case CC_OP_MULS: - helper_evaluate_flags_muls(); + env->pregs[PR_CCS] = helper_evaluate_flags_muls(env, + env->pregs[PR_CCS], env->cc_result, + env->pregs[PR_MOF]); break; case CC_OP_MULU: - helper_evaluate_flags_mulu(); + env->pregs[PR_CCS] = helper_evaluate_flags_mulu(env, + env->pregs[PR_CCS], env->cc_result, + env->pregs[PR_MOF]); break; case CC_OP_MOVE: case CC_OP_AND: @@ -603,32 +593,53 @@ void helper_top_evaluate_flags(void) case CC_OP_ASR: case CC_OP_LSR: case CC_OP_LSL: - switch (env->cc_size) - { - case 4: - helper_evaluate_flags_move_4(); - break; - case 2: - helper_evaluate_flags_move_2(); - break; - default: - helper_evaluate_flags(); - break; - } - break; + switch (env->cc_size) + { + case 4: + env->pregs[PR_CCS] = + helper_evaluate_flags_move_4(env, + env->pregs[PR_CCS], + env->cc_result); + break; + case 2: + env->pregs[PR_CCS] = + helper_evaluate_flags_move_2(env, + env->pregs[PR_CCS], + env->cc_result); + break; + default: + helper_evaluate_flags(env); + break; + } + break; case CC_OP_FLAGS: /* live. */ break; + case CC_OP_SUB: + case CC_OP_CMP: + if (env->cc_size == 4) + env->pregs[PR_CCS] = + helper_evaluate_flags_sub_4(env, + env->pregs[PR_CCS], + env->cc_src, env->cc_dest, + env->cc_result); + else + helper_evaluate_flags(env); + break; default: { switch (env->cc_size) { - case 4: - helper_evaluate_flags_alu_4(); - break; - default: - helper_evaluate_flags(); - break; + case 4: + env->pregs[PR_CCS] = + helper_evaluate_flags_alu_4(env, + env->pregs[PR_CCS], + env->cc_src, env->cc_dest, + env->cc_result); + break; + default: + helper_evaluate_flags(env); + break; } } break;