summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/arm/interpreter/armemu.cpp32
-rw-r--r--src/core/arm/interpreter/armsupp.cpp8
-rw-r--r--src/core/arm/skyeye_common/armemu.h1
3 files changed, 28 insertions, 13 deletions
diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp
index 578d71380..23469f4df 100644
--- a/src/core/arm/interpreter/armemu.cpp
+++ b/src/core/arm/interpreter/armemu.cpp
@@ -6478,22 +6478,28 @@ L_stm_s_takeabort:
6478 const s16 rn_lo = (rn_val & 0xFFFF); 6478 const s16 rn_lo = (rn_val & 0xFFFF);
6479 const s16 rn_hi = ((rn_val >> 16) & 0xFFFF); 6479 const s16 rn_hi = ((rn_val >> 16) & 0xFFFF);
6480 6480
6481 // SMUAD 6481 const u32 product1 = (rn_lo * rm_lo);
6482 if ((instr & 0xf0d0) == 0xf010) { 6482 const u32 product2 = (rn_hi * rm_hi);
6483 state->Reg[rd_idx] = (rn_lo * rm_lo) + (rn_hi * rm_hi); 6483
6484 } 6484 // SMUAD and SMLAD
6485 // SMUSD 6485 if (BIT(6) == 0) {
6486 else if ((instr & 0xf0d0) == 0xf050) { 6486 state->Reg[rd_idx] = product1 + product2;
6487 state->Reg[rd_idx] = (rn_lo * rm_lo) - (rn_hi * rm_hi); 6487
6488 } 6488 if (BITS(12, 15) != 15) {
6489 // SMLAD 6489 state->Reg[rd_idx] += state->Reg[ra_idx];
6490 else if ((instr & 0xd0) == 0x10) { 6490 ARMul_AddOverflowQ(state, product1 + product2, state->Reg[ra_idx]);
6491 state->Reg[rd_idx] = (rn_lo * rm_lo) + (rn_hi * rm_hi) + (s32)state->Reg[ra_idx]; 6491 }
6492
6493 ARMul_AddOverflowQ(state, product1, product2);
6492 } 6494 }
6493 // SMLSD 6495 // SMUSD and SMLSD
6494 else { 6496 else {
6495 state->Reg[rd_idx] = ((rn_lo * rm_lo) - (rn_hi * rm_hi)) + (s32)state->Reg[ra_idx]; 6497 state->Reg[rd_idx] = product1 - product2;
6498
6499 if (BITS(12, 15) != 15)
6500 state->Reg[rd_idx] += state->Reg[ra_idx];
6496 } 6501 }
6502
6497 return 1; 6503 return 1;
6498 } 6504 }
6499 break; 6505 break;
diff --git a/src/core/arm/interpreter/armsupp.cpp b/src/core/arm/interpreter/armsupp.cpp
index b31c0ea24..6774f8a74 100644
--- a/src/core/arm/interpreter/armsupp.cpp
+++ b/src/core/arm/interpreter/armsupp.cpp
@@ -444,6 +444,14 @@ ARMul_AddOverflow (ARMul_State * state, ARMword a, ARMword b, ARMword result)
444 ASSIGNV (AddOverflow (a, b, result)); 444 ASSIGNV (AddOverflow (a, b, result));
445} 445}
446 446
447/* Assigns the Q flag if the given result is considered an overflow from the addition of a and b */
448void ARMul_AddOverflowQ(ARMul_State* state, ARMword a, ARMword b)
449{
450 u32 result = a + b;
451 if (((result ^ a) & (u32)0x80000000) && ((a ^ b) & (u32)0x80000000) == 0)
452 SETQ;
453}
454
447/* Assigns the C flag after an subtraction of a and b to give result. */ 455/* Assigns the C flag after an subtraction of a and b to give result. */
448 456
449void 457void
diff --git a/src/core/arm/skyeye_common/armemu.h b/src/core/arm/skyeye_common/armemu.h
index e1b286f0f..3ea14b5a3 100644
--- a/src/core/arm/skyeye_common/armemu.h
+++ b/src/core/arm/skyeye_common/armemu.h
@@ -602,6 +602,7 @@ extern ARMword ARMul_SwitchMode (ARMul_State *, ARMword, ARMword);
602extern void ARMul_MSRCpsr (ARMul_State *, ARMword, ARMword); 602extern void ARMul_MSRCpsr (ARMul_State *, ARMword, ARMword);
603extern void ARMul_SubOverflow (ARMul_State *, ARMword, ARMword, ARMword); 603extern void ARMul_SubOverflow (ARMul_State *, ARMword, ARMword, ARMword);
604extern void ARMul_AddOverflow (ARMul_State *, ARMword, ARMword, ARMword); 604extern void ARMul_AddOverflow (ARMul_State *, ARMword, ARMword, ARMword);
605extern void ARMul_AddOverflowQ(ARMul_State*, ARMword, ARMword);
605extern void ARMul_SubCarry (ARMul_State *, ARMword, ARMword, ARMword); 606extern void ARMul_SubCarry (ARMul_State *, ARMword, ARMword, ARMword);
606extern void ARMul_AddCarry (ARMul_State *, ARMword, ARMword, ARMword); 607extern void ARMul_AddCarry (ARMul_State *, ARMword, ARMword, ARMword);
607extern tdstate ARMul_ThumbDecode (ARMul_State *, ARMword, ARMword, ARMword *); 608extern tdstate ARMul_ThumbDecode (ARMul_State *, ARMword, ARMword, ARMword *);