summaryrefslogtreecommitdiffstats
path: root/src/core/arm/interpreter
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/arm/interpreter')
-rw-r--r--src/core/arm/interpreter/armemu.cpp301
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);
}