diff options
Diffstat (limited to 'src/core/arm/interpreter')
-rw-r--r-- | src/core/arm/interpreter/armemu.cpp | 136 |
1 files changed, 92 insertions, 44 deletions
diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index 399ee0886..7408b6f08 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -5681,11 +5681,8 @@ L_stm_s_takeabort: /* Attempt to emulate an ARMv6 instruction. Returns non-zero upon success. */ - static int - handle_v6_insn (ARMul_State * state, ARMword instr) { - ARMword lhs, temp; - - switch (BITS (20, 27)) { + static int handle_v6_insn(ARMul_State* state, ARMword instr) { + switch (BITS(20, 27)) { case 0x03: printf ("Unhandled v6 insn: ldr\n"); break; @@ -5719,7 +5716,7 @@ L_stm_s_takeabort: /* strex */ u32 l = LHSReg; u32 r = RHSReg; - lhs = LHS; + u32 lhs = LHS; bool enter = false; @@ -5744,7 +5741,7 @@ L_stm_s_takeabort: case 0x19: /* ldrex */ if (BITS(4, 7) == 0x9) { - lhs = LHS; + u32 lhs = LHS; state->currentexaddr = lhs; state->currentexval = ARMul_ReadWord(state, lhs); @@ -5763,7 +5760,7 @@ L_stm_s_takeabort: case 0x1c: if (BITS(4, 7) == 0x9) { /* strexb */ - lhs = LHS; + u32 lhs = LHS; bool enter = false; @@ -5793,11 +5790,11 @@ L_stm_s_takeabort: case 0x1d: if ((BITS(4, 7)) == 0x9) { /* ldrexb */ - temp = LHS; - LoadByte(state, instr, temp, LUNSIGNED); + u32 lhs = LHS; + LoadByte(state, instr, lhs, LUNSIGNED); - state->currentexaddr = temp; - state->currentexval = (u32)ARMul_ReadByte(state, temp); + state->currentexaddr = lhs; + state->currentexval = (u32)ARMul_ReadByte(state, lhs); //state->Reg[BITS(12, 15)] = ARMul_LoadByte(state, state->Reg[BITS(16, 19)]); //printf("ldrexb\n"); @@ -5839,29 +5836,56 @@ L_stm_s_takeabort: const s16 rm_lo = (state->Reg[rm_idx] & 0xFFFF); const s16 rm_hi = ((state->Reg[rm_idx] >> 16) & 0xFFFF); + s32 lo_result; + s32 hi_result; + // SSUB16 if ((instr & 0xFF0) == 0xf70) { - state->Reg[rd_idx] = ((rn_lo - rm_lo) & 0xFFFF) | (((rn_hi - rm_hi) & 0xFFFF) << 16); + lo_result = (rn_lo - rm_lo); + hi_result = (rn_hi - rm_hi); } // SADD16 else if ((instr & 0xFF0) == 0xf10) { - state->Reg[rd_idx] = ((rn_lo + rm_lo) & 0xFFFF) | (((rn_hi + rm_hi) & 0xFFFF) << 16); + lo_result = (rn_lo + rm_lo); + hi_result = (rn_hi + rm_hi); } // SSAX else if ((instr & 0xFF0) == 0xf50) { - state->Reg[rd_idx] = ((rn_lo + rm_hi) & 0xFFFF) | (((rn_hi - rm_lo) & 0xFFFF) << 16); + lo_result = (rn_lo + rm_hi); + hi_result = (rn_hi - rm_lo); } // SASX else { - state->Reg[rd_idx] = ((rn_lo - rm_hi) & 0xFFFF) | (((rn_hi + rm_lo) & 0xFFFF) << 16); + lo_result = (rn_lo - rm_hi); + hi_result = (rn_hi + rm_lo); + } + + state->Reg[rd_idx] = (lo_result & 0xFFFF) | ((hi_result & 0xFFFF) << 16); + + if (lo_result >= 0) { + state->Cpsr |= (1 << 16); + state->Cpsr |= (1 << 17); + } else { + state->Cpsr &= ~(1 << 16); + state->Cpsr &= ~(1 << 17); + } + + if (hi_result >= 0) { + state->Cpsr |= (1 << 18); + state->Cpsr |= (1 << 19); + } else { + state->Cpsr &= ~(1 << 18); + state->Cpsr &= ~(1 << 19); } return 1; } else { printf("Unhandled v6 insn: %08x", BITS(20, 27)); } break; - case 0x62: // QSUB16 and QADD16 - if ((instr & 0xFF0) == 0xf70 || (instr & 0xFF0) == 0xf10) { + case 0x62: // QADD16, QASX, QSAX, and QSUB16 + if ((instr & 0xFF0) == 0xf10 || (instr & 0xFF0) == 0xf30 || + (instr & 0xFF0) == 0xf50 || (instr & 0xFF0) == 0xf70) + { const u8 rd_idx = BITS(12, 15); const u8 rn_idx = BITS(16, 19); const u8 rm_idx = BITS(0, 3); @@ -5873,15 +5897,26 @@ L_stm_s_takeabort: s32 lo_result; s32 hi_result; + // QADD16 + if ((instr & 0xFF0) == 0xf10) { + lo_result = (rn_lo + rm_lo); + hi_result = (rn_hi + rm_hi); + } + // QASX + else if ((instr & 0xFF0) == 0xf30) { + lo_result = (rn_lo - rm_hi); + hi_result = (rn_hi + rm_lo); + } + // QSAX + else if ((instr & 0xFF0) == 0xf50) { + lo_result = (rn_lo + rm_hi); + hi_result = (rn_hi - rm_lo); + } // QSUB16 - if ((instr & 0xFF0) == 0xf70) { + else { lo_result = (rn_lo - rm_lo); hi_result = (rn_hi - rm_hi); } - else { // QADD16 - lo_result = (rn_lo + rm_lo); - hi_result = (rn_hi + rm_hi); - } if (lo_result > 0x7FFF) lo_result = 0x7FFF; @@ -6084,7 +6119,7 @@ L_stm_s_takeabort: break; } - Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFF) | ((state->Reg[BITS(0, 3)] << (32 - ror)) & 0xFF) & 0xFF; + Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFF) | (((state->Reg[BITS(0, 3)] << (32 - ror)) & 0xFF) & 0xFF); if (Rm & 0x80) Rm |= 0xffffff00; @@ -6129,7 +6164,7 @@ L_stm_s_takeabort: if (ror == -1) break; - Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFFFF) | ((state->Reg[BITS(0, 3)] << (32 - ror)) & 0xFFFF) & 0xFFFF; + Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFFFF) | (((state->Reg[BITS(0, 3)] << (32 - ror)) & 0xFFFF) & 0xFFFF); if (Rm & 0x8000) Rm |= 0xffff0000; @@ -6192,18 +6227,27 @@ L_stm_s_takeabort: //ichfly //USAT16 { - u8 tar = BITS(12, 15); - u8 src = BITS(0, 3); - u8 val = BITS(16, 19); - s16 a1 = (state->Reg[src]); - s16 a2 = (state->Reg[src] >> 0x10); - s16 max = 0xFFFF >> (16 - val); - if (max < a1) a1 = max; - if (max < a2) a2 = max; - u32 temp2 = ((u32)(a2)) << 0x10; - state->Reg[tar] = (a1 & 0xFFFF) | (temp2); + const u8 rd_idx = BITS(12, 15); + const u8 rn_idx = BITS(0, 3); + const u8 num_bits = BITS(16, 19); + const s16 max = 0xFFFF >> (16 - num_bits); + s16 rn_lo = (state->Reg[rn_idx]); + s16 rn_hi = (state->Reg[rn_idx] >> 16); + + if (max < rn_lo) + rn_lo = max; + else if (rn_lo < 0) + rn_lo = 0; + + if (max < rn_hi) + rn_hi = max; + else if (rn_hi < 0) + rn_hi = 0; + + state->Reg[rd_idx] = (rn_lo & 0xFFFF) | ((rn_hi << 16) & 0xFFFF); + return 1; } - return 1; + default: break; } @@ -6216,7 +6260,7 @@ L_stm_s_takeabort: break; } - Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFF) | ((state->Reg[BITS(0, 3)] << (32 - ror)) & 0xFF) & 0xFF; + Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFF) | (((state->Reg[BITS(0, 3)] << (32 - ror)) & 0xFF) & 0xFF); if (BITS(16, 19) == 0xf) /* UXTB */ @@ -6260,7 +6304,7 @@ L_stm_s_takeabort: if (ror == -1) break; - Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFFFF) | ((state->Reg[BITS(0, 3)] << (32 - ror)) & 0xFFFF) & 0xFFFF; + Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFFFF) | (((state->Reg[BITS(0, 3)] << (32 - ror)) & 0xFFFF) & 0xFFFF); /* UXT */ /* state->Reg[BITS (12, 15)] = Rm; */ @@ -6283,11 +6327,14 @@ L_stm_s_takeabort: } case 0x70: // ichfly - // SMUAD, SMUSD, SMLAD - if ((instr & 0xf0d0) == 0xf010 || (instr & 0xf0d0) == 0xf050 || (instr & 0xd0) == 0x10) { + // SMUAD, SMUSD, SMLAD, and SMLSD + if ((instr & 0xf0d0) == 0xf010 || (instr & 0xf0d0) == 0xf050 || + (instr & 0xd0) == 0x10 || (instr & 0xd0) == 0x50) + { const u8 rd_idx = BITS(16, 19); const u8 rn_idx = BITS(0, 3); const u8 rm_idx = BITS(8, 11); + const u8 ra_idx = BITS(12, 15); const bool do_swap = (BIT(5) == 1); u32 rm_val = state->Reg[rm_idx]; @@ -6310,13 +6357,14 @@ L_stm_s_takeabort: state->Reg[rd_idx] = (rn_lo * rm_lo) - (rn_hi * rm_hi); } // SMLAD - else { - const u8 ra_idx = BITS(12, 15); + else if ((instr & 0xd0) == 0x10) { state->Reg[rd_idx] = (rn_lo * rm_lo) + (rn_hi * rm_hi) + (s32)state->Reg[ra_idx]; } + // SMLSD + else { + state->Reg[rd_idx] = ((rn_lo * rm_lo) - (rn_hi * rm_hi)) + (s32)state->Reg[ra_idx]; + } return 1; - } else { - printf ("Unhandled v6 insn: smlsd\n"); } break; case 0x74: |