diff options
author | edgar_igl <edgar_igl@c046a42c-6fe2-441c-8c8c-71466251a162> | 2008-05-02 22:16:17 +0000 |
---|---|---|
committer | edgar_igl <edgar_igl@c046a42c-6fe2-441c-8c8c-71466251a162> | 2008-05-02 22:16:17 +0000 |
commit | b41f7df0189dbda34be3944a48db3b98348e4bc6 (patch) | |
tree | b6c2840eabbfce1f272c47e754686af9e9473403 /target-cris/op.c | |
parent | ff56ff7a07fe8fbcc4e9f74972d8399ca1ab8051 (diff) |
CRIS updates:
* Support both the I and D MMUs and improve the accuracy of the MMU model.
* Handle the automatic user/kernel stack pointer switching when leaving or entering user mode.
* Move the CCS evaluation into helper funcs.
* Make sure user-mode cannot change flags only writeable in kernel mode.
* More conversion of the translator into TCG.
* Handle exceptions while in a delayslot.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4299 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'target-cris/op.c')
-rw-r--r-- | target-cris/op.c | 397 |
1 files changed, 46 insertions, 351 deletions
diff --git a/target-cris/op.c b/target-cris/op.c index d44185c4d4..a446e20d93 100644 --- a/target-cris/op.c +++ b/target-cris/op.c @@ -192,17 +192,32 @@ void OPPROTO op_ccs_lshift (void) } void OPPROTO op_ccs_rshift (void) { - uint32_t ccs; + register uint32_t ccs; /* Apply the ccs shift. */ ccs = env->pregs[PR_CCS]; ccs = (ccs & 0xc0000000) | ((ccs & 0x0fffffff) >> 10); + if (ccs & U_FLAG) + { + /* Enter user mode. */ + env->ksp = env->regs[R_SP]; + env->regs[R_SP] = env->pregs[PR_USP]; + } + env->pregs[PR_CCS] = ccs; + RETURN(); } void OPPROTO op_setf (void) { + if (!(env->pregs[PR_CCS] & U_FLAG) && (PARAM1 & U_FLAG)) + { + /* Enter user mode. */ + env->ksp = env->regs[R_SP]; + env->regs[R_SP] = env->pregs[PR_USP]; + } + env->pregs[PR_CCS] |= PARAM1; RETURN(); } @@ -265,7 +280,11 @@ void OPPROTO op_movl_flags_T0 (void) void OPPROTO op_movl_sreg_T0 (void) { - env->sregs[env->pregs[PR_SRS]][PARAM1] = T0; + uint32_t srs; + srs = env->pregs[PR_SRS]; + srs &= 3; + + env->sregs[srs][PARAM1] = T0; RETURN(); } @@ -285,7 +304,10 @@ void OPPROTO op_movl_tlb_hi_T0 (void) void OPPROTO op_movl_tlb_lo_T0 (void) { uint32_t srs; + + env->pregs[PR_SRS] &= 3; srs = env->pregs[PR_SRS]; + if (srs == 1 || srs == 2) { uint32_t set; @@ -309,7 +331,28 @@ void OPPROTO op_movl_tlb_lo_T0 (void) void OPPROTO op_movl_T0_sreg (void) { - T0 = env->sregs[env->pregs[PR_SRS]][PARAM1]; + uint32_t srs; + env->pregs[PR_SRS] &= 3; + srs = env->pregs[PR_SRS]; + + if (srs == 1 || srs == 2) + { + uint32_t set; + uint32_t idx; + uint32_t lo, hi; + + idx = set = env->sregs[SFR_RW_MM_TLB_SEL]; + set >>= 4; + set &= 3; + idx &= 15; + + /* Update the mirror regs. */ + hi = env->tlbsets[srs - 1][set][idx].hi; + lo = env->tlbsets[srs - 1][set][idx].lo; + env->sregs[SFR_RW_MM_TLB_HI] = hi; + env->sregs[SFR_RW_MM_TLB_LO] = lo; + } + T0 = env->sregs[srs][PARAM1]; RETURN(); } @@ -363,340 +406,6 @@ void OPPROTO op_update_cc_x (void) RETURN(); } -/* FIXME: is this allowed? */ -extern inline void evaluate_flags_writeback(uint32_t flags) -{ - int x; - - /* Extended arithmetics, leave the z flag alone. */ - env->debug3 = env->pregs[PR_CCS]; - - if (env->cc_x_live) - x = env->cc_x; - else - x = env->pregs[PR_CCS] & X_FLAG; - - if ((x || env->cc_op == CC_OP_ADDC) - && flags & Z_FLAG) - env->cc_mask &= ~Z_FLAG; - - /* 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; - RETURN(); -} - -void OPPROTO op_evaluate_flags_muls(void) -{ - uint32_t src; - uint32_t dst; - uint32_t res; - uint32_t flags = 0; - /* were gonna have to redo the muls. */ - int64_t tmp, t0 ,t1; - int32_t mof; - int dneg; - - src = env->cc_src; - dst = env->cc_dest; - res = env->cc_result; - - - /* cast into signed values to make GCC sign extend. */ - t0 = (int32_t)src; - t1 = (int32_t)dst; - dneg = ((int32_t)res) < 0; - - tmp = t0 * t1; - mof = tmp >> 32; - if (tmp == 0) - flags |= Z_FLAG; - else if (tmp < 0) - flags |= N_FLAG; - if ((dneg && mof != -1) - || (!dneg && mof != 0)) - flags |= V_FLAG; - evaluate_flags_writeback(flags); - RETURN(); -} - -void OPPROTO op_evaluate_flags_mulu(void) -{ - uint32_t src; - uint32_t dst; - uint32_t res; - uint32_t flags = 0; - /* were gonna have to redo the muls. */ - uint64_t tmp, t0 ,t1; - uint32_t mof; - - src = env->cc_src; - dst = env->cc_dest; - res = env->cc_result; - - - /* cast into signed values to make GCC sign extend. */ - t0 = src; - t1 = dst; - - tmp = t0 * t1; - mof = tmp >> 32; - if (tmp == 0) - flags |= Z_FLAG; - else if (tmp >> 63) - flags |= N_FLAG; - if (mof) - flags |= V_FLAG; - - evaluate_flags_writeback(flags); - RETURN(); -} - -void OPPROTO op_evaluate_flags_mcp(void) -{ - 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; - - if ((res & 0x80000000L) != 0L) - { - flags |= N_FLAG; - if (((src & 0x80000000L) == 0L) - && ((dst & 0x80000000L) == 0L)) - { - flags |= V_FLAG; - } - else if (((src & 0x80000000L) != 0L) && - ((dst & 0x80000000L) != 0L)) - { - flags |= R_FLAG; - } - } - else - { - if (res == 0L) - flags |= Z_FLAG; - if (((src & 0x80000000L) != 0L) - && ((dst & 0x80000000L) != 0L)) - flags |= V_FLAG; - if ((dst & 0x80000000L) != 0L - || (src & 0x80000000L) != 0L) - flags |= R_FLAG; - } - - evaluate_flags_writeback(flags); - RETURN(); -} - -void OPPROTO op_evaluate_flags_alu_4(void) -{ - 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; - - if ((res & 0x80000000L) != 0L) - { - flags |= N_FLAG; - if (((src & 0x80000000L) == 0L) - && ((dst & 0x80000000L) == 0L)) - { - flags |= V_FLAG; - } - else if (((src & 0x80000000L) != 0L) && - ((dst & 0x80000000L) != 0L)) - { - flags |= C_FLAG; - } - } - else - { - if (res == 0L) - flags |= Z_FLAG; - if (((src & 0x80000000L) != 0L) - && ((dst & 0x80000000L) != 0L)) - flags |= V_FLAG; - if ((dst & 0x80000000L) != 0L - || (src & 0x80000000L) != 0L) - flags |= C_FLAG; - } - - if (env->cc_op == CC_OP_SUB - || env->cc_op == CC_OP_CMP) { - flags ^= C_FLAG; - } - evaluate_flags_writeback(flags); - RETURN(); -} - -void OPPROTO op_evaluate_flags_move_4 (void) -{ - uint32_t src; - uint32_t res; - uint32_t flags = 0; - - src = env->cc_src; - res = env->cc_result; - - if ((int32_t)res < 0) - flags |= N_FLAG; - else if (res == 0L) - flags |= Z_FLAG; - - evaluate_flags_writeback(flags); - RETURN(); -} -void OPPROTO op_evaluate_flags_move_2 (void) -{ - 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(); -} - -/* 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 OPPROTO op_evaluate_flags (void) -{ - 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; - - - /* Now, evaluate the flags. This stuff is based on - Per Zander's CRISv10 simulator. */ - switch (env->cc_size) - { - case 1: - if ((res & 0x80L) != 0L) - { - flags |= N_FLAG; - if (((src & 0x80L) == 0L) - && ((dst & 0x80L) == 0L)) - { - flags |= V_FLAG; - } - else if (((src & 0x80L) != 0L) - && ((dst & 0x80L) != 0L)) - { - flags |= C_FLAG; - } - } - else - { - if ((res & 0xFFL) == 0L) - { - flags |= Z_FLAG; - } - if (((src & 0x80L) != 0L) - && ((dst & 0x80L) != 0L)) - { - flags |= V_FLAG; - } - if ((dst & 0x80L) != 0L - || (src & 0x80L) != 0L) - { - flags |= C_FLAG; - } - } - break; - case 2: - if ((res & 0x8000L) != 0L) - { - flags |= N_FLAG; - if (((src & 0x8000L) == 0L) - && ((dst & 0x8000L) == 0L)) - { - flags |= V_FLAG; - } - else if (((src & 0x8000L) != 0L) - && ((dst & 0x8000L) != 0L)) - { - flags |= C_FLAG; - } - } - else - { - if ((res & 0xFFFFL) == 0L) - { - flags |= Z_FLAG; - } - if (((src & 0x8000L) != 0L) - && ((dst & 0x8000L) != 0L)) - { - flags |= V_FLAG; - } - if ((dst & 0x8000L) != 0L - || (src & 0x8000L) != 0L) - { - flags |= C_FLAG; - } - } - break; - case 4: - if ((res & 0x80000000L) != 0L) - { - flags |= N_FLAG; - if (((src & 0x80000000L) == 0L) - && ((dst & 0x80000000L) == 0L)) - { - flags |= V_FLAG; - } - else if (((src & 0x80000000L) != 0L) && - ((dst & 0x80000000L) != 0L)) - { - flags |= C_FLAG; - } - } - else - { - if (res == 0L) - flags |= Z_FLAG; - if (((src & 0x80000000L) != 0L) - && ((dst & 0x80000000L) != 0L)) - flags |= V_FLAG; - if ((dst & 0x80000000L) != 0L - || (src & 0x80000000L) != 0L) - flags |= C_FLAG; - } - break; - default: - break; - } - - if (env->cc_op == CC_OP_SUB - || env->cc_op == CC_OP_CMP) { - flags ^= C_FLAG; - } - evaluate_flags_writeback(flags); - RETURN(); -} - void OPPROTO op_extb_T0_T0 (void) { T0 = ((int8_t)T0); @@ -1274,17 +983,3 @@ void OPPROTO op_jmp1 (void) env->pc = env->btarget; RETURN(); } - -/* Load and store */ -#define MEMSUFFIX _raw -#include "op_mem.c" -#undef MEMSUFFIX -#if !defined(CONFIG_USER_ONLY) -#define MEMSUFFIX _user -#include "op_mem.c" -#undef MEMSUFFIX - -#define MEMSUFFIX _kernel -#include "op_mem.c" -#undef MEMSUFFIX -#endif |