diff options
Diffstat (limited to 'ARMInterpreter_ALU.cpp')
-rw-r--r-- | ARMInterpreter_ALU.cpp | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/ARMInterpreter_ALU.cpp b/ARMInterpreter_ALU.cpp index 8e897b6..88b69e7 100644 --- a/ARMInterpreter_ALU.cpp +++ b/ARMInterpreter_ALU.cpp @@ -863,6 +863,101 @@ void A_SMLAL(ARM* cpu) cpu->Cycles += cycles; } +void A_SMLAxy(ARM* cpu) +{ + // TODO: ARM9 only + + u32 rm = cpu->R[cpu->CurInstr & 0xF]; + u32 rs = cpu->R[(cpu->CurInstr >> 8) & 0xF]; + u32 rn = cpu->R[(cpu->CurInstr >> 12) & 0xF]; + + if (cpu->CurInstr & (1<<5)) rm >>= 16; + else rm &= 0xFFFF; + if (cpu->CurInstr & (1<<6)) rs >>= 16; + else rs &= 0xFFFF; + + u32 res_mul = ((s16)rm * (s16)rs); + u32 res = res_mul + rn; + + cpu->R[(cpu->CurInstr >> 16) & 0xF] = res; + if (OVERFLOW_ADD(res_mul, rn, res)) + cpu->CPSR |= 0x08000000; +} + +void A_SMLAWy(ARM* cpu) +{ + // TODO: ARM9 only + + u32 rm = cpu->R[cpu->CurInstr & 0xF]; + u32 rs = cpu->R[(cpu->CurInstr >> 8) & 0xF]; + u32 rn = cpu->R[(cpu->CurInstr >> 12) & 0xF]; + + if (cpu->CurInstr & (1<<6)) rs >>= 16; + else rs &= 0xFFFF; + + u32 res_mul = ((s32)rm * (s16)rs) >> 16; // CHECKME + u32 res = res_mul + rn; + + cpu->R[(cpu->CurInstr >> 16) & 0xF] = res; + if (OVERFLOW_ADD(res_mul, rn, res)) + cpu->CPSR |= 0x08000000; +} + +void A_SMULxy(ARM* cpu) +{ + // TODO: ARM9 only + + u32 rm = cpu->R[cpu->CurInstr & 0xF]; + u32 rs = cpu->R[(cpu->CurInstr >> 8) & 0xF]; + + if (cpu->CurInstr & (1<<5)) rm >>= 16; + else rm &= 0xFFFF; + if (cpu->CurInstr & (1<<6)) rs >>= 16; + else rs &= 0xFFFF; + + u32 res = ((s16)rm * (s16)rs); + + cpu->R[(cpu->CurInstr >> 16) & 0xF] = res; +} + +void A_SMULWy(ARM* cpu) +{ + // TODO: ARM9 only + + u32 rm = cpu->R[cpu->CurInstr & 0xF]; + u32 rs = cpu->R[(cpu->CurInstr >> 8) & 0xF]; + + if (cpu->CurInstr & (1<<6)) rs >>= 16; + else rs &= 0xFFFF; + + u32 res = ((s32)rm * (s16)rs) >> 16; // CHECKME + + cpu->R[(cpu->CurInstr >> 16) & 0xF] = res; +} + +void A_SMLALxy(ARM* cpu) +{ + // TODO: ARM9 only + + u32 rm = cpu->R[cpu->CurInstr & 0xF]; + u32 rs = cpu->R[(cpu->CurInstr >> 8) & 0xF]; + + if (cpu->CurInstr & (1<<5)) rm >>= 16; + else rm &= 0xFFFF; + if (cpu->CurInstr & (1<<6)) rs >>= 16; + else rs &= 0xFFFF; + + s64 res = (s64)(s16)rm * (s64)(s16)rs; + + s64 rd = (s64)((u64)cpu->R[(cpu->CurInstr >> 12) & 0xF] | ((u64)cpu->R[(cpu->CurInstr >> 16) & 0xF] << 32ULL)); + res += rd; + + cpu->R[(cpu->CurInstr >> 12) & 0xF] = (u32)res; + cpu->R[(cpu->CurInstr >> 16) & 0xF] = (u32)(res >> 32ULL); + + cpu->Cycles += 1; +} + void A_CLZ(ARM* cpu) @@ -888,6 +983,90 @@ void A_CLZ(ARM* cpu) cpu->R[(cpu->CurInstr >> 12) & 0xF] = res; } +void A_QADD(ARM* cpu) +{ + // TODO: ARM9 only + + u32 rm = cpu->R[cpu->CurInstr & 0xF]; + u32 rn = cpu->R[(cpu->CurInstr >> 16) & 0xF]; + + u32 res = rm + rn; + if (OVERFLOW_ADD(rm, rn, res)) + { + res = (res & 0x80000000) ? 0x7FFFFFFF : 0x80000000; + cpu->CPSR |= 0x08000000; + } + + cpu->R[(cpu->CurInstr >> 16) & 0xF] = res; +} + +void A_QSUB(ARM* cpu) +{ + // TODO: ARM9 only + + u32 rm = cpu->R[cpu->CurInstr & 0xF]; + u32 rn = cpu->R[(cpu->CurInstr >> 16) & 0xF]; + + u32 res = rm - rn; + if (OVERFLOW_SUB(rm, rn, res)) + { + res = (res & 0x80000000) ? 0x7FFFFFFF : 0x80000000; + cpu->CPSR |= 0x08000000; + } + + cpu->R[(cpu->CurInstr >> 16) & 0xF] = res; +} + +void A_QDADD(ARM* cpu) +{ + // TODO: ARM9 only + + u32 rm = cpu->R[cpu->CurInstr & 0xF]; + u32 rn = cpu->R[(cpu->CurInstr >> 16) & 0xF]; + + if (rn & 0x40000000) + { + rn = (rn & 0x80000000) ? 0x80000000 : 0x7FFFFFFF; + cpu->CPSR |= 0x08000000; // CHECKME + } + else + rn <<= 1; + + u32 res = rm + rn; + if (OVERFLOW_ADD(rm, rn, res)) + { + res = (res & 0x80000000) ? 0x7FFFFFFF : 0x80000000; + cpu->CPSR |= 0x08000000; + } + + cpu->R[(cpu->CurInstr >> 16) & 0xF] = res; +} + +void A_QDSUB(ARM* cpu) +{ + // TODO: ARM9 only + + u32 rm = cpu->R[cpu->CurInstr & 0xF]; + u32 rn = cpu->R[(cpu->CurInstr >> 16) & 0xF]; + + if (rn & 0x40000000) + { + rn = (rn & 0x80000000) ? 0x80000000 : 0x7FFFFFFF; + cpu->CPSR |= 0x08000000; // CHECKME + } + else + rn <<= 1; + + u32 res = rm - rn; + if (OVERFLOW_SUB(rm, rn, res)) + { + res = (res & 0x80000000) ? 0x7FFFFFFF : 0x80000000; + cpu->CPSR |= 0x08000000; + } + + cpu->R[(cpu->CurInstr >> 16) & 0xF] = res; +} + // ---- THUMB ---------------------------------- |