+ // case 0x18: MULT
+ // case 0x19: MULTU
+ // case 0x1A: DIV
+ // case 0x1B: DIVU
+ if(dops[i].rs1&&dops[i].rs2)
+ {
+ switch(dops[i].opcode2)
+ {
+ case 0x18: // MULT
+ case 0x19: // MULTU
+ {
+ signed char m1=get_reg(i_regs->regmap,dops[i].rs1);
+ signed char m2=get_reg(i_regs->regmap,dops[i].rs2);
+ signed char hi=get_reg(i_regs->regmap,HIREG);
+ signed char lo=get_reg(i_regs->regmap,LOREG);
+ assert(m1>=0);
+ assert(m2>=0);
+ assert(hi>=0);
+ assert(lo>=0);
+
+ if(dops[i].opcode2==0x18) // MULT
+ emit_smull(m1,m2,hi);
+ else // MULTU
+ emit_umull(m1,m2,hi);
+
+ emit_mov(hi,lo);
+ emit_shrimm64(hi,32,hi);
+ break;
+ }
+ case 0x1A: // DIV
+ case 0x1B: // DIVU
+ {
+ signed char numerator=get_reg(i_regs->regmap,dops[i].rs1);
+ signed char denominator=get_reg(i_regs->regmap,dops[i].rs2);
+ signed char quotient=get_reg(i_regs->regmap,LOREG);
+ signed char remainder=get_reg(i_regs->regmap,HIREG);
+ assert(numerator>=0);
+ assert(denominator>=0);
+ assert(quotient>=0);
+ assert(remainder>=0);
+
+ if (dops[i].opcode2 == 0x1A) // DIV
+ emit_sdiv(numerator,denominator,quotient);
+ else // DIVU
+ emit_udiv(numerator,denominator,quotient);
+ emit_msub(quotient,denominator,numerator,remainder);
+
+ // div 0 quotient (remainder is already correct)
+ host_tempreg_acquire();
+ if (dops[i].opcode2 == 0x1A) // DIV
+ emit_sub_asrimm(0,numerator,31,HOST_TEMPREG);
+ else
+ emit_movimm(~0,HOST_TEMPREG);
+ emit_test(denominator,denominator);
+ emit_cmoveq_reg(HOST_TEMPREG,quotient);
+ host_tempreg_release();
+ break;
+ }
+ default:
+ assert(0);
+ }
+ }
+ else
+ {
+ signed char hr=get_reg(i_regs->regmap,HIREG);
+ signed char lr=get_reg(i_regs->regmap,LOREG);
+ if ((dops[i].opcode2==0x1A || dops[i].opcode2==0x1B) && dops[i].rs2==0) // div 0
+ {
+ if (dops[i].rs1) {
+ signed char numerator = get_reg(i_regs->regmap, dops[i].rs1);
+ assert(numerator >= 0);
+ if (hr >= 0)
+ emit_mov(numerator,hr);
+ if (lr >= 0) {
+ if (dops[i].opcode2 == 0x1A) // DIV
+ emit_sub_asrimm(0,numerator,31,lr);
+ else
+ emit_movimm(~0,lr);
+ }
+ }
+ else {
+ if (hr >= 0) emit_zeroreg(hr);
+ if (lr >= 0) emit_movimm(~0,lr);
+ }
+ }
+ else
+ {
+ // Multiply by zero is zero.
+ if (hr >= 0) emit_zeroreg(hr);
+ if (lr >= 0) emit_zeroreg(lr);
+ }
+ }