+ /*T = (Q == M);*/
+ SET_SR_T (Q == M);
+ /*return T;*/
+}
+
+static void
+dmul_s (uint32_t rm, uint32_t rn)
+{
+ int64_t res = (int64_t)(int32_t)rm * (int64_t)(int32_t)rn;
+ MACH = (uint32_t)((uint64_t)res >> 32);
+ MACL = (uint32_t)res;
+}
+
+static void
+dmul_u (uint32_t rm, uint32_t rn)
+{
+ uint64_t res = (uint64_t)(uint32_t)rm * (uint64_t)(uint32_t)rn;
+ MACH = (uint32_t)(res >> 32);
+ MACL = (uint32_t)res;
+}
+
+static void
+macw (int *regs, unsigned char *memory, int n, int m, int endianw)
+{
+ long tempm, tempn;
+ long prod, macl, sum;
+
+ tempm=RSWAT (regs[m]); regs[m]+=2;
+ tempn=RSWAT (regs[n]); regs[n]+=2;
+
+ macl = MACL;
+ prod = (long) (short) tempm * (long) (short) tempn;
+ sum = prod + macl;
+ if (S)
+ {
+ if ((~(prod ^ macl) & (sum ^ prod)) < 0)
+ {
+ /* MACH's lsb is a sticky overflow bit. */
+ MACH |= 1;
+ /* Store the smallest negative number in MACL if prod is
+ negative, and the largest positive number otherwise. */
+ sum = 0x7fffffff + (prod < 0);
+ }
+ }
+ else
+ {
+ long mach;
+ /* Add to MACH the sign extended product, and carry from low sum. */
+ mach = MACH + (-(prod < 0)) + ((unsigned long) sum < prod);
+ /* Sign extend at 10:th bit in MACH. */
+ MACH = (mach & 0x1ff) | -(mach & 0x200);
+ }
+ MACL = sum;
+}
+
+static void
+macl (int *regs, unsigned char *memory, int n, int m)
+{
+ long tempm, tempn;
+ long macl, mach;
+ long long ans;
+ long long mac64;
+
+ tempm = RSLAT (regs[m]);
+ regs[m] += 4;
+
+ tempn = RSLAT (regs[n]);
+ regs[n] += 4;
+
+ mach = MACH;
+ macl = MACL;
+
+ mac64 = ((long long) macl & 0xffffffff) |
+ ((long long) mach & 0xffffffff) << 32;
+
+ ans = (long long) tempm * (long long) tempn; /* Multiply 32bit * 32bit */
+
+ mac64 += ans; /* Accumulate 64bit + 64 bit */
+
+ macl = (long) (mac64 & 0xffffffff);
+ mach = (long) ((mac64 >> 32) & 0xffffffff);
+
+ if (S) /* Store only 48 bits of the result */
+ {
+ if (mach < 0) /* Result is negative */
+ {
+ mach = mach & 0x0000ffff; /* Mask higher 16 bits */
+ mach |= 0xffff8000; /* Sign extend higher 16 bits */
+ }
+ else
+ mach = mach & 0x00007fff; /* Postive Result */
+ }
+
+ MACL = macl;
+ MACH = mach;
+}
+
+enum {
+ B_BCLR = 0,
+ B_BSET = 1,
+ B_BST = 2,
+ B_BLD = 3,
+ B_BAND = 4,
+ B_BOR = 5,
+ B_BXOR = 6,
+ B_BLDNOT = 11,
+ B_BANDNOT = 12,
+ B_BORNOT = 13,
+
+ MOVB_RM = 0x0000,
+ MOVW_RM = 0x1000,
+ MOVL_RM = 0x2000,
+ FMOV_RM = 0x3000,
+ MOVB_MR = 0x4000,
+ MOVW_MR = 0x5000,
+ MOVL_MR = 0x6000,
+ FMOV_MR = 0x7000,
+ MOVU_BMR = 0x8000,
+ MOVU_WMR = 0x9000,
+};
+
+/* Do extended displacement move instructions. */
+static void
+do_long_move_insn (int op, int disp12, int m, int n, int *thatlock)
+{
+ int memstalls = 0;
+ int thislock = *thatlock;
+ int endianw = global_endianw;
+ int *R = &(saved_state.asregs.regs[0]);
+ unsigned char *memory = saved_state.asregs.memory;
+ int maskb = ~((saved_state.asregs.msize - 1) & ~0);
+ unsigned char *insn_ptr = PT2H (saved_state.asregs.pc);
+
+ switch (op) {
+ case MOVB_RM: /* signed */
+ WBAT (disp12 * 1 + R[n], R[m]);
+ break;
+ case MOVW_RM:
+ WWAT (disp12 * 2 + R[n], R[m]);
+ break;
+ case MOVL_RM:
+ WLAT (disp12 * 4 + R[n], R[m]);
+ break;
+ case FMOV_RM: /* floating point */
+ if (FPSCR_SZ)
+ {
+ MA (1);
+ WDAT (R[n] + 8 * disp12, m);
+ }
+ else
+ WLAT (R[n] + 4 * disp12, FI (m));
+ break;
+ case MOVB_MR:
+ R[n] = RSBAT (disp12 * 1 + R[m]);
+ L (n);
+ break;
+ case MOVW_MR:
+ R[n] = RSWAT (disp12 * 2 + R[m]);
+ L (n);
+ break;
+ case MOVL_MR:
+ R[n] = RLAT (disp12 * 4 + R[m]);
+ L (n);
+ break;
+ case FMOV_MR:
+ if (FPSCR_SZ) {
+ MA (1);
+ RDAT (R[m] + 8 * disp12, n);
+ }
+ else
+ SET_FI (n, RLAT (R[m] + 4 * disp12));
+ break;
+ case MOVU_BMR: /* unsigned */
+ R[n] = RBAT (disp12 * 1 + R[m]);
+ L (n);
+ break;
+ case MOVU_WMR:
+ R[n] = RWAT (disp12 * 2 + R[m]);
+ L (n);
+ break;
+ default:
+ RAISE_EXCEPTION (SIGINT);
+ exit (1);
+ }
+ saved_state.asregs.memstalls += memstalls;
+ *thatlock = thislock;
+}
+
+/* Do binary logical bit-manipulation insns. */
+static void
+do_blog_insn (int imm, int addr, int binop,
+ unsigned char *memory, int maskb)
+{
+ int oldval = RBAT (addr);
+
+ switch (binop) {
+ case B_BCLR: /* bclr.b */
+ WBAT (addr, oldval & ~imm);
+ break;
+ case B_BSET: /* bset.b */
+ WBAT (addr, oldval | imm);
+ break;
+ case B_BST: /* bst.b */
+ if (T)
+ WBAT (addr, oldval | imm);
+ else
+ WBAT (addr, oldval & ~imm);
+ break;
+ case B_BLD: /* bld.b */
+ SET_SR_T ((oldval & imm) != 0);
+ break;
+ case B_BAND: /* band.b */
+ SET_SR_T (T && ((oldval & imm) != 0));
+ break;
+ case B_BOR: /* bor.b */
+ SET_SR_T (T || ((oldval & imm) != 0));
+ break;
+ case B_BXOR: /* bxor.b */
+ SET_SR_T (T ^ ((oldval & imm) != 0));
+ break;
+ case B_BLDNOT: /* bldnot.b */
+ SET_SR_T ((oldval & imm) == 0);
+ break;
+ case B_BANDNOT: /* bandnot.b */
+ SET_SR_T (T && ((oldval & imm) == 0));
+ break;
+ case B_BORNOT: /* bornot.b */
+ SET_SR_T (T || ((oldval & imm) == 0));
+ break;
+ }