diff options
Diffstat (limited to 'src/core/arm')
-rw-r--r-- | src/core/arm/interpreter/armemu.cpp | 301 |
1 files changed, 190 insertions, 111 deletions
diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index 0d1b2e60e..63cfd03c6 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -1356,7 +1356,13 @@ mainswitch: } break; - case 0x04: /* SUB reg */ + case 0x04: /* SUB reg */ + // Signifies UMAAL + if (state->is_v6 && BITS(4, 7) == 0x09) { + if (handle_v6_insn(state, instr)) + break; + } + #ifdef MODET if (BITS (4, 7) == 0xB) { /* STRH immediate offset, no write-back, down, post indexed. */ @@ -3103,12 +3109,18 @@ mainswitch: state->Reg[idest] = (state->Reg[rfis] & 0xFFFF) | ((state->Reg[rlast] << ishi) & 0xFFFF0000); break; } else if ((instr & 0x70) == 0x50) { //pkhtb - u8 idest = BITS(12, 15); - u8 rfis = BITS(16, 19); - u8 rlast = BITS(0, 3); - u8 ishi = BITS(7, 11); - if (ishi == 0)ishi = 0x20; - state->Reg[idest] = (((int)(state->Reg[rlast]) >> (int)(ishi))& 0xFFFF) | ((state->Reg[rfis]) & 0xFFFF0000); + const u8 rd_idx = BITS(12, 15); + const u8 rn_idx = BITS(16, 19); + const u8 rm_idx = BITS(0, 3); + const u8 imm5 = BITS(7, 11); + + ARMword val; + if (imm5 >= 32) + val = (state->Reg[rm_idx] >> 31); + else + val = (state->Reg[rm_idx] >> imm5); + + state->Reg[rd_idx] = (val & 0xFFFF) | ((state->Reg[rn_idx]) & 0xFFFF0000); break; } else if (BIT (4)) { #ifdef MODE32 @@ -5674,8 +5686,24 @@ L_stm_s_takeabort: case 0x03: printf ("Unhandled v6 insn: ldr\n"); break; - case 0x04: - printf ("Unhandled v6 insn: umaal\n"); + case 0x04: // UMAAL + { + const u8 rm_idx = BITS(8, 11); + const u8 rn_idx = BITS(0, 3); + const u8 rd_lo_idx = BITS(12, 15); + const u8 rd_hi_idx = BITS(16, 19); + + const u32 rm_val = state->Reg[rm_idx]; + const u32 rn_val = state->Reg[rn_idx]; + const u32 rd_lo_val = state->Reg[rd_lo_idx]; + const u32 rd_hi_val = state->Reg[rd_hi_idx]; + + const u64 result = (rn_val * rm_val) + rd_lo_val + rd_hi_val; + + state->Reg[rd_lo_idx] = (result & 0xFFFFFFFF); + state->Reg[rd_hi_idx] = ((result >> 32) & 0xFFFFFFFF); + return 1; + } break; case 0x06: printf ("Unhandled v6 insn: mls/str\n"); @@ -5796,83 +5824,102 @@ L_stm_s_takeabort: case 0x3f: printf ("Unhandled v6 insn: rbit\n"); break; - case 0x61: - if ((instr & 0xFF0) == 0xf70) { //ssub16 - u8 tar = BITS(12, 15); - u8 src1 = BITS(16, 19); - u8 src2 = BITS(0, 3); - s16 a1 = (state->Reg[src1] & 0xFFFF); - s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF); - s16 b1 = (state->Reg[src2] & 0xFFFF); - s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF); - state->Reg[tar] = ((a1 - a2) & 0xFFFF) | (((b1 - b2) & 0xFFFF) << 0x10); - return 1; - } else if ((instr & 0xFF0) == 0xf10) { //sadd16 - u8 tar = BITS(12, 15); - u8 src1 = BITS(16, 19); - u8 src2 = BITS(0, 3); - s16 a1 = (state->Reg[src1] & 0xFFFF); - s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF); - s16 b1 = (state->Reg[src2] & 0xFFFF); - s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF); - state->Reg[tar] = ((a1 + a2) & 0xFFFF) | (((b1 + b2) & 0xFFFF) << 0x10); - return 1; - } else if ((instr & 0xFF0) == 0xf50) { //ssax - u8 tar = BITS(12, 15); - u8 src1 = BITS(16, 19); - u8 src2 = BITS(0, 3); - s16 a1 = (state->Reg[src1] & 0xFFFF); - s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF); - s16 b1 = (state->Reg[src2] & 0xFFFF); - s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF); - state->Reg[tar] = ((a1 + b2) & 0xFFFF) | (((a2 - b1) & 0xFFFF) << 0x10); - return 1; - } else if ((instr & 0xFF0) == 0xf30) { //sasx - u8 tar = BITS(12, 15); - u8 src1 = BITS(16, 19); - u8 src2 = BITS(0, 3); - s16 a1 = (state->Reg[src1] & 0xFFFF); - s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF); - s16 b1 = (state->Reg[src2] & 0xFFFF); - s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF); - state->Reg[tar] = ((a1 - b2) & 0xFFFF) | (((a2 + b1) & 0xFFFF) << 0x10); + case 0x61: // SSUB16, SADD16, SSAX, and SASX + if ((instr & 0xFF0) == 0xf70 || (instr & 0xFF0) == 0xf10 || + (instr & 0xFF0) == 0xf50 || (instr & 0xFF0) == 0xf30) + { + const u8 rd_idx = BITS(12, 15); + const u8 rm_idx = BITS(0, 3); + const u8 rn_idx = BITS(16, 19); + const s16 rn_lo = (state->Reg[rn_idx] & 0xFFFF); + const s16 rn_hi = ((state->Reg[rn_idx] >> 16) & 0xFFFF); + 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) { + lo_result = (rn_lo - rm_lo); + hi_result = (rn_hi - rm_hi); + } + // SADD16 + else if ((instr & 0xFF0) == 0xf10) { + lo_result = (rn_lo + rm_lo); + hi_result = (rn_hi + rm_hi); + } + // SSAX + else if ((instr & 0xFF0) == 0xf50) { + lo_result = (rn_lo + rm_hi); + hi_result = (rn_hi - rm_lo); + } + // SASX + else { + 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: sadd/ssub/ssax/sasx\n"); + } else { + printf("Unhandled v6 insn: %08x", BITS(20, 27)); + } break; - case 0x62: - if ((instr & 0xFF0) == 0xf70) { //QSUB16 - u8 tar = BITS(12, 15); - u8 src1 = BITS(16, 19); - u8 src2 = BITS(0, 3); - s16 a1 = (state->Reg[src1] & 0xFFFF); - s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF); - s16 b1 = (state->Reg[src2] & 0xFFFF); - s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF); - s32 res1 = (a1 - b1); - s32 res2 = (a2 - b2); - if (res1 > 0x7FFF) res1 = 0x7FFF; - if (res2 > 0x7FFF) res2 = 0x7FFF; - if (res1 < 0x7FFF) res1 = -0x8000; - if (res2 < 0x7FFF) res2 = -0x8000; - state->Reg[tar] = (res1 & 0xFFFF) | ((res2 & 0xFFFF) << 0x10); - return 1; - } else if ((instr & 0xFF0) == 0xf10) { //QADD16 - u8 tar = BITS(12, 15); - u8 src1 = BITS(16, 19); - u8 src2 = BITS(0, 3); - s16 a1 = (state->Reg[src1] & 0xFFFF); - s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF); - s16 b1 = (state->Reg[src2] & 0xFFFF); - s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF); - s32 res1 = (a1 + b1); - s32 res2 = (a2 + b2); - if (res1 > 0x7FFF) res1 = 0x7FFF; - if (res2 > 0x7FFF) res2 = 0x7FFF; - if (res1 < 0x7FFF) res1 = -0x8000; - if (res2 < 0x7FFF) res2 = -0x8000; - state->Reg[tar] = ((res1) & 0xFFFF) | (((res2) & 0xFFFF) << 0x10); + case 0x62: // QSUB16 and QADD16 + if ((instr & 0xFF0) == 0xf70 || (instr & 0xFF0) == 0xf10) { + const u8 rd_idx = BITS(12, 15); + const u8 rn_idx = BITS(16, 19); + const u8 rm_idx = BITS(0, 3); + const s16 rm_lo = (state->Reg[rm_idx] & 0xFFFF); + const s16 rm_hi = ((state->Reg[rm_idx] >> 0x10) & 0xFFFF); + const s16 rn_lo = (state->Reg[rn_idx] & 0xFFFF); + const s16 rn_hi = ((state->Reg[rn_idx] >> 0x10) & 0xFFFF); + + s32 lo_result; + s32 hi_result; + + // QSUB16 + if ((instr & 0xFF0) == 0xf70) { + 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; + else if (lo_result < -0x8000) + lo_result = -0x8000; + + if (hi_result > 0x7FFF) + hi_result = 0x7FFF; + else if (hi_result < -0x8000) + hi_result = -0x8000; + + state->Reg[rd_idx] = (lo_result & 0xFFFF) | ((hi_result & 0xFFFF) << 16); return 1; - } else printf ("Unhandled v6 insn: qadd16/qsub16\n"); + } else { + printf("Unhandled v6 insn: %08x", BITS(20, 27)); + } break; case 0x63: printf ("Unhandled v6 insn: shadd/shsub\n"); @@ -5922,11 +5969,29 @@ L_stm_s_takeabort: b2 = ((u8)(from >> 8) + (u8)(to >> 8)); b3 = ((u8)(from >> 16) + (u8)(to >> 16)); b4 = ((u8)(from >> 24) + (u8)(to >> 24)); - if (b1 & 0xffffff00) state->Cpsr |= (1 << 16); - if (b2 & 0xffffff00) state->Cpsr |= (1 << 17); - if (b3 & 0xffffff00) state->Cpsr |= (1 << 18); - if (b4 & 0xffffff00) state->Cpsr |= (1 << 19); + + if (b1 & 0xffffff00) + state->Cpsr |= (1 << 16); + else + state->Cpsr &= ~(1 << 16); + + if (b2 & 0xffffff00) + state->Cpsr |= (1 << 17); + else + state->Cpsr &= ~(1 << 17); + + if (b3 & 0xffffff00) + state->Cpsr |= (1 << 18); + else + state->Cpsr &= ~(1 << 18); + + + if (b4 & 0xffffff00) + state->Cpsr |= (1 << 19); + else + state->Cpsr &= ~(1 << 19); } + state->Reg[rd] = (u32)(b1 | (b2 & 0xff) << 8 | (b3 & 0xff) << 16 | (b4 & 0xff) << 24); return 1; } @@ -6041,7 +6106,7 @@ L_stm_s_takeabort: break; } - Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFF); + Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFF) | (((state->Reg[BITS(0, 3)] << (32 - ror)) & 0xFF) & 0xFF); if (Rm & 0x80) Rm |= 0xffffff00; @@ -6050,11 +6115,12 @@ L_stm_s_takeabort: state->Reg[BITS(12, 15)] = Rm; else /* SXTAB */ - state->Reg[BITS(12, 15)] += Rm; + state->Reg[BITS(12, 15)] = state->Reg[BITS(16, 19)] + Rm; return 1; } - case 0x6b: { + case 0x6b: + { ARMword Rm; int ror = -1; @@ -6072,10 +6138,10 @@ L_stm_s_takeabort: ror = 24; break; - case 0xf3: + case 0xf3: // REV DEST = ((RHS & 0xFF) << 24) | ((RHS & 0xFF00)) << 8 | ((RHS & 0xFF0000) >> 8) | ((RHS & 0xFF000000) >> 24); return 1; - case 0xfb: + case 0xfb: // REV16 DEST = ((RHS & 0xFF) << 8) | ((RHS & 0xFF00)) >> 8 | ((RHS & 0xFF0000) << 8) | ((RHS & 0xFF000000) >> 8); return 1; default: @@ -6085,7 +6151,7 @@ L_stm_s_takeabort: if (ror == -1) break; - Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFFFF); + Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFFFF) | (((state->Reg[BITS(0, 3)] << (32 - ror)) & 0xFFFF) & 0xFFFF); if (Rm & 0x8000) Rm |= 0xffff0000; @@ -6148,18 +6214,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; } @@ -6172,7 +6247,7 @@ L_stm_s_takeabort: break; } - Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFF); + Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFF) | (((state->Reg[BITS(0, 3)] << (32 - ror)) & 0xFF) & 0xFF); if (BITS(16, 19) == 0xf) /* UXTB */ @@ -6202,9 +6277,13 @@ L_stm_s_takeabort: ror = 24; break; - case 0xfb: - printf("Unhandled v6 insn: revsh\n"); - return 0; + case 0xfb: // REVSH + { + DEST = ((RHS & 0xFF) << 8) | ((RHS & 0xFF00) >> 8); + if (DEST & 0x8000) + DEST |= 0xffff0000; + return 1; + } default: break; } @@ -6212,13 +6291,13 @@ L_stm_s_takeabort: if (ror == -1) break; - Rm = ((state->Reg[BITS(0, 3)] >> ror) & 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; */ /* dyf add */ if (BITS(16, 19) == 0xf) { - state->Reg[BITS(12, 15)] = (Rm >> (8 * BITS(10, 11))) & 0x0000FFFF; + state->Reg[BITS(12, 15)] = Rm; } else { /* UXTAH */ @@ -6226,7 +6305,7 @@ L_stm_s_takeabort: // printf("rd is %x rn is %x rm is %x rotate is %x\n", state->Reg[BITS (12, 15)], state->Reg[BITS (16, 19)] // , Rm, BITS(10, 11)); // printf("icounter is %lld\n", state->NumInstrs); - state->Reg[BITS(12, 15)] = (state->Reg[BITS(16, 19)] >> (8 * (BITS(10, 11)))) + Rm; + state->Reg[BITS(12, 15)] = state->Reg[BITS(16, 19)] + Rm; // printf("rd is %x\n", state->Reg[BITS (12, 15)]); // exit(-1); } |