+static int is_mflohi(int i)
+{
+ return (dops[i].itype == MOV && (dops[i].rs1 == HIREG || dops[i].rs1 == LOREG));
+}
+
+static int check_multdiv(int i, int *cycles)
+{
+ if (dops[i].itype != MULTDIV)
+ return 0;
+ if (dops[i].opcode2 == 0x18 || dops[i].opcode2 == 0x19) // MULT(U)
+ *cycles = 11; // approx from 7 11 14
+ else
+ *cycles = 37;
+ return 1;
+}
+
+static void multdiv_prepare_stall(int i, const struct regstat *i_regs, int ccadj_)
+{
+ int j, found = 0, c = 0;
+ if (HACK_ENABLED(NDHACK_NO_STALLS))
+ return;
+ if (get_reg(i_regs->regmap, CCREG) != HOST_CCREG) {
+ // happens occasionally... cc evicted? Don't bother then
+ return;
+ }
+ for (j = i + 1; j < slen; j++) {
+ if (dops[j].bt)
+ break;
+ if ((found = is_mflohi(j)))
+ break;
+ if (dops[j].is_jump) {
+ // check ds
+ if (j + 1 < slen && (found = is_mflohi(j + 1)))
+ j++;
+ break;
+ }
+ }
+ if (found)
+ // handle all in multdiv_do_stall()
+ return;
+ check_multdiv(i, &c);
+ assert(c > 0);
+ assem_debug("; muldiv prepare stall %d\n", c);
+ host_tempreg_acquire();
+ emit_addimm(HOST_CCREG, ccadj_ + c, HOST_TEMPREG);
+ emit_writeword(HOST_TEMPREG, &psxRegs.muldivBusyCycle);
+ host_tempreg_release();
+}
+
+static void multdiv_do_stall(int i, const struct regstat *i_regs)
+{
+ int j, known_cycles = 0;
+ u_int reglist = get_host_reglist(i_regs->regmap);
+ int rtmp = get_reg(i_regs->regmap, -1);
+ if (rtmp < 0)
+ rtmp = reglist_find_free(reglist);
+ if (HACK_ENABLED(NDHACK_NO_STALLS))
+ return;
+ if (get_reg(i_regs->regmap, CCREG) != HOST_CCREG || rtmp < 0) {
+ // happens occasionally... cc evicted? Don't bother then
+ //printf("no cc/rtmp %08x\n", start + i*4);
+ return;
+ }
+ if (!dops[i].bt) {
+ for (j = i - 1; j >= 0; j--) {
+ if (dops[j].is_ds) break;
+ if (check_multdiv(j, &known_cycles))
+ break;
+ if (is_mflohi(j))
+ // already handled by this op
+ return;
+ if (dops[j].bt || (j > 0 && ccadj[j - 1] > ccadj[j]))
+ break;
+ }
+ j = max(j, 0);
+ }
+ if (known_cycles > 0) {
+ known_cycles -= ccadj[i] - ccadj[j];
+ assem_debug("; muldiv stall resolved %d\n", known_cycles);
+ if (known_cycles > 0)
+ emit_addimm(HOST_CCREG, known_cycles, HOST_CCREG);
+ return;
+ }
+ assem_debug("; muldiv stall unresolved\n");
+ host_tempreg_acquire();
+ emit_readword(&psxRegs.muldivBusyCycle, rtmp);
+ emit_addimm(rtmp, -ccadj[i], rtmp);
+ emit_sub(rtmp, HOST_CCREG, HOST_TEMPREG);
+ emit_cmpimm(HOST_TEMPREG, 37);
+ emit_cmovb_reg(rtmp, HOST_CCREG);
+ //emit_log_gte_stall(i, 0, reglist);
+ host_tempreg_release();
+}
+