From b4256431aa148148182a00af205dc137b9833e41 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sun, 7 Dec 2014 23:47:26 -0500 Subject: armemu: Fix parenthesis warnings regarding bitwise ops --- src/core/arm/interpreter/armemu.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/core/arm/interpreter/armemu.cpp') diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index 73223874e..cb7c27030 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -5724,7 +5724,7 @@ L_stm_s_takeabort: 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); + state->Reg[tar] = ((a1 - a2) & 0xFFFF) | (((b1 - b2)&0xFFFF)<< 0x10); return 1; } else if ((instr & 0xFF0) == 0xf10)//sadd16 @@ -5736,7 +5736,7 @@ L_stm_s_takeabort: 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); + state->Reg[tar] = ((a1 + a2) & 0xFFFF) | (((b1 + b2)&0xFFFF)<< 0x10); return 1; } else if ((instr & 0xFF0) == 0xf50)//ssax @@ -5748,7 +5748,7 @@ L_stm_s_takeabort: 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); + state->Reg[tar] = ((a1 - b2) & 0xFFFF) | (((a2 + b1) & 0xFFFF) << 0x10); return 1; } else if ((instr & 0xFF0) == 0xf30)//sasx @@ -5760,7 +5760,7 @@ L_stm_s_takeabort: s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF); s16 b1 = (state->Reg[src2] & 0xFFFF); s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF); - state->Reg[tar] = (a2 - b1) & 0xFFFF | (((a2 + b1) & 0xFFFF) << 0x10); + state->Reg[tar] = ((a2 - b1) & 0xFFFF) | (((a2 + b1) & 0xFFFF) << 0x10); return 1; } else printf ("Unhandled v6 insn: sadd/ssub\n"); -- cgit v1.2.3 From 62fd564854b31f7e3203db3fb6f113231c30a3b7 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 8 Dec 2014 01:44:37 -0500 Subject: armemu: Fix SASX --- src/core/arm/interpreter/armemu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core/arm/interpreter/armemu.cpp') diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index cb7c27030..d327252dc 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -5760,7 +5760,7 @@ L_stm_s_takeabort: s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF); s16 b1 = (state->Reg[src2] & 0xFFFF); s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF); - state->Reg[tar] = ((a2 - b1) & 0xFFFF) | (((a2 + b1) & 0xFFFF) << 0x10); + state->Reg[tar] = ((a1 - b2) & 0xFFFF) | (((a2 + b1) & 0xFFFF) << 0x10); return 1; } else printf ("Unhandled v6 insn: sadd/ssub\n"); -- cgit v1.2.3 From 905e3b616a70abfc2a68b519bc05a6b0f38151af Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 8 Dec 2014 15:47:20 -0500 Subject: armemu: Fix SSAX --- src/core/arm/interpreter/armemu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core/arm/interpreter/armemu.cpp') diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index d327252dc..d717bd2c8 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -5748,7 +5748,7 @@ L_stm_s_takeabort: 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); + state->Reg[tar] = ((a1 + b2) & 0xFFFF) | (((a2 - b1) & 0xFFFF) << 0x10); return 1; } else if ((instr & 0xFF0) == 0xf30)//sasx -- cgit v1.2.3 From 0600e2d8b5b30bd68c8b19cb1f2051e096e7caa9 Mon Sep 17 00:00:00 2001 From: Yuri Kunde Schlesner Date: Fri, 5 Dec 2014 23:53:49 -0200 Subject: Convert old logging calls to new logging macros --- src/core/arm/interpreter/armemu.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/core/arm/interpreter/armemu.cpp') diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index d717bd2c8..825955ade 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -949,7 +949,7 @@ ARMul_Emulate26 (ARMul_State * state) //printf("t decode %04lx -> %08lx\n", instr & 0xffff, armOp); if (armOp == 0xDEADC0DE) { - DEBUG("Failed to decode thumb opcode %04X at %08X\n", instr, pc); + LOG_ERROR(Core_ARM11, "Failed to decode thumb opcode %04X at %08X", instr, pc); } instr = armOp; @@ -3437,7 +3437,7 @@ mainswitch: case 0x7f: /* Load Byte, WriteBack, Pre Inc, Reg. */ if (BIT (4)) { - DEBUG("got unhandled special breakpoint\n"); + LOG_DEBUG(Core_ARM11, "got unhandled special breakpoint"); return 1; } UNDEF_LSRBaseEQOffWb; -- cgit v1.2.3 From d26b7146cefd6a2048cb5093c8419a761b06ae69 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 13 Dec 2014 01:24:03 -0500 Subject: ARM: Pull some SkyEye fixes from 3dmoo. --- src/core/arm/interpreter/armemu.cpp | 896 +++++++++++++++++++----------------- 1 file changed, 481 insertions(+), 415 deletions(-) (limited to 'src/core/arm/interpreter/armemu.cpp') diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index 825955ade..ec40881f8 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -1166,7 +1166,7 @@ mainswitch: else if ((((int)BITS(21, 27)) == 0x3e) && ((int)BITS(4, 6) == 0x1)) { //(ARMword)(instr<<(31-(n))) >> ((31-(n))+(m)) unsigned msb ,tmp_rn, tmp_rd, dst; - msb = tmp_rd = tmp_rn = dst = 0; + tmp_rd = tmp_rn = dst = 0; Rd = BITS(12, 15); Rn = BITS(0, 3); lsb = BITS(7, 11); @@ -1737,7 +1737,7 @@ mainswitch: //chy 2006-02-15 if in user mode, can not set cpsr 0:23 //from p165 of ARMARM book state->Cpsr = GETSPSR (state->Bank); - //ARMul_CPSRAltered (state); + ARMul_CPSRAltered (state); #else rhs = DPRegRHS; temp = LHS & rhs; @@ -1877,7 +1877,7 @@ mainswitch: /* TEQP reg */ #ifdef MODE32 state->Cpsr = GETSPSR (state->Bank); - //ARMul_CPSRAltered (state); + ARMul_CPSRAltered (state); #else rhs = DPRegRHS; temp = LHS ^ rhs; @@ -1993,7 +1993,7 @@ mainswitch: /* CMPP reg. */ #ifdef MODE32 state->Cpsr = GETSPSR (state->Bank); - //ARMul_CPSRAltered (state); + ARMul_CPSRAltered (state); #else rhs = DPRegRHS; temp = LHS - rhs; @@ -2112,7 +2112,7 @@ mainswitch: if (DESTReg == 15) { #ifdef MODE32 state->Cpsr = GETSPSR (state->Bank); - //ARMul_CPSRAltered (state); + ARMul_CPSRAltered (state); #else rhs = DPRegRHS; temp = LHS + rhs; @@ -2200,17 +2200,57 @@ mainswitch: Handle_Store_Double (state, instr); break; } + if (BITS(4, 11) == 0xF9) { //strexd + u32 l = LHSReg; + + bool enter = false; + + if (state->currentexval == (u32)ARMul_ReadWord(state, state->currentexaddr)&& + state->currentexvald == (u32)ARMul_ReadWord(state, state->currentexaddr + 4)) + enter = true; + + + //todo bug this and STREXD and LDREXD http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0360e/CHDGJGGC.html + + + if (enter) { + ARMul_StoreWordN(state, LHS, state->Reg[RHSReg]); + ARMul_StoreWordN(state,LHS + 4 , state->Reg[RHSReg + 1]); + state->Reg[DESTReg] = 0; + } else { + state->Reg[DESTReg] = 1; + } + + break; + } #endif dest = DPRegRHS; WRITEDEST (dest); break; - case 0x1b: /* MOVS reg */ + case 0x1B: /* MOVS reg */ #ifdef MODET + /* ldrexd ichfly */ + if (BITS(0, 11) == 0xF9F) { //strexd + lhs = LHS; + + state->currentexaddr = lhs; + state->currentexval = (u32)ARMul_ReadWord(state, lhs); + state->currentexvald = (u32)ARMul_ReadWord(state, lhs + 4); + + state->Reg[DESTReg] = ARMul_LoadWordN(state, lhs); + state->Reg[DESTReg] = ARMul_LoadWordN(state, lhs + 4); + break; + } + if ((BITS (4, 11) & 0xF9) == 0x9) /* LDR register offset, write-back, up, pre indexed. */ LHPREUPWB (); /* Continue with remaining instruction decoding. */ + + + + #endif dest = DPSRegRHS; WRITESDEST (dest); @@ -2297,12 +2337,12 @@ mainswitch: if (state->currentexval == (u32)ARMul_LoadHalfWord(state, state->currentexaddr))enter = true; - ARMul_StoreHalfWord(state, lhs, RHS); //StoreWord(state, lhs, RHS) if (state->Aborted) { TAKEABORT; } if (enter) { + ARMul_StoreHalfWord(state, lhs, RHS); state->Reg[DESTReg] = 0; } else { state->Reg[DESTReg] = 1; @@ -2520,7 +2560,7 @@ mainswitch: /* TSTP immed. */ #ifdef MODE32 state->Cpsr = GETSPSR (state->Bank); - //ARMul_CPSRAltered (state); + ARMul_CPSRAltered (state); #else temp = LHS & DPImmRHS; SETR15PSR (temp); @@ -2547,7 +2587,7 @@ mainswitch: /* TEQP immed. */ #ifdef MODE32 state->Cpsr = GETSPSR (state->Bank); - //ARMul_CPSRAltered (state); + ARMul_CPSRAltered (state); #else temp = LHS ^ DPImmRHS; SETR15PSR (temp); @@ -2568,7 +2608,7 @@ mainswitch: /* CMPP immed. */ #ifdef MODE32 state->Cpsr = GETSPSR (state->Bank); - //ARMul_CPSRAltered (state); + ARMul_CPSRAltered (state); #else temp = LHS - DPImmRHS; SETR15PSR (temp); @@ -2604,7 +2644,7 @@ mainswitch: /* CMNP immed. */ #ifdef MODE32 state->Cpsr = GETSPSR (state->Bank); - //ARMul_CPSRAltered (state); + ARMul_CPSRAltered (state); #else temp = LHS + DPImmRHS; SETR15PSR (temp); @@ -3055,17 +3095,14 @@ mainswitch: case 0x68: /* Store Word, No WriteBack, Post Inc, Reg. */ //ichfly PKHBT PKHTB todo check this - if ((instr & 0x70) == 0x10) //pkhbt - { + if ((instr & 0x70) == 0x10) { //pkhbt u8 idest = BITS(12, 15); u8 rfis = BITS(16, 19); u8 rlast = BITS(0, 3); u8 ishi = BITS(7,11); state->Reg[idest] = (state->Reg[rfis] & 0xFFFF) | ((state->Reg[rlast] << ishi) & 0xFFFF0000); break; - } - else if ((instr & 0x70) == 0x50)//pkhtb - { + } else if ((instr & 0x70) == 0x50) { //pkhtb u8 idest = BITS(12, 15); u8 rfis = BITS(16, 19); u8 rlast = BITS(0, 3); @@ -3073,8 +3110,7 @@ mainswitch: if (ishi == 0)ishi = 0x20; state->Reg[idest] = (((int)(state->Reg[rlast]) >> (int)(ishi))& 0xFFFF) | ((state->Reg[rfis]) & 0xFFFF0000); break; - } - else if (BIT (4)) { + } else if (BIT (4)) { #ifdef MODE32 if (state->is_v6 && handle_v6_insn (state, instr)) @@ -3686,13 +3722,11 @@ mainswitch: /* Co-Processor Data Transfers. */ case 0xc4: - if ((instr & 0x0FF00FF0) == 0xC400B10) //vmov BIT(0-3), BIT(12-15), BIT(16-20), vmov d0, r0, r0 - { + if ((instr & 0x0FF00FF0) == 0xC400B10) { //vmov BIT(0-3), BIT(12-15), BIT(16-20), vmov d0, r0, r0 state->ExtReg[BITS(0, 3) << 1] = state->Reg[BITS(12, 15)]; state->ExtReg[(BITS(0, 3) << 1) + 1] = state->Reg[BITS(16, 20)]; break; - } - else if (state->is_v5) { + } else if (state->is_v5) { /* Reading from R15 is UNPREDICTABLE. */ if (BITS (12, 15) == 15 || BITS (16, 19) == 15) ARMul_UndefInstr (state, instr); @@ -3712,22 +3746,18 @@ mainswitch: break; case 0xc5: - if ((instr & 0x00000FF0) == 0xB10) //vmov BIT(12-15), BIT(16-20), BIT(0-3) vmov r0, r0, d0 - { + if ((instr & 0x00000FF0) == 0xB10) { //vmov BIT(12-15), BIT(16-20), BIT(0-3) vmov r0, r0, d0 state->Reg[BITS(12, 15)] = state->ExtReg[BITS(0, 3) << 1]; state->Reg[BITS(16, 19)] = state->ExtReg[(BITS(0, 3) << 1) + 1]; break; - } - else if (state->is_v5) { + } else if (state->is_v5) { /* Writes to R15 are UNPREDICATABLE. */ if (DESTReg == 15 || LHSReg == 15) ARMul_UndefInstr (state, instr); /* Is access to the coprocessor allowed ? */ - else if (!CP_ACCESS_ALLOWED(state, CPNum)) - { + else if (!CP_ACCESS_ALLOWED(state, CPNum)) { ARMul_UndefInstr(state, instr); - } - else { + } else { /* MRRC, ARMv5TE and up */ ARMul_MRRC (state, instr, &DEST, &(state->Reg[LHSReg])); break; @@ -4565,7 +4595,7 @@ out: #ifdef MODE32 if (state->Bank > 0) { state->Cpsr = state->Spsr[state->Bank]; - //ARMul_CPSRAltered (state); + ARMul_CPSRAltered (state); } #ifdef MODET if (TFLAG) @@ -5256,7 +5286,7 @@ L_ldm_s_makeabort: //chy 2006-02-16 , should not consider system mode, don't conside 26bit mode if (state->Mode != USER26MODE && state->Mode != USER32MODE ) { state->Cpsr = GETSPSR (state->Bank); - //ARMul_CPSRAltered (state); + ARMul_CPSRAltered (state); } WriteR15 (state, PC); @@ -5641,30 +5671,9 @@ L_stm_s_takeabort: static int handle_v6_insn (ARMul_State * state, ARMword instr) { - switch (BITS (20, 27)) { - //ichfly - case 0x66: //UQSUB8 - if ((instr & 0x0FF00FF0) == 0x06600FF0) { - u32 rd = (instr >> 12) & 0xF; - u32 rm = (instr >> 16) & 0xF; - u32 rn = (instr >> 0) & 0xF; - u32 subfrom = state->Reg[rm]; - u32 tosub = state->Reg[rn]; + ARMword lhs, temp; - u8 b1 = (u8)((u8)(subfrom)-(u8)(tosub)); - if (b1 > (u8)(subfrom)) b1 = 0; - u8 b2 = (u8)((u8)(subfrom >> 8) - (u8)(tosub >> 8)); - if (b2 > (u8)(subfrom >> 8)) b2 = 0; - u8 b3 = (u8)((u8)(subfrom >> 16) - (u8)(tosub >> 16)); - if (b3 > (u8)(subfrom >> 16)) b3 = 0; - u8 b4 = (u8)((u8)(subfrom >> 24) - (u8)(tosub >> 24)); - if (b4 > (u8)(subfrom >> 24)) b4 = 0; - state->Reg[rd] = (u32)(b1 | b2 << 8 | b3 << 16 | b4 << 24); - return 1; - } else { - printf("UQSUB8 decoding fail %08X",instr); - } -#if 0 + switch (BITS (20, 27)) { case 0x03: printf ("Unhandled v6 insn: ldr\n"); break; @@ -5678,9 +5687,43 @@ L_stm_s_takeabort: printf ("Unhandled v6 insn: smi\n"); break; case 0x18: + if (BITS(4, 7) == 0x9) { + /* strex */ + u32 l = LHSReg; + u32 r = RHSReg; + lhs = LHS; + + bool enter = false; + + if (state->currentexval == (u32)ARMul_ReadWord(state, state->currentexaddr))enter = true; + //StoreWord(state, lhs, RHS) + if (state->Aborted) { + TAKEABORT; + } + + if (enter) { + ARMul_StoreWordS(state, lhs, RHS); + state->Reg[DESTReg] = 0; + } + else { + state->Reg[DESTReg] = 1; + } + + return 1; + } printf ("Unhandled v6 insn: strex\n"); break; case 0x19: + /* ldrex */ + if (BITS(4, 7) == 0x9) { + lhs = LHS; + + state->currentexaddr = lhs; + state->currentexval = ARMul_ReadWord(state, lhs); + + LoadWord(state, instr, lhs); + return 1; + } printf ("Unhandled v6 insn: ldrex\n"); break; case 0x1a: @@ -5690,9 +5733,52 @@ L_stm_s_takeabort: printf ("Unhandled v6 insn: ldrexd\n"); break; case 0x1c: + if (BITS(4, 7) == 0x9) { + /* strexb */ + lhs = LHS; + + bool enter = false; + + if (state->currentexval == (u32)ARMul_ReadByte(state, state->currentexaddr))enter = true; + + BUSUSEDINCPCN; + if (state->Aborted) { + TAKEABORT; + } + + + if (enter) { + ARMul_StoreByte(state, lhs, RHS); + state->Reg[DESTReg] = 0; + } + else { + state->Reg[DESTReg] = 1; + } + + //printf("In %s, strexb not implemented\n", __FUNCTION__); + UNDEF_LSRBPC; + /* WRITESDEST (dest); */ + return 1; + } printf ("Unhandled v6 insn: strexb\n"); break; case 0x1d: + if ((BITS(4, 7)) == 0x9) { + /* ldrexb */ + temp = LHS; + LoadByte(state, instr, temp, LUNSIGNED); + + state->currentexaddr = temp; + state->currentexval = (u32)ARMul_ReadByte(state, temp); + + //state->Reg[BITS(12, 15)] = ARMul_LoadByte(state, state->Reg[BITS(16, 19)]); + //printf("ldrexb\n"); + //printf("instr is %x rm is %d\n", instr, BITS(16, 19)); + //exit(-1); + + //printf("In %s, ldrexb not implemented\n", __FUNCTION__); + return 1; + } printf ("Unhandled v6 insn: ldrexb\n"); break; case 0x1e: @@ -5713,10 +5799,8 @@ L_stm_s_takeabort: case 0x3f: printf ("Unhandled v6 insn: rbit\n"); break; -#endif case 0x61: - if ((instr & 0xFF0) == 0xf70)//ssub16 - { + if ((instr & 0xFF0) == 0xf70) { //ssub16 u8 tar = BITS(12, 15); u8 src1 = BITS(16, 19); u8 src2 = BITS(0, 3); @@ -5724,11 +5808,9 @@ L_stm_s_takeabort: 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); + state->Reg[tar] = ((a1 - a2) & 0xFFFF) | (((b1 - b2) & 0xFFFF) << 0x10); return 1; - } - else if ((instr & 0xFF0) == 0xf10)//sadd16 - { + } else if ((instr & 0xFF0) == 0xf10) { //sadd16 u8 tar = BITS(12, 15); u8 src1 = BITS(16, 19); u8 src2 = BITS(0, 3); @@ -5736,11 +5818,9 @@ L_stm_s_takeabort: 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); + state->Reg[tar] = ((a1 + a2) & 0xFFFF) | (((b1 + b2) & 0xFFFF) << 0x10); return 1; - } - else if ((instr & 0xFF0) == 0xf50)//ssax - { + } else if ((instr & 0xFF0) == 0xf50) { //ssax u8 tar = BITS(12, 15); u8 src1 = BITS(16, 19); u8 src2 = BITS(0, 3); @@ -5748,11 +5828,9 @@ L_stm_s_takeabort: 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); + state->Reg[tar] = ((a1 + b2) & 0xFFFF) | (((a2 - b1) & 0xFFFF) << 0x10); return 1; - } - else if ((instr & 0xFF0) == 0xf30)//sasx - { + } else if ((instr & 0xFF0) == 0xf30) { //sasx u8 tar = BITS(12, 15); u8 src1 = BITS(16, 19); u8 src2 = BITS(0, 3); @@ -5760,14 +5838,12 @@ L_stm_s_takeabort: 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); + state->Reg[tar] = ((a1 - b2) & 0xFFFF) | (((a2 + b1) & 0xFFFF) << 0x10); return 1; - } - else printf ("Unhandled v6 insn: sadd/ssub\n"); + } else printf ("Unhandled v6 insn: sadd/ssub/ssax/sasx\n"); break; case 0x62: - if ((instr & 0xFF0) == 0xf70)//QSUB16 - { + if ((instr & 0xFF0) == 0xf70) { //QSUB16 u8 tar = BITS(12, 15); u8 src1 = BITS(16, 19); u8 src2 = BITS(0, 3); @@ -5783,9 +5859,7 @@ L_stm_s_takeabort: if (res2 < 0x7FFF) res2 = -0x8000; state->Reg[tar] = (res1 & 0xFFFF) | ((res2 & 0xFFFF) << 0x10); return 1; - } - else if ((instr & 0xFF0) == 0xf10)//QADD16 - { + } else if ((instr & 0xFF0) == 0xf10) { //QADD16 u8 tar = BITS(12, 15); u8 src1 = BITS(16, 19); u8 src2 = BITS(0, 3); @@ -5801,29 +5875,234 @@ L_stm_s_takeabort: if (res2 < 0x7FFF) res2 = -0x8000; state->Reg[tar] = ((res1) & 0xFFFF) | (((res2) & 0xFFFF) << 0x10); return 1; - } - else printf ("Unhandled v6 insn: qadd/qsub\n"); + } else printf ("Unhandled v6 insn: qadd16/qsub16\n"); break; -#if 0 case 0x63: printf ("Unhandled v6 insn: shadd/shsub\n"); break; case 0x65: - printf ("Unhandled v6 insn: uadd/usub\n"); + { + u32 rd = (instr >> 12) & 0xF; + u32 rn = (instr >> 16) & 0xF; + u32 rm = (instr >> 0) & 0xF; + u32 from = state->Reg[rn]; + u32 to = state->Reg[rm]; + + if ((instr & 0xFF0) == 0xF10 || (instr & 0xFF0) == 0xF70) { // UADD16/USUB16 + u32 h1, h2; + state->Cpsr &= 0xfff0ffff; + 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); + } + 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); + } + state->Reg[rd] = (u32)((h1 & 0xffff) | ((h2 & 0xffff) << 16)); + return 1; + } + else + if ((instr & 0xFF0) == 0xF90 || (instr & 0xFF0) == 0xFF0) { // UADD8/USUB8 + u32 b1, b2, b3, b4; + state->Cpsr &= 0xfff0ffff; + if ((instr & 0x0F0) == 0x0F0) { // USUB8 + b1 = ((u8)from - (u8)to); + 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); + } + else { // UADD8 + b1 = ((u8)from + (u8)to); + 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); + } + state->Reg[rd] = (u32)(b1 | (b2 & 0xff) << 8 | (b3 & 0xff) << 16 | (b4 & 0xff) << 24); + return 1; + } + } + printf("Unhandled v6 insn: uasx/usax\n"); break; case 0x66: - printf ("Unhandled v6 insn: uqadd/uqsub\n"); + if ((instr & 0x0FF00FF0) == 0x06600FF0) { //uqsub8 + u32 rd = (instr >> 12) & 0xF; + u32 rm = (instr >> 16) & 0xF; + u32 rn = (instr >> 0) & 0xF; + u32 subfrom = state->Reg[rm]; + u32 tosub = state->Reg[rn]; + + u8 b1 = (u8)((u8)(subfrom)-(u8)(tosub)); + if (b1 > (u8)(subfrom)) b1 = 0; + u8 b2 = (u8)((u8)(subfrom >> 8) - (u8)(tosub >> 8)); + if (b2 > (u8)(subfrom >> 8)) b2 = 0; + u8 b3 = (u8)((u8)(subfrom >> 16) - (u8)(tosub >> 16)); + if (b3 > (u8)(subfrom >> 16)) b3 = 0; + u8 b4 = (u8)((u8)(subfrom >> 24) - (u8)(tosub >> 24)); + if (b4 > (u8)(subfrom >> 24)) b4 = 0; + state->Reg[rd] = (u32)(b1 | b2 << 8 | b3 << 16 | b4 << 24); + return 1; + } else { + printf ("Unhandled v6 insn: uqsub16\n"); + } break; case 0x67: printf ("Unhandled v6 insn: uhadd/uhsub\n"); break; case 0x68: - printf ("Unhandled v6 insn: pkh/sxtab/selsxtb\n"); + { + u32 rd = (instr >> 12) & 0xF; + u32 rn = (instr >> 16) & 0xF; + u32 rm = (instr >> 0) & 0xF; + u32 from = state->Reg[rn]; + u32 to = state->Reg[rm]; + u32 cpsr = state->Cpsr; + if ((instr & 0xFF0) == 0xFB0) { // SEL + u32 result; + if (cpsr & (1 << 16)) + result = from & 0xff; + else + result = to & 0xff; + if (cpsr & (1 << 17)) + result |= from & 0x0000ff00; + else + result |= to & 0x0000ff00; + if (cpsr & (1 << 18)) + result |= from & 0x00ff0000; + else + result |= to & 0x00ff0000; + if (cpsr & (1 << 19)) + result |= from & 0xff000000; + else + result |= to & 0xff000000; + state->Reg[rd] = result; + return 1; + } + } + printf("Unhandled v6 insn: pkh/sxtab/selsxtb\n"); break; -#endif + case 0x6a: { + ARMword Rm; + int ror = -1; + + switch (BITS(4, 11)) { + case 0x07: + ror = 0; + break; + case 0x47: + ror = 8; + break; + case 0x87: + ror = 16; + break; + case 0xc7: + ror = 24; + break; + + case 0x01: + case 0xf3: + //ichfly + //SSAT16 + { + u8 tar = BITS(12, 15); + u8 src = BITS(0, 3); + u8 val = BITS(16, 19) + 1; + s16 a1 = (state->Reg[src]); + s16 a2 = (state->Reg[src] >> 0x10); + s16 min = (s16)(0x8000 >> (16 - val)); + s16 max = 0x7FFF >> (16 - val); + if (min > a1) a1 = min; + if (max < a1) a1 = max; + if (min > a2) a2 = min; + if (max < a2) a2 = max; + u32 temp2 = ((u32)(a2)) << 0x10; + state->Reg[tar] = (a1 & 0xFFFF) | (temp2); + } + + return 1; + default: + break; + } + + if (ror == -1) { + if (BITS(4, 6) == 0x7) { + printf("Unhandled v6 insn: ssat\n"); + return 0; + } + break; + } + + Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFF); + if (Rm & 0x80) + Rm |= 0xffffff00; + + if (BITS(16, 19) == 0xf) + /* SXTB */ + state->Reg[BITS(12, 15)] = Rm; + else + /* SXTAB */ + state->Reg[BITS(12, 15)] += Rm; + + return 1; + } + case 0x6b: { + ARMword Rm; + int ror = -1; + + switch (BITS(4, 11)) { + case 0x07: + ror = 0; + break; + case 0x47: + ror = 8; + break; + case 0x87: + ror = 16; + break; + case 0xc7: + ror = 24; + break; + + case 0xf3: + DEST = ((RHS & 0xFF) << 24) | ((RHS & 0xFF00)) << 8 | ((RHS & 0xFF0000) >> 8) | ((RHS & 0xFF000000) >> 24); + return 1; + case 0xfb: + DEST = ((RHS & 0xFF) << 8) | ((RHS & 0xFF00)) >> 8 | ((RHS & 0xFF0000) << 8) | ((RHS & 0xFF000000) >> 8); + return 1; + default: + break; + } + + if (ror == -1) + break; + + Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFFFF); + if (Rm & 0x8000) + Rm |= 0xffff0000; + + if (BITS(16, 19) == 0xf) + /* SXTH */ + state->Reg[BITS(12, 15)] = Rm; + else + /* SXTAH */ + state->Reg[BITS(12, 15)] = state->Reg[BITS(16, 19)] + Rm; + + return 1; + } case 0x6c: - if ((instr & 0xf03f0) == 0xf0070) //uxtb16 - { + if ((instr & 0xf03f0) == 0xf0070) { //uxtb16 u8 src1 = BITS(0, 3); u8 tar = BITS(12, 15); u32 base = state->Reg[src1]; @@ -5831,13 +6110,119 @@ L_stm_s_takeabort: u32 in = ((base << (32 - shamt)) | (base >> shamt)); state->Reg[tar] = in & 0x00FF00FF; return 1; - } - else - printf ("Unhandled v6 insn: uxtb16/uxtab16\n"); + } else + printf ("Unhandled v6 insn: uxtab16\n"); break; + case 0x6e: { + ARMword Rm; + int ror = -1; + + switch (BITS(4, 11)) { + case 0x07: + ror = 0; + break; + case 0x47: + ror = 8; + break; + case 0x87: + ror = 16; + break; + case 0xc7: + ror = 24; + break; + + case 0x01: + case 0xf3: + //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); + } + return 1; + default: + break; + } + + if (ror == -1) { + if (BITS(4, 6) == 0x7) { + printf("Unhandled v6 insn: usat\n"); + return 0; + } + break; + } + + Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFF); + + if (BITS(16, 19) == 0xf) + /* UXTB */ + state->Reg[BITS(12, 15)] = Rm; + else + /* UXTAB */ + state->Reg[BITS(12, 15)] = state->Reg[BITS(16, 19)] + Rm; + + return 1; + } + + case 0x6f: { + ARMword Rm; + int ror = -1; + + switch (BITS(4, 11)) { + case 0x07: + ror = 0; + break; + case 0x47: + ror = 8; + break; + case 0x87: + ror = 16; + break; + case 0xc7: + ror = 24; + break; + + case 0xfb: + printf("Unhandled v6 insn: revsh\n"); + return 0; + default: + break; + } + + if (ror == -1) + break; + + Rm = ((state->Reg[BITS(0, 3)] >> ror) & 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; + } + else { + /* UXTAH */ + /* state->Reg[BITS (12, 15)] = state->Reg [BITS (16, 19)] + Rm; */ + // 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; + // printf("rd is %x\n", state->Reg[BITS (12, 15)]); + // exit(-1); + } + + return 1; + } case 0x70: - if ((instr & 0xf0d0) == 0xf010)//smuad //ichfly - { + if ((instr & 0xf0d0) == 0xf010) { //smuad //ichfly u8 tar = BITS(16, 19); u8 src1 = BITS(0, 3); u8 src2 = BITS(8, 11); @@ -5849,9 +6234,7 @@ L_stm_s_takeabort: state->Reg[tar] = a1*a2 + b1*b2; return 1; - } - else if ((instr & 0xf0d0) == 0xf050)//smusd - { + } else if ((instr & 0xf0d0) == 0xf050) { //smusd u8 tar = BITS(16, 19); u8 src1 = BITS(0, 3); u8 src2 = BITS(8, 11); @@ -5862,9 +6245,7 @@ L_stm_s_takeabort: s16 b2 = swap ? (state->Reg[src2] & 0xFFFF) : ((state->Reg[src2] >> 0x10) & 0xFFFF); state->Reg[tar] = a1*a2 - b1*b2; return 1; - } - else if ((instr & 0xd0) == 0x10)//smlad - { + } else if ((instr & 0xd0) == 0x10) { //smlad u8 tar = BITS(16, 19); u8 src1 = BITS(0, 3); u8 src2 = BITS(8, 11); @@ -5879,8 +6260,7 @@ L_stm_s_takeabort: s16 b2 = swap ? (state->Reg[src2] & 0xFFFF) : ((state->Reg[src2] >> 0x10) & 0xFFFF); state->Reg[tar] = a1*a2 + b1*b2 + a3; return 1; - } - else printf ("Unhandled v6 insn: smuad/smusd/smlad/smlsd\n"); + } else printf ("Unhandled v6 insn: smuad/smusd/smlad/smlsd\n"); break; case 0x74: printf ("Unhandled v6 insn: smlald/smlsld\n"); @@ -5891,332 +6271,18 @@ L_stm_s_takeabort: case 0x78: printf ("Unhandled v6 insn: usad/usada8\n"); break; -#if 0 case 0x7a: printf ("Unhandled v6 insn: usbfx\n"); break; case 0x7c: printf ("Unhandled v6 insn: bfc/bfi\n"); break; -#endif - - - /* add new instr for arm v6. */ - ARMword lhs, temp; - case 0x18: { /* ORR reg */ - /* dyf add armv6 instr strex 2010.9.17 */ - if (BITS (4, 7) == 0x9) { - u32 l = LHSReg; - u32 r = RHSReg; - lhs = LHS; - - bool enter = false; - - if (state->currentexval == (u32)ARMul_ReadWord(state, state->currentexaddr))enter = true; - ARMul_StoreWordS(state, lhs, RHS); - //StoreWord(state, lhs, RHS) - if (state->Aborted) { - TAKEABORT; - } - - if (enter) { - state->Reg[DESTReg] = 0; - } else { - state->Reg[DESTReg] = 1; - } - - return 1; - } - break; - } - - case 0x19: { /* orrs reg */ - /* dyf add armv6 instr ldrex */ - if (BITS (4, 7) == 0x9) { - lhs = LHS; - - state->currentexaddr = lhs; - state->currentexval = ARMul_ReadWord(state, lhs); - - LoadWord (state, instr, lhs); - return 1; - } - break; - } - - case 0x1c: { /* BIC reg */ - /* dyf add for STREXB */ - if (BITS (4, 7) == 0x9) { - lhs = LHS; - - bool enter = false; - - if (state->currentexval == (u32)ARMul_ReadByte(state, state->currentexaddr))enter = true; - - ARMul_StoreByte (state, lhs, RHS); - BUSUSEDINCPCN; - if (state->Aborted) { - TAKEABORT; - } - - - if (enter) { - state->Reg[DESTReg] = 0; - } else { - state->Reg[DESTReg] = 1; - } - - //printf("In %s, strexb not implemented\n", __FUNCTION__); - UNDEF_LSRBPC; - /* WRITESDEST (dest); */ - return 1; - } - break; - } - - case 0x1d: { /* BICS reg */ - if ((BITS (4, 7)) == 0x9) { - /* ldrexb */ - temp = LHS; - LoadByte (state, instr, temp, LUNSIGNED); - - state->currentexaddr = temp; - state->currentexval = (u32)ARMul_ReadByte(state, temp); - - //state->Reg[BITS(12, 15)] = ARMul_LoadByte(state, state->Reg[BITS(16, 19)]); - //printf("ldrexb\n"); - //printf("instr is %x rm is %d\n", instr, BITS(16, 19)); - //exit(-1); - - //printf("In %s, ldrexb not implemented\n", __FUNCTION__); - return 1; - } - break; - } - /* add end */ - - case 0x6a: { - ARMword Rm; - int ror = -1; - - switch (BITS (4, 11)) { - case 0x07: - ror = 0; - break; - case 0x47: - ror = 8; - break; - case 0x87: - ror = 16; - break; - case 0xc7: - ror = 24; - break; - - case 0x01: - case 0xf3: - //ichfly - //SSAT16 - { - u8 tar = BITS(12,15); - u8 src = BITS(0, 3); - u8 val = BITS(16, 19) + 1; - s16 a1 = (state->Reg[src]); - s16 a2 = (state->Reg[src] >> 0x10); - s16 min = (s16)(0x8000) >> (16 - val); - s16 max = 0x7FFF >> (16 - val); - if (min > a1) a1 = min; - if (max < a1) a1 = max; - if (min > a2) a2 = min; - if (max < a2) a2 = max; - u32 temp2 = ((u32)(a2)) << 0x10; - state->Reg[tar] = (a1&0xFFFF) | (temp2); - } - - return 1; - default: - break; - } - - if (ror == -1) { - if (BITS (4, 6) == 0x7) { - printf ("Unhandled v6 insn: ssat\n"); - return 0; - } - break; - } - - Rm = ((state->Reg[BITS (0, 3)] >> ror) & 0xFF); - if (Rm & 0x80) - Rm |= 0xffffff00; - - if (BITS (16, 19) == 0xf) - /* SXTB */ - state->Reg[BITS (12, 15)] = Rm; - else - /* SXTAB */ - state->Reg[BITS (12, 15)] += Rm; - } - return 1; - - case 0x6b: { - ARMword Rm; - int ror = -1; - - switch (BITS (4, 11)) { - case 0x07: - ror = 0; - break; - case 0x47: - ror = 8; - break; - case 0x87: - ror = 16; - break; - case 0xc7: - ror = 24; - break; - - case 0xf3: - DEST = ((RHS & 0xFF) << 24) | ((RHS & 0xFF00)) << 8 | ((RHS & 0xFF0000) >> 8) | ((RHS & 0xFF000000) >> 24); - return 1; - case 0xfb: - DEST = ((RHS & 0xFF) << 8) | ((RHS & 0xFF00)) >> 8 | ((RHS & 0xFF0000) << 8) | ((RHS & 0xFF000000) >> 8); - return 1; - default: - break; - } - - if (ror == -1) - break; - - Rm = ((state->Reg[BITS (0, 3)] >> ror) & 0xFFFF); - if (Rm & 0x8000) - Rm |= 0xffff0000; - - if (BITS (16, 19) == 0xf) - /* SXTH */ - state->Reg[BITS (12, 15)] = Rm; - else - /* SXTAH */ - state->Reg[BITS (12, 15)] = state->Reg[BITS (16, 19)] + Rm; - } - return 1; - - case 0x6e: { - ARMword Rm; - int ror = -1; - - switch (BITS (4, 11)) { - case 0x07: - ror = 0; - break; - case 0x47: - ror = 8; - break; - case 0x87: - ror = 16; - break; - case 0xc7: - ror = 24; - break; - - case 0x01: - case 0xf3: - //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); - } - return 1; - default: - break; - } - - if (ror == -1) { - if (BITS (4, 6) == 0x7) { - printf ("Unhandled v6 insn: usat\n"); - return 0; - } - break; - } - - Rm = ((state->Reg[BITS (0, 3)] >> ror) & 0xFF); - - if (BITS (16, 19) == 0xf) - /* UXTB */ - state->Reg[BITS (12, 15)] = Rm; - else - /* UXTAB */ - state->Reg[BITS (12, 15)] = state->Reg[BITS (16, 19)] + Rm; - } - return 1; - - case 0x6f: { - ARMword Rm; - int ror = -1; - - switch (BITS (4, 11)) { - case 0x07: - ror = 0; - break; - case 0x47: - ror = 8; - break; - case 0x87: - ror = 16; - break; - case 0xc7: - ror = 24; - break; - - case 0xfb: - printf ("Unhandled v6 insn: revsh\n"); - return 0; - default: - break; - } - - if (ror == -1) - break; - - Rm = ((state->Reg[BITS (0, 3)] >> ror) & 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; - } else { - /* UXTAH */ - /* state->Reg[BITS (12, 15)] = state->Reg [BITS (16, 19)] + Rm; */ -// 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; -// printf("rd is %x\n", state->Reg[BITS (12, 15)]); -// exit(-1); - } - } - return 1; - -#if 0 case 0x84: printf ("Unhandled v6 insn: srs\n"); break; -#endif default: break; } printf("Unhandled v6 insn: UNKNOWN: %08x %08X\n", instr, BITS(20, 27)); return 0; - } + } \ No newline at end of file -- cgit v1.2.3 From 2b0acd36e19f27720b2740efbe68d0f7598ee5c5 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sun, 14 Dec 2014 23:00:29 -0500 Subject: armemu: Fix UXTB16 Rotation bits are 10 and 11, not 9 and 10. --- src/core/arm/interpreter/armemu.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'src/core/arm/interpreter/armemu.cpp') diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index ec40881f8..33ebc7986 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -6101,18 +6101,18 @@ L_stm_s_takeabort: return 1; } - case 0x6c: - if ((instr & 0xf03f0) == 0xf0070) { //uxtb16 - u8 src1 = BITS(0, 3); - u8 tar = BITS(12, 15); - u32 base = state->Reg[src1]; - u32 shamt = BITS(9,10)* 8; - u32 in = ((base << (32 - shamt)) | (base >> shamt)); - state->Reg[tar] = in & 0x00FF00FF; - return 1; - } else - printf ("Unhandled v6 insn: uxtab16\n"); - break; + case 0x6c: + if ((instr & 0xf03f0) == 0xf0070) { //uxtb16 + u8 rm_idx = BITS(0, 3); + u8 rd_idx = BITS(12, 15); + u32 rm_val = state->Reg[rm_idx]; + u32 rotation = BITS(10, 11) * 8; + u32 in = ((rm_val << (32 - rotation)) | (rm_val >> rotation)); + state->Reg[rd_idx] = in & 0x00FF00FF; + return 1; + } else + printf ("Unhandled v6 insn: uxtab16\n"); + break; case 0x6e: { ARMword Rm; int ror = -1; -- cgit v1.2.3 From 1c7f77334c32fe304b1db22f6bae210c837ba40f Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 15 Dec 2014 20:16:38 -0500 Subject: armemu: Implement UXTAB16 --- src/core/arm/interpreter/armemu.cpp | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) (limited to 'src/core/arm/interpreter/armemu.cpp') diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index 33ebc7986..b846fbe9c 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -6101,17 +6101,32 @@ L_stm_s_takeabort: return 1; } - case 0x6c: - if ((instr & 0xf03f0) == 0xf0070) { //uxtb16 - u8 rm_idx = BITS(0, 3); - u8 rd_idx = BITS(12, 15); - u32 rm_val = state->Reg[rm_idx]; - u32 rotation = BITS(10, 11) * 8; - u32 in = ((rm_val << (32 - rotation)) | (rm_val >> rotation)); - state->Reg[rd_idx] = in & 0x00FF00FF; + case 0x6c: // UXTB16 and UXTAB16 + { + const u8 rm_idx = BITS(0, 3); + const u8 rn_idx = BITS(16, 19); + const u8 rd_idx = BITS(12, 15); + const u32 rm_val = state->Reg[rm_idx]; + const u32 rn_val = state->Reg[rn_idx]; + const u32 rotation = BITS(10, 11) * 8; + const u32 rotated_rm = ((rm_val << (32 - rotation)) | (rm_val >> rotation)); + + // UXTB16 + if ((instr & 0xf03f0) == 0xf0070) { + state->Reg[rd_idx] = rotated_rm & 0x00FF00FF; + } + else { // UXTAB16 + const u8 lo_rotated = (rotated_rm & 0xFF); + const u16 lo_result = (rn_val & 0xFFFF) + (u16)lo_rotated; + + const u8 hi_rotated = (rotated_rm >> 16) & 0xFF; + const u16 hi_result = (rn_val >> 16) + (u16)hi_rotated; + + state->Reg[rd_idx] = ((hi_result << 16) | (lo_result & 0xFFFF)); + } + return 1; - } else - printf ("Unhandled v6 insn: uxtab16\n"); + } break; case 0x6e: { ARMword Rm; -- cgit v1.2.3 From 49817e89d9b496be0d38cbf92890d01f94f855b8 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 15 Dec 2014 23:46:58 -0500 Subject: armemu: Join QADD16 and QSUB16 together. The only difference between these ops is one adds and one subtracts. Everything is literally the same. --- src/core/arm/interpreter/armemu.cpp | 70 ++++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 33 deletions(-) (limited to 'src/core/arm/interpreter/armemu.cpp') diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index 33ebc7986..8ee8badd5 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -5842,40 +5842,44 @@ L_stm_s_takeabort: return 1; } else printf ("Unhandled v6 insn: sadd/ssub/ssax/sasx\n"); 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 < 0x7FFF) + lo_result = -0x8000; + + if (hi_result > 0x7FFF) + hi_result = 0x7FFF; + else if (hi_result < 0x7FFF) + 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"); -- cgit v1.2.3 From 4c537992290cf143bd9d4585c164698f1473376d Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 15 Dec 2014 23:48:39 -0500 Subject: armemu: Fix lower-bound signed saturation clamping for QADD16/QSUB16. --- src/core/arm/interpreter/armemu.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/core/arm/interpreter/armemu.cpp') diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index 8ee8badd5..e46b4d15b 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -5867,12 +5867,12 @@ L_stm_s_takeabort: if (lo_result > 0x7FFF) lo_result = 0x7FFF; - else if (lo_result < 0x7FFF) + else if (lo_result < -0x8000) lo_result = -0x8000; if (hi_result > 0x7FFF) hi_result = 0x7FFF; - else if (hi_result < 0x7FFF) + else if (hi_result < -0x8000) hi_result = -0x8000; state->Reg[rd_idx] = (lo_result & 0xFFFF) | ((hi_result & 0xFFFF) << 16); -- cgit v1.2.3 From 0f9e3baf39efdfe8a6604a473405764e936a897d Mon Sep 17 00:00:00 2001 From: Lioncash Date: Tue, 16 Dec 2014 01:59:46 -0500 Subject: armemu: Join SMUAD, SMUSD, and SMLAD --- src/core/arm/interpreter/armemu.cpp | 73 ++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 38 deletions(-) (limited to 'src/core/arm/interpreter/armemu.cpp') diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index 33ebc7986..967506f45 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -6222,45 +6222,42 @@ L_stm_s_takeabort: return 1; } case 0x70: - if ((instr & 0xf0d0) == 0xf010) { //smuad //ichfly - u8 tar = BITS(16, 19); - u8 src1 = BITS(0, 3); - u8 src2 = BITS(8, 11); - u8 swap = BIT(5); - s16 a1 = (state->Reg[src1] & 0xFFFF); - s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF); - s16 b1 = swap ? ((state->Reg[src2] >> 0x10) & 0xFFFF) : (state->Reg[src2] & 0xFFFF); - s16 b2 = swap ? (state->Reg[src2] & 0xFFFF) : ((state->Reg[src2] >> 0x10) & 0xFFFF); - state->Reg[tar] = a1*a2 + b1*b2; - return 1; - - } else if ((instr & 0xf0d0) == 0xf050) { //smusd - u8 tar = BITS(16, 19); - u8 src1 = BITS(0, 3); - u8 src2 = BITS(8, 11); - u8 swap = BIT(5); - s16 a1 = (state->Reg[src1] & 0xFFFF); - s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF); - s16 b1 = swap ? ((state->Reg[src2] >> 0x10) & 0xFFFF) : (state->Reg[src2] & 0xFFFF); - s16 b2 = swap ? (state->Reg[src2] & 0xFFFF) : ((state->Reg[src2] >> 0x10) & 0xFFFF); - state->Reg[tar] = a1*a2 - b1*b2; - return 1; - } else if ((instr & 0xd0) == 0x10) { //smlad - u8 tar = BITS(16, 19); - u8 src1 = BITS(0, 3); - u8 src2 = BITS(8, 11); - u8 src3 = BITS(12, 15); - u8 swap = BIT(5); - - u32 a3 = state->Reg[src3]; - - s16 a1 = (state->Reg[src1] & 0xFFFF); - s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF); - s16 b1 = swap ? ((state->Reg[src2] >> 0x10) & 0xFFFF) : (state->Reg[src2] & 0xFFFF); - s16 b2 = swap ? (state->Reg[src2] & 0xFFFF) : ((state->Reg[src2] >> 0x10) & 0xFFFF); - state->Reg[tar] = a1*a2 + b1*b2 + a3; + // ichfly + // SMUAD, SMUSD, SMLAD + if ((instr & 0xf0d0) == 0xf010 || (instr & 0xf0d0) == 0xf050 || (instr & 0xd0) == 0x10) { + const u8 rd_idx = BITS(16, 19); + const u8 rn_idx = BITS(0, 3); + const u8 rm_idx = BITS(8, 11); + const bool do_swap = (BIT(5) == 1); + + u32 rm_val = state->Reg[rm_idx]; + const u32 rn_val = state->Reg[rn_idx]; + + if (do_swap) + rm_val = (((rm_val & 0xFFFF) << 16) | (rm_val >> 16)); + + const s16 rm_lo = (rm_val & 0xFFFF); + const s16 rm_hi = ((rm_val >> 16) & 0xFFFF); + 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 * rn_hi) + (rm_lo * rm_hi); + } + // SMUSD + else if ((instr & 0xf0d0) == 0xf050) { + state->Reg[rd_idx] = (rn_lo * rn_hi) - (rm_lo * rm_hi); + } + // SMLAD + else { + const u8 ra_idx = BITS(12, 15); + state->Reg[rd_idx] = (rn_lo * rn_hi) + (rm_lo * rm_hi) + (s32)state->Reg[ra_idx]; + } return 1; - } else printf ("Unhandled v6 insn: smuad/smusd/smlad/smlsd\n"); + } else { + printf ("Unhandled v6 insn: smlsd\n"); + } break; case 0x74: printf ("Unhandled v6 insn: smlald/smlsld\n"); -- cgit v1.2.3 From d5bcddb77c9922f8345dd4014031662ab17e2b33 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Tue, 16 Dec 2014 02:03:48 -0500 Subject: armemu: Fix SMUAD, SMUSD, and SMLAD Wrong values were being multiplied together. --- src/core/arm/interpreter/armemu.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/core/arm/interpreter/armemu.cpp') diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index 967506f45..e4159ceb0 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -6243,16 +6243,16 @@ L_stm_s_takeabort: // SMUAD if ((instr & 0xf0d0) == 0xf010) { - state->Reg[rd_idx] = (rn_lo * rn_hi) + (rm_lo * rm_hi); + state->Reg[rd_idx] = (rn_lo * rm_lo) + (rn_hi * rm_hi); } // SMUSD else if ((instr & 0xf0d0) == 0xf050) { - state->Reg[rd_idx] = (rn_lo * rn_hi) - (rm_lo * rm_hi); + state->Reg[rd_idx] = (rn_lo * rm_lo) - (rn_hi * rm_hi); } // SMLAD else { const u8 ra_idx = BITS(12, 15); - state->Reg[rd_idx] = (rn_lo * rn_hi) + (rm_lo * rm_hi) + (s32)state->Reg[ra_idx]; + state->Reg[rd_idx] = (rn_lo * rm_lo) + (rn_hi * rm_hi) + (s32)state->Reg[ra_idx]; } return 1; } else { -- cgit v1.2.3 From efebd5589a53f3f21f36d1a3c92a4e567bd89c8e Mon Sep 17 00:00:00 2001 From: Normmatt Date: Wed, 17 Dec 2014 02:28:12 -0500 Subject: armemu: Fix SXTAH --- src/core/arm/interpreter/armemu.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/core/arm/interpreter/armemu.cpp') diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index 5752d116f..843323293 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -6057,7 +6057,8 @@ L_stm_s_takeabort: return 1; } - case 0x6b: { + case 0x6b: + { ARMword Rm; int ror = -1; @@ -6088,7 +6089,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; -- cgit v1.2.3 From b5dbd6f2a27cc85a7262920942dd1c78fff21bb5 Mon Sep 17 00:00:00 2001 From: Normmatt Date: Wed, 17 Dec 2014 02:54:24 -0500 Subject: armemu: Fix SXTAB --- src/core/arm/interpreter/armemu.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/core/arm/interpreter/armemu.cpp') diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index 843323293..cffbae7e7 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -6044,7 +6044,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; @@ -6053,7 +6053,7 @@ 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; } -- cgit v1.2.3 From bc81cc94901b72bf68e8241cf65e0e830b43fc93 Mon Sep 17 00:00:00 2001 From: Normmatt Date: Wed, 17 Dec 2014 02:56:58 -0500 Subject: armemu: Fix UXTAB/UXTAH --- src/core/arm/interpreter/armemu.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/core/arm/interpreter/armemu.cpp') diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index cffbae7e7..a62658b7c 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -6176,7 +6176,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 */ @@ -6216,13 +6216,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 */ @@ -6230,7 +6230,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); } -- cgit v1.2.3 From 8045df14d2494e34c064b58bc1772101014172a2 Mon Sep 17 00:00:00 2001 From: Normmatt Date: Wed, 17 Dec 2014 03:01:42 -0500 Subject: armemu: Implement REVSH --- src/core/arm/interpreter/armemu.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'src/core/arm/interpreter/armemu.cpp') diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index a62658b7c..71cae3db0 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -6076,10 +6076,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: @@ -6206,9 +6206,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; } -- cgit v1.2.3 From 73211dc8fef861570b9e5ce422d20f36e6174967 Mon Sep 17 00:00:00 2001 From: Normmatt Date: Wed, 17 Dec 2014 03:13:44 -0500 Subject: armemu: Fix PKHTB --- src/core/arm/interpreter/armemu.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'src/core/arm/interpreter/armemu.cpp') diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index 71cae3db0..de178a890 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -3103,12 +3103,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 -- cgit v1.2.3 From 5289a496a75bd7abe4d18bfc586cb1cfac84fc48 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Wed, 17 Dec 2014 09:36:23 -0500 Subject: armemu: Fix SADD16 The lo and hi parts of the result were being constructed as a result of hi and lo halfword intermixing from the rm and rn regs. However the lo part of the result should be constructed only from the lo halfwords of rm and rn, and the hi part of the result should only be constructed from the hi halfwords of rm and rn. --- src/core/arm/interpreter/armemu.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'src/core/arm/interpreter/armemu.cpp') diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index 5752d116f..dbfb9d858 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -5811,14 +5811,15 @@ L_stm_s_takeabort: 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); + const u8 rd_idx = BITS(12, 15); + const u8 rm_idx = BITS(0, 3); + const u8 rn_idx = BITS(16, 19); + const s16 rm_lo = (state->Reg[rm_idx] & 0xFFFF); + const s16 rm_hi = ((state->Reg[rm_idx] >> 16) & 0xFFFF); + const s16 rn_lo = (state->Reg[rn_idx] & 0xFFFF); + const s16 rn_hi = ((state->Reg[rn_idx] >> 16) & 0xFFFF); + + state->Reg[rd_idx] = ((rn_lo + rm_lo) & 0xFFFF) | (((rn_hi + rm_hi) & 0xFFFF) << 16); return 1; } else if ((instr & 0xFF0) == 0xf50) { //ssax u8 tar = BITS(12, 15); -- cgit v1.2.3 From 2d91164bb9aa24829381f2518faed9abbdd4d6fa Mon Sep 17 00:00:00 2001 From: Lioncash Date: Wed, 17 Dec 2014 10:05:26 -0500 Subject: armemu: Narrow the scope of some variables in handle_v6_insn There's no reason to have these in the outer-most scope. --- src/core/arm/interpreter/armemu.cpp | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) (limited to 'src/core/arm/interpreter/armemu.cpp') diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index 5752d116f..0d1b2e60e 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -5669,11 +5669,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; @@ -5691,7 +5688,7 @@ L_stm_s_takeabort: /* strex */ u32 l = LHSReg; u32 r = RHSReg; - lhs = LHS; + u32 lhs = LHS; bool enter = false; @@ -5716,7 +5713,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); @@ -5735,7 +5732,7 @@ L_stm_s_takeabort: case 0x1c: if (BITS(4, 7) == 0x9) { /* strexb */ - lhs = LHS; + u32 lhs = LHS; bool enter = false; @@ -5765,11 +5762,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"); -- cgit v1.2.3 From 5820dba6b7b24a0f23474ffd1d303961be398687 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Wed, 17 Dec 2014 12:13:35 -0500 Subject: armemu: Implement UMAAL --- src/core/arm/interpreter/armemu.cpp | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) (limited to 'src/core/arm/interpreter/armemu.cpp') diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index 5752d116f..5074542a4 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. */ @@ -5677,8 +5683,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"); -- cgit v1.2.3 From 58dc5547333cfb946f3881eb746811794a0f39a7 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Wed, 17 Dec 2014 15:34:58 -0500 Subject: armemu: Fix SSUB16 Broken from the same reason SADD16 was. The lo part of the result should only be constructed from the lo halfwords of rm and rn. The hi part of the result should only be constructed from the hi halfwords of rm and rn. --- src/core/arm/interpreter/armemu.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'src/core/arm/interpreter/armemu.cpp') diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index 1a589e39c..2b5d8c68e 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -5801,14 +5801,14 @@ L_stm_s_takeabort: 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); + 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); + state->Reg[rd_idx] = ((rn_lo - rm_lo) & 0xFFFF) | (((rn_hi - rm_hi) & 0xFFFF) << 16); return 1; } else if ((instr & 0xFF0) == 0xf10) { //sadd16 const u8 rd_idx = BITS(12, 15); -- cgit v1.2.3 From 41fee1c94005f5848addb3da253b4f883b4b1a71 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Wed, 17 Dec 2014 17:53:53 -0500 Subject: armemu: Unset GE flags for UADD8 if results are < 0x100 Reference manual states these must be set to zero if this case is true. --- src/core/arm/interpreter/armemu.cpp | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) (limited to 'src/core/arm/interpreter/armemu.cpp') diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index 1a589e39c..b207416dd 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -5930,11 +5930,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; } -- cgit v1.2.3 From 85c318078db2e950696d86f9f49dad17f88bedcb Mon Sep 17 00:00:00 2001 From: Lioncash Date: Wed, 17 Dec 2014 21:14:42 -0500 Subject: armemu: Combine SSUB16, SADD16, SASX, and SSAX. --- src/core/arm/interpreter/armemu.cpp | 57 +++++++++++++++---------------------- 1 file changed, 23 insertions(+), 34 deletions(-) (limited to 'src/core/arm/interpreter/armemu.cpp') diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index 14330156b..c032c7168 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -5805,8 +5805,10 @@ L_stm_s_takeabort: case 0x3f: printf ("Unhandled v6 insn: rbit\n"); break; - case 0x61: - if ((instr & 0xFF0) == 0xf70) { //ssub16 + 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); @@ -5814,40 +5816,27 @@ L_stm_s_takeabort: 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); - state->Reg[rd_idx] = ((rn_lo - rm_lo) & 0xFFFF) | (((rn_hi - rm_hi) & 0xFFFF) << 16); - return 1; - } else if ((instr & 0xFF0) == 0xf10) { //sadd16 - const u8 rd_idx = BITS(12, 15); - const u8 rm_idx = BITS(0, 3); - const u8 rn_idx = BITS(16, 19); - const s16 rm_lo = (state->Reg[rm_idx] & 0xFFFF); - const s16 rm_hi = ((state->Reg[rm_idx] >> 16) & 0xFFFF); - const s16 rn_lo = (state->Reg[rn_idx] & 0xFFFF); - const s16 rn_hi = ((state->Reg[rn_idx] >> 16) & 0xFFFF); - state->Reg[rd_idx] = ((rn_lo + rm_lo) & 0xFFFF) | (((rn_hi + rm_hi) & 0xFFFF) << 16); - 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); + // SSUB16 + if ((instr & 0xFF0) == 0xf70) { + state->Reg[rd_idx] = ((rn_lo - rm_lo) & 0xFFFF) | (((rn_hi - rm_hi) & 0xFFFF) << 16); + } + // SADD16 + else if ((instr & 0xFF0) == 0xf10) { + state->Reg[rd_idx] = ((rn_lo + rm_lo) & 0xFFFF) | (((rn_hi + rm_hi) & 0xFFFF) << 16); + } + // SSAX + else if ((instr & 0xFF0) == 0xf50) { + state->Reg[rd_idx] = ((rn_lo + rm_hi) & 0xFFFF) | (((rn_hi - rm_lo) & 0xFFFF) << 16); + } + // SASX + else { + state->Reg[rd_idx] = ((rn_lo - rm_hi) & 0xFFFF) | (((rn_hi + rm_lo) & 0xFFFF) << 16); + } return 1; - } else printf ("Unhandled v6 insn: sadd/ssub/ssax/sasx\n"); + } else { + printf("Unhandled v6 insn: %08x", BITS(20, 27)); + } break; case 0x62: // QSUB16 and QADD16 if ((instr & 0xFF0) == 0xf70 || (instr & 0xFF0) == 0xf10) { -- cgit v1.2.3 From 4dc8eb40be94e8376e0f2d2f59a5e1a85590d6b1 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Thu, 18 Dec 2014 11:11:30 -0500 Subject: armemu: Set GE flags correctly for SSUB16, SADD16, SSAX, and SASX. --- src/core/arm/interpreter/armemu.cpp | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) (limited to 'src/core/arm/interpreter/armemu.cpp') diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index b9ac8b9ad..f4452f356 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -5839,21 +5839,46 @@ 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 { -- cgit v1.2.3 From eaae0ad502f174823633c61c0cb934c434d1afb2 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Thu, 18 Dec 2014 12:07:18 -0500 Subject: armemu: Get rid of bitwise parenthesis warnings --- src/core/arm/interpreter/armemu.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/core/arm/interpreter/armemu.cpp') diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index b9ac8b9ad..522f9a1dd 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -6084,7 +6084,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 +6129,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; @@ -6216,7 +6216,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 +6260,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; */ -- cgit v1.2.3 From 6b632bbe37d6728ec2a7a7468ffad6e058642b66 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Thu, 18 Dec 2014 14:25:07 -0500 Subject: armemu: More concise names for USAT16-related variables --- src/core/arm/interpreter/armemu.cpp | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) (limited to 'src/core/arm/interpreter/armemu.cpp') diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index b9ac8b9ad..ae865aa72 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -6192,18 +6192,22 @@ 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; + if (max < rn_hi) + rn_hi = max; + + state->Reg[rd_idx] = (rn_lo & 0xFFFF) | (rn_hi); + return 1; } - return 1; + default: break; } -- cgit v1.2.3 From e683f654ce2b143fb34c3a36d889d08af310db9c Mon Sep 17 00:00:00 2001 From: Lioncash Date: Thu, 18 Dec 2014 16:50:41 -0500 Subject: armemu: Fix lower-bounds clamping for USAT16 --- src/core/arm/interpreter/armemu.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src/core/arm/interpreter/armemu.cpp') diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index ae865aa72..99fc6c45d 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -6201,10 +6201,15 @@ L_stm_s_takeabort: 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); + state->Reg[rd_idx] = (rn_lo & 0xFFFF) | ((rn_hi << 16) & 0xFFFF); return 1; } -- cgit v1.2.3 From b9fc0b4b80c37b949f559fd59ca6c666fc7d19bd Mon Sep 17 00:00:00 2001 From: Lioncash Date: Thu, 18 Dec 2014 17:47:44 -0500 Subject: armemu: Clean up naming and formatting for SSAT16 --- src/core/arm/interpreter/armemu.cpp | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) (limited to 'src/core/arm/interpreter/armemu.cpp') diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index 07d205755..837875d4f 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -6081,22 +6081,28 @@ L_stm_s_takeabort: //ichfly //SSAT16 { - u8 tar = BITS(12, 15); - u8 src = BITS(0, 3); - u8 val = BITS(16, 19) + 1; - s16 a1 = (state->Reg[src]); - s16 a2 = (state->Reg[src] >> 0x10); - s16 min = (s16)(0x8000 >> (16 - val)); - s16 max = 0x7FFF >> (16 - val); - if (min > a1) a1 = min; - if (max < a1) a1 = max; - if (min > a2) a2 = min; - 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) + 1; + const s16 min = (0x8000 >> (16 - num_bits)); + const s16 max = (0x7FFF >> (16 - num_bits)); + s16 rn_lo = (state->Reg[rn_idx]); + s16 rn_hi = (state->Reg[rn_idx] >> 16); + + if (rn_lo > max) + rn_lo = max; + else if (rn_lo < min) + rn_lo = min; + + if (rn_hi > max) + rn_hi = max; + else if (rn_hi < min) + rn_hi = min; + + state->Reg[rd_idx] = (rn_lo & 0xFFFF) | ((rn_hi & 0xFFFF) << 16); + return 1; } - return 1; default: break; } -- cgit v1.2.3 From 92c53fe52220630664ae77a4c915d5af768b8adc Mon Sep 17 00:00:00 2001 From: Lioncash Date: Thu, 18 Dec 2014 20:35:10 -0500 Subject: armemu: Fix SSAT16 The lower-bound would never be negative like it should --- src/core/arm/interpreter/armemu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core/arm/interpreter/armemu.cpp') diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index 837875d4f..e39ea2cae 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -6084,7 +6084,7 @@ L_stm_s_takeabort: const u8 rd_idx = BITS(12, 15); const u8 rn_idx = BITS(0, 3); const u8 num_bits = BITS(16, 19) + 1; - const s16 min = (0x8000 >> (16 - num_bits)); + const s16 min = -(0x8000 >> (16 - num_bits)); const s16 max = (0x7FFF >> (16 - num_bits)); s16 rn_lo = (state->Reg[rn_idx]); s16 rn_hi = (state->Reg[rn_idx] >> 16); -- cgit v1.2.3 From 00e8ec4a9ed2d7c1877e6dfe3f520cf072b5fe17 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Thu, 18 Dec 2014 21:44:39 -0500 Subject: armemu: Implement USAD8 and USADA8 --- src/core/arm/interpreter/armemu.cpp | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) (limited to 'src/core/arm/interpreter/armemu.cpp') diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index b9ac8b9ad..399ee0886 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -6326,7 +6326,30 @@ L_stm_s_takeabort: printf ("Unhandled v6 insn: smmla/smmls/smmul\n"); break; case 0x78: - printf ("Unhandled v6 insn: usad/usada8\n"); + if (BITS(20, 24) == 0x18) + { + const u8 rm_idx = BITS(8, 11); + const u8 rn_idx = BITS(0, 3); + const u8 rd_idx = BITS(16, 19); + + const u32 rm_val = state->Reg[rm_idx]; + const u32 rn_val = state->Reg[rn_idx]; + + const u8 diff1 = (u8)::abs((rn_val & 0xFF) - (rm_val & 0xFF)); + const u8 diff2 = (u8)::abs(((rn_val >> 8) & 0xFF) - ((rm_val >> 8) & 0xFF)); + const u8 diff3 = (u8)::abs(((rn_val >> 16) & 0xFF) - ((rm_val >> 16) & 0xFF)); + const u8 diff4 = (u8)::abs(((rn_val >> 24) & 0xFF) - ((rm_val >> 24) & 0xFF)); + + u32 finalDif = (diff1 + diff2 + diff3 + diff4); + + // Op is USADA8 if true. + const u8 ra_idx = BITS(12, 15); + if (ra_idx != 15) + finalDif += state->Reg[ra_idx]; + + state->Reg[rd_idx] = finalDif; + return 1; + } break; case 0x7a: printf ("Unhandled v6 insn: usbfx\n"); -- cgit v1.2.3 From 0f3a6a161c05c4e4f96450bb0443cfa90813d7ca Mon Sep 17 00:00:00 2001 From: Lioncash Date: Fri, 19 Dec 2014 09:38:10 -0500 Subject: armemu: Implement SMLSD --- src/core/arm/interpreter/armemu.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'src/core/arm/interpreter/armemu.cpp') diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index 07d205755..4e11e068f 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -6317,11 +6317,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]; @@ -6344,13 +6347,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: -- cgit v1.2.3 From 4b506cec017dab0244349780b70f53dc762d61f8 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Fri, 19 Dec 2014 14:05:18 -0500 Subject: armemu: Implement QASX and QSAX --- src/core/arm/interpreter/armemu.cpp | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) (limited to 'src/core/arm/interpreter/armemu.cpp') diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index 07d205755..bafeb024c 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -5885,8 +5885,10 @@ L_stm_s_takeabort: 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); @@ -5898,15 +5900,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; -- cgit v1.2.3 From 2a097f09908bff63037b56d1b1c46ea6c3e76a2b Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sat, 20 Dec 2014 15:30:06 -0500 Subject: armemu: Should be using labs for USAD8/USADA8 --- src/core/arm/interpreter/armemu.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/core/arm/interpreter/armemu.cpp') diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index 7408b6f08..06439b73c 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -6383,10 +6383,10 @@ L_stm_s_takeabort: const u32 rm_val = state->Reg[rm_idx]; const u32 rn_val = state->Reg[rn_idx]; - const u8 diff1 = (u8)::abs((rn_val & 0xFF) - (rm_val & 0xFF)); - const u8 diff2 = (u8)::abs(((rn_val >> 8) & 0xFF) - ((rm_val >> 8) & 0xFF)); - const u8 diff3 = (u8)::abs(((rn_val >> 16) & 0xFF) - ((rm_val >> 16) & 0xFF)); - const u8 diff4 = (u8)::abs(((rn_val >> 24) & 0xFF) - ((rm_val >> 24) & 0xFF)); + const u8 diff1 = (u8)std::labs((rn_val & 0xFF) - (rm_val & 0xFF)); + const u8 diff2 = (u8)std::labs(((rn_val >> 8) & 0xFF) - ((rm_val >> 8) & 0xFF)); + const u8 diff3 = (u8)std::labs(((rn_val >> 16) & 0xFF) - ((rm_val >> 16) & 0xFF)); + const u8 diff4 = (u8)std::labs(((rn_val >> 24) & 0xFF) - ((rm_val >> 24) & 0xFF)); u32 finalDif = (diff1 + diff2 + diff3 + diff4); -- cgit v1.2.3 From 855eda6f85b7e4e6965bd42d65a68239d4c99dc0 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sat, 20 Dec 2014 22:38:44 -0500 Subject: armemu: Implement SADD8/SSUB8 --- src/core/arm/interpreter/armemu.cpp | 101 +++++++++++++++++++++++++++++++----- 1 file changed, 87 insertions(+), 14 deletions(-) (limited to 'src/core/arm/interpreter/armemu.cpp') diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index 7a319b635..610e04f10 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -5824,9 +5824,9 @@ L_stm_s_takeabort: case 0x3f: printf ("Unhandled v6 insn: rbit\n"); break; - case 0x61: // SSUB16, SADD16, SSAX, and SASX - if ((instr & 0xFF0) == 0xf70 || (instr & 0xFF0) == 0xf10 || - (instr & 0xFF0) == 0xf50 || (instr & 0xFF0) == 0xf30) + case 0x61: // SADD16, SASX, SSAX, and SSUB16 + if ((instr & 0xFF0) == 0xf10 || (instr & 0xFF0) == 0xf30 || + (instr & 0xFF0) == 0xf50 || (instr & 0xFF0) == 0xf70) { const u8 rd_idx = BITS(12, 15); const u8 rm_idx = BITS(0, 3); @@ -5839,25 +5839,25 @@ L_stm_s_takeabort: 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) { + if ((instr & 0xFF0) == 0xf10) { lo_result = (rn_lo + rm_lo); hi_result = (rn_hi + rm_hi); } + // SASX + else if ((instr & 0xFF0) == 0xf30) { + lo_result = (rn_lo - rm_hi); + hi_result = (rn_hi + rm_lo); + } // SSAX else if ((instr & 0xFF0) == 0xf50) { lo_result = (rn_lo + rm_hi); hi_result = (rn_hi - rm_lo); } - // SASX + // SSUB16 else { - lo_result = (rn_lo - rm_hi); - hi_result = (rn_hi + rm_lo); + lo_result = (rn_lo - rm_lo); + hi_result = (rn_hi - rm_hi); } state->Reg[rd_idx] = (lo_result & 0xFFFF) | ((hi_result & 0xFFFF) << 16); @@ -5878,8 +5878,81 @@ L_stm_s_takeabort: state->Cpsr &= ~(1 << 19); } return 1; - } else { - printf("Unhandled v6 insn: %08x", BITS(20, 27)); + } + // SADD8/SSUB8 + else if ((instr & 0xFF0) == 0xf90 || (instr & 0xFF0) == 0xff0) + { + const u8 rd_idx = BITS(12, 15); + const u8 rm_idx = BITS(0, 3); + const u8 rn_idx = BITS(16, 19); + const u32 rm_val = state->Reg[rm_idx]; + const u32 rn_val = state->Reg[rn_idx]; + + u8 lo_val1; + u8 lo_val2; + u8 hi_val1; + u8 hi_val2; + + // SADD8 + if ((instr & 0xFF0) == 0xf90) { + lo_val1 = (u8)((rn_val & 0xFF) + (rm_val & 0xFF)); + lo_val2 = (u8)(((rn_val >> 8) & 0xFF) + ((rm_val >> 8) & 0xFF)); + hi_val1 = (u8)(((rn_val >> 16) & 0xFF) + ((rm_val >> 16) & 0xFF)); + hi_val2 = (u8)(((rn_val >> 24) & 0xFF) + ((rm_val >> 24) & 0xFF)); + + if (lo_val1 & 0x80) + state->Cpsr |= (1 << 16); + else + state->Cpsr &= ~(1 << 16); + + if (lo_val2 & 0x80) + state->Cpsr |= (1 << 17); + else + state->Cpsr &= ~(1 << 17); + + if (hi_val1 & 0x80) + state->Cpsr |= (1 << 18); + else + state->Cpsr &= ~(1 << 18); + + if (hi_val2 & 0x80) + state->Cpsr |= (1 << 19); + else + state->Cpsr &= ~(1 << 19); + } + // SSUB8 + else { + lo_val1 = (u8)((rn_val & 0xFF) - (rm_val & 0xFF)); + lo_val2 = (u8)(((rn_val >> 8) & 0xFF) - ((rm_val >> 8) & 0xFF)); + hi_val1 = (u8)(((rn_val >> 16) & 0xFF) - ((rm_val >> 16) & 0xFF)); + hi_val2 = (u8)(((rn_val >> 24) & 0xFF) - ((rm_val >> 24) & 0xFF)); + + if (!(lo_val1 & 0x80)) + state->Cpsr |= (1 << 16); + else + state->Cpsr &= ~(1 << 16); + + if (!(lo_val2 & 0x80)) + state->Cpsr |= (1 << 17); + else + state->Cpsr &= ~(1 << 17); + + if (!(hi_val1 & 0x80)) + state->Cpsr |= (1 << 18); + else + state->Cpsr &= ~(1 << 18); + + if (!(hi_val2 & 0x80)) + state->Cpsr |= (1 << 19); + else + state->Cpsr &= ~(1 << 19); + } + + state->Reg[rd_idx] = (lo_val1 | lo_val2 << 8 | hi_val1 << 16 | hi_val2 << 24); + return 1; + } + else { + printf("Unhandled v6 insn: %08x", instr); } break; case 0x62: // QADD16, QASX, QSAX, and QSUB16 -- cgit v1.2.3 From 8c723224225f65557d115683f473748d43d15eac Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 22 Dec 2014 21:44:03 -0500 Subject: armemu: Fix retrieval of the CPSR in MRS instructions. --- src/core/arm/interpreter/armemu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core/arm/interpreter/armemu.cpp') diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index 610e04f10..db9d12797 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -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; } -- cgit v1.2.3 From 8e2accd9746d33116c6398e6f30db5b8b4e1f188 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 22 Dec 2014 22:10:47 -0500 Subject: armemu: Fix construction of the CPSR --- src/core/arm/interpreter/armemu.cpp | 55 +++++++++++++++++++++++++++++++------ 1 file changed, 46 insertions(+), 9 deletions(-) (limited to 'src/core/arm/interpreter/armemu.cpp') diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index 610e04f10..d19d3a49f 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -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; } -- cgit v1.2.3 From f66d3569389e7e8a364a654d5254a2b9cc1cf8cc Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 22 Dec 2014 23:28:41 -0500 Subject: armemu: Fix SEL Needs to use the updated state of the CPSR. --- src/core/arm/interpreter/armemu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core/arm/interpreter/armemu.cpp') diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index d19d3a49f..81a4fdb92 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -6153,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)) -- cgit v1.2.3 From 6446331938c4d7c5bc4f54bc2b973b3eb43d7852 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 22 Dec 2014 23:43:14 -0500 Subject: armemu: Properly set the Q flag for SSAT16/USAT16 upon saturation. --- src/core/arm/interpreter/armemu.cpp | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) (limited to 'src/core/arm/interpreter/armemu.cpp') diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index 81a4fdb92..e69789142 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -6209,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; } @@ -6350,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; } -- cgit v1.2.3 From 79a7a432c524c7c999eed177e3ed34ba2646359a Mon Sep 17 00:00:00 2001 From: Lioncash Date: Tue, 23 Dec 2014 09:55:07 -0500 Subject: armemu: Set the Q flag properly for SMLAD/SMUAD --- src/core/arm/interpreter/armemu.cpp | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) (limited to 'src/core/arm/interpreter/armemu.cpp') 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: 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; -- cgit v1.2.3 From 20fc5f2a35782693af15b1f02de85c8d48c58cd0 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Tue, 23 Dec 2014 09:59:35 -0500 Subject: armemu: Set the Q flag correctly for much of the other ops They were setting the old S flag. --- src/core/arm/interpreter/armemu.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'src/core/arm/interpreter/armemu.cpp') diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index 23469f4df..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; @@ -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; } -- cgit v1.2.3 From 6b7808e412ca9db41ac194a0a0e35d515cb1d38a Mon Sep 17 00:00:00 2001 From: Lioncash Date: Wed, 24 Dec 2014 07:56:57 -0500 Subject: armemu: Fix GE/Q flag setting semantics --- src/core/arm/interpreter/armemu.cpp | 118 +++++++++++++++++------------------- 1 file changed, 56 insertions(+), 62 deletions(-) (limited to 'src/core/arm/interpreter/armemu.cpp') diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index b2f671f94..c4c09d1fb 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -5863,22 +5863,21 @@ L_stm_s_takeabort: state->Reg[rd_idx] = (lo_result & 0xFFFF) | ((hi_result & 0xFFFF) << 16); if (lo_result >= 0) { - state->Cpsr |= (1 << 16); - state->Cpsr |= (1 << 17); + state->GEFlag |= (1 << 16); + state->GEFlag |= (1 << 17); } else { - state->Cpsr &= ~(1 << 16); - state->Cpsr &= ~(1 << 17); + state->GEFlag &= ~(1 << 16); + state->GEFlag &= ~(1 << 17); } if (hi_result >= 0) { - state->Cpsr |= (1 << 18); - state->Cpsr |= (1 << 19); + state->GEFlag |= (1 << 18); + state->GEFlag |= (1 << 19); } else { - state->Cpsr &= ~(1 << 18); - state->Cpsr &= ~(1 << 19); + state->GEFlag &= ~(1 << 18); + state->GEFlag &= ~(1 << 19); } - ARMul_CPSRAltered(state); return 1; } // SADD8/SSUB8 @@ -5903,24 +5902,24 @@ L_stm_s_takeabort: hi_val2 = (u8)(((rn_val >> 24) & 0xFF) + ((rm_val >> 24) & 0xFF)); if (lo_val1 & 0x80) - state->Cpsr |= (1 << 16); + state->GEFlag |= (1 << 16); else - state->Cpsr &= ~(1 << 16); + state->GEFlag &= ~(1 << 16); if (lo_val2 & 0x80) - state->Cpsr |= (1 << 17); + state->GEFlag |= (1 << 17); else - state->Cpsr &= ~(1 << 17); + state->GEFlag &= ~(1 << 17); if (hi_val1 & 0x80) - state->Cpsr |= (1 << 18); + state->GEFlag |= (1 << 18); else - state->Cpsr &= ~(1 << 18); + state->GEFlag &= ~(1 << 18); if (hi_val2 & 0x80) - state->Cpsr |= (1 << 19); + state->GEFlag |= (1 << 19); else - state->Cpsr &= ~(1 << 19); + state->GEFlag &= ~(1 << 19); } // SSUB8 else { @@ -5930,27 +5929,26 @@ L_stm_s_takeabort: hi_val2 = (u8)(((rn_val >> 24) & 0xFF) - ((rm_val >> 24) & 0xFF)); if (!(lo_val1 & 0x80)) - state->Cpsr |= (1 << 16); + state->GEFlag |= (1 << 16); else - state->Cpsr &= ~(1 << 16); + state->GEFlag &= ~(1 << 16); if (!(lo_val2 & 0x80)) - state->Cpsr |= (1 << 17); + state->GEFlag |= (1 << 17); else - state->Cpsr &= ~(1 << 17); + state->GEFlag &= ~(1 << 17); if (!(hi_val1 & 0x80)) - state->Cpsr |= (1 << 18); + state->GEFlag |= (1 << 18); else - state->Cpsr &= ~(1 << 18); + state->GEFlag &= ~(1 << 18); if (!(hi_val2 & 0x80)) - state->Cpsr |= (1 << 19); + state->GEFlag |= (1 << 19); else - state->Cpsr &= ~(1 << 19); + state->GEFlag &= ~(1 << 19); } - ARMul_CPSRAltered(state); state->Reg[rd_idx] = (lo_val1 | lo_val2 << 8 | hi_val1 << 16 | hi_val2 << 24); return 1; } @@ -6029,31 +6027,30 @@ L_stm_s_takeabort: h2 = ((u16)(from >> 16) - (u16)(to >> 16)); if (!(h1 & 0xffff0000)) - state->Cpsr |= (3 << 16); + state->GEFlag |= (3 << 16); else - state->Cpsr &= ~(3 << 16); + state->GEFlag &= ~(3 << 16); if (!(h2 & 0xffff0000)) - state->Cpsr |= (3 << 18); + state->GEFlag |= (3 << 18); else - state->Cpsr &= ~(3 << 18); + state->GEFlag &= ~(3 << 18); } else { // UADD16 h1 = ((u16)from + (u16)to); h2 = ((u16)(from >> 16) + (u16)(to >> 16)); if (h1 & 0xffff0000) - state->Cpsr |= (3 << 16); + state->GEFlag |= (3 << 16); else - state->Cpsr &= ~(3 << 16); + state->GEFlag &= ~(3 << 16); if (h2 & 0xffff0000) - state->Cpsr |= (3 << 18); + state->GEFlag |= (3 << 18); else - state->Cpsr &= ~(3 << 18); + state->GEFlag &= ~(3 << 18); } - ARMul_CPSRAltered(state); state->Reg[rd] = (u32)((h1 & 0xffff) | ((h2 & 0xffff) << 16)); return 1; } @@ -6068,24 +6065,24 @@ L_stm_s_takeabort: b4 = ((u8)(from >> 24) - (u8)(to >> 24)); if (!(b1 & 0xffffff00)) - state->Cpsr |= (1 << 16); + state->GEFlag |= (1 << 16); else - state->Cpsr &= ~(1 << 16); + state->GEFlag &= ~(1 << 16); if (!(b2 & 0xffffff00)) - state->Cpsr |= (1 << 17); + state->GEFlag |= (1 << 17); else - state->Cpsr &= ~(1 << 17); + state->GEFlag &= ~(1 << 17); if (!(b3 & 0xffffff00)) - state->Cpsr |= (1 << 18); + state->GEFlag |= (1 << 18); else - state->Cpsr &= ~(1 << 18); + state->GEFlag &= ~(1 << 18); if (!(b4 & 0xffffff00)) - state->Cpsr |= (1 << 19); + state->GEFlag |= (1 << 19); else - state->Cpsr &= ~(1 << 19); + state->GEFlag &= ~(1 << 19); } else { // UADD8 b1 = ((u8)from + (u8)to); @@ -6094,27 +6091,26 @@ L_stm_s_takeabort: b4 = ((u8)(from >> 24) + (u8)(to >> 24)); if (b1 & 0xffffff00) - state->Cpsr |= (1 << 16); + state->GEFlag |= (1 << 16); else - state->Cpsr &= ~(1 << 16); + state->GEFlag &= ~(1 << 16); if (b2 & 0xffffff00) - state->Cpsr |= (1 << 17); + state->GEFlag |= (1 << 17); else - state->Cpsr &= ~(1 << 17); + state->GEFlag &= ~(1 << 17); if (b3 & 0xffffff00) - state->Cpsr |= (1 << 18); + state->GEFlag |= (1 << 18); else - state->Cpsr &= ~(1 << 18); + state->GEFlag &= ~(1 << 18); if (b4 & 0xffffff00) - state->Cpsr |= (1 << 19); + state->GEFlag |= (1 << 19); else - state->Cpsr &= ~(1 << 19); + state->GEFlag &= ~(1 << 19); } - ARMul_CPSRAltered(state); state->Reg[rd] = (u32)(b1 | (b2 & 0xff) << 8 | (b3 & 0xff) << 16 | (b4 & 0xff) << 24); return 1; } @@ -6211,21 +6207,20 @@ L_stm_s_takeabort: if (rn_lo > max) { rn_lo = max; - state->Cpsr |= (1 << 27); + SETQ; } else if (rn_lo < min) { rn_lo = min; - state->Cpsr |= (1 << 27); + SETQ; } if (rn_hi > max) { rn_hi = max; - state->Cpsr |= (1 << 27); + SETQ; } else if (rn_hi < min) { rn_hi = min; - state->Cpsr |= (1 << 27); + SETQ; } - ARMul_CPSRAltered(state); state->Reg[rd_idx] = (rn_lo & 0xFFFF) | ((rn_hi & 0xFFFF) << 16); return 1; } @@ -6359,21 +6354,20 @@ L_stm_s_takeabort: if (max < rn_lo) { rn_lo = max; - state->Cpsr |= (1 << 27); + SETQ; } else if (rn_lo < 0) { rn_lo = 0; - state->Cpsr |= (1 << 27); + SETQ; } if (max < rn_hi) { rn_hi = max; - state->Cpsr |= (1 << 27); + SETQ; } else if (rn_hi < 0) { rn_hi = 0; - state->Cpsr |= (1 << 27); + SETQ; } - ARMul_CPSRAltered(state); state->Reg[rd_idx] = (rn_lo & 0xFFFF) | ((rn_hi << 16) & 0xFFFF); return 1; } -- cgit v1.2.3 From 82c3962b9545c1149bcd2a6753d83b94b198ac42 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Wed, 24 Dec 2014 09:26:48 -0500 Subject: armemu: Implement SMLALD/SMLSLD --- src/core/arm/interpreter/armemu.cpp | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) (limited to 'src/core/arm/interpreter/armemu.cpp') diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index b2f671f94..27467bb5d 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -6503,8 +6503,39 @@ L_stm_s_takeabort: return 1; } break; - case 0x74: - printf ("Unhandled v6 insn: smlald/smlsld\n"); + case 0x74: // SMLALD and SMLSLD + { + const u8 rm_idx = BITS(8, 11); + const u8 rn_idx = BITS(0, 3); + const u8 rdlo_idx = BITS(12, 15); + const u8 rdhi_idx = BITS(16, 19); + const bool do_swap = (BIT(5) == 1); + + const u32 rdlo_val = state->Reg[rdlo_idx]; + const u32 rdhi_val = state->Reg[rdhi_idx]; + const u32 rn_val = state->Reg[rn_idx]; + u32 rm_val = state->Reg[rm_idx]; + + if (do_swap) + rm_val = (((rm_val & 0xFFFF) << 16) | (rm_val >> 16)); + + const s32 product1 = (s16)(rn_val & 0xFFFF) * (s16)(rm_val & 0xFFFF); + const s32 product2 = (s16)((rn_val >> 16) & 0xFFFF) * (s16)((rm_val >> 16) & 0xFFFF); + s64 result; + + // SMLALD + if (BIT(6) == 0) { + result = (product1 + product2) + (s64)(rdlo_val | ((s64)rdhi_val << 32)); + } + // SMLSLD + else { + result = (product1 - product2) + (s64)(rdlo_val | ((s64)rdhi_val << 32)); + } + + state->Reg[rdlo_idx] = (result & 0xFFFFFFFF); + state->Reg[rdhi_idx] = ((result >> 32) & 0xFFFFFFFF); + return 1; + } break; case 0x75: printf ("Unhandled v6 insn: smmla/smmls/smmul\n"); -- cgit v1.2.3 From 35dbfc7ab0514e04c4aec4514167bba875d01285 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Thu, 25 Dec 2014 13:33:49 -0500 Subject: armemu: Implement SMMUL, SMMLA, and SMMLS. --- src/core/arm/interpreter/armemu.cpp | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) (limited to 'src/core/arm/interpreter/armemu.cpp') diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index b2f671f94..8d803a0af 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -6506,8 +6506,36 @@ L_stm_s_takeabort: case 0x74: printf ("Unhandled v6 insn: smlald/smlsld\n"); break; - case 0x75: - printf ("Unhandled v6 insn: smmla/smmls/smmul\n"); + case 0x75: // SMMLA, SMMUL, and SMMLS + { + const u8 rm_idx = BITS(8, 11); + const u8 rn_idx = BITS(0, 3); + const u8 ra_idx = BITS(12, 15); + const u8 rd_idx = BITS(16, 19); + const bool do_round = (BIT(5) == 1); + + const u32 rm_val = state->Reg[rm_idx]; + const u32 rn_val = state->Reg[rn_idx]; + + // Assume SMMUL by default. + s64 result = (s64)(s32)rn_val * (s64)(s32)rm_val; + + if (ra_idx != 15) { + const u32 ra_val = state->Reg[ra_idx]; + + // SMMLA, otherwise SMMLS + if (BIT(6) == 0) + result += ((s64)ra_val << 32); + else + result = ((s64)ra_val << 32) - result; + } + + if (do_round) + result += 0x80000000; + + state->Reg[rd_idx] = ((result >> 32) & 0xFFFFFFFF); + return 1; + } break; case 0x78: if (BITS(20, 24) == 0x18) -- cgit v1.2.3 From 84a0438cf5cb6e367e16a6873fd3b36b4aa77b21 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Fri, 26 Dec 2014 23:40:15 -0500 Subject: armemu: Implement UHADD8, UHADD16, UHSUB8, UHSUB16, UHASX, and UHSAX --- src/core/arm/interpreter/armemu.cpp | 75 ++++++++++++++++++++++++++++++++++++- 1 file changed, 73 insertions(+), 2 deletions(-) (limited to 'src/core/arm/interpreter/armemu.cpp') diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index d54dbeac5..9b680c1e2 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -6139,8 +6139,79 @@ L_stm_s_takeabort: printf ("Unhandled v6 insn: uqsub16\n"); } break; - case 0x67: - printf ("Unhandled v6 insn: uhadd/uhsub\n"); + case 0x67: // UHADD16, UHASX, UHSAX, UHSUB16, UHADD8, and UHSUB8. + { + const u8 op2 = BITS(5, 7); + + const u8 rm_idx = BITS(0, 3); + const u8 rn_idx = BITS(16, 19); + const u8 rd_idx = BITS(12, 15); + + const u32 rm_val = state->Reg[rm_idx]; + const u32 rn_val = state->Reg[rn_idx]; + + if (op2 == 0x00 || op2 == 0x01 || op2 == 0x02 || op2 == 0x03) + { + u32 lo_val = 0; + u32 hi_val = 0; + + // UHADD16 + if (op2 == 0x00) { + lo_val = (rn_val & 0xFFFF) + (rm_val & 0xFFFF); + hi_val = ((rn_val >> 16) & 0xFFFF) + ((rm_val >> 16) & 0xFFFF); + } + // UHASX + else if (op2 == 0x01) { + lo_val = (rn_val & 0xFFFF) - ((rm_val >> 16) & 0xFFFF); + hi_val = ((rn_val >> 16) & 0xFFFF) + (rm_val & 0xFFFF); + } + // UHSAX + else if (op2 == 0x02) { + lo_val = (rn_val & 0xFFFF) + ((rm_val >> 16) & 0xFFFF); + hi_val = ((rn_val >> 16) & 0xFFFF) - (rm_val & 0xFFFF); + } + // UHSUB16 + else if (op2 == 0x03) { + lo_val = (rn_val & 0xFFFF) - (rm_val & 0xFFFF); + hi_val = ((rn_val >> 16) & 0xFFFF) - ((rm_val >> 16) & 0xFFFF); + } + + lo_val >>= 1; + hi_val >>= 1; + + state->Reg[rd_idx] = (lo_val & 0xFFFF) | ((hi_val & 0xFFFF) << 16); + return 1; + } + else if (op2 == 0x04 || op2 == 0x07) { + u32 sum1; + u32 sum2; + u32 sum3; + u32 sum4; + + // UHADD8 + if (op2 == 0x04) { + sum1 = (rn_val & 0xFF) + (rm_val & 0xFF); + sum2 = ((rn_val >> 8) & 0xFF) + ((rm_val >> 8) & 0xFF); + sum3 = ((rn_val >> 16) & 0xFF) + ((rm_val >> 16) & 0xFF); + sum4 = ((rn_val >> 24) & 0xFF) + ((rm_val >> 24) & 0xFF); + } + // UHSUB8 + else { + sum1 = (rn_val & 0xFF) - (rm_val & 0xFF); + sum2 = ((rn_val >> 8) & 0xFF) - ((rm_val >> 8) & 0xFF); + sum3 = ((rn_val >> 16) & 0xFF) - ((rm_val >> 16) & 0xFF); + sum4 = ((rn_val >> 24) & 0xFF) - ((rm_val >> 24) & 0xFF); + } + + sum1 >>= 1; + sum2 >>= 1; + sum3 >>= 1; + sum4 >>= 1; + + state->Reg[rd_idx] = (sum1 & 0xFF) | ((sum2 & 0xFF) << 8) | ((sum3 & 0xFF) << 16) | ((sum4 & 0xFF) << 24); + return 1; + } + } break; case 0x68: { -- cgit v1.2.3 From 60523113a9301e16bae91af61063bd8833926e8c Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sat, 27 Dec 2014 17:06:19 -0500 Subject: armemu: Implement UQADD8, UQADD16, UQSUB16, UQASX, and UQSAX --- src/core/arm/interpreter/armemu.cpp | 67 ++++++++++++++++++++++++++----------- 1 file changed, 48 insertions(+), 19 deletions(-) (limited to 'src/core/arm/interpreter/armemu.cpp') diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index 9b680c1e2..5d26456c7 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -6117,26 +6117,55 @@ L_stm_s_takeabort: } printf("Unhandled v6 insn: uasx/usax\n"); break; - case 0x66: - if ((instr & 0x0FF00FF0) == 0x06600FF0) { //uqsub8 - u32 rd = (instr >> 12) & 0xF; - u32 rm = (instr >> 16) & 0xF; - u32 rn = (instr >> 0) & 0xF; - u32 subfrom = state->Reg[rm]; - u32 tosub = state->Reg[rn]; - - u8 b1 = (u8)((u8)(subfrom)-(u8)(tosub)); - if (b1 > (u8)(subfrom)) b1 = 0; - u8 b2 = (u8)((u8)(subfrom >> 8) - (u8)(tosub >> 8)); - if (b2 > (u8)(subfrom >> 8)) b2 = 0; - u8 b3 = (u8)((u8)(subfrom >> 16) - (u8)(tosub >> 16)); - if (b3 > (u8)(subfrom >> 16)) b3 = 0; - u8 b4 = (u8)((u8)(subfrom >> 24) - (u8)(tosub >> 24)); - if (b4 > (u8)(subfrom >> 24)) b4 = 0; - state->Reg[rd] = (u32)(b1 | b2 << 8 | b3 << 16 | b4 << 24); + case 0x66: // UQADD16, UQASX, UQSAX, UQSUB16, UQADD8, and UQSUB8 + { + const u8 rd_idx = BITS(12, 15); + const u8 rm_idx = BITS(0, 3); + const u8 rn_idx = BITS(16, 19); + const u8 op2 = BITS(5, 7); + const u32 rm_val = state->Reg[rm_idx]; + const u32 rn_val = state->Reg[rn_idx]; + + u16 lo_val = 0; + u16 hi_val = 0; + + // UQADD16 + if (op2 == 0x00) { + lo_val = ARMul_UnsignedSaturatedAdd16(rn_val & 0xFFFF, rm_val & 0xFFFF); + hi_val = ARMul_UnsignedSaturatedAdd16((rn_val >> 16) & 0xFFFF, (rm_val >> 16) & 0xFFFF); + } + // UQASX + else if (op2 == 0x01) { + lo_val = ARMul_UnsignedSaturatedSub16(rn_val & 0xFFFF, (rm_val >> 16) & 0xFFFF); + hi_val = ARMul_UnsignedSaturatedAdd16((rn_val >> 16) & 0xFFFF, rm_val & 0xFFFF); + } + // UQSAX + else if (op2 == 0x02) { + lo_val = ARMul_UnsignedSaturatedAdd16(rn_val & 0xFFFF, (rm_val >> 16) & 0xFFFF); + hi_val = ARMul_UnsignedSaturatedSub16((rn_val >> 16) & 0xFFFF, rm_val & 0xFFFF); + } + // UQSUB16 + else if (op2 == 0x03) { + lo_val = ARMul_UnsignedSaturatedSub16(rn_val & 0xFFFF, rm_val & 0xFFFF); + hi_val = ARMul_UnsignedSaturatedSub16((rn_val >> 16) & 0xFFFF, (rm_val >> 16) & 0xFFFF); + } + // UQADD8 + else if (op2 == 0x04) { + lo_val = ARMul_UnsignedSaturatedAdd8(rn_val, rm_val) | + ARMul_UnsignedSaturatedAdd8(rn_val >> 8, rm_val >> 8) << 8; + hi_val = ARMul_UnsignedSaturatedAdd8(rn_val >> 16, rm_val >> 16) | + ARMul_UnsignedSaturatedAdd8(rn_val >> 24, rm_val >> 24) << 8; + } + // UQSUB8 + else { + lo_val = ARMul_UnsignedSaturatedSub8(rn_val, rm_val) | + ARMul_UnsignedSaturatedSub8(rn_val >> 8, rm_val >> 8) << 8; + hi_val = ARMul_UnsignedSaturatedSub8(rn_val >> 16, rm_val >> 16) | + ARMul_UnsignedSaturatedSub8(rn_val >> 24, rm_val >> 24) << 8; + } + + state->Reg[rd_idx] = ((lo_val & 0xFFFF) | hi_val << 16); return 1; - } else { - printf ("Unhandled v6 insn: uqsub16\n"); } break; case 0x67: // UHADD16, UHASX, UHSAX, UHSUB16, UHADD8, and UHSUB8. -- cgit v1.2.3 From 059c65a27af538cba40aa43d2eeb3a544661a9b8 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sun, 28 Dec 2014 06:07:24 -0500 Subject: armemu: Fix underflows in USAD8/USADA8 Initially reported by xdec. --- src/core/arm/interpreter/armemu.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/core/arm/interpreter/armemu.cpp') diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index 9b680c1e2..404012b2a 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -6643,10 +6643,10 @@ L_stm_s_takeabort: const u32 rm_val = state->Reg[rm_idx]; const u32 rn_val = state->Reg[rn_idx]; - const u8 diff1 = (u8)std::labs((rn_val & 0xFF) - (rm_val & 0xFF)); - const u8 diff2 = (u8)std::labs(((rn_val >> 8) & 0xFF) - ((rm_val >> 8) & 0xFF)); - const u8 diff3 = (u8)std::labs(((rn_val >> 16) & 0xFF) - ((rm_val >> 16) & 0xFF)); - const u8 diff4 = (u8)std::labs(((rn_val >> 24) & 0xFF) - ((rm_val >> 24) & 0xFF)); + const u8 diff1 = ARMul_UnsignedAbsoluteDifference(rn_val & 0xFF, rm_val & 0xFF); + const u8 diff2 = ARMul_UnsignedAbsoluteDifference((rn_val >> 8) & 0xFF, (rm_val >> 8) & 0xFF); + const u8 diff3 = ARMul_UnsignedAbsoluteDifference((rn_val >> 16) & 0xFF, (rm_val >> 16) & 0xFF); + const u8 diff4 = ARMul_UnsignedAbsoluteDifference((rn_val >> 24) & 0xFF, (rm_val >> 24) & 0xFF); u32 finalDif = (diff1 + diff2 + diff3 + diff4); -- cgit v1.2.3 From 5e16216afb0d41855aeabaff81f17cd4bee59fe5 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sun, 28 Dec 2014 11:45:13 -0500 Subject: armemu: Simplify REVSH/UXTH/UXTAH --- src/core/arm/interpreter/armemu.cpp | 71 ++++++++++++------------------------- 1 file changed, 23 insertions(+), 48 deletions(-) (limited to 'src/core/arm/interpreter/armemu.cpp') diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index 5d26456c7..a955d6aac 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -6496,58 +6496,33 @@ L_stm_s_takeabort: return 1; } - case 0x6f: { - ARMword Rm; - int ror = -1; - - switch (BITS(4, 11)) { - case 0x07: - ror = 0; - break; - case 0x47: - ror = 8; - break; - case 0x87: - ror = 16; - break; - case 0xc7: - ror = 24; - break; + case 0x6f: // UXTH, UXTAH, and REVSH. + { + const u8 op2 = BITS(5, 7); - case 0xfb: // REVSH - { - DEST = ((RHS & 0xFF) << 8) | ((RHS & 0xFF00) >> 8); - if (DEST & 0x8000) - DEST |= 0xffff0000; - return 1; - } - default: - break; + // REVSH + if (op2 == 0x05) { + DEST = ((RHS & 0xFF) << 8) | ((RHS & 0xFF00) >> 8); + if (DEST & 0x8000) + DEST |= 0xffff0000; + return 1; } + // UXTH and UXTAH + else if (op2 == 0x03) { + const u8 rotate = BITS(10, 11) * 8; + const ARMword rm = ((state->Reg[BITS(0, 3)] >> rotate) & 0xFFFF) | (((state->Reg[BITS(0, 3)] << (32 - rotate)) & 0xFFFF) & 0xFFFF); + + // UXTH + if (BITS(16, 19) == 0xf) { + state->Reg[BITS(12, 15)] = rm; + } + // UXTAH + else { + state->Reg[BITS(12, 15)] = state->Reg[BITS(16, 19)] + rm; + } - if (ror == -1) - break; - - 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; - } - else { - /* UXTAH */ - /* state->Reg[BITS (12, 15)] = state->Reg [BITS (16, 19)] + Rm; */ - // 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)] + Rm; - // printf("rd is %x\n", state->Reg[BITS (12, 15)]); - // exit(-1); + return 1; } - - return 1; } case 0x70: // ichfly -- cgit v1.2.3 From 914ecfe04fa21d9370491318373a7c34fe4a79af Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sun, 28 Dec 2014 11:56:16 -0500 Subject: armemu: Simplify USAT16/UXTB/UXTAB --- src/core/arm/interpreter/armemu.cpp | 107 ++++++++++++++---------------------- 1 file changed, 42 insertions(+), 65 deletions(-) (limited to 'src/core/arm/interpreter/armemu.cpp') diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index a955d6aac..dcc0acafe 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -6422,79 +6422,56 @@ L_stm_s_takeabort: return 1; } break; - case 0x6e: { - ARMword Rm; - int ror = -1; - - switch (BITS(4, 11)) { - case 0x07: - ror = 0; - break; - case 0x47: - ror = 8; - break; - case 0x87: - ror = 16; - break; - case 0xc7: - ror = 24; - break; - - case 0x01: - case 0xf3: - //ichfly - //USAT16 - { - 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; - SETQ; - } else if (rn_lo < 0) { - rn_lo = 0; - SETQ; - } - - if (max < rn_hi) { - rn_hi = max; - SETQ; - } else if (rn_hi < 0) { - rn_hi = 0; - SETQ; - } + case 0x6e: // USAT, USAT16, UXTB, and UXTAB + { + const u8 op2 = BITS(5, 7); - state->Reg[rd_idx] = (rn_lo & 0xFFFF) | ((rn_hi << 16) & 0xFFFF); - return 1; + // USAT16 + if (op2 == 0x01) { + 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; + SETQ; + } else if (rn_lo < 0) { + rn_lo = 0; + SETQ; } - - default: - break; - } - - if (ror == -1) { - if (BITS(4, 6) == 0x7) { - printf("Unhandled v6 insn: usat\n"); - return 0; + + if (max < rn_hi) { + rn_hi = max; + SETQ; + } else if (rn_hi < 0) { + rn_hi = 0; + SETQ; } - break; + + state->Reg[rd_idx] = (rn_lo & 0xFFFF) | ((rn_hi << 16) & 0xFFFF); + return 1; } - - Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFF) | (((state->Reg[BITS(0, 3)] << (32 - ror)) & 0xFF) & 0xFF); - - if (BITS(16, 19) == 0xf) + else if (op2 == 0x03) { + const u8 rotate = BITS(10, 11) * 8; + const u32 rm = ((state->Reg[BITS(0, 3)] >> rotate) & 0xFF) | (((state->Reg[BITS(0, 3)] << (32 - rotate)) & 0xFF) & 0xFF); + + if (BITS(16, 19) == 0xf) /* UXTB */ - state->Reg[BITS(12, 15)] = Rm; - else + state->Reg[BITS(12, 15)] = rm; + else /* UXTAB */ - state->Reg[BITS(12, 15)] = state->Reg[BITS(16, 19)] + Rm; + state->Reg[BITS(12, 15)] = state->Reg[BITS(16, 19)] + rm; - return 1; + return 1; + } + else { + printf("Unimplemented op: USAT"); + } } + break; case 0x6f: // UXTH, UXTAH, and REVSH. { -- cgit v1.2.3 From 9f5b53f9ff616d7df3b8ea3709963831f4e96f42 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sun, 28 Dec 2014 12:13:13 -0500 Subject: armemu: Simplify REV/REV16/SXTH/SXTAH --- src/core/arm/interpreter/armemu.cpp | 64 +++++++++++++++---------------------- 1 file changed, 26 insertions(+), 38 deletions(-) (limited to 'src/core/arm/interpreter/armemu.cpp') diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index dcc0acafe..1b3a3478d 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -6350,51 +6350,39 @@ L_stm_s_takeabort: return 1; } - case 0x6b: - { - ARMword Rm; - int ror = -1; - switch (BITS(4, 11)) { - case 0x07: - ror = 0; - break; - case 0x47: - ror = 8; - break; - case 0x87: - ror = 16; - break; - case 0xc7: - ror = 24; - break; + case 0x6b: // REV, REV16, SXTH, and SXTAH + { + const u8 op2 = BITS(5, 7); - case 0xf3: // REV - DEST = ((RHS & 0xFF) << 24) | ((RHS & 0xFF00)) << 8 | ((RHS & 0xFF0000) >> 8) | ((RHS & 0xFF000000) >> 24); - return 1; - case 0xfb: // REV16 - DEST = ((RHS & 0xFF) << 8) | ((RHS & 0xFF00)) >> 8 | ((RHS & 0xFF0000) << 8) | ((RHS & 0xFF000000) >> 8); - return 1; - default: - break; + // REV + if (op2 == 0x01) { + DEST = ((RHS & 0xFF) << 24) | ((RHS & 0xFF00)) << 8 | ((RHS & 0xFF0000) >> 8) | ((RHS & 0xFF000000) >> 24); + return 1; } + // REV16 + else if (op2 == 0x05) { + DEST = ((RHS & 0xFF) << 8) | ((RHS & 0xFF00)) >> 8 | ((RHS & 0xFF0000) << 8) | ((RHS & 0xFF000000) >> 8); + return 1; + } + else if (op2 == 0x03) { + const u8 rotate = BITS(10, 11) * 8; - if (ror == -1) - break; - - Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFFFF) | (((state->Reg[BITS(0, 3)] << (32 - ror)) & 0xFFFF) & 0xFFFF); - if (Rm & 0x8000) - Rm |= 0xffff0000; + u32 rm = ((state->Reg[BITS(0, 3)] >> rotate) & 0xFFFF) | (((state->Reg[BITS(0, 3)] << (32 - rotate)) & 0xFFFF) & 0xFFFF); + if (rm & 0x8000) + rm |= 0xffff0000; - if (BITS(16, 19) == 0xf) - /* SXTH */ - state->Reg[BITS(12, 15)] = Rm; - else - /* SXTAH */ - state->Reg[BITS(12, 15)] = state->Reg[BITS(16, 19)] + Rm; + // SXTH, otherwise SXTAH + if (BITS(16, 19) == 15) + state->Reg[BITS(12, 15)] = rm; + else + state->Reg[BITS(12, 15)] = state->Reg[BITS(16, 19)] + rm; - return 1; + return 1; + } } + break; + case 0x6c: // UXTB16 and UXTAB16 { const u8 rm_idx = BITS(0, 3); -- cgit v1.2.3 From 6ce2a38ec401019e96ab0e6896cb3cb59e64752e Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sun, 28 Dec 2014 12:19:31 -0500 Subject: armemu: Simplify SSAT/SSAT16/SXTB/SXTAB --- src/core/arm/interpreter/armemu.cpp | 119 +++++++++++++++--------------------- 1 file changed, 48 insertions(+), 71 deletions(-) (limited to 'src/core/arm/interpreter/armemu.cpp') diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index 1b3a3478d..01d4e7708 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -6272,84 +6272,61 @@ L_stm_s_takeabort: return 1; } } - printf("Unhandled v6 insn: pkh/sxtab/selsxtb\n"); - break; - case 0x6a: { - ARMword Rm; - int ror = -1; - - switch (BITS(4, 11)) { - case 0x07: - ror = 0; - break; - case 0x47: - ror = 8; - break; - case 0x87: - ror = 16; - break; - case 0xc7: - ror = 24; - break; - - case 0x01: - case 0xf3: - //ichfly - //SSAT16 - { - const u8 rd_idx = BITS(12, 15); - const u8 rn_idx = BITS(0, 3); - const u8 num_bits = BITS(16, 19) + 1; - const s16 min = -(0x8000 >> (16 - num_bits)); - const s16 max = (0x7FFF >> (16 - num_bits)); - s16 rn_lo = (state->Reg[rn_idx]); - s16 rn_hi = (state->Reg[rn_idx] >> 16); - - if (rn_lo > max) { - rn_lo = max; - SETQ; - } else if (rn_lo < min) { - rn_lo = min; - SETQ; - } - - if (rn_hi > max) { - rn_hi = max; - SETQ; - } else if (rn_hi < min) { - rn_hi = min; - SETQ; - } - - state->Reg[rd_idx] = (rn_lo & 0xFFFF) | ((rn_hi & 0xFFFF) << 16); - return 1; - } + printf("Unhandled v6 insn: pkh/sxtab/selsxtb\n"); + break; - default: - break; - } + case 0x6a: // SSAT, SSAT16, SXTB, and SXTAB + { + const u8 op2 = BITS(5, 7); + + // SSAT16 + if (op2 == 0x01) { + const u8 rd_idx = BITS(12, 15); + const u8 rn_idx = BITS(0, 3); + const u8 num_bits = BITS(16, 19) + 1; + const s16 min = -(0x8000 >> (16 - num_bits)); + const s16 max = (0x7FFF >> (16 - num_bits)); + s16 rn_lo = (state->Reg[rn_idx]); + s16 rn_hi = (state->Reg[rn_idx] >> 16); - if (ror == -1) { - if (BITS(4, 6) == 0x7) { - printf("Unhandled v6 insn: ssat\n"); - return 0; + if (rn_lo > max) { + rn_lo = max; + SETQ; + } else if (rn_lo < min) { + rn_lo = min; + SETQ; } - break; - } - Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFF) | (((state->Reg[BITS(0, 3)] << (32 - ror)) & 0xFF) & 0xFF); - if (Rm & 0x80) - Rm |= 0xffffff00; + if (rn_hi > max) { + rn_hi = max; + SETQ; + } else if (rn_hi < min) { + rn_hi = min; + SETQ; + } - if (BITS(16, 19) == 0xf) - /* SXTB */ - state->Reg[BITS(12, 15)] = Rm; - else - /* SXTAB */ - state->Reg[BITS(12, 15)] = state->Reg[BITS(16, 19)] + Rm; + state->Reg[rd_idx] = (rn_lo & 0xFFFF) | ((rn_hi & 0xFFFF) << 16); + return 1; + } + else if (op2 == 0x03) { + const u8 rotation = BITS(10, 11) * 8; + u32 rm = ((state->Reg[BITS(0, 3)] >> rotation) & 0xFF) | (((state->Reg[BITS(0, 3)] << (32 - rotation)) & 0xFF) & 0xFF); + if (rm & 0x80) + rm |= 0xffffff00; + + // SXTB, otherwise SXTAB + if (BITS(16, 19) == 0xf) + state->Reg[BITS(12, 15)] = rm; + else + state->Reg[BITS(12, 15)] = state->Reg[BITS(16, 19)] + rm; - return 1; + return 1; + } + else { + printf("Unimplemented op: SSAT"); + } } + break; case 0x6b: // REV, REV16, SXTH, and SXTAH { -- cgit v1.2.3 From 58cb62fe7b383ef5f91a35a89fb92ca3c5287b1c Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 28 Dec 2014 16:18:52 -0500 Subject: armemu: Fix PKHTB to do an arithmetic shift and correctly decode immediate field. --- src/core/arm/interpreter/armemu.cpp | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) (limited to 'src/core/arm/interpreter/armemu.cpp') diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index 2873da897..9c6602f09 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -3100,7 +3100,6 @@ mainswitch: break; case 0x68: /* Store Word, No WriteBack, Post Inc, Reg. */ - //ichfly PKHBT PKHTB todo check this if ((instr & 0x70) == 0x10) { //pkhbt u8 idest = BITS(12, 15); u8 rfis = BITS(16, 19); @@ -3109,18 +3108,11 @@ mainswitch: state->Reg[idest] = (state->Reg[rfis] & 0xFFFF) | ((state->Reg[rlast] << ishi) & 0xFFFF0000); break; } else if ((instr & 0x70) == 0x50) { //pkhtb - 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); + u8 rd_idx = BITS(12, 15); + u8 rn_idx = BITS(16, 19); + u8 rm_idx = BITS(0, 3); + u8 imm5 = BITS(7, 11) ? BITS(7, 11) : 31; + state->Reg[rd_idx] = ((static_cast(state->Reg[rm_idx]) >> imm5) & 0xFFFF) | ((state->Reg[rn_idx]) & 0xFFFF0000); break; } else if (BIT (4)) { #ifdef MODE32 -- cgit v1.2.3 From 7ad400d5a72d87233cce6d327218fedad44fa6e2 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 29 Dec 2014 00:49:10 -0500 Subject: armemu: Implement QADD8/QSUB8 --- src/core/arm/interpreter/armemu.cpp | 68 +++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 33 deletions(-) (limited to 'src/core/arm/interpreter/armemu.cpp') diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index f0d349de7..b9c2aa6c2 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -5948,56 +5948,58 @@ L_stm_s_takeabort: printf("Unhandled v6 insn: %08x", instr); } break; - case 0x62: // QADD16, QASX, QSAX, and QSUB16 - if ((instr & 0xFF0) == 0xf10 || (instr & 0xFF0) == 0xf30 || - (instr & 0xFF0) == 0xf50 || (instr & 0xFF0) == 0xf70) + case 0x62: // QADD16, QASX, QSAX, QSUB16, QADD8, and QSUB8 { + const u8 op2 = BITS(5, 7); + 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); + const u16 rm_lo = (state->Reg[rm_idx] & 0xFFFF); + const u16 rm_hi = ((state->Reg[rm_idx] >> 0x10) & 0xFFFF); + const u16 rn_lo = (state->Reg[rn_idx] & 0xFFFF); + const u16 rn_hi = ((state->Reg[rn_idx] >> 0x10) & 0xFFFF); - s32 lo_result; - s32 hi_result; + u16 lo_result = 0; + u16 hi_result = 0; // QADD16 - if ((instr & 0xFF0) == 0xf10) { - lo_result = (rn_lo + rm_lo); - hi_result = (rn_hi + rm_hi); + if (op2 == 0x00) { + lo_result = ARMul_SignedSaturatedAdd16(rn_lo, rm_lo); + hi_result = ARMul_SignedSaturatedAdd16(rn_hi, rm_hi); } // QASX - else if ((instr & 0xFF0) == 0xf30) { - lo_result = (rn_lo - rm_hi); - hi_result = (rn_hi + rm_lo); + else if (op2 == 0x01) { + lo_result = ARMul_SignedSaturatedSub16(rn_lo, rm_hi); + hi_result = ARMul_SignedSaturatedAdd16(rn_hi, rm_lo); } // QSAX - else if ((instr & 0xFF0) == 0xf50) { - lo_result = (rn_lo + rm_hi); - hi_result = (rn_hi - rm_lo); + else if (op2 == 0x02) { + lo_result = ARMul_SignedSaturatedAdd16(rn_lo, rm_hi); + hi_result = ARMul_SignedSaturatedSub16(rn_hi, rm_lo); } // QSUB16 - else { - lo_result = (rn_lo - rm_lo); - hi_result = (rn_hi - rm_hi); + else if (op2 == 0x03) { + lo_result = ARMul_SignedSaturatedSub16(rn_lo, rm_lo); + hi_result = ARMul_SignedSaturatedSub16(rn_hi, rm_hi); + } + // QADD8 + else if (op2 == 0x04) { + lo_result = ARMul_SignedSaturatedAdd8(rn_lo & 0xFF, rm_lo & 0xFF) | + ARMul_SignedSaturatedAdd8(rn_lo >> 8, rm_lo >> 8) << 8; + hi_result = ARMul_SignedSaturatedAdd8(rn_hi & 0xFF, rm_hi & 0xFF) | + ARMul_SignedSaturatedAdd8(rn_hi >> 8, rm_hi >> 8) << 8; + } + // QSUB8 + else if (op2 == 0x07) { + lo_result = ARMul_SignedSaturatedSub8(rn_lo & 0xFF, rm_lo & 0xFF) | + ARMul_SignedSaturatedSub8(rn_lo >> 8, rm_lo >> 8) << 8; + hi_result = ARMul_SignedSaturatedSub8(rn_hi & 0xFF, rm_hi & 0xFF) | + ARMul_SignedSaturatedSub8(rn_hi >> 8, rm_hi >> 8) << 8; } - - 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: %08x", BITS(20, 27)); } break; case 0x63: -- cgit v1.2.3