diff options
Diffstat (limited to 'src/devices/cpu/arm7/arm7ops.cpp')
-rw-r--r-- | src/devices/cpu/arm7/arm7ops.cpp | 78 |
1 files changed, 50 insertions, 28 deletions
diff --git a/src/devices/cpu/arm7/arm7ops.cpp b/src/devices/cpu/arm7/arm7ops.cpp index ea10a36be4d..084634a77c0 100644 --- a/src/devices/cpu/arm7/arm7ops.cpp +++ b/src/devices/cpu/arm7/arm7ops.cpp @@ -66,18 +66,12 @@ uint32_t arm7_cpu_device::decodeShift(uint32_t insn, uint32_t *pCarry) if ((insn & 0x80) == 0x80) LOG(("%08x: RegShift ERROR (p36)\n", R15)); #endif - - // see p35 for check on this - //k = GetRegister(k >> 1) & 0x1f; - // Keep only the bottom 8 bits for a Register Shift k = GetRegister(k >> 1) & 0xff; if (k == 0) /* Register shift by 0 is a no-op */ { // LOG(("%08x: NO-OP Regshift\n", R15)); - /* TODO this is wrong for at least ROR by reg with lower - * 5 bits 0 but lower 8 bits non zero */ if (pCarry) *pCarry = GET_CPSR & C_MASK; return rm; @@ -145,11 +139,19 @@ uint32_t arm7_cpu_device::decodeShift(uint32_t insn, uint32_t *pCarry) case 3: /* ROR and RRX */ if (k) { - while (k > 32) - k -= 32; - if (pCarry) - *pCarry = rm & (1 << (k - 1)); - return ROR(rm, k); + k &= 31; + if (k) + { + if (pCarry) + *pCarry = rm & (1 << (k - 1)); + return ROR(rm, k); + } + else + { + if (pCarry) + *pCarry = rm & SIGN_BIT; + return rm; + } } else { @@ -262,22 +264,13 @@ int arm7_cpu_device::storeInc(uint32_t pat, uint32_t rbv, int mode) int arm7_cpu_device::storeDec(uint32_t pat, uint32_t rbv, int mode) { - int i, result = 0, cnt; - // pre-count the # of registers being stored - for (i = 15; i >= 0; i--) - { - if ((pat >> i) & 1) - { - result++; + int const result = population_count_32(pat & 0x0000ffff); - // starting address - rbv -= 4; - } - } + // adjust starting address + rbv -= (result << 2); - cnt = 0; - for (i = 0; i <= 15; i++) + for (int i = 0; i <= 15; i++) { if ((pat >> i) & 1) { @@ -285,8 +278,8 @@ int arm7_cpu_device::storeDec(uint32_t pat, uint32_t rbv, int mode) if (i == 15) /* R15 is plus 12 from address of STM */ LOG(("%08x: StoreDec on R15\n", R15)); #endif - WRITE32(rbv + (cnt * 4), GetModeRegister(mode, i)); - cnt++; + WRITE32(rbv, GetModeRegister(mode, i)); + rbv += 4; } } return result; @@ -387,8 +380,8 @@ void arm7_cpu_device::HandleBranch(uint32_t insn, bool h_bit) off |= (insn & 0x01000000) >> 23; } - /* Save PC into LR if this is a branch with link */ - if (insn & INSN_BL) + /* Save PC into LR if this is a branch with link or a BLX */ + if ((insn & INSN_BL) || ((m_archRev >= 5) && ((insn & 0xfe000000) == 0xfa000000))) { SetRegister(14, R15 + 4); } @@ -501,6 +494,11 @@ void arm7_cpu_device::HandleMemSingle(uint32_t insn) R15 = (R15 & ~0x03FFFFFC) /* N Z C V I F M1 M0 */ | ((data - 4) & 0x03FFFFFC); // LDR, PC takes 2S + 2N + 1I (5 total cycles) ARM7_ICOUNT -= 2; + if ((data & 1) && m_archRev >= 5) + { + set_cpsr(GET_CPSR | T_MASK); + R15--; + } } else { @@ -1380,6 +1378,12 @@ void arm7_cpu_device::HandleMemBlock(uint32_t insn) SwitchMode(temp & 3); } } + else + if ((R15 & 1) && m_archRev >= 5) + { + set_cpsr(GET_CPSR | T_MASK); + R15--; + } // LDM PC - takes 2 extra cycles ARM7_ICOUNT -= 2; } @@ -1437,6 +1441,12 @@ void arm7_cpu_device::HandleMemBlock(uint32_t insn) SwitchMode(temp & 3); } } + else + if ((R15 & 1) && m_archRev >= 5) + { + set_cpsr(GET_CPSR | T_MASK); + R15--; + } // LDM PC - takes 2 extra cycles ARM7_ICOUNT -= 2; } @@ -1650,6 +1660,18 @@ void arm7_cpu_device::arm7ops_0123(uint32_t insn) R15--; } } + else if ((insn & 0x0ff000f0) == 0x01200030) // BLX Rn - v5 + { + // save link address + SetRegister(14, R15 + 4); + + R15 = GetRegister(insn & 0x0f); + // If new PC address has A0 set, switch to Thumb mode + if (R15 & 1) { + set_cpsr(GET_CPSR|T_MASK); + R15--; + } + } else if ((insn & 0x0ff000f0) == 0x01600010) // CLZ - v5 { uint32_t rm = insn&0xf; |