//64bit multiply instructions (SMULL/UMULL/SMLAL/UMLAL) internal uint ExecuteDataOpMultiplyLong(DataOpMultiplyLongRaw opHandler, uint opcode, bool setflags) { //See comment in ExecuteDataOpMultiply uint Rm = (opcode) & 0xf; uint Rs = (opcode >> 8) & 0xf; uint RdHi = (opcode >> 16) & 0xf; uint RdLo = (opcode >> 12) & 0xf; uint rs_value = get_reg(Rs); uint rm_value = get_reg(Rm); UInt64 rdhilo_value = (((UInt64)get_reg(RdHi)) << 32) | (UInt64)get_reg(RdLo); //The number of cycles taken for multiplication varies depending //on the magnitude of rs_value. uint M = calculateMultM(rs_value); LongMultiplyOpResult result = opHandler(rdhilo_value, rs_value, rm_value); mGPR[RdHi] = (UInt32)((result.output_value >> 32) & 0xffffffff); mGPR[RdLo] = (UInt32)((result.output_value) & 0xffffffff); //If we set the flags after a long multiply, the N flag is based on bit 63, not bit 31. if (setflags) { CPSR.set_NZCV((result.output_value & 0x8000000000000000) != 0, result.output_value == 0, CPSR.cf, CPSR.vf); } return(result.cycles + M); }
} //calculateMultM //32bit multiply instructions (MUL/MLA) internal uint ExecuteDataOpMultiply(DataOpMultiplyRaw opHandler, uint opcode, bool setflags) { //The original code used the masks rd_mask, rn_mask, rm_mask and rs_mask here //But the operands are in a strange order so the masks were used in a confusing way. //Therefore, we have one of the rare cases where it's better to use magic numbers... uint Rm = (opcode) & 0xf; uint Rs = (opcode >> 8) & 0xf; uint Rd = (opcode >> 16) & 0xf; uint Rn = (opcode >> 12) & 0xf; uint rs_value = get_reg(Rs); uint rm_value = get_reg(Rm); uint rn_value = get_reg(Rn); //The number of cycles taken for multiplication varies depending //on the magnitude of rs_value. uint M = calculateMultM(rs_value); MultiplyOpResult result = opHandler(rn_value, rs_value, rm_value); mGPR[Rd] = result.output_value; if (setflags) { CPSR.set_NZCV((result.output_value & 0x80000000) != 0, result.output_value == 0, CPSR.cf, CPSR.vf); } return(M + result.cycles); }
internal void DataOpHandleSetFlagsAWC_CMP(uint opcode, uint Rd, AWCResult awcResult) { //The CPSR is set the same way for all AWC-based instructions (the only difference //is the input to AWC). CPSR.set_NZCV((awcResult.result & 0x80000000) != 0, awcResult.result == 0, awcResult.carry_out, awcResult.overflow); }
internal void DataOpHandleSetFlagsLogical_CMP(uint opcode, uint Rd, uint result, bool shift_carry) { //The CPSR is always set the same way for logical operations //cf. MOV (ARMv7 A8.8.102) CPSR.set_NZCV((result & 0x80000000) != 0, result == 0, shift_carry, CPSR.vf); }