diff options
Diffstat (limited to '')
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | src/core/arm/interpreter/armemu.cpp | 139 | ||||
-rw-r--r-- | src/core/arm/interpreter/armsupp.cpp | 13 | ||||
-rw-r--r-- | src/core/arm/skyeye_common/armdefs.h | 2 | ||||
-rw-r--r-- | src/core/arm/skyeye_common/armemu.h | 8 |
5 files changed, 116 insertions, 48 deletions
@@ -10,7 +10,7 @@ For development discussion, please join us @ #citra on [freenode](http://webchat ### Development -If you want to contribute please take a took at the [Contributor's Guide](CONTRIBUTING.md), [Roadmap](https://github.com/citra-emu/citra/wiki/Roadmap) and [Developer Information](https://github.com/citra-emu/citra/wiki/Developer-Information) pages. You should as well contact any of the developers in the forum in order to know about the current state of the emulator. +If you want to contribute please take a look at the [Contributor's Guide](CONTRIBUTING.md), [Roadmap](https://github.com/citra-emu/citra/wiki/Roadmap) and [Developer Information](https://github.com/citra-emu/citra/wiki/Developer-Information) pages. You should as well contact any of the developers in the forum in order to know about the current state of the emulator. ### Building diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index 610e04f10..b2f671f94 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -1670,7 +1670,7 @@ mainswitch: op1 *= op2; //printf("SMLA_INST:BB,op1=0x%x, op2=0x%x. Rn=0x%x\n", op1, op2, Rn); if (AddOverflow(op1, Rn, op1 + Rn)) - SETS; + SETQ; state->Reg[BITS (16, 19)] = op1 + Rn; break; } @@ -1682,7 +1682,7 @@ mainswitch: ARMword result = op1 + op2; if (AddOverflow(op1, op2, result)) { result = POS (result) ? 0x80000000 : 0x7fffffff; - SETS; + SETQ; } state->Reg[BITS (12, 15)] = result; break; @@ -1724,7 +1724,7 @@ mainswitch: TAKEABORT; } else if ((BITS (0, 11) == 0) && (LHSReg == 15)) { /* MRS CPSR */ UNDEF_MRSPC; - DEST = ECC | EINT | EMODE; + DEST = ARMul_GetCPSR(state); } else { UNDEF_Test; } @@ -1795,7 +1795,7 @@ mainswitch: ARMword Rn = state->Reg[BITS(12, 15)]; if (AddOverflow((ARMword)result, Rn, (ARMword)(result + Rn))) - SETS; + SETQ; result += Rn; } state->Reg[BITS (16, 19)] = (ARMword)result; @@ -1811,7 +1811,7 @@ mainswitch: if (SubOverflow (op1, op2, result)) { result = POS (result) ? 0x80000000 : 0x7fffffff; - SETS; + SETQ; } state->Reg[BITS (12, 15)] = result; @@ -1934,13 +1934,13 @@ mainswitch: if (AddOverflow (op2, op2, op2d)) { - SETS; + SETQ; op2d = POS (op2d) ? 0x80000000 : 0x7fffffff; } result = op1 + op2d; if (AddOverflow(op1, op2d, result)) { - SETS; + SETQ; result = POS (result) ? 0x80000000 : 0x7fffffff; } @@ -2053,13 +2053,13 @@ mainswitch: ARMword result; if (AddOverflow(op2, op2, op2d)) { - SETS; + SETQ; op2d = POS (op2d) ? 0x80000000 : 0x7fffffff; } result = op1 - op2d; if (SubOverflow(op1, op2d, result)) { - SETS; + SETQ; result = POS (result) ? 0x80000000 : 0x7fffffff; } @@ -5877,6 +5877,8 @@ L_stm_s_takeabort: state->Cpsr &= ~(1 << 18); state->Cpsr &= ~(1 << 19); } + + ARMul_CPSRAltered(state); return 1; } // SADD8/SSUB8 @@ -5948,6 +5950,7 @@ L_stm_s_takeabort: state->Cpsr &= ~(1 << 19); } + ARMul_CPSRAltered(state); state->Reg[rd_idx] = (lo_val1 | lo_val2 << 8 | hi_val1 << 16 | hi_val2 << 24); return 1; } @@ -6024,15 +6027,33 @@ L_stm_s_takeabort: if ((instr & 0x0F0) == 0x070) { // USUB16 h1 = ((u16)from - (u16)to); h2 = ((u16)(from >> 16) - (u16)(to >> 16)); - if (!(h1 & 0xffff0000)) state->Cpsr |= (3 << 16); - if (!(h2 & 0xffff0000)) state->Cpsr |= (3 << 18); + + if (!(h1 & 0xffff0000)) + state->Cpsr |= (3 << 16); + else + state->Cpsr &= ~(3 << 16); + + if (!(h2 & 0xffff0000)) + state->Cpsr |= (3 << 18); + else + state->Cpsr &= ~(3 << 18); } else { // UADD16 h1 = ((u16)from + (u16)to); h2 = ((u16)(from >> 16) + (u16)(to >> 16)); - if (h1 & 0xffff0000) state->Cpsr |= (3 << 16); - if (h2 & 0xffff0000) state->Cpsr |= (3 << 18); + + if (h1 & 0xffff0000) + state->Cpsr |= (3 << 16); + else + state->Cpsr &= ~(3 << 16); + + if (h2 & 0xffff0000) + state->Cpsr |= (3 << 18); + else + state->Cpsr &= ~(3 << 18); } + + ARMul_CPSRAltered(state); state->Reg[rd] = (u32)((h1 & 0xffff) | ((h2 & 0xffff) << 16)); return 1; } @@ -6045,10 +6066,26 @@ 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); } else { // UADD8 b1 = ((u8)from + (u8)to); @@ -6071,13 +6108,13 @@ L_stm_s_takeabort: else state->Cpsr &= ~(1 << 18); - if (b4 & 0xffffff00) state->Cpsr |= (1 << 19); else state->Cpsr &= ~(1 << 19); } + ARMul_CPSRAltered(state); state->Reg[rd] = (u32)(b1 | (b2 & 0xff) << 8 | (b3 & 0xff) << 16 | (b4 & 0xff) << 24); return 1; } @@ -6116,7 +6153,7 @@ L_stm_s_takeabort: u32 rm = (instr >> 0) & 0xF; u32 from = state->Reg[rn]; u32 to = state->Reg[rm]; - u32 cpsr = state->Cpsr; + u32 cpsr = ARMul_GetCPSR(state); if ((instr & 0xFF0) == 0xFB0) { // SEL u32 result; if (cpsr & (1 << 16)) @@ -6172,16 +6209,23 @@ L_stm_s_takeabort: s16 rn_lo = (state->Reg[rn_idx]); s16 rn_hi = (state->Reg[rn_idx] >> 16); - if (rn_lo > max) + if (rn_lo > max) { rn_lo = max; - else if (rn_lo < min) + state->Cpsr |= (1 << 27); + } else if (rn_lo < min) { rn_lo = min; + state->Cpsr |= (1 << 27); + } - if (rn_hi > max) + if (rn_hi > max) { rn_hi = max; - else if (rn_hi < min) + state->Cpsr |= (1 << 27); + } else if (rn_hi < min) { rn_hi = min; + state->Cpsr |= (1 << 27); + } + ARMul_CPSRAltered(state); state->Reg[rd_idx] = (rn_lo & 0xFFFF) | ((rn_hi & 0xFFFF) << 16); return 1; } @@ -6313,16 +6357,23 @@ L_stm_s_takeabort: s16 rn_lo = (state->Reg[rn_idx]); s16 rn_hi = (state->Reg[rn_idx] >> 16); - if (max < rn_lo) + if (max < rn_lo) { rn_lo = max; - else if (rn_lo < 0) + state->Cpsr |= (1 << 27); + } else if (rn_lo < 0) { rn_lo = 0; + state->Cpsr |= (1 << 27); + } - if (max < rn_hi) + if (max < rn_hi) { rn_hi = max; - else if (rn_hi < 0) + state->Cpsr |= (1 << 27); + } else if (rn_hi < 0) { rn_hi = 0; - + state->Cpsr |= (1 << 27); + } + + ARMul_CPSRAltered(state); state->Reg[rd_idx] = (rn_lo & 0xFFFF) | ((rn_hi << 16) & 0xFFFF); return 1; } @@ -6427,22 +6478,28 @@ L_stm_s_takeabort: const s16 rn_lo = (rn_val & 0xFFFF); const s16 rn_hi = ((rn_val >> 16) & 0xFFFF); - // SMUAD - if ((instr & 0xf0d0) == 0xf010) { - state->Reg[rd_idx] = (rn_lo * rm_lo) + (rn_hi * rm_hi); - } - // SMUSD - else if ((instr & 0xf0d0) == 0xf050) { - state->Reg[rd_idx] = (rn_lo * rm_lo) - (rn_hi * rm_hi); - } - // SMLAD - else if ((instr & 0xd0) == 0x10) { - state->Reg[rd_idx] = (rn_lo * rm_lo) + (rn_hi * rm_hi) + (s32)state->Reg[ra_idx]; + const u32 product1 = (rn_lo * rm_lo); + const u32 product2 = (rn_hi * rm_hi); + + // SMUAD and SMLAD + if (BIT(6) == 0) { + state->Reg[rd_idx] = product1 + product2; + + if (BITS(12, 15) != 15) { + state->Reg[rd_idx] += state->Reg[ra_idx]; + ARMul_AddOverflowQ(state, product1 + product2, state->Reg[ra_idx]); + } + + ARMul_AddOverflowQ(state, product1, product2); } - // SMLSD + // SMUSD and SMLSD else { - state->Reg[rd_idx] = ((rn_lo * rm_lo) - (rn_hi * rm_hi)) + (s32)state->Reg[ra_idx]; + state->Reg[rd_idx] = product1 - product2; + + if (BITS(12, 15) != 15) + state->Reg[rd_idx] += state->Reg[ra_idx]; } + return 1; } break; diff --git a/src/core/arm/interpreter/armsupp.cpp b/src/core/arm/interpreter/armsupp.cpp index 30519f216..6774f8a74 100644 --- a/src/core/arm/interpreter/armsupp.cpp +++ b/src/core/arm/interpreter/armsupp.cpp @@ -227,8 +227,9 @@ ARMul_CPSRAltered (ARMul_State * state) //state->Cpsr &= ~CBIT; ASSIGNV ((state->Cpsr & VBIT) != 0); //state->Cpsr &= ~VBIT; - ASSIGNS ((state->Cpsr & SBIT) != 0); - //state->Cpsr &= ~SBIT; + ASSIGNQ ((state->Cpsr & QBIT) != 0); + //state->Cpsr &= ~QBIT; + state->GEFlag = (state->Cpsr & 0x000F0000); #ifdef MODET ASSIGNT ((state->Cpsr & TBIT) != 0); //state->Cpsr &= ~TBIT; @@ -443,6 +444,14 @@ ARMul_AddOverflow (ARMul_State * state, ARMword a, ARMword b, ARMword result) ASSIGNV (AddOverflow (a, b, result)); } +/* Assigns the Q flag if the given result is considered an overflow from the addition of a and b */ +void ARMul_AddOverflowQ(ARMul_State* state, ARMword a, ARMword b) +{ + u32 result = a + b; + if (((result ^ a) & (u32)0x80000000) && ((a ^ b) & (u32)0x80000000) == 0) + SETQ; +} + /* Assigns the C flag after an subtraction of a and b to give result. */ void diff --git a/src/core/arm/skyeye_common/armdefs.h b/src/core/arm/skyeye_common/armdefs.h index 28a4a0db4..34eb5aaf7 100644 --- a/src/core/arm/skyeye_common/armdefs.h +++ b/src/core/arm/skyeye_common/armdefs.h @@ -198,7 +198,7 @@ struct ARMul_State //ARMword translate_pc; /* add armv6 flags dyf:2010-08-09 */ - ARMword GEFlag, EFlag, AFlag, QFlags; + ARMword GEFlag, EFlag, AFlag, QFlag; //chy:2003-08-19, used in arm v5e|xscale ARMword SFlag; #ifdef MODET diff --git a/src/core/arm/skyeye_common/armemu.h b/src/core/arm/skyeye_common/armemu.h index 7f7c0e682..3ea14b5a3 100644 --- a/src/core/arm/skyeye_common/armemu.h +++ b/src/core/arm/skyeye_common/armemu.h @@ -34,7 +34,7 @@ #define ZBIT (1L << 30) #define CBIT (1L << 29) #define VBIT (1L << 28) -#define SBIT (1L << 27) +#define QBIT (1L << 27) #define IBIT (1L << 7) #define FBIT (1L << 6) #define IFBITS (3L << 6) @@ -156,13 +156,14 @@ #define R15PCMODE (state->Reg[15] & (R15PCBITS | R15MODEBITS)) #define R15MODE (state->Reg[15] & R15MODEBITS) -#define ECC ((NFLAG << 31) | (ZFLAG << 30) | (CFLAG << 29) | (VFLAG << 28) | (SFLAG << 27)) +#define ECC ((NFLAG << 31) | (ZFLAG << 30) | (CFLAG << 29) | (VFLAG << 28) | (QFLAG << 27)) #define EINT (IFFLAGS << 6) #define ER15INT (IFFLAGS << 26) #define EMODE (state->Mode) +#define EGEBITS (state->GEFlag & 0x000F0000) #ifdef MODET -#define CPSR (ECC | EINT | EMODE | (TFLAG << 5)) +#define CPSR (ECC | EGEBITS | (EFLAG << 9) | (AFLAG << 8) | EINT | (TFLAG << 5) | EMODE) #else #define CPSR (ECC | EINT | EMODE) #endif @@ -601,6 +602,7 @@ extern ARMword ARMul_SwitchMode (ARMul_State *, ARMword, ARMword); extern void ARMul_MSRCpsr (ARMul_State *, ARMword, ARMword); extern void ARMul_SubOverflow (ARMul_State *, ARMword, ARMword, ARMword); extern void ARMul_AddOverflow (ARMul_State *, ARMword, ARMword, ARMword); +extern void ARMul_AddOverflowQ(ARMul_State*, ARMword, ARMword); extern void ARMul_SubCarry (ARMul_State *, ARMword, ARMword, ARMword); extern void ARMul_AddCarry (ARMul_State *, ARMword, ARMword, ARMword); extern tdstate ARMul_ThumbDecode (ARMul_State *, ARMword, ARMword, ARMword *); |