1 // SPDX-License-Identifier: LGPL-2.1-or-later
3 * Copyright (C) 2014-2021 Paul Cercueil <paul@crapouillou.net>
6 #include "blockcache.h"
8 #include "disassembler.h"
10 #include "lightning-wrapper.h"
11 #include "optimizer.h"
17 typedef void (*lightrec_rec_func_t)(struct lightrec_cstate *, const struct block *, u16);
19 /* Forward declarations */
20 static void rec_SPECIAL(struct lightrec_cstate *state, const struct block *block, u16 offset);
21 static void rec_REGIMM(struct lightrec_cstate *state, const struct block *block, u16 offset);
22 static void rec_CP0(struct lightrec_cstate *state, const struct block *block, u16 offset);
23 static void rec_CP2(struct lightrec_cstate *state, const struct block *block, u16 offset);
25 static void unknown_opcode(struct lightrec_cstate *state, const struct block *block, u16 offset)
27 pr_warn("Unknown opcode: 0x%08x at PC 0x%08x\n",
28 block->opcode_list[offset].c.opcode,
29 block->pc + (offset << 2));
32 static void lightrec_emit_end_of_block(struct lightrec_cstate *state,
33 const struct block *block, u16 offset,
34 s8 reg_new_pc, u32 imm, u8 ra_reg,
35 u32 link, bool update_cycles)
37 struct regcache *reg_cache = state->reg_cache;
38 u32 cycles = state->cycles;
39 jit_state_t *_jit = block->_jit;
40 const struct opcode *op = &block->opcode_list[offset],
41 *next = &block->opcode_list[offset + 1];
43 jit_note(__FILE__, __LINE__);
46 /* Update the $ra register */
47 u8 link_reg = lightrec_alloc_reg_out(reg_cache, _jit, ra_reg, 0);
48 jit_movi(link_reg, link);
49 lightrec_free_reg(reg_cache, link_reg);
53 reg_new_pc = lightrec_alloc_reg(reg_cache, _jit, JIT_V0);
54 lightrec_lock_reg(reg_cache, _jit, reg_new_pc);
56 jit_movi(reg_new_pc, imm);
59 if (has_delay_slot(op->c) &&
60 !(op->flags & (LIGHTREC_NO_DS | LIGHTREC_LOCAL_BRANCH))) {
61 cycles += lightrec_cycles_of_opcode(next->c);
63 /* Recompile the delay slot */
65 lightrec_rec_opcode(state, block, offset + 1);
68 /* Store back remaining registers */
69 lightrec_storeback_regs(reg_cache, _jit);
71 jit_movr(JIT_V0, reg_new_pc);
73 if (cycles && update_cycles) {
74 jit_subi(LIGHTREC_REG_CYCLE, LIGHTREC_REG_CYCLE, cycles);
75 pr_debug("EOB: %u cycles\n", cycles);
78 if (offset + !!(op->flags & LIGHTREC_NO_DS) < block->nb_ops - 1)
79 state->branches[state->nb_branches++] = jit_b();
82 void lightrec_emit_eob(struct lightrec_cstate *state, const struct block *block,
83 u16 offset, bool after_op)
85 struct regcache *reg_cache = state->reg_cache;
86 jit_state_t *_jit = block->_jit;
87 union code c = block->opcode_list[offset].c;
88 u32 cycles = state->cycles;
91 cycles -= lightrec_cycles_of_opcode(c);
93 lightrec_storeback_regs(reg_cache, _jit);
95 jit_movi(JIT_V0, block->pc + (offset << 2));
96 jit_subi(LIGHTREC_REG_CYCLE, LIGHTREC_REG_CYCLE, cycles);
98 state->branches[state->nb_branches++] = jit_b();
101 static u8 get_jr_jalr_reg(struct lightrec_cstate *state, const struct block *block, u16 offset)
103 struct regcache *reg_cache = state->reg_cache;
104 jit_state_t *_jit = block->_jit;
105 const struct opcode *op = &block->opcode_list[offset];
108 rs = lightrec_request_reg_in(reg_cache, _jit, op->r.rs, JIT_V0);
109 lightrec_lock_reg(reg_cache, _jit, rs);
114 static void rec_special_JR(struct lightrec_cstate *state, const struct block *block, u16 offset)
116 u8 rs = get_jr_jalr_reg(state, block, offset);
118 _jit_name(block->_jit, __func__);
119 lightrec_emit_end_of_block(state, block, offset, rs, 0, 31, 0, true);
122 static void rec_special_JALR(struct lightrec_cstate *state, const struct block *block, u16 offset)
124 u8 rs = get_jr_jalr_reg(state, block, offset);
125 union code c = block->opcode_list[offset].c;
127 _jit_name(block->_jit, __func__);
128 lightrec_emit_end_of_block(state, block, offset, rs, 0, c.r.rd,
129 get_branch_pc(block, offset, 2), true);
132 static void rec_J(struct lightrec_cstate *state, const struct block *block, u16 offset)
134 union code c = block->opcode_list[offset].c;
136 _jit_name(block->_jit, __func__);
137 lightrec_emit_end_of_block(state, block, offset, -1,
138 (block->pc & 0xf0000000) | (c.j.imm << 2),
142 static void rec_JAL(struct lightrec_cstate *state, const struct block *block, u16 offset)
144 union code c = block->opcode_list[offset].c;
146 _jit_name(block->_jit, __func__);
147 lightrec_emit_end_of_block(state, block, offset, -1,
148 (block->pc & 0xf0000000) | (c.j.imm << 2),
149 31, get_branch_pc(block, offset, 2), true);
152 static void rec_b(struct lightrec_cstate *state, const struct block *block, u16 offset,
153 jit_code_t code, u32 link, bool unconditional, bool bz)
155 struct regcache *reg_cache = state->reg_cache;
156 struct native_register *regs_backup;
157 jit_state_t *_jit = block->_jit;
158 struct lightrec_branch *branch;
159 const struct opcode *op = &block->opcode_list[offset],
160 *next = &block->opcode_list[offset + 1];
163 u32 target_offset, cycles = state->cycles;
164 bool is_forward = (s16)op->i.imm >= -1;
167 jit_note(__FILE__, __LINE__);
169 if (!(op->flags & LIGHTREC_NO_DS))
170 cycles += lightrec_cycles_of_opcode(next->c);
175 jit_subi(LIGHTREC_REG_CYCLE, LIGHTREC_REG_CYCLE, cycles);
177 if (!unconditional) {
178 u8 rs = lightrec_alloc_reg_in(reg_cache, _jit, op->i.rs, REG_EXT),
179 rt = bz ? 0 : lightrec_alloc_reg_in(reg_cache,
180 _jit, op->i.rt, REG_EXT);
182 /* Generate the branch opcode */
183 addr = jit_new_node_pww(code, NULL, rs, rt);
185 lightrec_free_regs(reg_cache);
186 regs_backup = lightrec_regcache_enter_branch(reg_cache);
189 if (op->flags & LIGHTREC_LOCAL_BRANCH) {
190 if (next && !(op->flags & LIGHTREC_NO_DS)) {
191 /* Recompile the delay slot */
193 lightrec_rec_opcode(state, block, offset + 1);
197 /* Update the $ra register */
198 link_reg = lightrec_alloc_reg_out(reg_cache, _jit, 31, 0);
199 jit_movi(link_reg, link);
200 lightrec_free_reg(reg_cache, link_reg);
203 /* Store back remaining registers */
204 lightrec_storeback_regs(reg_cache, _jit);
206 target_offset = offset + 1 + (s16)op->i.imm
207 - !!(OPT_SWITCH_DELAY_SLOTS && (op->flags & LIGHTREC_NO_DS));
208 pr_debug("Adding local branch to offset 0x%x\n",
210 branch = &state->local_branches[
211 state->nb_local_branches++];
213 branch->target = target_offset;
215 branch->branch = jit_b();
217 branch->branch = jit_bgti(LIGHTREC_REG_CYCLE, 0);
220 if (!(op->flags & LIGHTREC_LOCAL_BRANCH) || !is_forward) {
221 next_pc = get_branch_pc(block, offset, 1 + (s16)op->i.imm);
222 lightrec_emit_end_of_block(state, block, offset, -1, next_pc,
226 if (!unconditional) {
228 lightrec_regcache_leave_branch(reg_cache, regs_backup);
231 /* Update the $ra register */
232 link_reg = lightrec_alloc_reg_out(reg_cache, _jit,
234 jit_movi(link_reg, (s32)link);
235 lightrec_free_reg(reg_cache, link_reg);
238 if (!(op->flags & LIGHTREC_NO_DS) && next->opcode)
239 lightrec_rec_opcode(state, block, offset + 1);
243 static void rec_BNE(struct lightrec_cstate *state,
244 const struct block *block, u16 offset)
246 union code c = block->opcode_list[offset].c;
248 _jit_name(block->_jit, __func__);
251 rec_b(state, block, offset, jit_code_beqi, 0, false, true);
253 rec_b(state, block, offset, jit_code_beqr, 0, false, false);
256 static void rec_BEQ(struct lightrec_cstate *state,
257 const struct block *block, u16 offset)
259 union code c = block->opcode_list[offset].c;
261 _jit_name(block->_jit, __func__);
264 rec_b(state, block, offset, jit_code_bnei, 0, c.i.rs == 0, true);
266 rec_b(state, block, offset, jit_code_bner, 0, c.i.rs == c.i.rt, false);
269 static void rec_BLEZ(struct lightrec_cstate *state,
270 const struct block *block, u16 offset)
272 union code c = block->opcode_list[offset].c;
274 _jit_name(block->_jit, __func__);
275 rec_b(state, block, offset, jit_code_bgti, 0, c.i.rs == 0, true);
278 static void rec_BGTZ(struct lightrec_cstate *state,
279 const struct block *block, u16 offset)
281 _jit_name(block->_jit, __func__);
282 rec_b(state, block, offset, jit_code_blei, 0, false, true);
285 static void rec_regimm_BLTZ(struct lightrec_cstate *state,
286 const struct block *block, u16 offset)
288 _jit_name(block->_jit, __func__);
289 rec_b(state, block, offset, jit_code_bgei, 0, false, true);
292 static void rec_regimm_BLTZAL(struct lightrec_cstate *state,
293 const struct block *block, u16 offset)
295 _jit_name(block->_jit, __func__);
296 rec_b(state, block, offset, jit_code_bgei,
297 get_branch_pc(block, offset, 2), false, true);
300 static void rec_regimm_BGEZ(struct lightrec_cstate *state,
301 const struct block *block, u16 offset)
303 union code c = block->opcode_list[offset].c;
305 _jit_name(block->_jit, __func__);
306 rec_b(state, block, offset, jit_code_blti, 0, !c.i.rs, true);
309 static void rec_regimm_BGEZAL(struct lightrec_cstate *state,
310 const struct block *block, u16 offset)
312 const struct opcode *op = &block->opcode_list[offset];
313 _jit_name(block->_jit, __func__);
314 rec_b(state, block, offset, jit_code_blti,
315 get_branch_pc(block, offset, 2),
319 static void rec_alu_imm(struct lightrec_cstate *state, const struct block *block,
320 u16 offset, jit_code_t code, bool slti)
322 struct regcache *reg_cache = state->reg_cache;
323 union code c = block->opcode_list[offset].c;
324 jit_state_t *_jit = block->_jit;
325 u8 rs, rt, out_flags = REG_EXT;
328 out_flags |= REG_ZEXT;
330 jit_note(__FILE__, __LINE__);
331 rs = lightrec_alloc_reg_in(reg_cache, _jit, c.i.rs, REG_EXT);
332 rt = lightrec_alloc_reg_out(reg_cache, _jit, c.i.rt, out_flags);
334 jit_new_node_www(code, rt, rs, (s32)(s16) c.i.imm);
336 lightrec_free_reg(reg_cache, rs);
337 lightrec_free_reg(reg_cache, rt);
340 static void rec_alu_special(struct lightrec_cstate *state, const struct block *block,
341 u16 offset, jit_code_t code, bool out_ext)
343 struct regcache *reg_cache = state->reg_cache;
344 union code c = block->opcode_list[offset].c;
345 jit_state_t *_jit = block->_jit;
348 jit_note(__FILE__, __LINE__);
349 rs = lightrec_alloc_reg_in(reg_cache, _jit, c.r.rs, REG_EXT);
350 rt = lightrec_alloc_reg_in(reg_cache, _jit, c.r.rt, REG_EXT);
351 rd = lightrec_alloc_reg_out(reg_cache, _jit, c.r.rd,
352 out_ext ? REG_EXT | REG_ZEXT : 0);
354 jit_new_node_www(code, rd, rs, rt);
356 lightrec_free_reg(reg_cache, rs);
357 lightrec_free_reg(reg_cache, rt);
358 lightrec_free_reg(reg_cache, rd);
361 static void rec_alu_shiftv(struct lightrec_cstate *state, const struct block *block,
362 u16 offset, jit_code_t code)
364 struct regcache *reg_cache = state->reg_cache;
365 union code c = block->opcode_list[offset].c;
366 jit_state_t *_jit = block->_jit;
367 u8 rd, rt, rs, temp, flags = 0;
369 jit_note(__FILE__, __LINE__);
370 rs = lightrec_alloc_reg_in(reg_cache, _jit, c.r.rs, 0);
372 if (code == jit_code_rshr)
374 else if (code == jit_code_rshr_u)
377 rt = lightrec_alloc_reg_in(reg_cache, _jit, c.r.rt, flags);
378 rd = lightrec_alloc_reg_out(reg_cache, _jit, c.r.rd, flags);
380 if (rs != rd && rt != rd) {
381 jit_andi(rd, rs, 0x1f);
382 jit_new_node_www(code, rd, rt, rd);
384 temp = lightrec_alloc_reg_temp(reg_cache, _jit);
385 jit_andi(temp, rs, 0x1f);
386 jit_new_node_www(code, rd, rt, temp);
387 lightrec_free_reg(reg_cache, temp);
390 lightrec_free_reg(reg_cache, rs);
391 lightrec_free_reg(reg_cache, rt);
392 lightrec_free_reg(reg_cache, rd);
395 static void rec_ADDIU(struct lightrec_cstate *state,
396 const struct block *block, u16 offset)
398 _jit_name(block->_jit, __func__);
399 rec_alu_imm(state, block, offset, jit_code_addi, false);
402 static void rec_ADDI(struct lightrec_cstate *state,
403 const struct block *block, u16 offset)
405 /* TODO: Handle the exception? */
406 _jit_name(block->_jit, __func__);
407 rec_alu_imm(state, block, offset, jit_code_addi, false);
410 static void rec_SLTIU(struct lightrec_cstate *state,
411 const struct block *block, u16 offset)
413 _jit_name(block->_jit, __func__);
414 rec_alu_imm(state, block, offset, jit_code_lti_u, true);
417 static void rec_SLTI(struct lightrec_cstate *state,
418 const struct block *block, u16 offset)
420 _jit_name(block->_jit, __func__);
421 rec_alu_imm(state, block, offset, jit_code_lti, true);
424 static void rec_ANDI(struct lightrec_cstate *state,
425 const struct block *block, u16 offset)
427 struct regcache *reg_cache = state->reg_cache;
428 union code c = block->opcode_list[offset].c;
429 jit_state_t *_jit = block->_jit;
432 _jit_name(block->_jit, __func__);
433 jit_note(__FILE__, __LINE__);
434 rs = lightrec_alloc_reg_in(reg_cache, _jit, c.i.rs, 0);
435 rt = lightrec_alloc_reg_out(reg_cache, _jit, c.i.rt,
438 /* PSX code uses ANDI 0xff / ANDI 0xffff a lot, which are basically
439 * casts to uint8_t / uint16_t. */
442 else if (c.i.imm == 0xffff)
445 jit_andi(rt, rs, (u32)(u16) c.i.imm);
447 lightrec_free_reg(reg_cache, rs);
448 lightrec_free_reg(reg_cache, rt);
451 static void rec_alu_or_xor(struct lightrec_cstate *state, const struct block *block,
452 u16 offset, jit_code_t code)
454 struct regcache *reg_cache = state->reg_cache;
455 union code c = block->opcode_list[offset].c;
456 jit_state_t *_jit = block->_jit;
459 jit_note(__FILE__, __LINE__);
460 rs = lightrec_alloc_reg_in(reg_cache, _jit, c.i.rs, 0);
461 rt = lightrec_alloc_reg_out(reg_cache, _jit, c.i.rt, 0);
463 flags = lightrec_get_reg_in_flags(reg_cache, rs);
464 lightrec_set_reg_out_flags(reg_cache, rt, flags);
466 jit_new_node_www(code, rt, rs, (u32)(u16) c.i.imm);
468 lightrec_free_reg(reg_cache, rs);
469 lightrec_free_reg(reg_cache, rt);
473 static void rec_ORI(struct lightrec_cstate *state,
474 const struct block *block, u16 offset)
476 _jit_name(block->_jit, __func__);
477 rec_alu_or_xor(state, block, offset, jit_code_ori);
480 static void rec_XORI(struct lightrec_cstate *state,
481 const struct block *block, u16 offset)
483 _jit_name(block->_jit, __func__);
484 rec_alu_or_xor(state, block, offset, jit_code_xori);
487 static void rec_LUI(struct lightrec_cstate *state,
488 const struct block *block, u16 offset)
490 struct regcache *reg_cache = state->reg_cache;
491 union code c = block->opcode_list[offset].c;
492 jit_state_t *_jit = block->_jit;
493 u8 rt, flags = REG_EXT;
496 jit_note(__FILE__, __LINE__);
498 if (!(c.i.imm & BIT(15)))
501 rt = lightrec_alloc_reg_out(reg_cache, _jit, c.i.rt, flags);
503 jit_movi(rt, (s32)(c.i.imm << 16));
505 lightrec_free_reg(reg_cache, rt);
508 static void rec_special_ADDU(struct lightrec_cstate *state,
509 const struct block *block, u16 offset)
511 _jit_name(block->_jit, __func__);
512 rec_alu_special(state, block, offset, jit_code_addr, false);
515 static void rec_special_ADD(struct lightrec_cstate *state,
516 const struct block *block, u16 offset)
518 /* TODO: Handle the exception? */
519 _jit_name(block->_jit, __func__);
520 rec_alu_special(state, block, offset, jit_code_addr, false);
523 static void rec_special_SUBU(struct lightrec_cstate *state,
524 const struct block *block, u16 offset)
526 _jit_name(block->_jit, __func__);
527 rec_alu_special(state, block, offset, jit_code_subr, false);
530 static void rec_special_SUB(struct lightrec_cstate *state,
531 const struct block *block, u16 offset)
533 /* TODO: Handle the exception? */
534 _jit_name(block->_jit, __func__);
535 rec_alu_special(state, block, offset, jit_code_subr, false);
538 static void rec_special_AND(struct lightrec_cstate *state,
539 const struct block *block, u16 offset)
541 struct regcache *reg_cache = state->reg_cache;
542 union code c = block->opcode_list[offset].c;
543 jit_state_t *_jit = block->_jit;
544 u8 rd, rt, rs, flags_rs, flags_rt, flags_rd;
546 _jit_name(block->_jit, __func__);
547 jit_note(__FILE__, __LINE__);
548 rs = lightrec_alloc_reg_in(reg_cache, _jit, c.r.rs, 0);
549 rt = lightrec_alloc_reg_in(reg_cache, _jit, c.r.rt, 0);
550 rd = lightrec_alloc_reg_out(reg_cache, _jit, c.r.rd, 0);
552 flags_rs = lightrec_get_reg_in_flags(reg_cache, rs);
553 flags_rt = lightrec_get_reg_in_flags(reg_cache, rt);
555 /* Z(rd) = Z(rs) | Z(rt) */
556 flags_rd = REG_ZEXT & (flags_rs | flags_rt);
558 /* E(rd) = (E(rt) & Z(rt)) | (E(rs) & Z(rs)) | (E(rs) & E(rt)) */
559 if (((flags_rs & REG_EXT) && (flags_rt & REG_ZEXT)) ||
560 ((flags_rt & REG_EXT) && (flags_rs & REG_ZEXT)) ||
561 (REG_EXT & flags_rs & flags_rt))
564 lightrec_set_reg_out_flags(reg_cache, rd, flags_rd);
566 jit_andr(rd, rs, rt);
568 lightrec_free_reg(reg_cache, rs);
569 lightrec_free_reg(reg_cache, rt);
570 lightrec_free_reg(reg_cache, rd);
573 static void rec_special_or_nor(struct lightrec_cstate *state,
574 const struct block *block, u16 offset, bool nor)
576 struct regcache *reg_cache = state->reg_cache;
577 union code c = block->opcode_list[offset].c;
578 jit_state_t *_jit = block->_jit;
579 u8 rd, rt, rs, flags_rs, flags_rt, flags_rd = 0;
581 jit_note(__FILE__, __LINE__);
582 rs = lightrec_alloc_reg_in(reg_cache, _jit, c.r.rs, 0);
583 rt = lightrec_alloc_reg_in(reg_cache, _jit, c.r.rt, 0);
584 rd = lightrec_alloc_reg_out(reg_cache, _jit, c.r.rd, 0);
586 flags_rs = lightrec_get_reg_in_flags(reg_cache, rs);
587 flags_rt = lightrec_get_reg_in_flags(reg_cache, rt);
589 /* or: Z(rd) = Z(rs) & Z(rt)
592 flags_rd = REG_ZEXT & flags_rs & flags_rt;
594 /* E(rd) = (E(rs) & E(rt)) | (E(rt) & !Z(rt)) | (E(rs) & !Z(rs)) */
595 if ((REG_EXT & flags_rs & flags_rt) ||
596 (flags_rt & (REG_EXT | REG_ZEXT) == REG_EXT) ||
597 (flags_rs & (REG_EXT | REG_ZEXT) == REG_EXT))
600 lightrec_set_reg_out_flags(reg_cache, rd, flags_rd);
607 lightrec_free_reg(reg_cache, rs);
608 lightrec_free_reg(reg_cache, rt);
609 lightrec_free_reg(reg_cache, rd);
612 static void rec_special_OR(struct lightrec_cstate *state,
613 const struct block *block, u16 offset)
615 _jit_name(block->_jit, __func__);
616 rec_special_or_nor(state, block, offset, false);
619 static void rec_special_NOR(struct lightrec_cstate *state,
620 const struct block *block, u16 offset)
622 _jit_name(block->_jit, __func__);
623 rec_special_or_nor(state, block, offset, true);
626 static void rec_special_XOR(struct lightrec_cstate *state,
627 const struct block *block, u16 offset)
629 struct regcache *reg_cache = state->reg_cache;
630 union code c = block->opcode_list[offset].c;
631 jit_state_t *_jit = block->_jit;
632 u8 rd, rt, rs, flags_rs, flags_rt, flags_rd;
634 _jit_name(block->_jit, __func__);
636 jit_note(__FILE__, __LINE__);
637 rs = lightrec_alloc_reg_in(reg_cache, _jit, c.r.rs, 0);
638 rt = lightrec_alloc_reg_in(reg_cache, _jit, c.r.rt, 0);
639 rd = lightrec_alloc_reg_out(reg_cache, _jit, c.r.rd, 0);
641 flags_rs = lightrec_get_reg_in_flags(reg_cache, rs);
642 flags_rt = lightrec_get_reg_in_flags(reg_cache, rt);
644 /* Z(rd) = Z(rs) & Z(rt) */
645 flags_rd = REG_ZEXT & flags_rs & flags_rt;
647 /* E(rd) = E(rs) & E(rt) */
648 flags_rd |= REG_EXT & flags_rs & flags_rt;
650 lightrec_set_reg_out_flags(reg_cache, rd, flags_rd);
652 jit_xorr(rd, rs, rt);
654 lightrec_free_reg(reg_cache, rs);
655 lightrec_free_reg(reg_cache, rt);
656 lightrec_free_reg(reg_cache, rd);
659 static void rec_special_SLTU(struct lightrec_cstate *state,
660 const struct block *block, u16 offset)
662 _jit_name(block->_jit, __func__);
663 rec_alu_special(state, block, offset, jit_code_ltr_u, true);
666 static void rec_special_SLT(struct lightrec_cstate *state,
667 const struct block *block, u16 offset)
669 _jit_name(block->_jit, __func__);
670 rec_alu_special(state, block, offset, jit_code_ltr, true);
673 static void rec_special_SLLV(struct lightrec_cstate *state,
674 const struct block *block, u16 offset)
676 _jit_name(block->_jit, __func__);
677 rec_alu_shiftv(state, block, offset, jit_code_lshr);
680 static void rec_special_SRLV(struct lightrec_cstate *state,
681 const struct block *block, u16 offset)
683 _jit_name(block->_jit, __func__);
684 rec_alu_shiftv(state, block, offset, jit_code_rshr_u);
687 static void rec_special_SRAV(struct lightrec_cstate *state,
688 const struct block *block, u16 offset)
690 _jit_name(block->_jit, __func__);
691 rec_alu_shiftv(state, block, offset, jit_code_rshr);
694 static void rec_alu_shift(struct lightrec_cstate *state, const struct block *block,
695 u16 offset, jit_code_t code)
697 struct regcache *reg_cache = state->reg_cache;
698 union code c = block->opcode_list[offset].c;
699 jit_state_t *_jit = block->_jit;
700 u8 rd, rt, flags = 0;
702 jit_note(__FILE__, __LINE__);
704 if (code == jit_code_rshi)
706 else if (code == jit_code_rshi_u)
709 rt = lightrec_alloc_reg_in(reg_cache, _jit, c.r.rt, flags);
711 /* Input reg is zero-extended, if we SRL at least by one bit, we know
712 * the output reg will be both zero-extended and sign-extended. */
713 if (code == jit_code_rshi_u && c.r.imm)
715 rd = lightrec_alloc_reg_out(reg_cache, _jit, c.r.rd, flags);
717 jit_new_node_www(code, rd, rt, c.r.imm);
719 lightrec_free_reg(reg_cache, rt);
720 lightrec_free_reg(reg_cache, rd);
723 static void rec_special_SLL(struct lightrec_cstate *state,
724 const struct block *block, u16 offset)
726 _jit_name(block->_jit, __func__);
727 rec_alu_shift(state, block, offset, jit_code_lshi);
730 static void rec_special_SRL(struct lightrec_cstate *state,
731 const struct block *block, u16 offset)
733 _jit_name(block->_jit, __func__);
734 rec_alu_shift(state, block, offset, jit_code_rshi_u);
737 static void rec_special_SRA(struct lightrec_cstate *state,
738 const struct block *block, u16 offset)
740 _jit_name(block->_jit, __func__);
741 rec_alu_shift(state, block, offset, jit_code_rshi);
744 static void rec_alu_mult(struct lightrec_cstate *state,
745 const struct block *block, u16 offset, bool is_signed)
747 struct regcache *reg_cache = state->reg_cache;
748 union code c = block->opcode_list[offset].c;
749 u16 flags = block->opcode_list[offset].flags;
750 u8 reg_lo = get_mult_div_lo(c);
751 u8 reg_hi = get_mult_div_hi(c);
752 jit_state_t *_jit = block->_jit;
753 u8 lo, hi, rs, rt, rflags = 0;
755 jit_note(__FILE__, __LINE__);
762 rs = lightrec_alloc_reg_in(reg_cache, _jit, c.r.rs, rflags);
763 rt = lightrec_alloc_reg_in(reg_cache, _jit, c.r.rt, rflags);
765 if (!(flags & LIGHTREC_NO_LO))
766 lo = lightrec_alloc_reg_out(reg_cache, _jit, reg_lo, 0);
767 else if (__WORDSIZE == 32)
768 lo = lightrec_alloc_reg_temp(reg_cache, _jit);
770 if (!(flags & LIGHTREC_NO_HI))
771 hi = lightrec_alloc_reg_out(reg_cache, _jit, reg_hi, REG_EXT);
773 if (__WORDSIZE == 32) {
774 /* On 32-bit systems, do a 32*32->64 bit operation, or a 32*32->32 bit
775 * operation if the MULT was detected a 32-bit only. */
776 if (!(flags & LIGHTREC_NO_HI)) {
778 jit_qmulr(lo, hi, rs, rt);
780 jit_qmulr_u(lo, hi, rs, rt);
782 jit_mulr(lo, rs, rt);
785 /* On 64-bit systems, do a 64*64->64 bit operation. */
786 if (flags & LIGHTREC_NO_LO) {
787 jit_mulr(hi, rs, rt);
788 jit_rshi(hi, hi, 32);
790 jit_mulr(lo, rs, rt);
792 /* The 64-bit output value is in $lo, store the upper 32 bits in $hi */
793 if (!(flags & LIGHTREC_NO_HI))
794 jit_rshi(hi, lo, 32);
798 lightrec_free_reg(reg_cache, rs);
799 lightrec_free_reg(reg_cache, rt);
800 if (!(flags & LIGHTREC_NO_LO) || __WORDSIZE == 32)
801 lightrec_free_reg(reg_cache, lo);
802 if (!(flags & LIGHTREC_NO_HI))
803 lightrec_free_reg(reg_cache, hi);
806 static void rec_alu_div(struct lightrec_cstate *state,
807 const struct block *block, u16 offset, bool is_signed)
809 struct regcache *reg_cache = state->reg_cache;
810 union code c = block->opcode_list[offset].c;
811 u16 flags = block->opcode_list[offset].flags;
812 bool no_check = flags & LIGHTREC_NO_DIV_CHECK;
813 u8 reg_lo = get_mult_div_lo(c);
814 u8 reg_hi = get_mult_div_hi(c);
815 jit_state_t *_jit = block->_jit;
816 jit_node_t *branch, *to_end;
817 u8 lo = 0, hi = 0, rs, rt, rflags = 0;
819 jit_note(__FILE__, __LINE__);
826 rs = lightrec_alloc_reg_in(reg_cache, _jit, c.r.rs, rflags);
827 rt = lightrec_alloc_reg_in(reg_cache, _jit, c.r.rt, rflags);
829 if (!(flags & LIGHTREC_NO_LO))
830 lo = lightrec_alloc_reg_out(reg_cache, _jit, reg_lo, 0);
832 if (!(flags & LIGHTREC_NO_HI))
833 hi = lightrec_alloc_reg_out(reg_cache, _jit, reg_hi, 0);
835 /* Jump to special handler if dividing by zero */
837 branch = jit_beqi(rt, 0);
839 if (flags & LIGHTREC_NO_LO) {
841 jit_remr(hi, rs, rt);
843 jit_remr_u(hi, rs, rt);
844 } else if (flags & LIGHTREC_NO_HI) {
846 jit_divr(lo, rs, rt);
848 jit_divr_u(lo, rs, rt);
851 jit_qdivr(lo, hi, rs, rt);
853 jit_qdivr_u(lo, hi, rs, rt);
857 /* Jump above the div-by-zero handler */
862 if (!(flags & LIGHTREC_NO_LO)) {
868 jit_movi(lo, 0xffffffff);
872 if (!(flags & LIGHTREC_NO_HI))
878 lightrec_free_reg(reg_cache, rs);
879 lightrec_free_reg(reg_cache, rt);
881 if (!(flags & LIGHTREC_NO_LO))
882 lightrec_free_reg(reg_cache, lo);
884 if (!(flags & LIGHTREC_NO_HI))
885 lightrec_free_reg(reg_cache, hi);
888 static void rec_special_MULT(struct lightrec_cstate *state,
889 const struct block *block, u16 offset)
891 _jit_name(block->_jit, __func__);
892 rec_alu_mult(state, block, offset, true);
895 static void rec_special_MULTU(struct lightrec_cstate *state,
896 const struct block *block, u16 offset)
898 _jit_name(block->_jit, __func__);
899 rec_alu_mult(state, block, offset, false);
902 static void rec_special_DIV(struct lightrec_cstate *state,
903 const struct block *block, u16 offset)
905 _jit_name(block->_jit, __func__);
906 rec_alu_div(state, block, offset, true);
909 static void rec_special_DIVU(struct lightrec_cstate *state,
910 const struct block *block, u16 offset)
912 _jit_name(block->_jit, __func__);
913 rec_alu_div(state, block, offset, false);
916 static void rec_alu_mv_lo_hi(struct lightrec_cstate *state,
917 const struct block *block, u8 dst, u8 src)
919 struct regcache *reg_cache = state->reg_cache;
920 jit_state_t *_jit = block->_jit;
922 jit_note(__FILE__, __LINE__);
923 src = lightrec_alloc_reg_in(reg_cache, _jit, src, 0);
924 dst = lightrec_alloc_reg_out(reg_cache, _jit, dst, REG_EXT);
926 jit_extr_i(dst, src);
928 lightrec_free_reg(reg_cache, src);
929 lightrec_free_reg(reg_cache, dst);
932 static void rec_special_MFHI(struct lightrec_cstate *state,
933 const struct block *block, u16 offset)
935 union code c = block->opcode_list[offset].c;
937 _jit_name(block->_jit, __func__);
938 rec_alu_mv_lo_hi(state, block, c.r.rd, REG_HI);
941 static void rec_special_MTHI(struct lightrec_cstate *state,
942 const struct block *block, u16 offset)
944 union code c = block->opcode_list[offset].c;
946 _jit_name(block->_jit, __func__);
947 rec_alu_mv_lo_hi(state, block, REG_HI, c.r.rs);
950 static void rec_special_MFLO(struct lightrec_cstate *state,
951 const struct block *block, u16 offset)
953 union code c = block->opcode_list[offset].c;
955 _jit_name(block->_jit, __func__);
956 rec_alu_mv_lo_hi(state, block, c.r.rd, REG_LO);
959 static void rec_special_MTLO(struct lightrec_cstate *state,
960 const struct block *block, u16 offset)
962 union code c = block->opcode_list[offset].c;
964 _jit_name(block->_jit, __func__);
965 rec_alu_mv_lo_hi(state, block, REG_LO, c.r.rs);
968 static void call_to_c_wrapper(struct lightrec_cstate *state, const struct block *block,
969 u32 arg, bool with_arg, enum c_wrappers wrapper)
971 struct regcache *reg_cache = state->reg_cache;
972 jit_state_t *_jit = block->_jit;
975 tmp = lightrec_alloc_reg_temp(reg_cache, _jit);
976 jit_ldxi(tmp, LIGHTREC_REG_STATE,
977 offsetof(struct lightrec_state, wrappers_eps[wrapper]));
980 tmp2 = lightrec_alloc_reg_temp(reg_cache, _jit);
983 jit_stxi_i(offsetof(struct lightrec_state, c_wrapper_arg),
984 LIGHTREC_REG_STATE, tmp2);
986 lightrec_free_reg(reg_cache, tmp2);
989 lightrec_regcache_mark_live(reg_cache, _jit);
992 lightrec_free_reg(reg_cache, tmp);
993 lightrec_regcache_mark_live(reg_cache, _jit);
996 static void rec_io(struct lightrec_cstate *state,
997 const struct block *block, u16 offset,
998 bool load_rt, bool read_rt)
1000 struct regcache *reg_cache = state->reg_cache;
1001 jit_state_t *_jit = block->_jit;
1002 union code c = block->opcode_list[offset].c;
1003 u16 flags = block->opcode_list[offset].flags;
1004 bool is_tagged = LIGHTREC_FLAGS_GET_IO_MODE(flags);
1007 jit_note(__FILE__, __LINE__);
1009 lightrec_clean_reg_if_loaded(reg_cache, _jit, c.i.rs, false);
1011 if (read_rt && likely(c.i.rt))
1012 lightrec_clean_reg_if_loaded(reg_cache, _jit, c.i.rt, true);
1014 lightrec_clean_reg_if_loaded(reg_cache, _jit, c.i.rt, false);
1017 call_to_c_wrapper(state, block, c.opcode, true, C_WRAPPER_RW);
1019 lut_entry = lightrec_get_lut_entry(block);
1020 call_to_c_wrapper(state, block, (lut_entry << 16) | offset,
1021 true, C_WRAPPER_RW_GENERIC);
1025 static void rec_store_memory(struct lightrec_cstate *cstate,
1026 const struct block *block,
1027 u16 offset, jit_code_t code,
1028 uintptr_t addr_offset, u32 addr_mask,
1031 struct regcache *reg_cache = cstate->reg_cache;
1032 struct opcode *op = &block->opcode_list[offset];
1033 jit_state_t *_jit = block->_jit;
1034 union code c = op->c;
1035 u8 rs, rt, tmp, tmp2, tmp3, addr_reg, addr_reg2;
1036 s16 imm = (s16)c.i.imm;
1037 s32 simm = (s32)imm << (__WORDSIZE / 32 - 1);
1038 s32 lut_offt = offsetof(struct lightrec_state, code_lut);
1039 bool no_mask = op->flags & LIGHTREC_NO_MASK;
1040 bool add_imm = c.i.imm && invalidate && simm + lut_offt != (s16)(simm + lut_offt);
1041 bool need_tmp = !no_mask || addr_offset || add_imm;
1042 bool need_tmp2 = addr_offset || invalidate;
1044 rt = lightrec_alloc_reg_in(reg_cache, _jit, c.i.rt, 0);
1045 rs = lightrec_alloc_reg_in(reg_cache, _jit, c.i.rs, 0);
1047 tmp = lightrec_alloc_reg_temp(reg_cache, _jit);
1052 jit_addi(tmp, addr_reg, (s16)c.i.imm);
1060 jit_andi(tmp, addr_reg, addr_mask);
1065 tmp2 = lightrec_alloc_reg_temp(reg_cache, _jit);
1068 jit_addi(tmp2, addr_reg, addr_offset);
1071 addr_reg2 = addr_reg;
1074 jit_new_node_www(code, imm, addr_reg2, rt);
1075 lightrec_free_reg(reg_cache, rt);
1078 tmp3 = lightrec_alloc_reg_in(reg_cache, _jit, 0, 0);
1080 if (c.i.op != OP_SW) {
1081 jit_andi(tmp2, addr_reg, ~3);
1085 if (__WORDSIZE == 64) {
1086 jit_lshi(tmp2, addr_reg, 1);
1090 if (__WORDSIZE == 64 || addr_reg != rs || c.i.rs != 0) {
1091 jit_addr(tmp2, addr_reg, LIGHTREC_REG_STATE);
1095 jit_stxi(lut_offt, addr_reg, tmp3);
1097 lightrec_free_reg(reg_cache, tmp3);
1101 lightrec_free_reg(reg_cache, tmp2);
1103 lightrec_free_reg(reg_cache, tmp);
1104 lightrec_free_reg(reg_cache, rs);
1107 static void rec_store_ram(struct lightrec_cstate *cstate,
1108 const struct block *block,
1109 u16 offset, jit_code_t code,
1112 _jit_note(block->_jit, __FILE__, __LINE__);
1114 return rec_store_memory(cstate, block, offset, code,
1115 cstate->state->offset_ram,
1116 RAM_SIZE - 1, invalidate);
1119 static void rec_store_scratch(struct lightrec_cstate *cstate,
1120 const struct block *block,
1121 u16 offset, jit_code_t code)
1123 _jit_note(block->_jit, __FILE__, __LINE__);
1125 return rec_store_memory(cstate, block, offset, code,
1126 cstate->state->offset_scratch,
1130 static void rec_store_direct_no_invalidate(struct lightrec_cstate *cstate,
1131 const struct block *block,
1132 u16 offset, jit_code_t code)
1134 struct lightrec_state *state = cstate->state;
1135 struct regcache *reg_cache = cstate->reg_cache;
1136 union code c = block->opcode_list[offset].c;
1137 jit_state_t *_jit = block->_jit;
1138 jit_node_t *to_not_ram, *to_end;
1139 u8 tmp, tmp2, rs, rt;
1142 jit_note(__FILE__, __LINE__);
1143 rs = lightrec_alloc_reg_in(reg_cache, _jit, c.i.rs, 0);
1144 tmp = lightrec_alloc_reg_temp(reg_cache, _jit);
1146 if (state->offset_ram || state->offset_scratch)
1147 tmp2 = lightrec_alloc_reg_temp(reg_cache, _jit);
1149 /* Convert to KUNSEG and avoid RAM mirrors */
1150 if (state->mirrors_mapped) {
1152 jit_andi(tmp, rs, 0x1f800000 | (4 * RAM_SIZE - 1));
1153 } else if (c.i.imm) {
1155 jit_addi(tmp, rs, (s16)c.i.imm);
1156 jit_andi(tmp, tmp, 0x1f800000 | (RAM_SIZE - 1));
1159 jit_andi(tmp, rs, 0x1f800000 | (RAM_SIZE - 1));
1162 lightrec_free_reg(reg_cache, rs);
1164 if (state->offset_ram != state->offset_scratch) {
1165 to_not_ram = jit_bmsi(tmp, BIT(28));
1167 jit_movi(tmp2, state->offset_ram);
1170 jit_patch(to_not_ram);
1172 jit_movi(tmp2, state->offset_scratch);
1174 } else if (state->offset_ram) {
1175 jit_movi(tmp2, state->offset_ram);
1178 if (state->offset_ram || state->offset_scratch) {
1179 jit_addr(tmp, tmp, tmp2);
1180 lightrec_free_reg(reg_cache, tmp2);
1183 rt = lightrec_alloc_reg_in(reg_cache, _jit, c.i.rt, 0);
1184 jit_new_node_www(code, imm, tmp, rt);
1186 lightrec_free_reg(reg_cache, rt);
1187 lightrec_free_reg(reg_cache, tmp);
1190 static void rec_store_direct(struct lightrec_cstate *cstate, const struct block *block,
1191 u16 offset, jit_code_t code)
1193 struct lightrec_state *state = cstate->state;
1194 u32 ram_size = state->mirrors_mapped ? RAM_SIZE * 4 : RAM_SIZE;
1195 struct regcache *reg_cache = cstate->reg_cache;
1196 union code c = block->opcode_list[offset].c;
1197 jit_state_t *_jit = block->_jit;
1198 jit_node_t *to_not_ram, *to_end;
1199 u8 tmp, tmp2, tmp3, rs, rt;
1201 jit_note(__FILE__, __LINE__);
1203 rs = lightrec_alloc_reg_in(reg_cache, _jit, c.i.rs, 0);
1204 tmp2 = lightrec_alloc_reg_temp(reg_cache, _jit);
1205 tmp3 = lightrec_alloc_reg_in(reg_cache, _jit, 0, 0);
1207 /* Convert to KUNSEG and avoid RAM mirrors */
1209 jit_addi(tmp2, rs, (s16)c.i.imm);
1210 jit_andi(tmp2, tmp2, 0x1f800000 | (ram_size - 1));
1212 jit_andi(tmp2, rs, 0x1f800000 | (ram_size - 1));
1215 lightrec_free_reg(reg_cache, rs);
1216 tmp = lightrec_alloc_reg_temp(reg_cache, _jit);
1218 to_not_ram = jit_bgti(tmp2, ram_size);
1220 /* Compute the offset to the code LUT */
1221 jit_andi(tmp, tmp2, (RAM_SIZE - 1) & ~3);
1222 if (__WORDSIZE == 64)
1223 jit_lshi(tmp, tmp, 1);
1224 jit_addr(tmp, LIGHTREC_REG_STATE, tmp);
1226 /* Write NULL to the code LUT to invalidate any block that's there */
1227 jit_stxi(offsetof(struct lightrec_state, code_lut), tmp, tmp3);
1229 if (state->offset_ram != state->offset_scratch) {
1230 jit_movi(tmp, state->offset_ram);
1235 jit_patch(to_not_ram);
1237 if (state->offset_ram || state->offset_scratch)
1238 jit_movi(tmp, state->offset_scratch);
1240 if (state->offset_ram != state->offset_scratch)
1243 if (state->offset_ram || state->offset_scratch)
1244 jit_addr(tmp2, tmp2, tmp);
1246 lightrec_free_reg(reg_cache, tmp);
1247 lightrec_free_reg(reg_cache, tmp3);
1249 rt = lightrec_alloc_reg_in(reg_cache, _jit, c.i.rt, 0);
1250 jit_new_node_www(code, 0, tmp2, rt);
1252 lightrec_free_reg(reg_cache, rt);
1253 lightrec_free_reg(reg_cache, tmp2);
1256 static void rec_store(struct lightrec_cstate *state,
1257 const struct block *block, u16 offset, jit_code_t code)
1259 u16 flags = block->opcode_list[offset].flags;
1260 bool no_invalidate = (flags & LIGHTREC_NO_INVALIDATE) ||
1261 state->state->invalidate_from_dma_only;
1263 switch (LIGHTREC_FLAGS_GET_IO_MODE(flags)) {
1264 case LIGHTREC_IO_RAM:
1265 rec_store_ram(state, block, offset, code, !no_invalidate);
1267 case LIGHTREC_IO_SCRATCH:
1268 rec_store_scratch(state, block, offset, code);
1270 case LIGHTREC_IO_DIRECT:
1272 rec_store_direct_no_invalidate(state, block, offset, code);
1274 rec_store_direct(state, block, offset, code);
1277 rec_io(state, block, offset, true, false);
1282 static void rec_SB(struct lightrec_cstate *state,
1283 const struct block *block, u16 offset)
1285 _jit_name(block->_jit, __func__);
1286 rec_store(state, block, offset, jit_code_stxi_c);
1289 static void rec_SH(struct lightrec_cstate *state,
1290 const struct block *block, u16 offset)
1292 _jit_name(block->_jit, __func__);
1293 rec_store(state, block, offset, jit_code_stxi_s);
1296 static void rec_SW(struct lightrec_cstate *state,
1297 const struct block *block, u16 offset)
1300 _jit_name(block->_jit, __func__);
1301 rec_store(state, block, offset, jit_code_stxi_i);
1304 static void rec_SWL(struct lightrec_cstate *state,
1305 const struct block *block, u16 offset)
1307 _jit_name(block->_jit, __func__);
1308 rec_io(state, block, offset, true, false);
1311 static void rec_SWR(struct lightrec_cstate *state,
1312 const struct block *block, u16 offset)
1314 _jit_name(block->_jit, __func__);
1315 rec_io(state, block, offset, true, false);
1318 static void rec_SWC2(struct lightrec_cstate *state,
1319 const struct block *block, u16 offset)
1321 _jit_name(block->_jit, __func__);
1322 rec_io(state, block, offset, false, false);
1325 static void rec_load_memory(struct lightrec_cstate *cstate,
1326 const struct block *block,
1327 u16 offset, jit_code_t code, bool is_unsigned,
1328 uintptr_t addr_offset, u32 addr_mask)
1330 struct regcache *reg_cache = cstate->reg_cache;
1331 struct opcode *op = &block->opcode_list[offset];
1332 jit_state_t *_jit = block->_jit;
1333 u8 rs, rt, addr_reg, flags = REG_EXT;
1334 union code c = op->c;
1342 rs = lightrec_alloc_reg_in(reg_cache, _jit, c.i.rs, 0);
1343 rt = lightrec_alloc_reg_out(reg_cache, _jit, c.i.rt, flags);
1345 if (!(op->flags & LIGHTREC_NO_MASK)) {
1346 jit_andi(rt, rs, addr_mask);
1353 jit_addi(rt, addr_reg, addr_offset);
1357 jit_new_node_www(code, rt, addr_reg, (s16)c.i.imm);
1359 lightrec_free_reg(reg_cache, rs);
1360 lightrec_free_reg(reg_cache, rt);
1363 static void rec_load_ram(struct lightrec_cstate *cstate,
1364 const struct block *block,
1365 u16 offset, jit_code_t code, bool is_unsigned)
1367 _jit_note(block->_jit, __FILE__, __LINE__);
1369 rec_load_memory(cstate, block, offset, code, is_unsigned,
1370 cstate->state->offset_ram, RAM_SIZE - 1);
1373 static void rec_load_bios(struct lightrec_cstate *cstate,
1374 const struct block *block,
1375 u16 offset, jit_code_t code, bool is_unsigned)
1377 _jit_note(block->_jit, __FILE__, __LINE__);
1379 rec_load_memory(cstate, block, offset, code, is_unsigned,
1380 cstate->state->offset_bios, 0x1fffffff);
1383 static void rec_load_scratch(struct lightrec_cstate *cstate,
1384 const struct block *block,
1385 u16 offset, jit_code_t code, bool is_unsigned)
1387 _jit_note(block->_jit, __FILE__, __LINE__);
1389 rec_load_memory(cstate, block, offset, code, is_unsigned,
1390 cstate->state->offset_scratch, 0x1fffffff);
1393 static void rec_load_direct(struct lightrec_cstate *cstate, const struct block *block,
1394 u16 offset, jit_code_t code, bool is_unsigned)
1396 struct lightrec_state *state = cstate->state;
1397 struct regcache *reg_cache = cstate->reg_cache;
1398 union code c = block->opcode_list[offset].c;
1399 jit_state_t *_jit = block->_jit;
1400 jit_node_t *to_not_ram, *to_not_bios, *to_end, *to_end2;
1401 u8 tmp, rs, rt, addr_reg, flags = REG_EXT;
1410 jit_note(__FILE__, __LINE__);
1411 rs = lightrec_alloc_reg_in(reg_cache, _jit, c.i.rs, 0);
1412 rt = lightrec_alloc_reg_out(reg_cache, _jit, c.i.rt, flags);
1414 if ((state->offset_ram == state->offset_bios &&
1415 state->offset_ram == state->offset_scratch &&
1416 state->mirrors_mapped) || !c.i.imm) {
1420 jit_addi(rt, rs, (s16)c.i.imm);
1424 if (c.i.rs != c.i.rt)
1425 lightrec_free_reg(reg_cache, rs);
1428 tmp = lightrec_alloc_reg_temp(reg_cache, _jit);
1430 if (state->offset_ram == state->offset_bios &&
1431 state->offset_ram == state->offset_scratch) {
1432 if (!state->mirrors_mapped) {
1433 jit_andi(tmp, addr_reg, BIT(28));
1434 jit_rshi_u(tmp, tmp, 28 - 22);
1435 jit_ori(tmp, tmp, 0x1f800000 | (RAM_SIZE - 1));
1436 jit_andr(rt, addr_reg, tmp);
1438 jit_andi(rt, addr_reg, 0x1fffffff);
1441 if (state->offset_ram)
1442 jit_movi(tmp, state->offset_ram);
1444 to_not_ram = jit_bmsi(addr_reg, BIT(28));
1446 /* Convert to KUNSEG and avoid RAM mirrors */
1447 jit_andi(rt, addr_reg, RAM_SIZE - 1);
1449 if (state->offset_ram)
1450 jit_movi(tmp, state->offset_ram);
1454 jit_patch(to_not_ram);
1456 if (state->offset_bios != state->offset_scratch)
1457 to_not_bios = jit_bmci(addr_reg, BIT(22));
1459 /* Convert to KUNSEG */
1460 jit_andi(rt, addr_reg, 0x1fc00000 | (BIOS_SIZE - 1));
1462 jit_movi(tmp, state->offset_bios);
1464 if (state->offset_bios != state->offset_scratch) {
1467 jit_patch(to_not_bios);
1469 /* Convert to KUNSEG */
1470 jit_andi(rt, addr_reg, 0x1f800fff);
1472 if (state->offset_scratch)
1473 jit_movi(tmp, state->offset_scratch);
1481 if (state->offset_ram || state->offset_bios || state->offset_scratch)
1482 jit_addr(rt, rt, tmp);
1484 jit_new_node_www(code, rt, rt, imm);
1486 lightrec_free_reg(reg_cache, addr_reg);
1487 lightrec_free_reg(reg_cache, rt);
1488 lightrec_free_reg(reg_cache, tmp);
1491 static void rec_load(struct lightrec_cstate *state, const struct block *block,
1492 u16 offset, jit_code_t code, bool is_unsigned)
1494 u16 flags = block->opcode_list[offset].flags;
1496 switch (LIGHTREC_FLAGS_GET_IO_MODE(flags)) {
1497 case LIGHTREC_IO_RAM:
1498 rec_load_ram(state, block, offset, code, is_unsigned);
1500 case LIGHTREC_IO_BIOS:
1501 rec_load_bios(state, block, offset, code, is_unsigned);
1503 case LIGHTREC_IO_SCRATCH:
1504 rec_load_scratch(state, block, offset, code, is_unsigned);
1506 case LIGHTREC_IO_DIRECT:
1507 rec_load_direct(state, block, offset, code, is_unsigned);
1510 rec_io(state, block, offset, false, true);
1515 static void rec_LB(struct lightrec_cstate *state, const struct block *block, u16 offset)
1517 _jit_name(block->_jit, __func__);
1518 rec_load(state, block, offset, jit_code_ldxi_c, false);
1521 static void rec_LBU(struct lightrec_cstate *state, const struct block *block, u16 offset)
1523 _jit_name(block->_jit, __func__);
1524 rec_load(state, block, offset, jit_code_ldxi_uc, true);
1527 static void rec_LH(struct lightrec_cstate *state, const struct block *block, u16 offset)
1529 _jit_name(block->_jit, __func__);
1530 rec_load(state, block, offset, jit_code_ldxi_s, false);
1533 static void rec_LHU(struct lightrec_cstate *state, const struct block *block, u16 offset)
1535 _jit_name(block->_jit, __func__);
1536 rec_load(state, block, offset, jit_code_ldxi_us, true);
1539 static void rec_LWL(struct lightrec_cstate *state, const struct block *block, u16 offset)
1541 _jit_name(block->_jit, __func__);
1542 rec_io(state, block, offset, true, true);
1545 static void rec_LWR(struct lightrec_cstate *state, const struct block *block, u16 offset)
1547 _jit_name(block->_jit, __func__);
1548 rec_io(state, block, offset, true, true);
1551 static void rec_LW(struct lightrec_cstate *state, const struct block *block, u16 offset)
1553 _jit_name(block->_jit, __func__);
1554 rec_load(state, block, offset, jit_code_ldxi_i, false);
1557 static void rec_LWC2(struct lightrec_cstate *state, const struct block *block, u16 offset)
1559 _jit_name(block->_jit, __func__);
1560 rec_io(state, block, offset, false, false);
1563 static void rec_break_syscall(struct lightrec_cstate *state,
1564 const struct block *block, u16 offset, bool is_break)
1566 _jit_note(block->_jit, __FILE__, __LINE__);
1569 call_to_c_wrapper(state, block, 0, false, C_WRAPPER_BREAK);
1571 call_to_c_wrapper(state, block, 0, false, C_WRAPPER_SYSCALL);
1573 /* TODO: the return address should be "pc - 4" if we're a delay slot */
1574 lightrec_emit_end_of_block(state, block, offset, -1,
1575 get_ds_pc(block, offset, 0),
1579 static void rec_special_SYSCALL(struct lightrec_cstate *state,
1580 const struct block *block, u16 offset)
1582 _jit_name(block->_jit, __func__);
1583 rec_break_syscall(state, block, offset, false);
1586 static void rec_special_BREAK(struct lightrec_cstate *state,
1587 const struct block *block, u16 offset)
1589 _jit_name(block->_jit, __func__);
1590 rec_break_syscall(state, block, offset, true);
1593 static void rec_mtc(struct lightrec_cstate *state, const struct block *block, u16 offset)
1595 struct regcache *reg_cache = state->reg_cache;
1596 union code c = block->opcode_list[offset].c;
1597 jit_state_t *_jit = block->_jit;
1599 jit_note(__FILE__, __LINE__);
1600 lightrec_clean_reg_if_loaded(reg_cache, _jit, c.i.rs, false);
1601 lightrec_clean_reg_if_loaded(reg_cache, _jit, c.i.rt, false);
1603 call_to_c_wrapper(state, block, c.opcode, true, C_WRAPPER_MTC);
1605 if (c.i.op == OP_CP0 &&
1606 !(block->opcode_list[offset].flags & LIGHTREC_NO_DS) &&
1607 (c.r.rd == 12 || c.r.rd == 13))
1608 lightrec_emit_end_of_block(state, block, offset, -1,
1609 get_ds_pc(block, offset, 1),
1614 rec_mfc0(struct lightrec_cstate *state, const struct block *block, u16 offset)
1616 struct regcache *reg_cache = state->reg_cache;
1617 union code c = block->opcode_list[offset].c;
1618 jit_state_t *_jit = block->_jit;
1621 jit_note(__FILE__, __LINE__);
1623 rt = lightrec_alloc_reg_out(reg_cache, _jit, c.i.rt, REG_EXT);
1625 jit_ldxi_i(rt, LIGHTREC_REG_STATE,
1626 offsetof(struct lightrec_state, regs.cp0[c.r.rd]));
1628 lightrec_free_reg(reg_cache, rt);
1631 static bool block_in_bios(const struct lightrec_cstate *state,
1632 const struct block *block)
1634 const struct lightrec_mem_map *bios = &state->state->maps[PSX_MAP_BIOS];
1635 u32 pc = kunseg(block->pc);
1637 return pc >= bios->pc && pc < bios->pc + bios->length;
1641 rec_mtc0(struct lightrec_cstate *state, const struct block *block, u16 offset)
1643 struct regcache *reg_cache = state->reg_cache;
1644 const union code c = block->opcode_list[offset].c;
1645 jit_state_t *_jit = block->_jit;
1646 u8 rt, tmp = 0, tmp2, status;
1648 jit_note(__FILE__, __LINE__);
1656 /* Those registers are read-only */
1662 if (block_in_bios(state, block) && c.r.rd == 12) {
1663 /* If we are running code from the BIOS, handle writes to the
1664 * Status register in C. BIOS code may toggle bit 16 which will
1665 * map/unmap the RAM, while game code cannot do that. */
1666 rec_mtc(state, block, offset);
1670 rt = lightrec_alloc_reg_in(reg_cache, _jit, c.i.rt, 0);
1673 jit_stxi_i(offsetof(struct lightrec_state, regs.cp0[c.r.rd]),
1674 LIGHTREC_REG_STATE, rt);
1677 if (c.r.rd == 12 || c.r.rd == 13) {
1678 tmp = lightrec_alloc_reg_temp(reg_cache, _jit);
1679 jit_ldxi_i(tmp, LIGHTREC_REG_STATE,
1680 offsetof(struct lightrec_state, regs.cp0[13]));
1682 tmp2 = lightrec_alloc_reg_temp(reg_cache, _jit);
1687 } else if (c.r.rd == 13) {
1688 /* Cause = (Cause & ~0x0300) | (value & 0x0300) */
1689 jit_andi(tmp2, rt, 0x0300);
1690 jit_ori(tmp, tmp, 0x0300);
1691 jit_xori(tmp, tmp, 0x0300);
1692 jit_orr(tmp, tmp, tmp2);
1693 jit_ldxi_i(tmp2, LIGHTREC_REG_STATE,
1694 offsetof(struct lightrec_state, regs.cp0[12]));
1695 jit_stxi_i(offsetof(struct lightrec_state, regs.cp0[13]),
1696 LIGHTREC_REG_STATE, tmp);
1700 if (c.r.rd == 12 || c.r.rd == 13) {
1701 /* Exit dynarec in case there's a software interrupt.
1702 * exit_flags = !!(status & tmp & 0x0300) & status; */
1703 jit_andr(tmp, tmp, status);
1704 jit_andi(tmp, tmp, 0x0300);
1705 jit_nei(tmp, tmp, 0);
1706 jit_andr(tmp, tmp, status);
1710 /* Exit dynarec in case we unmask a hardware interrupt.
1711 * exit_flags = !(~status & 0x401) */
1713 jit_comr(tmp2, status);
1714 jit_andi(tmp2, tmp2, 0x401);
1715 jit_eqi(tmp2, tmp2, 0);
1716 jit_orr(tmp, tmp, tmp2);
1719 if (c.r.rd == 12 || c.r.rd == 13) {
1720 jit_stxi_i(offsetof(struct lightrec_state, exit_flags),
1721 LIGHTREC_REG_STATE, tmp);
1723 lightrec_free_reg(reg_cache, tmp);
1724 lightrec_free_reg(reg_cache, tmp2);
1727 lightrec_free_reg(reg_cache, rt);
1729 if (!(block->opcode_list[offset].flags & LIGHTREC_NO_DS) &&
1730 (c.r.rd == 12 || c.r.rd == 13))
1731 lightrec_emit_eob(state, block, offset + 1, true);
1734 static void rec_cp0_MFC0(struct lightrec_cstate *state,
1735 const struct block *block, u16 offset)
1737 _jit_name(block->_jit, __func__);
1738 rec_mfc0(state, block, offset);
1741 static void rec_cp0_CFC0(struct lightrec_cstate *state,
1742 const struct block *block, u16 offset)
1744 _jit_name(block->_jit, __func__);
1745 rec_mfc0(state, block, offset);
1748 static void rec_cp0_MTC0(struct lightrec_cstate *state,
1749 const struct block *block, u16 offset)
1751 _jit_name(block->_jit, __func__);
1752 rec_mtc0(state, block, offset);
1755 static void rec_cp0_CTC0(struct lightrec_cstate *state,
1756 const struct block *block, u16 offset)
1758 _jit_name(block->_jit, __func__);
1759 rec_mtc0(state, block, offset);
1762 static void rec_cp2_basic_MFC2(struct lightrec_cstate *state,
1763 const struct block *block, u16 offset)
1765 struct regcache *reg_cache = state->reg_cache;
1766 const union code c = block->opcode_list[offset].c;
1767 jit_state_t *_jit = block->_jit;
1768 const u32 zext_regs = 0x300f0080;
1769 u8 rt, tmp, tmp2, tmp3, out, flags;
1770 u8 reg = c.r.rd == 15 ? 14 : c.r.rd;
1773 _jit_name(block->_jit, __func__);
1775 flags = (zext_regs & BIT(reg)) ? REG_ZEXT : REG_EXT;
1776 rt = lightrec_alloc_reg_out(reg_cache, _jit, c.r.rt, flags);
1786 jit_ldxi_s(rt, LIGHTREC_REG_STATE,
1787 offsetof(struct lightrec_state, regs.cp2d[reg]));
1794 jit_ldxi_us(rt, LIGHTREC_REG_STATE,
1795 offsetof(struct lightrec_state, regs.cp2d[reg]));
1799 tmp = lightrec_alloc_reg_temp(reg_cache, _jit);
1800 tmp2 = lightrec_alloc_reg_temp(reg_cache, _jit);
1801 tmp3 = lightrec_alloc_reg_temp(reg_cache, _jit);
1803 for (i = 0; i < 3; i++) {
1804 out = i == 0 ? rt : tmp;
1806 jit_ldxi_s(tmp, LIGHTREC_REG_STATE,
1807 offsetof(struct lightrec_state, regs.cp2d[9 + i]));
1808 jit_movi(tmp2, 0x1f);
1809 jit_rshi(out, tmp, 7);
1811 jit_ltr(tmp3, tmp2, out);
1812 jit_movnr(out, tmp2, tmp3);
1814 jit_gei(tmp2, out, 0);
1815 jit_movzr(out, tmp2, tmp2);
1818 jit_lshi(tmp, tmp, 5 * i);
1819 jit_orr(rt, rt, tmp);
1824 lightrec_free_reg(reg_cache, tmp);
1825 lightrec_free_reg(reg_cache, tmp2);
1826 lightrec_free_reg(reg_cache, tmp3);
1829 jit_ldxi_i(rt, LIGHTREC_REG_STATE,
1830 offsetof(struct lightrec_state, regs.cp2d[reg]));
1834 lightrec_free_reg(reg_cache, rt);
1837 static void rec_cp2_basic_CFC2(struct lightrec_cstate *state,
1838 const struct block *block, u16 offset)
1840 struct regcache *reg_cache = state->reg_cache;
1841 const union code c = block->opcode_list[offset].c;
1842 jit_state_t *_jit = block->_jit;
1845 _jit_name(block->_jit, __func__);
1855 rt = lightrec_alloc_reg_out(reg_cache, _jit, c.r.rt, REG_EXT);
1856 jit_ldxi_s(rt, LIGHTREC_REG_STATE,
1857 offsetof(struct lightrec_state, regs.cp2c[c.r.rd]));
1860 rt = lightrec_alloc_reg_out(reg_cache, _jit, c.r.rt, REG_ZEXT);
1861 jit_ldxi_i(rt, LIGHTREC_REG_STATE,
1862 offsetof(struct lightrec_state, regs.cp2c[c.r.rd]));
1866 lightrec_free_reg(reg_cache, rt);
1869 static void rec_cp2_basic_MTC2(struct lightrec_cstate *state,
1870 const struct block *block, u16 offset)
1872 struct regcache *reg_cache = state->reg_cache;
1873 const union code c = block->opcode_list[offset].c;
1874 jit_state_t *_jit = block->_jit;
1875 jit_node_t *loop, *to_loop;
1876 u8 rt, tmp, tmp2, flags = 0;
1878 _jit_name(block->_jit, __func__);
1886 rt = lightrec_alloc_reg_in(reg_cache, _jit, c.r.rt, flags);
1890 tmp = lightrec_alloc_reg_temp(reg_cache, _jit);
1891 jit_ldxi_i(tmp, LIGHTREC_REG_STATE,
1892 offsetof(struct lightrec_state, regs.cp2d[13]));
1894 tmp2 = lightrec_alloc_reg_temp(reg_cache, _jit);
1895 jit_ldxi_i(tmp2, LIGHTREC_REG_STATE,
1896 offsetof(struct lightrec_state, regs.cp2d[14]));
1898 jit_stxi_i(offsetof(struct lightrec_state, regs.cp2d[12]),
1899 LIGHTREC_REG_STATE, tmp);
1900 jit_stxi_i(offsetof(struct lightrec_state, regs.cp2d[13]),
1901 LIGHTREC_REG_STATE, tmp2);
1902 jit_stxi_i(offsetof(struct lightrec_state, regs.cp2d[14]),
1903 LIGHTREC_REG_STATE, rt);
1905 lightrec_free_reg(reg_cache, tmp);
1906 lightrec_free_reg(reg_cache, tmp2);
1909 tmp = lightrec_alloc_reg_temp(reg_cache, _jit);
1911 jit_lshi(tmp, rt, 7);
1912 jit_andi(tmp, tmp, 0xf80);
1913 jit_stxi_s(offsetof(struct lightrec_state, regs.cp2d[9]),
1914 LIGHTREC_REG_STATE, tmp);
1916 jit_lshi(tmp, rt, 2);
1917 jit_andi(tmp, tmp, 0xf80);
1918 jit_stxi_s(offsetof(struct lightrec_state, regs.cp2d[10]),
1919 LIGHTREC_REG_STATE, tmp);
1921 jit_rshi(tmp, rt, 3);
1922 jit_andi(tmp, tmp, 0xf80);
1923 jit_stxi_s(offsetof(struct lightrec_state, regs.cp2d[11]),
1924 LIGHTREC_REG_STATE, tmp);
1926 lightrec_free_reg(reg_cache, tmp);
1929 tmp = lightrec_alloc_reg_temp(reg_cache, _jit);
1930 tmp2 = lightrec_alloc_reg_temp(reg_cache, _jit);
1932 /* if (rt < 0) rt = ~rt; */
1933 jit_rshi(tmp, rt, 31);
1934 jit_xorr(tmp, rt, tmp);
1936 /* We know the sign bit is 0. Left-shift by 1 to start the algorithm */
1937 jit_lshi(tmp, tmp, 1);
1940 /* Decrement tmp2 and right-shift the value by 1 until it equals zero */
1942 jit_subi(tmp2, tmp2, 1);
1943 jit_rshi_u(tmp, tmp, 1);
1944 to_loop = jit_bnei(tmp, 0);
1946 jit_patch_at(to_loop, loop);
1948 jit_stxi_i(offsetof(struct lightrec_state, regs.cp2d[31]),
1949 LIGHTREC_REG_STATE, tmp2);
1950 jit_stxi_i(offsetof(struct lightrec_state, regs.cp2d[30]),
1951 LIGHTREC_REG_STATE, rt);
1953 lightrec_free_reg(reg_cache, tmp);
1954 lightrec_free_reg(reg_cache, tmp2);
1957 jit_stxi_i(offsetof(struct lightrec_state, regs.cp2d[c.r.rd]),
1958 LIGHTREC_REG_STATE, rt);
1962 lightrec_free_reg(reg_cache, rt);
1965 static void rec_cp2_basic_CTC2(struct lightrec_cstate *state,
1966 const struct block *block, u16 offset)
1968 struct regcache *reg_cache = state->reg_cache;
1969 const union code c = block->opcode_list[offset].c;
1970 jit_state_t *_jit = block->_jit;
1973 _jit_name(block->_jit, __func__);
1975 rt = lightrec_alloc_reg_in(reg_cache, _jit, c.r.rt, 0);
1985 jit_stxi_s(offsetof(struct lightrec_state, regs.cp2c[c.r.rd]),
1986 LIGHTREC_REG_STATE, rt);
1989 tmp = lightrec_alloc_reg_temp(reg_cache, _jit);
1990 tmp2 = lightrec_alloc_reg_temp(reg_cache, _jit);
1992 jit_andi(tmp, rt, 0x7f87e000);
1993 jit_nei(tmp, tmp, 0);
1994 jit_lshi(tmp, tmp, 31);
1996 jit_andi(tmp2, rt, 0x7ffff000);
1997 jit_orr(tmp, tmp2, tmp);
1999 jit_stxi_i(offsetof(struct lightrec_state, regs.cp2c[31]),
2000 LIGHTREC_REG_STATE, tmp);
2002 lightrec_free_reg(reg_cache, tmp);
2003 lightrec_free_reg(reg_cache, tmp2);
2007 jit_stxi_i(offsetof(struct lightrec_state, regs.cp2c[c.r.rd]),
2008 LIGHTREC_REG_STATE, rt);
2011 lightrec_free_reg(reg_cache, rt);
2014 static void rec_cp0_RFE(struct lightrec_cstate *state,
2015 const struct block *block, u16 offset)
2017 struct regcache *reg_cache = state->reg_cache;
2018 jit_state_t *_jit = block->_jit;
2022 jit_note(__FILE__, __LINE__);
2024 status = lightrec_alloc_reg_temp(reg_cache, _jit);
2025 jit_ldxi_i(status, LIGHTREC_REG_STATE,
2026 offsetof(struct lightrec_state, regs.cp0[12]));
2028 tmp = lightrec_alloc_reg_temp(reg_cache, _jit);
2030 /* status = ((status >> 2) & 0xf) | status & ~0xf; */
2031 jit_rshi(tmp, status, 2);
2032 jit_andi(tmp, tmp, 0xf);
2033 jit_andi(status, status, ~0xful);
2034 jit_orr(status, status, tmp);
2036 jit_ldxi_i(tmp, LIGHTREC_REG_STATE,
2037 offsetof(struct lightrec_state, regs.cp0[13]));
2038 jit_stxi_i(offsetof(struct lightrec_state, regs.cp0[12]),
2039 LIGHTREC_REG_STATE, status);
2041 /* Exit dynarec in case there's a software interrupt.
2042 * exit_flags = !!(status & cause & 0x0300) & status; */
2043 jit_andr(tmp, tmp, status);
2044 jit_andi(tmp, tmp, 0x0300);
2045 jit_nei(tmp, tmp, 0);
2046 jit_andr(tmp, tmp, status);
2047 jit_stxi_i(offsetof(struct lightrec_state, exit_flags),
2048 LIGHTREC_REG_STATE, tmp);
2050 lightrec_free_reg(reg_cache, status);
2051 lightrec_free_reg(reg_cache, tmp);
2054 static void rec_CP(struct lightrec_cstate *state,
2055 const struct block *block, u16 offset)
2057 union code c = block->opcode_list[offset].c;
2058 jit_state_t *_jit = block->_jit;
2061 jit_note(__FILE__, __LINE__);
2063 call_to_c_wrapper(state, block, c.opcode, true, C_WRAPPER_CP);
2066 static void rec_meta_MOV(struct lightrec_cstate *state,
2067 const struct block *block, u16 offset)
2069 struct regcache *reg_cache = state->reg_cache;
2070 union code c = block->opcode_list[offset].c;
2071 jit_state_t *_jit = block->_jit;
2074 _jit_name(block->_jit, __func__);
2075 jit_note(__FILE__, __LINE__);
2077 rs = lightrec_alloc_reg_in(reg_cache, _jit, c.r.rs, 0);
2078 rd = lightrec_alloc_reg_out(reg_cache, _jit, c.r.rd, REG_EXT);
2086 lightrec_free_reg(reg_cache, rs);
2087 lightrec_free_reg(reg_cache, rd);
2090 static void rec_meta_EXTC_EXTS(struct lightrec_cstate *state,
2091 const struct block *block,
2094 struct regcache *reg_cache = state->reg_cache;
2095 union code c = block->opcode_list[offset].c;
2096 jit_state_t *_jit = block->_jit;
2099 _jit_name(block->_jit, __func__);
2100 jit_note(__FILE__, __LINE__);
2102 rs = lightrec_alloc_reg_in(reg_cache, _jit, c.i.rs, 0);
2103 rt = lightrec_alloc_reg_out(reg_cache, _jit, c.i.rt, REG_EXT);
2105 if (c.i.op == OP_META_EXTC)
2110 lightrec_free_reg(reg_cache, rs);
2111 lightrec_free_reg(reg_cache, rt);
2114 static const lightrec_rec_func_t rec_standard[64] = {
2115 SET_DEFAULT_ELM(rec_standard, unknown_opcode),
2116 [OP_SPECIAL] = rec_SPECIAL,
2117 [OP_REGIMM] = rec_REGIMM,
2122 [OP_BLEZ] = rec_BLEZ,
2123 [OP_BGTZ] = rec_BGTZ,
2124 [OP_ADDI] = rec_ADDI,
2125 [OP_ADDIU] = rec_ADDIU,
2126 [OP_SLTI] = rec_SLTI,
2127 [OP_SLTIU] = rec_SLTIU,
2128 [OP_ANDI] = rec_ANDI,
2130 [OP_XORI] = rec_XORI,
2146 [OP_LWC2] = rec_LWC2,
2147 [OP_SWC2] = rec_SWC2,
2149 [OP_META_MOV] = rec_meta_MOV,
2150 [OP_META_EXTC] = rec_meta_EXTC_EXTS,
2151 [OP_META_EXTS] = rec_meta_EXTC_EXTS,
2154 static const lightrec_rec_func_t rec_special[64] = {
2155 SET_DEFAULT_ELM(rec_special, unknown_opcode),
2156 [OP_SPECIAL_SLL] = rec_special_SLL,
2157 [OP_SPECIAL_SRL] = rec_special_SRL,
2158 [OP_SPECIAL_SRA] = rec_special_SRA,
2159 [OP_SPECIAL_SLLV] = rec_special_SLLV,
2160 [OP_SPECIAL_SRLV] = rec_special_SRLV,
2161 [OP_SPECIAL_SRAV] = rec_special_SRAV,
2162 [OP_SPECIAL_JR] = rec_special_JR,
2163 [OP_SPECIAL_JALR] = rec_special_JALR,
2164 [OP_SPECIAL_SYSCALL] = rec_special_SYSCALL,
2165 [OP_SPECIAL_BREAK] = rec_special_BREAK,
2166 [OP_SPECIAL_MFHI] = rec_special_MFHI,
2167 [OP_SPECIAL_MTHI] = rec_special_MTHI,
2168 [OP_SPECIAL_MFLO] = rec_special_MFLO,
2169 [OP_SPECIAL_MTLO] = rec_special_MTLO,
2170 [OP_SPECIAL_MULT] = rec_special_MULT,
2171 [OP_SPECIAL_MULTU] = rec_special_MULTU,
2172 [OP_SPECIAL_DIV] = rec_special_DIV,
2173 [OP_SPECIAL_DIVU] = rec_special_DIVU,
2174 [OP_SPECIAL_ADD] = rec_special_ADD,
2175 [OP_SPECIAL_ADDU] = rec_special_ADDU,
2176 [OP_SPECIAL_SUB] = rec_special_SUB,
2177 [OP_SPECIAL_SUBU] = rec_special_SUBU,
2178 [OP_SPECIAL_AND] = rec_special_AND,
2179 [OP_SPECIAL_OR] = rec_special_OR,
2180 [OP_SPECIAL_XOR] = rec_special_XOR,
2181 [OP_SPECIAL_NOR] = rec_special_NOR,
2182 [OP_SPECIAL_SLT] = rec_special_SLT,
2183 [OP_SPECIAL_SLTU] = rec_special_SLTU,
2186 static const lightrec_rec_func_t rec_regimm[64] = {
2187 SET_DEFAULT_ELM(rec_regimm, unknown_opcode),
2188 [OP_REGIMM_BLTZ] = rec_regimm_BLTZ,
2189 [OP_REGIMM_BGEZ] = rec_regimm_BGEZ,
2190 [OP_REGIMM_BLTZAL] = rec_regimm_BLTZAL,
2191 [OP_REGIMM_BGEZAL] = rec_regimm_BGEZAL,
2194 static const lightrec_rec_func_t rec_cp0[64] = {
2195 SET_DEFAULT_ELM(rec_cp0, rec_CP),
2196 [OP_CP0_MFC0] = rec_cp0_MFC0,
2197 [OP_CP0_CFC0] = rec_cp0_CFC0,
2198 [OP_CP0_MTC0] = rec_cp0_MTC0,
2199 [OP_CP0_CTC0] = rec_cp0_CTC0,
2200 [OP_CP0_RFE] = rec_cp0_RFE,
2203 static const lightrec_rec_func_t rec_cp2_basic[64] = {
2204 SET_DEFAULT_ELM(rec_cp2_basic, rec_CP),
2205 [OP_CP2_BASIC_MFC2] = rec_cp2_basic_MFC2,
2206 [OP_CP2_BASIC_CFC2] = rec_cp2_basic_CFC2,
2207 [OP_CP2_BASIC_MTC2] = rec_cp2_basic_MTC2,
2208 [OP_CP2_BASIC_CTC2] = rec_cp2_basic_CTC2,
2211 static void rec_SPECIAL(struct lightrec_cstate *state,
2212 const struct block *block, u16 offset)
2214 union code c = block->opcode_list[offset].c;
2215 lightrec_rec_func_t f = rec_special[c.r.op];
2217 if (!HAS_DEFAULT_ELM && unlikely(!f))
2218 unknown_opcode(state, block, offset);
2220 (*f)(state, block, offset);
2223 static void rec_REGIMM(struct lightrec_cstate *state,
2224 const struct block *block, u16 offset)
2226 union code c = block->opcode_list[offset].c;
2227 lightrec_rec_func_t f = rec_regimm[c.r.rt];
2229 if (!HAS_DEFAULT_ELM && unlikely(!f))
2230 unknown_opcode(state, block, offset);
2232 (*f)(state, block, offset);
2235 static void rec_CP0(struct lightrec_cstate *state,
2236 const struct block *block, u16 offset)
2238 union code c = block->opcode_list[offset].c;
2239 lightrec_rec_func_t f = rec_cp0[c.r.rs];
2241 if (!HAS_DEFAULT_ELM && unlikely(!f))
2242 rec_CP(state, block, offset);
2244 (*f)(state, block, offset);
2247 static void rec_CP2(struct lightrec_cstate *state,
2248 const struct block *block, u16 offset)
2250 union code c = block->opcode_list[offset].c;
2252 if (c.r.op == OP_CP2_BASIC) {
2253 lightrec_rec_func_t f = rec_cp2_basic[c.r.rs];
2255 if (HAS_DEFAULT_ELM || likely(f)) {
2256 (*f)(state, block, offset);
2261 rec_CP(state, block, offset);
2264 void lightrec_rec_opcode(struct lightrec_cstate *state,
2265 const struct block *block, u16 offset)
2267 struct regcache *reg_cache = state->reg_cache;
2268 struct lightrec_branch_target *target;
2269 const struct opcode *op = &block->opcode_list[offset];
2270 jit_state_t *_jit = block->_jit;
2271 lightrec_rec_func_t f;
2273 if (op->flags & LIGHTREC_SYNC) {
2274 jit_subi(LIGHTREC_REG_CYCLE, LIGHTREC_REG_CYCLE, state->cycles);
2277 lightrec_storeback_regs(reg_cache, _jit);
2278 lightrec_regcache_reset(reg_cache);
2280 pr_debug("Adding branch target at offset 0x%x\n", offset << 2);
2281 target = &state->targets[state->nb_targets++];
2282 target->offset = offset;
2283 target->label = jit_indirect();
2286 if (likely(op->opcode)) {
2287 f = rec_standard[op->i.op];
2289 if (!HAS_DEFAULT_ELM && unlikely(!f))
2290 unknown_opcode(state, block, offset);
2292 (*f)(state, block, offset);
2295 if (unlikely(op->flags & LIGHTREC_UNLOAD_RD)) {
2296 lightrec_clean_reg_if_loaded(reg_cache, _jit, op->r.rd, true);
2297 pr_debug("Cleaning RD reg %s\n", lightrec_reg_name(op->r.rd));
2299 if (unlikely(op->flags & LIGHTREC_UNLOAD_RS)) {
2300 lightrec_clean_reg_if_loaded(reg_cache, _jit, op->i.rs, true);
2301 pr_debug("Cleaning RS reg %s\n", lightrec_reg_name(op->i.rt));
2303 if (unlikely(op->flags & LIGHTREC_UNLOAD_RT)) {
2304 lightrec_clean_reg_if_loaded(reg_cache, _jit, op->i.rt, true);
2305 pr_debug("Cleaning RT reg %s\n", lightrec_reg_name(op->i.rt));