//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); }
internal void RegisterDataOpMultiply(DataOpMultiplyLongRaw opHandler, uint base_opcode, bool supports_setflags, string basename) { RegisterOpcode(base_opcode, 0xf00fff0f, delegate(uint opcode) { return(ExecuteDataOpMultiplyLong(opHandler, opcode, false)); }, basename); if (supports_setflags) { RegisterOpcode(base_opcode | s_mask, 0xf00fff0f, delegate(uint opcode) { return(ExecuteDataOpMultiplyLong(opHandler, opcode, true)); }, basename + "S"); } }