summaryrefslogtreecommitdiffstats
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/arm/dyncom/arm_dyncom_dec.h2
-rw-r--r--src/core/arm/dyncom/arm_dyncom_interpreter.cpp106
-rw-r--r--src/core/arm/dyncom/arm_dyncom_run.cpp1
-rw-r--r--src/core/arm/interpreter/armemu.cpp262
-rw-r--r--src/core/arm/interpreter/armsupp.cpp13
-rw-r--r--src/core/arm/skyeye_common/armdefs.h2
-rw-r--r--src/core/arm/skyeye_common/armemu.h8
-rw-r--r--src/core/hle/service/apt_u.cpp4
-rw-r--r--src/core/hle/service/fs/fs_user.cpp19
9 files changed, 316 insertions, 101 deletions
diff --git a/src/core/arm/dyncom/arm_dyncom_dec.h b/src/core/arm/dyncom/arm_dyncom_dec.h
index 19d94f369..70eb96e93 100644
--- a/src/core/arm/dyncom/arm_dyncom_dec.h
+++ b/src/core/arm/dyncom/arm_dyncom_dec.h
@@ -56,8 +56,6 @@
#define RN ((instr >> 16) & 0xF)
/*xxxx xxxx xxxx xxxx xxxx xxxx xxxx 1111 */
#define RM (instr & 0xF)
-#define BIT(n) ((instr >> (n)) & 1)
-#define BITS(a,b) ((instr >> (a)) & ((1 << (1+(b)-(a)))-1))
/* CP15 registers */
#define OPCODE_1 BITS(21, 23)
diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
index df698e8f1..460001b1a 100644
--- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
+++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
@@ -2390,15 +2390,41 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(pld)(unsigned int inst, int index)
return inst_base;
}
ARM_INST_PTR INTERPRETER_TRANSLATE(qadd)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("QADD"); }
-ARM_INST_PTR INTERPRETER_TRANSLATE(qadd16)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("QADD16"); }
ARM_INST_PTR INTERPRETER_TRANSLATE(qadd8)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("QADD8"); }
-ARM_INST_PTR INTERPRETER_TRANSLATE(qaddsubx)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("QADDSUBX"); }
+ARM_INST_PTR INTERPRETER_TRANSLATE(qadd16)(unsigned int inst, int index)
+{
+ arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst));
+ generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+ inst_base->load_r15 = 0;
+
+ inst_cream->Rm = BITS(inst, 0, 3);
+ inst_cream->Rn = BITS(inst, 16, 19);
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->op1 = BITS(inst, 20, 21);
+ inst_cream->op2 = BITS(inst, 5, 7);
+
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(qaddsubx)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(qadd16)(inst, index);
+}
ARM_INST_PTR INTERPRETER_TRANSLATE(qdadd)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("QDADD"); }
ARM_INST_PTR INTERPRETER_TRANSLATE(qdsub)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("QDSUB"); }
ARM_INST_PTR INTERPRETER_TRANSLATE(qsub)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("QSUB"); }
-ARM_INST_PTR INTERPRETER_TRANSLATE(qsub16)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("QSUB16"); }
ARM_INST_PTR INTERPRETER_TRANSLATE(qsub8)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("QSUB8"); }
-ARM_INST_PTR INTERPRETER_TRANSLATE(qsubaddx)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("QSUBADDX"); }
+ARM_INST_PTR INTERPRETER_TRANSLATE(qsub16)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(qadd16)(inst, index);
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(qsubaddx)(unsigned int inst, int index)
+{
+ return INTERPRETER_TRANSLATE(qadd16)(inst, index);
+}
ARM_INST_PTR INTERPRETER_TRANSLATE(rev)(unsigned int inst, int index)
{
arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(rev_inst));
@@ -3798,9 +3824,9 @@ unsigned InterpreterMainLoop(ARMul_State* state)
#define INC_ICOUNTER cpu->icounter++; \
if(cpu->Reg[15] > 0xc0000000) \
cpu->kernel_icounter++;
- //if (debug_function(core)) \
+ /*if (debug_function(core)) \
if (core->check_int_flag) \
- goto END
+ goto END*/
//LOG_TRACE(Core_ARM11, "icounter is %llx pc is %x\n", cpu->icounter, cpu->Reg[15])
#else
#define INC_ICOUNTER ;
@@ -4021,18 +4047,18 @@ unsigned InterpreterMainLoop(ARMul_State* state)
#define UPDATE_NFLAG(dst) (cpu->NFlag = BIT(dst, 31) ? 1 : 0)
#define UPDATE_ZFLAG(dst) (cpu->ZFlag = dst ? 0 : 1)
-// #define UPDATE_CFLAG(dst, lop, rop) (cpu->CFlag = ((ISNEG(lop) && ISPOS(rop)) || \
+/* #define UPDATE_CFLAG(dst, lop, rop) (cpu->CFlag = ((ISNEG(lop) && ISPOS(rop)) || \
(ISNEG(lop) && ISPOS(dst)) || \
- (ISPOS(rop) && ISPOS(dst))))
+ (ISPOS(rop) && ISPOS(dst)))) */
#define UPDATE_CFLAG(dst, lop, rop) (cpu->CFlag = ((dst < lop) || (dst < rop)))
#define UPDATE_CFLAG_CARRY_FROM_ADD(lop, rop, flag) (cpu->CFlag = (((uint64_t) lop + (uint64_t) rop + (uint64_t) flag) > 0xffffffff) )
#define UPDATE_CFLAG_NOT_BORROW_FROM_FLAG(lop, rop, flag) (cpu->CFlag = ((uint64_t) lop >= ((uint64_t) rop + (uint64_t) flag)))
#define UPDATE_CFLAG_NOT_BORROW_FROM(lop, rop) (cpu->CFlag = (lop >= rop))
#define UPDATE_CFLAG_WITH_NOT(dst, lop, rop) (cpu->CFlag = !(dst < lop))
#define UPDATE_CFLAG_WITH_SC cpu->CFlag = cpu->shifter_carry_out
-// #define UPDATE_CFLAG_WITH_NOT(dst, lop, rop) cpu->CFlag = !((ISNEG(lop) && ISPOS(rop)) || \
+/* #define UPDATE_CFLAG_WITH_NOT(dst, lop, rop) cpu->CFlag = !((ISNEG(lop) && ISPOS(rop)) || \
(ISNEG(lop) && ISPOS(dst)) || \
- (ISPOS(rop) && ISPOS(dst)))
+ (ISPOS(rop) && ISPOS(dst))) */
#define UPDATE_VFLAG(dst, lop, rop) (cpu->VFlag = (((lop < 0) && (rop < 0) && (dst >= 0)) || \
((lop >= 0) && (rop) >= 0 && (dst < 0))))
#define UPDATE_VFLAG_WITH_NOT(dst, lop, rop) (cpu->VFlag = !(((lop < 0) && (rop < 0) && (dst >= 0)) || \
@@ -5561,15 +5587,69 @@ unsigned InterpreterMainLoop(ARMul_State* state)
GOTO_NEXT_INST;
}
QADD_INST:
- QADD16_INST:
QADD8_INST:
+
+ QADD16_INST:
QADDSUBX_INST:
+ QSUB16_INST:
+ QSUBADDX_INST:
+ {
+ INC_ICOUNTER;
+ if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) {
+ generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component;
+ const s16 rm_lo = (RM & 0xFFFF);
+ const s16 rm_hi = ((RM >> 16) & 0xFFFF);
+ const s16 rn_lo = (RN & 0xFFFF);
+ const s16 rn_hi = ((RN >> 16) & 0xFFFF);
+ const u8 op2 = inst_cream->op2;
+
+ s32 lo_result = 0;
+ s32 hi_result = 0;
+
+ // QADD16
+ if (op2 == 0x00) {
+ lo_result = (rn_lo + rm_lo);
+ hi_result = (rn_hi + rm_hi);
+ }
+ // QASX
+ else if (op2 == 0x01) {
+ lo_result = (rn_lo - rm_hi);
+ hi_result = (rn_hi + rm_lo);
+ }
+ // QSAX
+ else if (op2 == 0x02) {
+ lo_result = (rn_lo + rm_hi);
+ hi_result = (rn_hi - rm_lo);
+ }
+ // QSUB16
+ else if (op2 == 0x03) {
+ lo_result = (rn_lo - rm_lo);
+ hi_result = (rn_hi - rm_hi);
+ }
+
+ if (lo_result > 0x7FFF)
+ lo_result = 0x7FFF;
+ else if (lo_result < -0x8000)
+ lo_result = -0x8000;
+
+ if (hi_result > 0x7FFF)
+ hi_result = 0x7FFF;
+ else if (hi_result < -0x8000)
+ hi_result = -0x8000;
+
+ RD = (lo_result & 0xFFFF) | ((hi_result & 0xFFFF) << 16);
+ }
+
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(generic_arm_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+
QDADD_INST:
QDSUB_INST:
QSUB_INST:
- QSUB16_INST:
QSUB8_INST:
- QSUBADDX_INST:
REV_INST:
{
INC_ICOUNTER;
diff --git a/src/core/arm/dyncom/arm_dyncom_run.cpp b/src/core/arm/dyncom/arm_dyncom_run.cpp
index a2026cbf3..b66b92cf5 100644
--- a/src/core/arm/dyncom/arm_dyncom_run.cpp
+++ b/src/core/arm/dyncom/arm_dyncom_run.cpp
@@ -29,7 +29,6 @@
void switch_mode(arm_core_t *core, uint32_t mode)
{
- uint32_t tmp1, tmp2;
if (core->Mode == mode) {
//Mode not changed.
//printf("mode not changed\n");
diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp
index 610e04f10..d54dbeac5 100644
--- a/src/core/arm/interpreter/armemu.cpp
+++ b/src/core/arm/interpreter/armemu.cpp
@@ -1670,7 +1670,7 @@ mainswitch:
op1 *= op2;
//printf("SMLA_INST:BB,op1=0x%x, op2=0x%x. Rn=0x%x\n", op1, op2, Rn);
if (AddOverflow(op1, Rn, op1 + Rn))
- SETS;
+ SETQ;
state->Reg[BITS (16, 19)] = op1 + Rn;
break;
}
@@ -1682,7 +1682,7 @@ mainswitch:
ARMword result = op1 + op2;
if (AddOverflow(op1, op2, result)) {
result = POS (result) ? 0x80000000 : 0x7fffffff;
- SETS;
+ SETQ;
}
state->Reg[BITS (12, 15)] = result;
break;
@@ -1724,7 +1724,7 @@ mainswitch:
TAKEABORT;
} else if ((BITS (0, 11) == 0) && (LHSReg == 15)) { /* MRS CPSR */
UNDEF_MRSPC;
- DEST = ECC | EINT | EMODE;
+ DEST = ARMul_GetCPSR(state);
} else {
UNDEF_Test;
}
@@ -1795,7 +1795,7 @@ mainswitch:
ARMword Rn = state->Reg[BITS(12, 15)];
if (AddOverflow((ARMword)result, Rn, (ARMword)(result + Rn)))
- SETS;
+ SETQ;
result += Rn;
}
state->Reg[BITS (16, 19)] = (ARMword)result;
@@ -1811,7 +1811,7 @@ mainswitch:
if (SubOverflow
(op1, op2, result)) {
result = POS (result) ? 0x80000000 : 0x7fffffff;
- SETS;
+ SETQ;
}
state->Reg[BITS (12, 15)] = result;
@@ -1934,13 +1934,13 @@ mainswitch:
if (AddOverflow
(op2, op2, op2d)) {
- SETS;
+ SETQ;
op2d = POS (op2d) ? 0x80000000 : 0x7fffffff;
}
result = op1 + op2d;
if (AddOverflow(op1, op2d, result)) {
- SETS;
+ SETQ;
result = POS (result) ? 0x80000000 : 0x7fffffff;
}
@@ -2053,13 +2053,13 @@ mainswitch:
ARMword result;
if (AddOverflow(op2, op2, op2d)) {
- SETS;
+ SETQ;
op2d = POS (op2d) ? 0x80000000 : 0x7fffffff;
}
result = op1 - op2d;
if (SubOverflow(op1, op2d, result)) {
- SETS;
+ SETQ;
result = POS (result) ? 0x80000000 : 0x7fffffff;
}
@@ -5863,20 +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);
}
+
return 1;
}
// SADD8/SSUB8
@@ -5901,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 {
@@ -5928,24 +5929,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);
}
state->Reg[rd_idx] = (lo_val1 | lo_val2 << 8 | hi_val1 << 16 | hi_val2 << 24);
@@ -6024,15 +6025,32 @@ 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->GEFlag |= (3 << 16);
+ else
+ state->GEFlag &= ~(3 << 16);
+
+ if (!(h2 & 0xffff0000))
+ state->GEFlag |= (3 << 18);
+ else
+ 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);
- if (h2 & 0xffff0000) state->Cpsr |= (3 << 18);
+
+ if (h1 & 0xffff0000)
+ state->GEFlag |= (3 << 16);
+ else
+ state->GEFlag &= ~(3 << 16);
+
+ if (h2 & 0xffff0000)
+ state->GEFlag |= (3 << 18);
+ else
+ state->GEFlag &= ~(3 << 18);
}
+
state->Reg[rd] = (u32)((h1 & 0xffff) | ((h2 & 0xffff) << 16));
return 1;
}
@@ -6045,10 +6063,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->GEFlag |= (1 << 16);
+ else
+ state->GEFlag &= ~(1 << 16);
+
+ if (!(b2 & 0xffffff00))
+ state->GEFlag |= (1 << 17);
+ else
+ state->GEFlag &= ~(1 << 17);
+
+ if (!(b3 & 0xffffff00))
+ state->GEFlag |= (1 << 18);
+ else
+ state->GEFlag &= ~(1 << 18);
+
+ if (!(b4 & 0xffffff00))
+ state->GEFlag |= (1 << 19);
+ else
+ state->GEFlag &= ~(1 << 19);
}
else { // UADD8
b1 = ((u8)from + (u8)to);
@@ -6057,25 +6091,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);
}
state->Reg[rd] = (u32)(b1 | (b2 & 0xff) << 8 | (b3 & 0xff) << 16 | (b4 & 0xff) << 24);
@@ -6116,7 +6149,7 @@ L_stm_s_takeabort:
u32 rm = (instr >> 0) & 0xF;
u32 from = state->Reg[rn];
u32 to = state->Reg[rm];
- u32 cpsr = state->Cpsr;
+ u32 cpsr = ARMul_GetCPSR(state);
if ((instr & 0xFF0) == 0xFB0) { // SEL
u32 result;
if (cpsr & (1 << 16))
@@ -6172,15 +6205,21 @@ 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)
+ SETQ;
+ } else if (rn_lo < min) {
rn_lo = min;
+ SETQ;
+ }
- if (rn_hi > max)
+ if (rn_hi > max) {
rn_hi = max;
- else if (rn_hi < min)
+ SETQ;
+ } else if (rn_hi < min) {
rn_hi = min;
+ SETQ;
+ }
state->Reg[rd_idx] = (rn_lo & 0xFFFF) | ((rn_hi & 0xFFFF) << 16);
return 1;
@@ -6313,16 +6352,22 @@ 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)
+ SETQ;
+ } else if (rn_lo < 0) {
rn_lo = 0;
+ SETQ;
+ }
- if (max < rn_hi)
+ if (max < rn_hi) {
rn_hi = max;
- else if (rn_hi < 0)
+ SETQ;
+ } else if (rn_hi < 0) {
rn_hi = 0;
-
+ SETQ;
+ }
+
state->Reg[rd_idx] = (rn_lo & 0xFFFF) | ((rn_hi << 16) & 0xFFFF);
return 1;
}
@@ -6427,30 +6472,95 @@ 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);
+ 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);
}
- // SMUSD
- else if ((instr & 0xf0d0) == 0xf050) {
- state->Reg[rd_idx] = (rn_lo * rm_lo) - (rn_hi * rm_hi);
+ // SMUSD and SMLSD
+ else {
+ state->Reg[rd_idx] = product1 - product2;
+
+ if (BITS(12, 15) != 15)
+ state->Reg[rd_idx] += state->Reg[ra_idx];
}
- // SMLAD
- else if ((instr & 0xd0) == 0x10) {
- state->Reg[rd_idx] = (rn_lo * rm_lo) + (rn_hi * rm_hi) + (s32)state->Reg[ra_idx];
+
+ return 1;
+ }
+ break;
+ 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));
}
- // SMLSD
+ // SMLSLD
else {
- state->Reg[rd_idx] = ((rn_lo * rm_lo) - (rn_hi * rm_hi)) + (s32)state->Reg[ra_idx];
+ 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 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)
diff --git a/src/core/arm/interpreter/armsupp.cpp b/src/core/arm/interpreter/armsupp.cpp
index 30519f216..6774f8a74 100644
--- a/src/core/arm/interpreter/armsupp.cpp
+++ b/src/core/arm/interpreter/armsupp.cpp
@@ -227,8 +227,9 @@ ARMul_CPSRAltered (ARMul_State * state)
//state->Cpsr &= ~CBIT;
ASSIGNV ((state->Cpsr & VBIT) != 0);
//state->Cpsr &= ~VBIT;
- ASSIGNS ((state->Cpsr & SBIT) != 0);
- //state->Cpsr &= ~SBIT;
+ ASSIGNQ ((state->Cpsr & QBIT) != 0);
+ //state->Cpsr &= ~QBIT;
+ state->GEFlag = (state->Cpsr & 0x000F0000);
#ifdef MODET
ASSIGNT ((state->Cpsr & TBIT) != 0);
//state->Cpsr &= ~TBIT;
@@ -443,6 +444,14 @@ ARMul_AddOverflow (ARMul_State * state, ARMword a, ARMword b, ARMword result)
ASSIGNV (AddOverflow (a, b, result));
}
+/* Assigns the Q flag if the given result is considered an overflow from the addition of a and b */
+void ARMul_AddOverflowQ(ARMul_State* state, ARMword a, ARMword b)
+{
+ u32 result = a + b;
+ if (((result ^ a) & (u32)0x80000000) && ((a ^ b) & (u32)0x80000000) == 0)
+ SETQ;
+}
+
/* Assigns the C flag after an subtraction of a and b to give result. */
void
diff --git a/src/core/arm/skyeye_common/armdefs.h b/src/core/arm/skyeye_common/armdefs.h
index 28a4a0db4..34eb5aaf7 100644
--- a/src/core/arm/skyeye_common/armdefs.h
+++ b/src/core/arm/skyeye_common/armdefs.h
@@ -198,7 +198,7 @@ struct ARMul_State
//ARMword translate_pc;
/* add armv6 flags dyf:2010-08-09 */
- ARMword GEFlag, EFlag, AFlag, QFlags;
+ ARMword GEFlag, EFlag, AFlag, QFlag;
//chy:2003-08-19, used in arm v5e|xscale
ARMword SFlag;
#ifdef MODET
diff --git a/src/core/arm/skyeye_common/armemu.h b/src/core/arm/skyeye_common/armemu.h
index 7f7c0e682..3ea14b5a3 100644
--- a/src/core/arm/skyeye_common/armemu.h
+++ b/src/core/arm/skyeye_common/armemu.h
@@ -34,7 +34,7 @@
#define ZBIT (1L << 30)
#define CBIT (1L << 29)
#define VBIT (1L << 28)
-#define SBIT (1L << 27)
+#define QBIT (1L << 27)
#define IBIT (1L << 7)
#define FBIT (1L << 6)
#define IFBITS (3L << 6)
@@ -156,13 +156,14 @@
#define R15PCMODE (state->Reg[15] & (R15PCBITS | R15MODEBITS))
#define R15MODE (state->Reg[15] & R15MODEBITS)
-#define ECC ((NFLAG << 31) | (ZFLAG << 30) | (CFLAG << 29) | (VFLAG << 28) | (SFLAG << 27))
+#define ECC ((NFLAG << 31) | (ZFLAG << 30) | (CFLAG << 29) | (VFLAG << 28) | (QFLAG << 27))
#define EINT (IFFLAGS << 6)
#define ER15INT (IFFLAGS << 26)
#define EMODE (state->Mode)
+#define EGEBITS (state->GEFlag & 0x000F0000)
#ifdef MODET
-#define CPSR (ECC | EINT | EMODE | (TFLAG << 5))
+#define CPSR (ECC | EGEBITS | (EFLAG << 9) | (AFLAG << 8) | EINT | (TFLAG << 5) | EMODE)
#else
#define CPSR (ECC | EINT | EMODE)
#endif
@@ -601,6 +602,7 @@ extern ARMword ARMul_SwitchMode (ARMul_State *, ARMword, ARMword);
extern void ARMul_MSRCpsr (ARMul_State *, ARMword, ARMword);
extern void ARMul_SubOverflow (ARMul_State *, ARMword, ARMword, ARMword);
extern void ARMul_AddOverflow (ARMul_State *, ARMword, ARMword, ARMword);
+extern void ARMul_AddOverflowQ(ARMul_State*, ARMword, ARMword);
extern void ARMul_SubCarry (ARMul_State *, ARMword, ARMword, ARMword);
extern void ARMul_AddCarry (ARMul_State *, ARMword, ARMword, ARMword);
extern tdstate ARMul_ThumbDecode (ARMul_State *, ARMword, ARMword, ARMword *);
diff --git a/src/core/hle/service/apt_u.cpp b/src/core/hle/service/apt_u.cpp
index e7df72ed7..d8b261ba7 100644
--- a/src/core/hle/service/apt_u.cpp
+++ b/src/core/hle/service/apt_u.cpp
@@ -315,8 +315,8 @@ Interface::Interface() {
if (file.IsOpen()) {
// Read shared font data
- shared_font.resize(file.GetSize());
- file.ReadBytes(shared_font.data(), file.GetSize());
+ shared_font.resize((size_t)file.GetSize());
+ file.ReadBytes(shared_font.data(), (size_t)file.GetSize());
// Create shared font memory object
shared_font_mem = Kernel::CreateSharedMemory("APT_U:shared_font_mem");
diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp
index 027c68d01..b1a465274 100644
--- a/src/core/hle/service/fs/fs_user.cpp
+++ b/src/core/hle/service/fs/fs_user.cpp
@@ -426,6 +426,23 @@ static void IsSdmcDetected(Service::Interface* self) {
}
/**
+ * FS_User::IsSdmcWriteable service function
+ * Outputs:
+ * 0 : Command header 0x08180000
+ * 1 : Result of function, 0 on success, otherwise error code
+ * 2 : Whether the Sdmc is currently writeable
+ */
+static void IsSdmcWriteable(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+ // If the SD isn't enabled, it can't be writeable...else, stubbed true
+ cmd_buff[2] = Settings::values.use_virtual_sd ? 1 : 0;
+
+ LOG_DEBUG(Service_FS, " (STUBBED)");
+}
+
+/**
* FS_User::FormatSaveData service function,
* formats the SaveData specified by the input path.
* Inputs:
@@ -510,7 +527,7 @@ const FSUserInterface::FunctionInfo FunctionTable[] = {
{0x08150000, nullptr, "GetNandArchiveResource"},
{0x08160000, nullptr, "GetSdmcFatfsErro"},
{0x08170000, IsSdmcDetected, "IsSdmcDetected"},
- {0x08180000, nullptr, "IsSdmcWritable"},
+ {0x08180000, IsSdmcWriteable, "IsSdmcWritable"},
{0x08190042, nullptr, "GetSdmcCid"},
{0x081A0042, nullptr, "GetNandCid"},
{0x081B0000, nullptr, "GetSdmcSpeedInfo"},