+ unsigned64 lhs, x, y, xcut, ycut, product, result;
+
+ check_mult_hilo (SD_, HIHISTORY, LOHISTORY);
+
+ lhs = (!accumulate_p ? 0 : double_p ? LO : U8_4 (HI, LO));
+ x = GPR[rs];
+ y = GPR[rt];
+
+ /* Work out the canonical form of X and Y from their significant bits. */
+ if (!short_p)
+ {
+ /* Normal sign-extension rule for 32-bit operands. */
+ xcut = EXTEND32 (x);
+ ycut = EXTEND32 (y);
+ }
+ else if (unsigned_p)
+ {
+ /* Operands must be zero-extended 16-bit numbers. */
+ xcut = x & 0xffff;
+ ycut = y & 0xffff;
+ }
+ else
+ {
+ /* Likewise but sign-extended. */
+ xcut = EXTEND16 (x);
+ ycut = EXTEND16 (y);
+ }
+ if (x != xcut || y != ycut)
+ sim_engine_abort (SD, CPU, CIA,
+ "invalid multiplication operand at 0x%08lx\n",
+ (long) CIA);
+
+ TRACE_ALU_INPUT2 (x, y);
+ product = (unsigned_p
+ ? V8_4 (x, 1) * V8_4 (y, 1)
+ : EXTEND32 (x) * EXTEND32 (y));
+ result = (subtract_p ? lhs - product : lhs + product);
+ if (saturate_p)
+ {
+ /* Saturate the result to 32 bits. An unsigned, unsaturated
+ result is zero-extended to 64 bits, but unsigned overflow
+ causes all 64 bits to be set. */
+ if (!unsigned_p && (unsigned64) EXTEND32 (result) != result)
+ result = ((signed64) result < 0 ? -0x7fffffff - 1 : 0x7fffffff);
+ else if (unsigned_p && (result >> 32) != 0)
+ result = (unsigned64) 0 - 1;
+ }
+ TRACE_ALU_RESULT (result);
+
+ if (double_p)
+ LO = result;
+ else
+ {
+ LO = EXTEND32 (result);
+ HI = EXTEND32 (VH4_8 (result));
+ }
+ if (rd != 0)
+ GPR[rd] = store_hi_p ? HI : LO;