+
+ if (state->state->ops.cop2_notify) {
+ /* We must call cop2_notify, handle that in C. */
+ rec_mfc(state, block, offset);
+ return;
+ }
+
+ switch (c.r.rd) {
+ case 4:
+ case 12:
+ case 20:
+ case 26:
+ case 27:
+ case 29:
+ case 30:
+ rt = lightrec_alloc_reg_out(reg_cache, _jit, c.r.rt, REG_EXT);
+ jit_ldxi_s(rt, LIGHTREC_REG_STATE, cp2c_s_offset(c.r.rd));
+ break;
+ default:
+ rt = lightrec_alloc_reg_out(reg_cache, _jit, c.r.rt, REG_ZEXT);
+ jit_ldxi_ui(rt, LIGHTREC_REG_STATE, cp2c_i_offset(c.r.rd));
+ break;
+ }
+
+ lightrec_free_reg(reg_cache, rt);
+}
+
+static void rec_cp2_do_mtc2(struct lightrec_cstate *state,
+ const struct block *block, u16 offset,
+ u8 reg, u8 in_reg)
+{
+ struct regcache *reg_cache = state->reg_cache;
+ jit_state_t *_jit = block->_jit;
+ u8 rt, tmp, tmp2, flags = 0;
+
+ _jit_name(block->_jit, __func__);
+
+ if (state->state->ops.cop2_notify) {
+ /* We must call cop2_notify, handle that in C. */
+ rec_mtc(state, block, offset);
+ return;
+ }
+
+ if (reg == 31)
+ return;
+
+ if (reg == 30)
+ flags |= REG_EXT;
+
+ rt = lightrec_alloc_reg_in(reg_cache, _jit, in_reg, flags);
+
+ switch (reg) {
+ case 15:
+ tmp = lightrec_alloc_reg_temp(reg_cache, _jit);
+ jit_ldxi_i(tmp, LIGHTREC_REG_STATE, cp2d_i_offset(13));
+
+ tmp2 = lightrec_alloc_reg_temp(reg_cache, _jit);
+ jit_ldxi_i(tmp2, LIGHTREC_REG_STATE, cp2d_i_offset(14));
+
+ jit_stxi_i(cp2d_i_offset(12), LIGHTREC_REG_STATE, tmp);
+ jit_stxi_i(cp2d_i_offset(13), LIGHTREC_REG_STATE, tmp2);
+ jit_stxi_i(cp2d_i_offset(14), LIGHTREC_REG_STATE, rt);
+
+ lightrec_free_reg(reg_cache, tmp);
+ lightrec_free_reg(reg_cache, tmp2);
+ break;
+ case 28:
+ tmp = lightrec_alloc_reg_temp(reg_cache, _jit);
+
+ jit_lshi(tmp, rt, 7);
+ jit_andi(tmp, tmp, 0xf80);
+ jit_stxi_s(cp2d_s_offset(9), LIGHTREC_REG_STATE, tmp);
+
+ jit_lshi(tmp, rt, 2);
+ jit_andi(tmp, tmp, 0xf80);
+ jit_stxi_s(cp2d_s_offset(10), LIGHTREC_REG_STATE, tmp);
+
+ jit_rshi(tmp, rt, 3);
+ jit_andi(tmp, tmp, 0xf80);
+ jit_stxi_s(cp2d_s_offset(11), LIGHTREC_REG_STATE, tmp);
+
+ lightrec_free_reg(reg_cache, tmp);
+ break;
+ case 30:
+ tmp = lightrec_alloc_reg_temp(reg_cache, _jit);
+
+ /* if (rt < 0) rt = ~rt; */
+ jit_rshi(tmp, rt, 31);
+ jit_xorr(tmp, rt, tmp);
+
+ /* Count leading zeros */
+ jit_clzr(tmp, tmp);
+ if (__WORDSIZE != 32)
+ jit_subi(tmp, tmp, __WORDSIZE - 32);
+
+ jit_stxi_i(cp2d_i_offset(31), LIGHTREC_REG_STATE, tmp);
+
+ lightrec_free_reg(reg_cache, tmp);
+ fallthrough;
+ default:
+ jit_stxi_i(cp2d_i_offset(reg), LIGHTREC_REG_STATE, rt);
+ break;
+ }
+
+ lightrec_free_reg(reg_cache, rt);