dev-release: try to make it work
[pcsx_rearmed.git] / deps / lightrec / emitter.c
CommitLineData
98fa08a5 1// SPDX-License-Identifier: LGPL-2.1-or-later
d16005f8 2/*
98fa08a5 3 * Copyright (C) 2014-2021 Paul Cercueil <paul@crapouillou.net>
d16005f8
PC
4 */
5
5eecf06d 6#include "arch.h"
d16005f8
PC
7#include "blockcache.h"
8#include "debug.h"
9#include "disassembler.h"
10#include "emitter.h"
98fa08a5 11#include "lightning-wrapper.h"
d16005f8
PC
12#include "optimizer.h"
13#include "regcache.h"
14
d16005f8
PC
15#include <stdbool.h>
16#include <stddef.h>
17
5459088b
PC
18#define LIGHTNING_UNALIGNED_32BIT 4
19
98fa08a5 20typedef void (*lightrec_rec_func_t)(struct lightrec_cstate *, const struct block *, u16);
d16005f8
PC
21
22/* Forward declarations */
98fa08a5
PC
23static void rec_SPECIAL(struct lightrec_cstate *state, const struct block *block, u16 offset);
24static void rec_REGIMM(struct lightrec_cstate *state, const struct block *block, u16 offset);
25static void rec_CP0(struct lightrec_cstate *state, const struct block *block, u16 offset);
26static void rec_CP2(struct lightrec_cstate *state, const struct block *block, u16 offset);
cb72ea13 27static void rec_META(struct lightrec_cstate *state, const struct block *block, u16 offset);
9259d748
PC
28static void rec_cp2_do_mtc2(struct lightrec_cstate *state,
29 const struct block *block, u16 offset, u8 reg, u8 in_reg);
30static void rec_cp2_do_mfc2(struct lightrec_cstate *state,
31 const struct block *block, u16 offset,
32 u8 reg, u8 out_reg);
d16005f8 33
ba3814c1 34static void
cb72ea13 35lightrec_jump_to_fn(jit_state_t *_jit, void (*fn)(void))
ba3814c1
PC
36{
37 /* Prevent jit_jmpi() from using our cycles register as a temporary */
38 jit_live(LIGHTREC_REG_CYCLE);
39
cb72ea13
PC
40 jit_patch_abs(jit_jmpi(), fn);
41}
42
43static void
44lightrec_jump_to_eob(struct lightrec_cstate *state, jit_state_t *_jit)
45{
46 lightrec_jump_to_fn(_jit, state->state->eob_wrapper_func);
47}
48
49static void
50lightrec_jump_to_ds_check(struct lightrec_cstate *state, jit_state_t *_jit)
51{
52 lightrec_jump_to_fn(_jit, state->state->ds_check_func);
ba3814c1
PC
53}
54
9259d748
PC
55static void update_ra_register(struct regcache *reg_cache, jit_state_t *_jit,
56 u8 ra_reg, u32 pc, u32 link)
57{
58 u8 link_reg;
59
60 link_reg = lightrec_alloc_reg_out(reg_cache, _jit, ra_reg, 0);
61 lightrec_load_imm(reg_cache, _jit, link_reg, pc, link);
62 lightrec_free_reg(reg_cache, link_reg);
63}
64
98fa08a5
PC
65static void lightrec_emit_end_of_block(struct lightrec_cstate *state,
66 const struct block *block, u16 offset,
d16005f8
PC
67 s8 reg_new_pc, u32 imm, u8 ra_reg,
68 u32 link, bool update_cycles)
69{
d16005f8 70 struct regcache *reg_cache = state->reg_cache;
d16005f8 71 jit_state_t *_jit = block->_jit;
98fa08a5 72 const struct opcode *op = &block->opcode_list[offset],
cb72ea13 73 *ds = get_delay_slot(block->opcode_list, offset);
684432ad 74 u32 cycles = state->cycles + lightrec_cycles_of_opcode(state->state, op->c);
d75d83f7 75 bool has_ds = has_delay_slot(op->c);
d16005f8
PC
76
77 jit_note(__FILE__, __LINE__);
78
9259d748
PC
79 if (link && ra_reg != reg_new_pc)
80 update_ra_register(reg_cache, _jit, ra_reg, block->pc, link);
d16005f8 81
9259d748
PC
82 if (reg_new_pc < 0)
83 lightrec_load_next_pc_imm(reg_cache, _jit, block->pc, imm);
84 else
85 lightrec_load_next_pc(reg_cache, _jit, reg_new_pc);
d16005f8 86
9259d748
PC
87 if (link && ra_reg == reg_new_pc) {
88 /* Handle the special case: JALR $r0, $r0
89 * In that case the target PC should be the old value of the
90 * register. */
91 update_ra_register(reg_cache, _jit, ra_reg, block->pc, link);
d16005f8
PC
92 }
93
d75d83f7 94 if (has_ds && !op_flag_no_ds(op->flags) && !op_flag_local_branch(op->flags)) {
684432ad 95 cycles += lightrec_cycles_of_opcode(state->state, ds->c);
d16005f8
PC
96
97 /* Recompile the delay slot */
cb72ea13 98 if (ds->c.opcode)
98fa08a5 99 lightrec_rec_opcode(state, block, offset + 1);
d16005f8
PC
100 }
101
03535202
PC
102 /* Clean the remaining registers */
103 lightrec_clean_regs(reg_cache, _jit);
d16005f8 104
d16005f8
PC
105 if (cycles && update_cycles) {
106 jit_subi(LIGHTREC_REG_CYCLE, LIGHTREC_REG_CYCLE, cycles);
5eecf06d 107 pr_debug("EOB: %"PRIu32" cycles\n", cycles);
d16005f8
PC
108 }
109
d75d83f7 110 if (has_ds && op_flag_load_delay(ds->flags)
a5a6f7b8 111 && opcode_has_load_delay(ds->c) && !state->no_load_delay) {
cb72ea13
PC
112 /* If the delay slot is a load opcode, its target register
113 * will be written after the first opcode of the target is
114 * executed. Handle this by jumping to a special section of
115 * the dispatcher. It expects the loaded value to be in
116 * REG_TEMP, and the target register number to be in JIT_V1.*/
117 jit_movi(JIT_V1, ds->c.i.rt);
118
119 lightrec_jump_to_ds_check(state, _jit);
120 } else {
121 lightrec_jump_to_eob(state, _jit);
122 }
0e720fb1
PC
123
124 lightrec_regcache_reset(reg_cache);
d16005f8
PC
125}
126
cb72ea13
PC
127void lightrec_emit_jump_to_interpreter(struct lightrec_cstate *state,
128 const struct block *block, u16 offset)
129{
130 struct regcache *reg_cache = state->reg_cache;
131 jit_state_t *_jit = block->_jit;
132
133 lightrec_clean_regs(reg_cache, _jit);
134
135 /* Call the interpreter with the block's address in JIT_V1 and the
136 * PC (which might have an offset) in JIT_V0. */
137 lightrec_load_imm(reg_cache, _jit, JIT_V0, block->pc,
138 block->pc + (offset << 2));
0e720fb1 139 if (lightrec_store_next_pc()) {
8afce295 140 jit_stxi_i(lightrec_offset(next_pc), LIGHTREC_REG_STATE, JIT_V0);
0e720fb1
PC
141 }
142
cb72ea13
PC
143 jit_movi(JIT_V1, (uintptr_t)block);
144
145 jit_subi(LIGHTREC_REG_CYCLE, LIGHTREC_REG_CYCLE, state->cycles);
146 lightrec_jump_to_fn(_jit, state->state->interpreter_func);
147}
148
149static void lightrec_emit_eob(struct lightrec_cstate *state,
150 const struct block *block, u16 offset)
d16005f8 151{
d16005f8
PC
152 struct regcache *reg_cache = state->reg_cache;
153 jit_state_t *_jit = block->_jit;
154
03535202 155 lightrec_clean_regs(reg_cache, _jit);
d16005f8 156
9259d748
PC
157 lightrec_load_imm(reg_cache, _jit, JIT_V0, block->pc,
158 block->pc + (offset << 2));
0e720fb1 159 if (lightrec_store_next_pc()) {
8afce295 160 jit_stxi_i(lightrec_offset(next_pc), LIGHTREC_REG_STATE, JIT_V0);
0e720fb1
PC
161 }
162
13b02197 163 jit_subi(LIGHTREC_REG_CYCLE, LIGHTREC_REG_CYCLE, state->cycles);
d16005f8 164
ba3814c1 165 lightrec_jump_to_eob(state, _jit);
d16005f8
PC
166}
167
98fa08a5 168static void rec_special_JR(struct lightrec_cstate *state, const struct block *block, u16 offset)
d16005f8 169{
9259d748 170 union code c = block->opcode_list[offset].c;
d16005f8
PC
171
172 _jit_name(block->_jit, __func__);
9259d748 173 lightrec_emit_end_of_block(state, block, offset, c.r.rs, 0, 31, 0, true);
98fa08a5
PC
174}
175
176static void rec_special_JALR(struct lightrec_cstate *state, const struct block *block, u16 offset)
177{
98fa08a5
PC
178 union code c = block->opcode_list[offset].c;
179
180 _jit_name(block->_jit, __func__);
9259d748 181 lightrec_emit_end_of_block(state, block, offset, c.r.rs, 0, c.r.rd,
98fa08a5 182 get_branch_pc(block, offset, 2), true);
d16005f8
PC
183}
184
98fa08a5 185static void rec_J(struct lightrec_cstate *state, const struct block *block, u16 offset)
d16005f8 186{
98fa08a5
PC
187 union code c = block->opcode_list[offset].c;
188
d16005f8 189 _jit_name(block->_jit, __func__);
98fa08a5
PC
190 lightrec_emit_end_of_block(state, block, offset, -1,
191 (block->pc & 0xf0000000) | (c.j.imm << 2),
192 31, 0, true);
d16005f8
PC
193}
194
98fa08a5 195static void rec_JAL(struct lightrec_cstate *state, const struct block *block, u16 offset)
d16005f8 196{
98fa08a5
PC
197 union code c = block->opcode_list[offset].c;
198
d16005f8 199 _jit_name(block->_jit, __func__);
98fa08a5
PC
200 lightrec_emit_end_of_block(state, block, offset, -1,
201 (block->pc & 0xf0000000) | (c.j.imm << 2),
202 31, get_branch_pc(block, offset, 2), true);
d16005f8
PC
203}
204
03535202
PC
205static void lightrec_do_early_unload(struct lightrec_cstate *state,
206 const struct block *block, u16 offset)
207{
208 struct regcache *reg_cache = state->reg_cache;
209 const struct opcode *op = &block->opcode_list[offset];
210 jit_state_t *_jit = block->_jit;
211 unsigned int i;
212 u8 reg;
213 struct {
214 u8 reg, op;
215 } reg_ops[3] = {
216 { op->r.rd, LIGHTREC_FLAGS_GET_RD(op->flags), },
217 { op->i.rt, LIGHTREC_FLAGS_GET_RT(op->flags), },
218 { op->i.rs, LIGHTREC_FLAGS_GET_RS(op->flags), },
219 };
220
221 for (i = 0; i < ARRAY_SIZE(reg_ops); i++) {
222 reg = reg_ops[i].reg;
223
224 switch (reg_ops[i].op) {
225 case LIGHTREC_REG_UNLOAD:
226 lightrec_clean_reg_if_loaded(reg_cache, _jit, reg, true);
227 break;
228
229 case LIGHTREC_REG_DISCARD:
230 lightrec_discard_reg_if_loaded(reg_cache, reg);
231 break;
232
233 case LIGHTREC_REG_CLEAN:
234 lightrec_clean_reg_if_loaded(reg_cache, _jit, reg, false);
235 break;
236 default:
237 break;
238 };
239 }
240}
241
98fa08a5 242static void rec_b(struct lightrec_cstate *state, const struct block *block, u16 offset,
ba3814c1 243 jit_code_t code, jit_code_t code2, u32 link, bool unconditional, bool bz)
d16005f8 244{
98fa08a5 245 struct regcache *reg_cache = state->reg_cache;
d16005f8
PC
246 struct native_register *regs_backup;
247 jit_state_t *_jit = block->_jit;
248 struct lightrec_branch *branch;
98fa08a5 249 const struct opcode *op = &block->opcode_list[offset],
cb72ea13 250 *ds = get_delay_slot(block->opcode_list, offset);
cb72ea13 251 bool is_forward = (s16)op->i.imm >= 0;
684432ad 252 int op_cycles = lightrec_cycles_of_opcode(state->state, op->c);
03535202 253 u32 target_offset, cycles = state->cycles + op_cycles;
ba3814c1 254 bool no_indirection = false;
5eecf06d 255 jit_node_t *addr = NULL;
98fa08a5 256 u32 next_pc;
9259d748 257 u8 rs, rt;
d16005f8
PC
258
259 jit_note(__FILE__, __LINE__);
260
03535202 261 if (!op_flag_no_ds(op->flags))
684432ad 262 cycles += lightrec_cycles_of_opcode(state->state, ds->c);
d16005f8 263
03535202
PC
264 state->cycles = -op_cycles;
265
266 if (!unconditional) {
267 rs = lightrec_alloc_reg_in(reg_cache, _jit, op->i.rs, REG_EXT);
268 rt = bz ? 0 : lightrec_alloc_reg_in(reg_cache,
269 _jit, op->i.rt, REG_EXT);
270
271 /* Unload dead registers before evaluating the branch */
272 if (OPT_EARLY_UNLOAD)
273 lightrec_do_early_unload(state, block, offset);
ba3814c1
PC
274
275 if (op_flag_local_branch(op->flags) &&
cb72ea13 276 (op_flag_no_ds(op->flags) || !ds->opcode) &&
ba3814c1
PC
277 is_forward && !lightrec_has_dirty_regs(reg_cache))
278 no_indirection = true;
279
280 if (no_indirection)
281 pr_debug("Using no indirection for branch at offset 0x%hx\n", offset << 2);
03535202 282 }
d16005f8
PC
283
284 if (cycles)
285 jit_subi(LIGHTREC_REG_CYCLE, LIGHTREC_REG_CYCLE, cycles);
286
287 if (!unconditional) {
d16005f8 288 /* Generate the branch opcode */
ba3814c1
PC
289 if (!no_indirection)
290 addr = jit_new_node_pww(code, NULL, rs, rt);
d16005f8
PC
291
292 lightrec_free_regs(reg_cache);
293 regs_backup = lightrec_regcache_enter_branch(reg_cache);
294 }
295
03535202
PC
296 if (op_flag_local_branch(op->flags)) {
297 /* Recompile the delay slot */
cb72ea13
PC
298 if (!op_flag_no_ds(op->flags) && ds->opcode) {
299 /* Never handle load delays with local branches. */
300 state->no_load_delay = true;
03535202 301 lightrec_rec_opcode(state, block, offset + 1);
cb72ea13 302 }
d16005f8 303
9259d748
PC
304 if (link)
305 update_ra_register(reg_cache, _jit, 31, block->pc, link);
d16005f8 306
03535202
PC
307 /* Clean remaining registers */
308 lightrec_clean_regs(reg_cache, _jit);
d16005f8 309
98fa08a5 310 target_offset = offset + 1 + (s16)op->i.imm
03535202 311 - !!op_flag_no_ds(op->flags);
5eecf06d 312 pr_debug("Adding local branch to offset 0x%"PRIx32"\n",
98fa08a5
PC
313 target_offset << 2);
314 branch = &state->local_branches[
315 state->nb_local_branches++];
d16005f8 316
98fa08a5 317 branch->target = target_offset;
ba3814c1
PC
318
319 if (no_indirection)
320 branch->branch = jit_new_node_pww(code2, NULL, rs, rt);
321 else if (is_forward)
22eee2ac 322 branch->branch = jit_b();
d16005f8
PC
323 else
324 branch->branch = jit_bgti(LIGHTREC_REG_CYCLE, 0);
325 }
326
03535202 327 if (!op_flag_local_branch(op->flags) || !is_forward) {
98fa08a5 328 next_pc = get_branch_pc(block, offset, 1 + (s16)op->i.imm);
cb72ea13 329 state->no_load_delay = op_flag_local_branch(op->flags);
98fa08a5 330 lightrec_emit_end_of_block(state, block, offset, -1, next_pc,
d16005f8
PC
331 31, link, false);
332 }
333
334 if (!unconditional) {
ba3814c1
PC
335 if (!no_indirection)
336 jit_patch(addr);
337
d16005f8
PC
338 lightrec_regcache_leave_branch(reg_cache, regs_backup);
339
9259d748
PC
340 if (bz && link)
341 update_ra_register(reg_cache, _jit, 31, block->pc, link);
d16005f8 342
cb72ea13
PC
343 if (!op_flag_no_ds(op->flags) && ds->opcode) {
344 state->no_load_delay = true;
98fa08a5 345 lightrec_rec_opcode(state, block, offset + 1);
cb72ea13 346 }
d16005f8
PC
347 }
348}
349
98fa08a5
PC
350static void rec_BNE(struct lightrec_cstate *state,
351 const struct block *block, u16 offset)
d16005f8 352{
98fa08a5
PC
353 union code c = block->opcode_list[offset].c;
354
d16005f8 355 _jit_name(block->_jit, __func__);
98fa08a5
PC
356
357 if (c.i.rt == 0)
ba3814c1 358 rec_b(state, block, offset, jit_code_beqi, jit_code_bnei, 0, false, true);
98fa08a5 359 else
ba3814c1 360 rec_b(state, block, offset, jit_code_beqr, jit_code_bner, 0, false, false);
d16005f8
PC
361}
362
98fa08a5
PC
363static void rec_BEQ(struct lightrec_cstate *state,
364 const struct block *block, u16 offset)
d16005f8 365{
98fa08a5
PC
366 union code c = block->opcode_list[offset].c;
367
d16005f8 368 _jit_name(block->_jit, __func__);
98fa08a5
PC
369
370 if (c.i.rt == 0)
ba3814c1 371 rec_b(state, block, offset, jit_code_bnei, jit_code_beqi, 0, c.i.rs == 0, true);
98fa08a5 372 else
ba3814c1 373 rec_b(state, block, offset, jit_code_bner, jit_code_beqr, 0, c.i.rs == c.i.rt, false);
d16005f8
PC
374}
375
98fa08a5
PC
376static void rec_BLEZ(struct lightrec_cstate *state,
377 const struct block *block, u16 offset)
d16005f8 378{
98fa08a5
PC
379 union code c = block->opcode_list[offset].c;
380
d16005f8 381 _jit_name(block->_jit, __func__);
ba3814c1 382 rec_b(state, block, offset, jit_code_bgti, jit_code_blei, 0, c.i.rs == 0, true);
d16005f8
PC
383}
384
98fa08a5
PC
385static void rec_BGTZ(struct lightrec_cstate *state,
386 const struct block *block, u16 offset)
d16005f8
PC
387{
388 _jit_name(block->_jit, __func__);
ba3814c1 389 rec_b(state, block, offset, jit_code_blei, jit_code_bgti, 0, false, true);
d16005f8
PC
390}
391
98fa08a5
PC
392static void rec_regimm_BLTZ(struct lightrec_cstate *state,
393 const struct block *block, u16 offset)
d16005f8
PC
394{
395 _jit_name(block->_jit, __func__);
ba3814c1 396 rec_b(state, block, offset, jit_code_bgei, jit_code_blti, 0, false, true);
d16005f8
PC
397}
398
98fa08a5
PC
399static void rec_regimm_BLTZAL(struct lightrec_cstate *state,
400 const struct block *block, u16 offset)
d16005f8
PC
401{
402 _jit_name(block->_jit, __func__);
ba3814c1 403 rec_b(state, block, offset, jit_code_bgei, jit_code_blti,
98fa08a5 404 get_branch_pc(block, offset, 2), false, true);
d16005f8
PC
405}
406
98fa08a5
PC
407static void rec_regimm_BGEZ(struct lightrec_cstate *state,
408 const struct block *block, u16 offset)
d16005f8 409{
98fa08a5
PC
410 union code c = block->opcode_list[offset].c;
411
d16005f8 412 _jit_name(block->_jit, __func__);
ba3814c1 413 rec_b(state, block, offset, jit_code_blti, jit_code_bgei, 0, !c.i.rs, true);
d16005f8
PC
414}
415
98fa08a5
PC
416static void rec_regimm_BGEZAL(struct lightrec_cstate *state,
417 const struct block *block, u16 offset)
d16005f8 418{
98fa08a5 419 const struct opcode *op = &block->opcode_list[offset];
d16005f8 420 _jit_name(block->_jit, __func__);
ba3814c1 421 rec_b(state, block, offset, jit_code_blti, jit_code_bgei,
98fa08a5
PC
422 get_branch_pc(block, offset, 2),
423 !op->i.rs, true);
d16005f8
PC
424}
425
684432ad
PC
426static void rec_alloc_rs_rd(struct regcache *reg_cache,
427 jit_state_t *_jit,
428 const struct opcode *op,
429 u8 rs, u8 rd,
430 u8 in_flags, u8 out_flags,
431 u8 *rs_out, u8 *rd_out)
432{
433 bool unload, discard;
434 u32 unload_flags;
435
436 if (OPT_EARLY_UNLOAD) {
437 unload_flags = LIGHTREC_FLAGS_GET_RS(op->flags);
438 unload = unload_flags == LIGHTREC_REG_UNLOAD;
439 discard = unload_flags == LIGHTREC_REG_DISCARD;
440 }
441
442 if (OPT_EARLY_UNLOAD && rs && rd != rs && (unload || discard)) {
443 rs = lightrec_alloc_reg_in(reg_cache, _jit, rs, in_flags);
444 lightrec_remap_reg(reg_cache, _jit, rs, rd, discard);
445 lightrec_set_reg_out_flags(reg_cache, rs, out_flags);
446 rd = rs;
447 } else {
448 rs = lightrec_alloc_reg_in(reg_cache, _jit, rs, in_flags);
449 rd = lightrec_alloc_reg_out(reg_cache, _jit, rd, out_flags);
450 }
451
452 *rs_out = rs;
453 *rd_out = rd;
454}
455
98fa08a5
PC
456static void rec_alu_imm(struct lightrec_cstate *state, const struct block *block,
457 u16 offset, jit_code_t code, bool slti)
d16005f8 458{
98fa08a5
PC
459 struct regcache *reg_cache = state->reg_cache;
460 union code c = block->opcode_list[offset].c;
d16005f8 461 jit_state_t *_jit = block->_jit;
98fa08a5
PC
462 u8 rs, rt, out_flags = REG_EXT;
463
464 if (slti)
465 out_flags |= REG_ZEXT;
d16005f8
PC
466
467 jit_note(__FILE__, __LINE__);
684432ad
PC
468
469 rec_alloc_rs_rd(reg_cache, _jit, &block->opcode_list[offset],
470 c.i.rs, c.i.rt, REG_EXT, out_flags, &rs, &rt);
d16005f8 471
98fa08a5 472 jit_new_node_www(code, rt, rs, (s32)(s16) c.i.imm);
d16005f8
PC
473
474 lightrec_free_reg(reg_cache, rs);
475 lightrec_free_reg(reg_cache, rt);
476}
477
98fa08a5
PC
478static void rec_alu_special(struct lightrec_cstate *state, const struct block *block,
479 u16 offset, jit_code_t code, bool out_ext)
d16005f8 480{
98fa08a5
PC
481 struct regcache *reg_cache = state->reg_cache;
482 union code c = block->opcode_list[offset].c;
d16005f8
PC
483 jit_state_t *_jit = block->_jit;
484 u8 rd, rt, rs;
485
486 jit_note(__FILE__, __LINE__);
684432ad 487
98fa08a5 488 rt = lightrec_alloc_reg_in(reg_cache, _jit, c.r.rt, REG_EXT);
684432ad
PC
489 rec_alloc_rs_rd(reg_cache, _jit, &block->opcode_list[offset],
490 c.r.rs, c.r.rd, REG_EXT,
491 out_ext ? REG_EXT | REG_ZEXT : 0, &rs, &rd);
d16005f8
PC
492
493 jit_new_node_www(code, rd, rs, rt);
494
495 lightrec_free_reg(reg_cache, rs);
496 lightrec_free_reg(reg_cache, rt);
497 lightrec_free_reg(reg_cache, rd);
498}
499
98fa08a5
PC
500static void rec_alu_shiftv(struct lightrec_cstate *state, const struct block *block,
501 u16 offset, jit_code_t code)
d16005f8 502{
98fa08a5
PC
503 struct regcache *reg_cache = state->reg_cache;
504 union code c = block->opcode_list[offset].c;
d16005f8 505 jit_state_t *_jit = block->_jit;
98fa08a5 506 u8 rd, rt, rs, temp, flags = 0;
d16005f8
PC
507
508 jit_note(__FILE__, __LINE__);
d16005f8 509
98fa08a5
PC
510 if (code == jit_code_rshr)
511 flags = REG_EXT;
512 else if (code == jit_code_rshr_u)
513 flags = REG_ZEXT;
d16005f8 514
684432ad
PC
515 rs = lightrec_alloc_reg_in(reg_cache, _jit, c.r.rs, 0);
516 rec_alloc_rs_rd(reg_cache, _jit, &block->opcode_list[offset],
517 c.r.rt, c.r.rd, flags, flags, &rt, &rd);
d16005f8 518
684432ad 519 if (rt != rd) {
98fa08a5
PC
520 jit_andi(rd, rs, 0x1f);
521 jit_new_node_www(code, rd, rt, rd);
522 } else {
523 temp = lightrec_alloc_reg_temp(reg_cache, _jit);
524 jit_andi(temp, rs, 0x1f);
d16005f8 525 jit_new_node_www(code, rd, rt, temp);
98fa08a5
PC
526 lightrec_free_reg(reg_cache, temp);
527 }
d16005f8
PC
528
529 lightrec_free_reg(reg_cache, rs);
d16005f8
PC
530 lightrec_free_reg(reg_cache, rt);
531 lightrec_free_reg(reg_cache, rd);
532}
533
02487de7
PC
534static void rec_movi(struct lightrec_cstate *state,
535 const struct block *block, u16 offset)
536{
537 struct regcache *reg_cache = state->reg_cache;
538 union code c = block->opcode_list[offset].c;
539 jit_state_t *_jit = block->_jit;
540 u16 flags = REG_EXT;
684432ad 541 s32 value = (s32)(s16) c.i.imm;
02487de7
PC
542 u8 rt;
543
684432ad
PC
544 if (block->opcode_list[offset].flags & LIGHTREC_MOVI)
545 value += (s32)((u32)state->movi_temp[c.i.rt] << 16);
546
547 if (value >= 0)
02487de7
PC
548 flags |= REG_ZEXT;
549
550 rt = lightrec_alloc_reg_out(reg_cache, _jit, c.i.rt, flags);
551
684432ad 552 jit_movi(rt, value);
02487de7
PC
553
554 lightrec_free_reg(reg_cache, rt);
555}
556
98fa08a5
PC
557static void rec_ADDIU(struct lightrec_cstate *state,
558 const struct block *block, u16 offset)
d16005f8 559{
684432ad
PC
560 const struct opcode *op = &block->opcode_list[offset];
561
d16005f8 562 _jit_name(block->_jit, __func__);
02487de7 563
684432ad 564 if (op->i.rs && !(op->flags & LIGHTREC_MOVI))
02487de7
PC
565 rec_alu_imm(state, block, offset, jit_code_addi, false);
566 else
567 rec_movi(state, block, offset);
d16005f8
PC
568}
569
98fa08a5
PC
570static void rec_ADDI(struct lightrec_cstate *state,
571 const struct block *block, u16 offset)
d16005f8
PC
572{
573 /* TODO: Handle the exception? */
574 _jit_name(block->_jit, __func__);
02487de7 575 rec_ADDIU(state, block, offset);
d16005f8
PC
576}
577
98fa08a5
PC
578static void rec_SLTIU(struct lightrec_cstate *state,
579 const struct block *block, u16 offset)
d16005f8
PC
580{
581 _jit_name(block->_jit, __func__);
98fa08a5 582 rec_alu_imm(state, block, offset, jit_code_lti_u, true);
d16005f8
PC
583}
584
98fa08a5
PC
585static void rec_SLTI(struct lightrec_cstate *state,
586 const struct block *block, u16 offset)
d16005f8
PC
587{
588 _jit_name(block->_jit, __func__);
98fa08a5 589 rec_alu_imm(state, block, offset, jit_code_lti, true);
d16005f8
PC
590}
591
98fa08a5
PC
592static void rec_ANDI(struct lightrec_cstate *state,
593 const struct block *block, u16 offset)
d16005f8 594{
98fa08a5
PC
595 struct regcache *reg_cache = state->reg_cache;
596 union code c = block->opcode_list[offset].c;
d16005f8
PC
597 jit_state_t *_jit = block->_jit;
598 u8 rs, rt;
599
600 _jit_name(block->_jit, __func__);
601 jit_note(__FILE__, __LINE__);
684432ad
PC
602
603 rec_alloc_rs_rd(reg_cache, _jit, &block->opcode_list[offset],
604 c.i.rs, c.i.rt, 0, REG_EXT | REG_ZEXT, &rs, &rt);
d16005f8
PC
605
606 /* PSX code uses ANDI 0xff / ANDI 0xffff a lot, which are basically
607 * casts to uint8_t / uint16_t. */
98fa08a5 608 if (c.i.imm == 0xff)
d16005f8 609 jit_extr_uc(rt, rs);
98fa08a5 610 else if (c.i.imm == 0xffff)
d16005f8
PC
611 jit_extr_us(rt, rs);
612 else
98fa08a5
PC
613 jit_andi(rt, rs, (u32)(u16) c.i.imm);
614
615 lightrec_free_reg(reg_cache, rs);
616 lightrec_free_reg(reg_cache, rt);
617}
618
619static void rec_alu_or_xor(struct lightrec_cstate *state, const struct block *block,
620 u16 offset, jit_code_t code)
621{
622 struct regcache *reg_cache = state->reg_cache;
623 union code c = block->opcode_list[offset].c;
624 jit_state_t *_jit = block->_jit;
625 u8 rs, rt, flags;
626
627 jit_note(__FILE__, __LINE__);
684432ad
PC
628
629 rec_alloc_rs_rd(reg_cache, _jit, &block->opcode_list[offset],
630 c.i.rs, c.i.rt, 0, 0, &rs, &rt);
98fa08a5
PC
631
632 flags = lightrec_get_reg_in_flags(reg_cache, rs);
633 lightrec_set_reg_out_flags(reg_cache, rt, flags);
634
635 jit_new_node_www(code, rt, rs, (u32)(u16) c.i.imm);
d16005f8
PC
636
637 lightrec_free_reg(reg_cache, rs);
638 lightrec_free_reg(reg_cache, rt);
639}
640
98fa08a5
PC
641
642static void rec_ORI(struct lightrec_cstate *state,
643 const struct block *block, u16 offset)
d16005f8 644{
684432ad
PC
645 const struct opcode *op = &block->opcode_list[offset];
646 struct regcache *reg_cache = state->reg_cache;
647 jit_state_t *_jit = block->_jit;
648 s32 val;
649 u8 rt;
650
651 _jit_name(_jit, __func__);
652
653 if (op->flags & LIGHTREC_MOVI) {
654 rt = lightrec_alloc_reg_out(reg_cache, _jit, op->i.rt, REG_EXT);
655
656 val = ((u32)state->movi_temp[op->i.rt] << 16) | op->i.imm;
657 jit_movi(rt, val);
658
659 lightrec_free_reg(reg_cache, rt);
660 } else {
661 rec_alu_or_xor(state, block, offset, jit_code_ori);
662 }
d16005f8
PC
663}
664
98fa08a5
PC
665static void rec_XORI(struct lightrec_cstate *state,
666 const struct block *block, u16 offset)
d16005f8
PC
667{
668 _jit_name(block->_jit, __func__);
98fa08a5 669 rec_alu_or_xor(state, block, offset, jit_code_xori);
d16005f8
PC
670}
671
98fa08a5
PC
672static void rec_LUI(struct lightrec_cstate *state,
673 const struct block *block, u16 offset)
d16005f8 674{
98fa08a5
PC
675 struct regcache *reg_cache = state->reg_cache;
676 union code c = block->opcode_list[offset].c;
d16005f8 677 jit_state_t *_jit = block->_jit;
98fa08a5 678 u8 rt, flags = REG_EXT;
d16005f8 679
684432ad
PC
680 if (block->opcode_list[offset].flags & LIGHTREC_MOVI) {
681 state->movi_temp[c.i.rt] = c.i.imm;
682 return;
683 }
684
d16005f8
PC
685 jit_name(__func__);
686 jit_note(__FILE__, __LINE__);
d16005f8 687
98fa08a5
PC
688 if (!(c.i.imm & BIT(15)))
689 flags |= REG_ZEXT;
690
691 rt = lightrec_alloc_reg_out(reg_cache, _jit, c.i.rt, flags);
692
693 jit_movi(rt, (s32)(c.i.imm << 16));
d16005f8
PC
694
695 lightrec_free_reg(reg_cache, rt);
696}
697
98fa08a5
PC
698static void rec_special_ADDU(struct lightrec_cstate *state,
699 const struct block *block, u16 offset)
d16005f8
PC
700{
701 _jit_name(block->_jit, __func__);
98fa08a5 702 rec_alu_special(state, block, offset, jit_code_addr, false);
d16005f8
PC
703}
704
98fa08a5
PC
705static void rec_special_ADD(struct lightrec_cstate *state,
706 const struct block *block, u16 offset)
d16005f8
PC
707{
708 /* TODO: Handle the exception? */
709 _jit_name(block->_jit, __func__);
98fa08a5 710 rec_alu_special(state, block, offset, jit_code_addr, false);
d16005f8
PC
711}
712
98fa08a5
PC
713static void rec_special_SUBU(struct lightrec_cstate *state,
714 const struct block *block, u16 offset)
d16005f8
PC
715{
716 _jit_name(block->_jit, __func__);
98fa08a5 717 rec_alu_special(state, block, offset, jit_code_subr, false);
d16005f8
PC
718}
719
98fa08a5
PC
720static void rec_special_SUB(struct lightrec_cstate *state,
721 const struct block *block, u16 offset)
d16005f8
PC
722{
723 /* TODO: Handle the exception? */
724 _jit_name(block->_jit, __func__);
98fa08a5 725 rec_alu_special(state, block, offset, jit_code_subr, false);
d16005f8
PC
726}
727
98fa08a5
PC
728static void rec_special_AND(struct lightrec_cstate *state,
729 const struct block *block, u16 offset)
d16005f8 730{
98fa08a5
PC
731 struct regcache *reg_cache = state->reg_cache;
732 union code c = block->opcode_list[offset].c;
733 jit_state_t *_jit = block->_jit;
734 u8 rd, rt, rs, flags_rs, flags_rt, flags_rd;
735
d16005f8 736 _jit_name(block->_jit, __func__);
98fa08a5 737 jit_note(__FILE__, __LINE__);
684432ad 738
98fa08a5 739 rt = lightrec_alloc_reg_in(reg_cache, _jit, c.r.rt, 0);
684432ad
PC
740 rec_alloc_rs_rd(reg_cache, _jit, &block->opcode_list[offset],
741 c.r.rs, c.r.rd, 0, 0, &rs, &rd);
98fa08a5
PC
742
743 flags_rs = lightrec_get_reg_in_flags(reg_cache, rs);
744 flags_rt = lightrec_get_reg_in_flags(reg_cache, rt);
745
746 /* Z(rd) = Z(rs) | Z(rt) */
747 flags_rd = REG_ZEXT & (flags_rs | flags_rt);
748
749 /* E(rd) = (E(rt) & Z(rt)) | (E(rs) & Z(rs)) | (E(rs) & E(rt)) */
750 if (((flags_rs & REG_EXT) && (flags_rt & REG_ZEXT)) ||
751 ((flags_rt & REG_EXT) && (flags_rs & REG_ZEXT)) ||
752 (REG_EXT & flags_rs & flags_rt))
753 flags_rd |= REG_EXT;
754
755 lightrec_set_reg_out_flags(reg_cache, rd, flags_rd);
756
757 jit_andr(rd, rs, rt);
758
759 lightrec_free_reg(reg_cache, rs);
760 lightrec_free_reg(reg_cache, rt);
761 lightrec_free_reg(reg_cache, rd);
d16005f8
PC
762}
763
98fa08a5
PC
764static void rec_special_or_nor(struct lightrec_cstate *state,
765 const struct block *block, u16 offset, bool nor)
766{
767 struct regcache *reg_cache = state->reg_cache;
768 union code c = block->opcode_list[offset].c;
769 jit_state_t *_jit = block->_jit;
770 u8 rd, rt, rs, flags_rs, flags_rt, flags_rd = 0;
771
772 jit_note(__FILE__, __LINE__);
684432ad 773
98fa08a5 774 rt = lightrec_alloc_reg_in(reg_cache, _jit, c.r.rt, 0);
684432ad
PC
775 rec_alloc_rs_rd(reg_cache, _jit, &block->opcode_list[offset],
776 c.r.rs, c.r.rd, 0, 0, &rs, &rd);
98fa08a5
PC
777
778 flags_rs = lightrec_get_reg_in_flags(reg_cache, rs);
779 flags_rt = lightrec_get_reg_in_flags(reg_cache, rt);
780
781 /* or: Z(rd) = Z(rs) & Z(rt)
782 * nor: Z(rd) = 0 */
783 if (!nor)
784 flags_rd = REG_ZEXT & flags_rs & flags_rt;
785
6ce0b00a
PC
786 /* E(rd) = E(rs) & E(rt) */
787 if (REG_EXT & flags_rs & flags_rt)
98fa08a5
PC
788 flags_rd |= REG_EXT;
789
790 lightrec_set_reg_out_flags(reg_cache, rd, flags_rd);
791
792 jit_orr(rd, rs, rt);
793
794 if (nor)
795 jit_comr(rd, rd);
796
797 lightrec_free_reg(reg_cache, rs);
798 lightrec_free_reg(reg_cache, rt);
799 lightrec_free_reg(reg_cache, rd);
800}
801
802static void rec_special_OR(struct lightrec_cstate *state,
803 const struct block *block, u16 offset)
d16005f8
PC
804{
805 _jit_name(block->_jit, __func__);
98fa08a5 806 rec_special_or_nor(state, block, offset, false);
d16005f8
PC
807}
808
98fa08a5
PC
809static void rec_special_NOR(struct lightrec_cstate *state,
810 const struct block *block, u16 offset)
d16005f8
PC
811{
812 _jit_name(block->_jit, __func__);
98fa08a5 813 rec_special_or_nor(state, block, offset, true);
d16005f8
PC
814}
815
98fa08a5
PC
816static void rec_special_XOR(struct lightrec_cstate *state,
817 const struct block *block, u16 offset)
d16005f8 818{
98fa08a5
PC
819 struct regcache *reg_cache = state->reg_cache;
820 union code c = block->opcode_list[offset].c;
d16005f8 821 jit_state_t *_jit = block->_jit;
98fa08a5 822 u8 rd, rt, rs, flags_rs, flags_rt, flags_rd;
d16005f8 823
98fa08a5
PC
824 _jit_name(block->_jit, __func__);
825
826 jit_note(__FILE__, __LINE__);
684432ad 827
98fa08a5 828 rt = lightrec_alloc_reg_in(reg_cache, _jit, c.r.rt, 0);
684432ad
PC
829 rec_alloc_rs_rd(reg_cache, _jit, &block->opcode_list[offset],
830 c.r.rs, c.r.rd, 0, 0, &rs, &rd);
d16005f8 831
98fa08a5
PC
832 flags_rs = lightrec_get_reg_in_flags(reg_cache, rs);
833 flags_rt = lightrec_get_reg_in_flags(reg_cache, rt);
d16005f8 834
98fa08a5
PC
835 /* Z(rd) = Z(rs) & Z(rt) */
836 flags_rd = REG_ZEXT & flags_rs & flags_rt;
837
838 /* E(rd) = E(rs) & E(rt) */
839 flags_rd |= REG_EXT & flags_rs & flags_rt;
840
841 lightrec_set_reg_out_flags(reg_cache, rd, flags_rd);
842
843 jit_xorr(rd, rs, rt);
844
845 lightrec_free_reg(reg_cache, rs);
846 lightrec_free_reg(reg_cache, rt);
d16005f8
PC
847 lightrec_free_reg(reg_cache, rd);
848}
849
98fa08a5
PC
850static void rec_special_SLTU(struct lightrec_cstate *state,
851 const struct block *block, u16 offset)
d16005f8
PC
852{
853 _jit_name(block->_jit, __func__);
98fa08a5 854 rec_alu_special(state, block, offset, jit_code_ltr_u, true);
d16005f8
PC
855}
856
98fa08a5
PC
857static void rec_special_SLT(struct lightrec_cstate *state,
858 const struct block *block, u16 offset)
d16005f8
PC
859{
860 _jit_name(block->_jit, __func__);
98fa08a5 861 rec_alu_special(state, block, offset, jit_code_ltr, true);
d16005f8
PC
862}
863
98fa08a5
PC
864static void rec_special_SLLV(struct lightrec_cstate *state,
865 const struct block *block, u16 offset)
d16005f8
PC
866{
867 _jit_name(block->_jit, __func__);
98fa08a5 868 rec_alu_shiftv(state, block, offset, jit_code_lshr);
d16005f8
PC
869}
870
98fa08a5
PC
871static void rec_special_SRLV(struct lightrec_cstate *state,
872 const struct block *block, u16 offset)
d16005f8
PC
873{
874 _jit_name(block->_jit, __func__);
98fa08a5 875 rec_alu_shiftv(state, block, offset, jit_code_rshr_u);
d16005f8
PC
876}
877
98fa08a5
PC
878static void rec_special_SRAV(struct lightrec_cstate *state,
879 const struct block *block, u16 offset)
d16005f8
PC
880{
881 _jit_name(block->_jit, __func__);
98fa08a5 882 rec_alu_shiftv(state, block, offset, jit_code_rshr);
d16005f8
PC
883}
884
98fa08a5
PC
885static void rec_alu_shift(struct lightrec_cstate *state, const struct block *block,
886 u16 offset, jit_code_t code)
d16005f8 887{
98fa08a5
PC
888 struct regcache *reg_cache = state->reg_cache;
889 union code c = block->opcode_list[offset].c;
d16005f8 890 jit_state_t *_jit = block->_jit;
684432ad 891 u8 rd, rt, flags = 0, out_flags = 0;
d16005f8
PC
892
893 jit_note(__FILE__, __LINE__);
894
98fa08a5
PC
895 if (code == jit_code_rshi)
896 flags = REG_EXT;
897 else if (code == jit_code_rshi_u)
898 flags = REG_ZEXT;
d16005f8 899
98fa08a5
PC
900 /* Input reg is zero-extended, if we SRL at least by one bit, we know
901 * the output reg will be both zero-extended and sign-extended. */
684432ad 902 out_flags = flags;
98fa08a5 903 if (code == jit_code_rshi_u && c.r.imm)
684432ad
PC
904 out_flags |= REG_EXT;
905
906 rec_alloc_rs_rd(reg_cache, _jit, &block->opcode_list[offset],
907 c.r.rt, c.r.rd, flags, out_flags, &rt, &rd);
98fa08a5
PC
908
909 jit_new_node_www(code, rd, rt, c.r.imm);
d16005f8
PC
910
911 lightrec_free_reg(reg_cache, rt);
912 lightrec_free_reg(reg_cache, rd);
913}
914
98fa08a5
PC
915static void rec_special_SLL(struct lightrec_cstate *state,
916 const struct block *block, u16 offset)
d16005f8
PC
917{
918 _jit_name(block->_jit, __func__);
98fa08a5 919 rec_alu_shift(state, block, offset, jit_code_lshi);
d16005f8
PC
920}
921
98fa08a5
PC
922static void rec_special_SRL(struct lightrec_cstate *state,
923 const struct block *block, u16 offset)
d16005f8
PC
924{
925 _jit_name(block->_jit, __func__);
98fa08a5 926 rec_alu_shift(state, block, offset, jit_code_rshi_u);
d16005f8
PC
927}
928
98fa08a5
PC
929static void rec_special_SRA(struct lightrec_cstate *state,
930 const struct block *block, u16 offset)
d16005f8
PC
931{
932 _jit_name(block->_jit, __func__);
98fa08a5 933 rec_alu_shift(state, block, offset, jit_code_rshi);
d16005f8
PC
934}
935
98fa08a5
PC
936static void rec_alu_mult(struct lightrec_cstate *state,
937 const struct block *block, u16 offset, bool is_signed)
d16005f8 938{
98fa08a5
PC
939 struct regcache *reg_cache = state->reg_cache;
940 union code c = block->opcode_list[offset].c;
03535202 941 u32 flags = block->opcode_list[offset].flags;
98fa08a5
PC
942 u8 reg_lo = get_mult_div_lo(c);
943 u8 reg_hi = get_mult_div_hi(c);
d16005f8 944 jit_state_t *_jit = block->_jit;
5eecf06d 945 u8 lo, hi = 0, rs, rt, rflags = 0;
5459088b
PC
946 bool no_lo = op_flag_no_lo(flags);
947 bool no_hi = op_flag_no_hi(flags);
d16005f8
PC
948
949 jit_note(__FILE__, __LINE__);
950
98fa08a5
PC
951 if (is_signed)
952 rflags = REG_EXT;
953 else
954 rflags = REG_ZEXT;
955
956 rs = lightrec_alloc_reg_in(reg_cache, _jit, c.r.rs, rflags);
957 rt = lightrec_alloc_reg_in(reg_cache, _jit, c.r.rt, rflags);
958
5459088b 959 if (!no_lo)
98fa08a5 960 lo = lightrec_alloc_reg_out(reg_cache, _jit, reg_lo, 0);
98fa08a5 961
5459088b 962 if (!no_hi)
98fa08a5
PC
963 hi = lightrec_alloc_reg_out(reg_cache, _jit, reg_hi, REG_EXT);
964
965 if (__WORDSIZE == 32) {
966 /* On 32-bit systems, do a 32*32->64 bit operation, or a 32*32->32 bit
967 * operation if the MULT was detected a 32-bit only. */
5459088b 968 if (no_lo) {
98fa08a5 969 if (is_signed)
5459088b 970 jit_hmulr(hi, rs, rt);
98fa08a5 971 else
5459088b
PC
972 jit_hmulr_u(hi, rs, rt);
973 } else if (no_hi) {
98fa08a5 974 jit_mulr(lo, rs, rt);
5459088b
PC
975 } else if (is_signed) {
976 jit_qmulr(lo, hi, rs, rt);
977 } else {
978 jit_qmulr_u(lo, hi, rs, rt);
98fa08a5 979 }
d16005f8 980 } else {
98fa08a5 981 /* On 64-bit systems, do a 64*64->64 bit operation. */
5459088b 982 if (no_lo) {
98fa08a5
PC
983 jit_mulr(hi, rs, rt);
984 jit_rshi(hi, hi, 32);
985 } else {
986 jit_mulr(lo, rs, rt);
d16005f8 987
98fa08a5 988 /* The 64-bit output value is in $lo, store the upper 32 bits in $hi */
5459088b 989 if (!no_hi)
98fa08a5
PC
990 jit_rshi(hi, lo, 32);
991 }
d16005f8
PC
992 }
993
d16005f8
PC
994 lightrec_free_reg(reg_cache, rs);
995 lightrec_free_reg(reg_cache, rt);
5459088b 996 if (!no_lo)
98fa08a5 997 lightrec_free_reg(reg_cache, lo);
5459088b 998 if (!no_hi)
d16005f8
PC
999 lightrec_free_reg(reg_cache, hi);
1000}
1001
98fa08a5
PC
1002static void rec_alu_div(struct lightrec_cstate *state,
1003 const struct block *block, u16 offset, bool is_signed)
d16005f8 1004{
98fa08a5
PC
1005 struct regcache *reg_cache = state->reg_cache;
1006 union code c = block->opcode_list[offset].c;
03535202
PC
1007 u32 flags = block->opcode_list[offset].flags;
1008 bool no_check = op_flag_no_div_check(flags);
98fa08a5
PC
1009 u8 reg_lo = get_mult_div_lo(c);
1010 u8 reg_hi = get_mult_div_hi(c);
d16005f8
PC
1011 jit_state_t *_jit = block->_jit;
1012 jit_node_t *branch, *to_end;
fd58fa32 1013 u8 lo = 0, hi = 0, rs, rt, rflags = 0;
d16005f8
PC
1014
1015 jit_note(__FILE__, __LINE__);
d16005f8 1016
98fa08a5
PC
1017 if (is_signed)
1018 rflags = REG_EXT;
1019 else
1020 rflags = REG_ZEXT;
1021
1022 rs = lightrec_alloc_reg_in(reg_cache, _jit, c.r.rs, rflags);
1023 rt = lightrec_alloc_reg_in(reg_cache, _jit, c.r.rt, rflags);
1024
03535202 1025 if (!op_flag_no_lo(flags))
98fa08a5
PC
1026 lo = lightrec_alloc_reg_out(reg_cache, _jit, reg_lo, 0);
1027
03535202 1028 if (!op_flag_no_hi(flags))
98fa08a5 1029 hi = lightrec_alloc_reg_out(reg_cache, _jit, reg_hi, 0);
d16005f8
PC
1030
1031 /* Jump to special handler if dividing by zero */
98fa08a5
PC
1032 if (!no_check)
1033 branch = jit_beqi(rt, 0);
d16005f8 1034
03535202 1035 if (op_flag_no_lo(flags)) {
98fa08a5
PC
1036 if (is_signed)
1037 jit_remr(hi, rs, rt);
1038 else
1039 jit_remr_u(hi, rs, rt);
03535202 1040 } else if (op_flag_no_hi(flags)) {
98fa08a5
PC
1041 if (is_signed)
1042 jit_divr(lo, rs, rt);
1043 else
1044 jit_divr_u(lo, rs, rt);
d16005f8 1045 } else {
98fa08a5
PC
1046 if (is_signed)
1047 jit_qdivr(lo, hi, rs, rt);
1048 else
1049 jit_qdivr_u(lo, hi, rs, rt);
d16005f8 1050 }
d16005f8 1051
98fa08a5 1052 if (!no_check) {
98fa08a5 1053 /* Jump above the div-by-zero handler */
22eee2ac 1054 to_end = jit_b();
d16005f8 1055
98fa08a5
PC
1056 jit_patch(branch);
1057
03535202 1058 if (!op_flag_no_lo(flags)) {
98fa08a5 1059 if (is_signed) {
9259d748 1060 jit_ltr(lo, rs, rt);
98fa08a5
PC
1061 jit_lshi(lo, lo, 1);
1062 jit_subi(lo, lo, 1);
1063 } else {
9259d748 1064 jit_subi(lo, rt, 1);
98fa08a5
PC
1065 }
1066 }
d16005f8 1067
03535202 1068 if (!op_flag_no_hi(flags))
98fa08a5 1069 jit_movr(hi, rs);
d16005f8 1070
98fa08a5
PC
1071 jit_patch(to_end);
1072 }
d16005f8
PC
1073
1074 lightrec_free_reg(reg_cache, rs);
1075 lightrec_free_reg(reg_cache, rt);
98fa08a5 1076
03535202 1077 if (!op_flag_no_lo(flags))
98fa08a5
PC
1078 lightrec_free_reg(reg_cache, lo);
1079
03535202 1080 if (!op_flag_no_hi(flags))
98fa08a5 1081 lightrec_free_reg(reg_cache, hi);
d16005f8
PC
1082}
1083
98fa08a5
PC
1084static void rec_special_MULT(struct lightrec_cstate *state,
1085 const struct block *block, u16 offset)
d16005f8
PC
1086{
1087 _jit_name(block->_jit, __func__);
98fa08a5 1088 rec_alu_mult(state, block, offset, true);
d16005f8
PC
1089}
1090
98fa08a5
PC
1091static void rec_special_MULTU(struct lightrec_cstate *state,
1092 const struct block *block, u16 offset)
d16005f8
PC
1093{
1094 _jit_name(block->_jit, __func__);
98fa08a5 1095 rec_alu_mult(state, block, offset, false);
d16005f8
PC
1096}
1097
98fa08a5
PC
1098static void rec_special_DIV(struct lightrec_cstate *state,
1099 const struct block *block, u16 offset)
d16005f8
PC
1100{
1101 _jit_name(block->_jit, __func__);
98fa08a5 1102 rec_alu_div(state, block, offset, true);
d16005f8
PC
1103}
1104
98fa08a5
PC
1105static void rec_special_DIVU(struct lightrec_cstate *state,
1106 const struct block *block, u16 offset)
d16005f8
PC
1107{
1108 _jit_name(block->_jit, __func__);
98fa08a5 1109 rec_alu_div(state, block, offset, false);
d16005f8
PC
1110}
1111
98fa08a5 1112static void rec_alu_mv_lo_hi(struct lightrec_cstate *state,
684432ad
PC
1113 const struct block *block, u16 offset,
1114 u8 dst, u8 src)
d16005f8 1115{
98fa08a5 1116 struct regcache *reg_cache = state->reg_cache;
d16005f8
PC
1117 jit_state_t *_jit = block->_jit;
1118
1119 jit_note(__FILE__, __LINE__);
684432ad
PC
1120
1121 rec_alloc_rs_rd(reg_cache, _jit, &block->opcode_list[offset],
1122 src, dst, 0, REG_EXT, &src, &dst);
d16005f8 1123
d16005f8 1124 jit_extr_i(dst, src);
d16005f8
PC
1125
1126 lightrec_free_reg(reg_cache, src);
1127 lightrec_free_reg(reg_cache, dst);
1128}
1129
98fa08a5
PC
1130static void rec_special_MFHI(struct lightrec_cstate *state,
1131 const struct block *block, u16 offset)
d16005f8 1132{
98fa08a5
PC
1133 union code c = block->opcode_list[offset].c;
1134
d16005f8 1135 _jit_name(block->_jit, __func__);
684432ad 1136 rec_alu_mv_lo_hi(state, block, offset, c.r.rd, REG_HI);
d16005f8
PC
1137}
1138
98fa08a5
PC
1139static void rec_special_MTHI(struct lightrec_cstate *state,
1140 const struct block *block, u16 offset)
d16005f8 1141{
98fa08a5
PC
1142 union code c = block->opcode_list[offset].c;
1143
d16005f8 1144 _jit_name(block->_jit, __func__);
684432ad 1145 rec_alu_mv_lo_hi(state, block, offset, REG_HI, c.r.rs);
d16005f8
PC
1146}
1147
98fa08a5
PC
1148static void rec_special_MFLO(struct lightrec_cstate *state,
1149 const struct block *block, u16 offset)
d16005f8 1150{
98fa08a5
PC
1151 union code c = block->opcode_list[offset].c;
1152
d16005f8 1153 _jit_name(block->_jit, __func__);
684432ad 1154 rec_alu_mv_lo_hi(state, block, offset, c.r.rd, REG_LO);
d16005f8
PC
1155}
1156
98fa08a5
PC
1157static void rec_special_MTLO(struct lightrec_cstate *state,
1158 const struct block *block, u16 offset)
d16005f8 1159{
98fa08a5
PC
1160 union code c = block->opcode_list[offset].c;
1161
d16005f8 1162 _jit_name(block->_jit, __func__);
684432ad 1163 rec_alu_mv_lo_hi(state, block, offset, REG_LO, c.r.rs);
d16005f8
PC
1164}
1165
ba3814c1
PC
1166static void call_to_c_wrapper(struct lightrec_cstate *state,
1167 const struct block *block, u32 arg,
1168 enum c_wrappers wrapper)
d16005f8 1169{
98fa08a5 1170 struct regcache *reg_cache = state->reg_cache;
d16005f8 1171 jit_state_t *_jit = block->_jit;
ba3814c1 1172 s8 tmp, tmp2;
d16005f8 1173
ba3814c1
PC
1174 /* Make sure JIT_R1 is not mapped; it will be used in the C wrapper. */
1175 tmp2 = lightrec_alloc_reg(reg_cache, _jit, JIT_R1);
d16005f8 1176
8afce295
PC
1177 jit_movi(tmp2, (unsigned int)wrapper << (1 + __WORDSIZE / 32));
1178
ba3814c1 1179 tmp = lightrec_get_reg_with_value(reg_cache,
8afce295 1180 (intptr_t) state->state->c_wrapper);
ba3814c1
PC
1181 if (tmp < 0) {
1182 tmp = lightrec_alloc_reg_temp(reg_cache, _jit);
8afce295 1183 jit_ldxi(tmp, LIGHTREC_REG_STATE, lightrec_offset(c_wrapper));
ba3814c1
PC
1184
1185 lightrec_temp_set_value(reg_cache, tmp,
8afce295 1186 (intptr_t) state->state->c_wrapper);
22eee2ac
PC
1187 }
1188
ba3814c1
PC
1189 lightrec_free_reg(reg_cache, tmp2);
1190
1191#ifdef __mips__
1192 /* On MIPS, register t9 is always used as the target register for JALR.
1193 * Therefore if it does not contain the target address we must
1194 * invalidate it. */
1195 if (tmp != _T9)
1196 lightrec_unload_reg(reg_cache, _jit, _T9);
1197#endif
1198
1199 jit_prepare();
1200 jit_pushargi(arg);
1201
22eee2ac 1202 lightrec_regcache_mark_live(reg_cache, _jit);
98fa08a5 1203 jit_callr(tmp);
d16005f8 1204
98fa08a5 1205 lightrec_free_reg(reg_cache, tmp);
98fa08a5
PC
1206 lightrec_regcache_mark_live(reg_cache, _jit);
1207}
1208
1209static void rec_io(struct lightrec_cstate *state,
1210 const struct block *block, u16 offset,
1211 bool load_rt, bool read_rt)
1212{
1213 struct regcache *reg_cache = state->reg_cache;
1214 jit_state_t *_jit = block->_jit;
1215 union code c = block->opcode_list[offset].c;
03535202 1216 u32 flags = block->opcode_list[offset].flags;
22eee2ac 1217 bool is_tagged = LIGHTREC_FLAGS_GET_IO_MODE(flags);
98fa08a5 1218 u32 lut_entry;
cb72ea13 1219 u8 zero;
d16005f8 1220
98fa08a5 1221 jit_note(__FILE__, __LINE__);
d16005f8 1222
98fa08a5
PC
1223 lightrec_clean_reg_if_loaded(reg_cache, _jit, c.i.rs, false);
1224
1225 if (read_rt && likely(c.i.rt))
1226 lightrec_clean_reg_if_loaded(reg_cache, _jit, c.i.rt, true);
d16005f8 1227 else if (load_rt)
98fa08a5 1228 lightrec_clean_reg_if_loaded(reg_cache, _jit, c.i.rt, false);
d16005f8 1229
cb72ea13
PC
1230 if (op_flag_load_delay(flags) && !state->no_load_delay) {
1231 /* Clear state->in_delay_slot_n. This notifies the lightrec_rw
1232 * wrapper that it should write the REG_TEMP register instead of
1233 * the actual output register of the opcode. */
1234 zero = lightrec_alloc_reg_in(reg_cache, _jit, 0, 0);
8afce295
PC
1235 jit_stxi_c(lightrec_offset(in_delay_slot_n),
1236 LIGHTREC_REG_STATE, zero);
cb72ea13
PC
1237 lightrec_free_reg(reg_cache, zero);
1238 }
1239
d16005f8 1240 if (is_tagged) {
ba3814c1 1241 call_to_c_wrapper(state, block, c.opcode, C_WRAPPER_RW);
d16005f8 1242 } else {
98fa08a5
PC
1243 lut_entry = lightrec_get_lut_entry(block);
1244 call_to_c_wrapper(state, block, (lut_entry << 16) | offset,
ba3814c1 1245 C_WRAPPER_RW_GENERIC);
d16005f8 1246 }
d16005f8
PC
1247}
1248
f5ee77ca 1249static u32 rec_ram_mask(const struct lightrec_state *state)
02487de7
PC
1250{
1251 return (RAM_SIZE << (state->mirrors_mapped * 2)) - 1;
1252}
1253
13b02197
PC
1254static u32 rec_io_mask(const struct lightrec_state *state)
1255{
1256 u32 length = state->maps[PSX_MAP_HW_REGISTERS].length;
1257
2ec79b77 1258 return 0x1f800000 | GENMASK(31 - clz32(length - 1), 0);
13b02197
PC
1259}
1260
878e6cda
PC
1261static void rec_add_offset(struct lightrec_cstate *cstate,
1262 jit_state_t *_jit, u8 reg_out, u8 reg_in,
1263 uintptr_t offset)
1264{
1265 struct regcache *reg_cache = cstate->reg_cache;
1266 u8 reg_imm;
1267
1268 reg_imm = lightrec_alloc_reg_temp_with_value(reg_cache, _jit, offset);
1269 jit_addr(reg_out, reg_in, reg_imm);
1270
1271 lightrec_free_reg(reg_cache, reg_imm);
1272}
1273
1274static void rec_and_mask(struct lightrec_cstate *cstate,
1275 jit_state_t *_jit, u8 reg_out, u8 reg_in, u32 mask)
1276{
1277 struct regcache *reg_cache = cstate->reg_cache;
1278 u8 reg_imm;
1279
5eecf06d
PC
1280 if (arch_has_fast_mask()
1281 && (is_low_mask(mask) || is_high_mask(mask))) {
1282 jit_andi(reg_out, reg_in, mask);
1283 } else {
1284 reg_imm = lightrec_alloc_reg_temp_with_value(reg_cache, _jit,
1285 mask);
1286 jit_andr(reg_out, reg_in, reg_imm);
878e6cda 1287
5eecf06d
PC
1288 lightrec_free_reg(reg_cache, reg_imm);
1289 }
878e6cda
PC
1290}
1291
22eee2ac
PC
1292static void rec_store_memory(struct lightrec_cstate *cstate,
1293 const struct block *block,
1294 u16 offset, jit_code_t code,
878e6cda
PC
1295 jit_code_t swap_code, uintptr_t addr_offset,
1296 u32 addr_mask, bool invalidate)
22eee2ac 1297{
02487de7 1298 const struct lightrec_state *state = cstate->state;
22eee2ac
PC
1299 struct regcache *reg_cache = cstate->reg_cache;
1300 struct opcode *op = &block->opcode_list[offset];
1301 jit_state_t *_jit = block->_jit;
1302 union code c = op->c;
3107c849 1303 u8 rs, rt, tmp = 0, tmp2 = 0, tmp3, addr_reg, addr_reg2, src_reg;
22eee2ac 1304 s16 imm = (s16)c.i.imm;
02487de7 1305 s32 simm = (s32)imm << (1 - lut_is_32bit(state));
8afce295 1306 s32 lut_offt = lightrec_offset(code_lut);
03535202 1307 bool no_mask = op_flag_no_mask(op->flags);
02487de7 1308 bool add_imm = c.i.imm &&
5459088b
PC
1309 (c.i.op == OP_META_SWU
1310 || (!state->mirrors_mapped && !no_mask) || (invalidate &&
02487de7 1311 ((imm & 0x3) || simm + lut_offt != (s16)(simm + lut_offt))));
684432ad 1312 bool need_tmp = !no_mask || add_imm || invalidate;
9259d748 1313 bool swc2 = c.i.op == OP_SWC2;
cb72ea13 1314 u8 in_reg = swc2 ? REG_TEMP : c.i.rt;
22eee2ac 1315
22eee2ac
PC
1316 rs = lightrec_alloc_reg_in(reg_cache, _jit, c.i.rs, 0);
1317 if (need_tmp)
1318 tmp = lightrec_alloc_reg_temp(reg_cache, _jit);
1319
1320 addr_reg = rs;
1321
1322 if (add_imm) {
1323 jit_addi(tmp, addr_reg, (s16)c.i.imm);
0e720fb1 1324 lightrec_free_reg(reg_cache, rs);
22eee2ac
PC
1325 addr_reg = tmp;
1326 imm = 0;
1327 } else if (simm) {
1328 lut_offt += simm;
1329 }
1330
1331 if (!no_mask) {
878e6cda 1332 rec_and_mask(cstate, _jit, tmp, addr_reg, addr_mask);
22eee2ac
PC
1333 addr_reg = tmp;
1334 }
1335
22eee2ac 1336 if (addr_offset) {
ba3814c1 1337 tmp2 = lightrec_alloc_reg_temp(reg_cache, _jit);
878e6cda 1338 rec_add_offset(cstate, _jit, tmp2, addr_reg, addr_offset);
22eee2ac
PC
1339 addr_reg2 = tmp2;
1340 } else {
1341 addr_reg2 = addr_reg;
1342 }
1343
684432ad 1344 rt = lightrec_alloc_reg_in(reg_cache, _jit, in_reg, 0);
3107c849 1345 src_reg = rt;
684432ad 1346
9259d748 1347 if (is_big_endian() && swap_code && in_reg) {
02487de7
PC
1348 tmp3 = lightrec_alloc_reg_temp(reg_cache, _jit);
1349
1350 jit_new_node_ww(swap_code, tmp3, rt);
5459088b 1351
3107c849
PC
1352 lightrec_free_reg(reg_cache, rt);
1353 src_reg = tmp3;
02487de7
PC
1354 }
1355
3107c849
PC
1356 if (c.i.op == OP_META_SWU)
1357 jit_unstr(addr_reg2, src_reg, LIGHTNING_UNALIGNED_32BIT);
1358 else
1359 jit_new_node_www(code, imm, addr_reg2, src_reg);
1360
1361 lightrec_free_reg(reg_cache, src_reg);
22eee2ac
PC
1362
1363 if (invalidate) {
1364 tmp3 = lightrec_alloc_reg_in(reg_cache, _jit, 0, 0);
1365
1366 if (c.i.op != OP_SW) {
ba3814c1
PC
1367 jit_andi(tmp, addr_reg, ~3);
1368 addr_reg = tmp;
22eee2ac
PC
1369 }
1370
02487de7 1371 if (!lut_is_32bit(state)) {
ba3814c1
PC
1372 jit_lshi(tmp, addr_reg, 1);
1373 addr_reg = tmp;
22eee2ac
PC
1374 }
1375
02487de7
PC
1376 if (addr_reg == rs && c.i.rs == 0) {
1377 addr_reg = LIGHTREC_REG_STATE;
1378 } else {
cb72ea13 1379 jit_add_state(tmp, addr_reg);
ba3814c1 1380 addr_reg = tmp;
22eee2ac
PC
1381 }
1382
02487de7
PC
1383 if (lut_is_32bit(state))
1384 jit_stxi_i(lut_offt, addr_reg, tmp3);
1385 else
1386 jit_stxi(lut_offt, addr_reg, tmp3);
22eee2ac
PC
1387
1388 lightrec_free_reg(reg_cache, tmp3);
1389 }
1390
ba3814c1 1391 if (addr_offset)
22eee2ac
PC
1392 lightrec_free_reg(reg_cache, tmp2);
1393 if (need_tmp)
1394 lightrec_free_reg(reg_cache, tmp);
1395 lightrec_free_reg(reg_cache, rs);
1396}
1397
1398static void rec_store_ram(struct lightrec_cstate *cstate,
1399 const struct block *block,
1400 u16 offset, jit_code_t code,
02487de7 1401 jit_code_t swap_code, bool invalidate)
22eee2ac 1402{
f5ee77ca 1403 const struct lightrec_state *state = cstate->state;
02487de7 1404
22eee2ac
PC
1405 _jit_note(block->_jit, __FILE__, __LINE__);
1406
02487de7
PC
1407 return rec_store_memory(cstate, block, offset, code, swap_code,
1408 state->offset_ram, rec_ram_mask(state),
1409 invalidate);
22eee2ac
PC
1410}
1411
1412static void rec_store_scratch(struct lightrec_cstate *cstate,
02487de7
PC
1413 const struct block *block, u16 offset,
1414 jit_code_t code, jit_code_t swap_code)
22eee2ac
PC
1415{
1416 _jit_note(block->_jit, __FILE__, __LINE__);
1417
02487de7 1418 return rec_store_memory(cstate, block, offset, code, swap_code,
22eee2ac
PC
1419 cstate->state->offset_scratch,
1420 0x1fffffff, false);
1421}
1422
ba3814c1
PC
1423static void rec_store_io(struct lightrec_cstate *cstate,
1424 const struct block *block, u16 offset,
1425 jit_code_t code, jit_code_t swap_code)
1426{
1427 _jit_note(block->_jit, __FILE__, __LINE__);
1428
1429 return rec_store_memory(cstate, block, offset, code, swap_code,
1430 cstate->state->offset_io,
13b02197 1431 rec_io_mask(cstate->state), false);
ba3814c1
PC
1432}
1433
98fa08a5
PC
1434static void rec_store_direct_no_invalidate(struct lightrec_cstate *cstate,
1435 const struct block *block,
02487de7
PC
1436 u16 offset, jit_code_t code,
1437 jit_code_t swap_code)
d16005f8 1438{
f5ee77ca 1439 const struct lightrec_state *state = cstate->state;
878e6cda 1440 u32 ram_size = state->mirrors_mapped ? RAM_SIZE * 4 : RAM_SIZE;
98fa08a5
PC
1441 struct regcache *reg_cache = cstate->reg_cache;
1442 union code c = block->opcode_list[offset].c;
d16005f8
PC
1443 jit_state_t *_jit = block->_jit;
1444 jit_node_t *to_not_ram, *to_end;
9259d748 1445 bool swc2 = c.i.op == OP_SWC2;
3107c849 1446 u8 addr_reg, tmp, tmp2 = 0, rs, rt, src_reg, in_reg = swc2 ? REG_TEMP : c.i.rt;
d16005f8
PC
1447 s16 imm;
1448
1449 jit_note(__FILE__, __LINE__);
98fa08a5 1450 rs = lightrec_alloc_reg_in(reg_cache, _jit, c.i.rs, 0);
d16005f8 1451 tmp = lightrec_alloc_reg_temp(reg_cache, _jit);
98fa08a5 1452
d16005f8 1453 /* Convert to KUNSEG and avoid RAM mirrors */
5459088b 1454 if ((c.i.op == OP_META_SWU || !state->mirrors_mapped) && c.i.imm) {
d16005f8 1455 imm = 0;
98fa08a5 1456 jit_addi(tmp, rs, (s16)c.i.imm);
878e6cda 1457 addr_reg = tmp;
d16005f8 1458 } else {
684432ad 1459 imm = (s16)c.i.imm;
878e6cda 1460 addr_reg = rs;
d16005f8
PC
1461 }
1462
878e6cda
PC
1463 rec_and_mask(cstate, _jit, tmp, addr_reg, 0x1f800000 | (ram_size - 1));
1464
d16005f8
PC
1465 lightrec_free_reg(reg_cache, rs);
1466
1467 if (state->offset_ram != state->offset_scratch) {
684432ad
PC
1468 tmp2 = lightrec_alloc_reg_temp(reg_cache, _jit);
1469
d16005f8
PC
1470 to_not_ram = jit_bmsi(tmp, BIT(28));
1471
1472 jit_movi(tmp2, state->offset_ram);
1473
22eee2ac 1474 to_end = jit_b();
d16005f8
PC
1475 jit_patch(to_not_ram);
1476
1477 jit_movi(tmp2, state->offset_scratch);
1478 jit_patch(to_end);
1479 } else if (state->offset_ram) {
684432ad
PC
1480 tmp2 = lightrec_alloc_reg_temp_with_value(reg_cache, _jit,
1481 state->offset_ram);
d16005f8
PC
1482 }
1483
684432ad 1484 if (state->offset_ram || state->offset_scratch) {
d16005f8 1485 jit_addr(tmp, tmp, tmp2);
98fa08a5
PC
1486 lightrec_free_reg(reg_cache, tmp2);
1487 }
d16005f8 1488
9259d748 1489 rt = lightrec_alloc_reg_in(reg_cache, _jit, in_reg, 0);
3107c849 1490 src_reg = rt;
ba3814c1 1491
9259d748 1492 if (is_big_endian() && swap_code && in_reg) {
02487de7
PC
1493 tmp2 = lightrec_alloc_reg_temp(reg_cache, _jit);
1494
1495 jit_new_node_ww(swap_code, tmp2, rt);
3107c849 1496 src_reg = tmp2;
5459088b 1497
3107c849 1498 lightrec_free_reg(reg_cache, rt);
02487de7 1499 }
d16005f8 1500
3107c849
PC
1501 if (c.i.op == OP_META_SWU)
1502 jit_unstr(tmp, src_reg, LIGHTNING_UNALIGNED_32BIT);
1503 else
1504 jit_new_node_www(code, imm, tmp, src_reg);
1505
1506 lightrec_free_reg(reg_cache, src_reg);
d16005f8
PC
1507 lightrec_free_reg(reg_cache, tmp);
1508}
1509
98fa08a5 1510static void rec_store_direct(struct lightrec_cstate *cstate, const struct block *block,
02487de7 1511 u16 offset, jit_code_t code, jit_code_t swap_code)
d16005f8 1512{
f5ee77ca 1513 const struct lightrec_state *state = cstate->state;
98fa08a5
PC
1514 u32 ram_size = state->mirrors_mapped ? RAM_SIZE * 4 : RAM_SIZE;
1515 struct regcache *reg_cache = cstate->reg_cache;
1516 union code c = block->opcode_list[offset].c;
d16005f8 1517 jit_state_t *_jit = block->_jit;
98fa08a5 1518 jit_node_t *to_not_ram, *to_end;
9259d748 1519 bool swc2 = c.i.op == OP_SWC2;
3107c849 1520 u8 src_reg, addr_reg, tmp, tmp2, tmp3, rs, rt, reg_imm;
cb72ea13 1521 u8 in_reg = swc2 ? REG_TEMP : c.i.rt;
878e6cda 1522 u32 mask;
f5ee77ca 1523 bool different_offsets = state->offset_ram != state->offset_scratch;
d16005f8
PC
1524
1525 jit_note(__FILE__, __LINE__);
1526
98fa08a5 1527 rs = lightrec_alloc_reg_in(reg_cache, _jit, c.i.rs, 0);
d16005f8 1528 tmp2 = lightrec_alloc_reg_temp(reg_cache, _jit);
98fa08a5 1529 tmp3 = lightrec_alloc_reg_in(reg_cache, _jit, 0, 0);
d16005f8
PC
1530
1531 /* Convert to KUNSEG and avoid RAM mirrors */
98fa08a5
PC
1532 if (c.i.imm) {
1533 jit_addi(tmp2, rs, (s16)c.i.imm);
878e6cda 1534 addr_reg = tmp2;
d16005f8 1535 } else {
878e6cda 1536 addr_reg = rs;
d16005f8
PC
1537 }
1538
878e6cda
PC
1539 rec_and_mask(cstate, _jit, tmp2, addr_reg, 0x1f800000 | (ram_size - 1));
1540
d16005f8
PC
1541 lightrec_free_reg(reg_cache, rs);
1542 tmp = lightrec_alloc_reg_temp(reg_cache, _jit);
1543
878e6cda
PC
1544 mask = c.i.op == OP_SW ? RAM_SIZE - 1 : (RAM_SIZE - 1) & ~3;
1545 reg_imm = lightrec_alloc_reg_temp_with_value(reg_cache, _jit, mask);
1546
f5ee77ca 1547 if (different_offsets) {
9259d748 1548 to_not_ram = jit_bgti(tmp2, ram_size);
878e6cda 1549 addr_reg = tmp2;
9259d748
PC
1550 } else {
1551 jit_lti_u(tmp, tmp2, ram_size);
1552 jit_movnr(tmp, tmp2, tmp);
878e6cda 1553 addr_reg = tmp;
9259d748 1554 }
98fa08a5 1555
d16005f8 1556 /* Compute the offset to the code LUT */
878e6cda 1557 jit_andr(tmp, addr_reg, reg_imm);
9259d748 1558
02487de7 1559 if (!lut_is_32bit(state))
98fa08a5 1560 jit_lshi(tmp, tmp, 1);
cb72ea13 1561 jit_add_state(tmp, tmp);
d16005f8
PC
1562
1563 /* Write NULL to the code LUT to invalidate any block that's there */
02487de7 1564 if (lut_is_32bit(state))
8afce295 1565 jit_stxi_i(lightrec_offset(code_lut), tmp, tmp3);
02487de7 1566 else
8afce295 1567 jit_stxi(lightrec_offset(code_lut), tmp, tmp3);
d16005f8 1568
5459088b
PC
1569 if (c.i.op == OP_META_SWU) {
1570 /* With a SWU opcode, we might have touched the following 32-bit
1571 * word, so invalidate it as well */
1572 if (lut_is_32bit(state)) {
8afce295 1573 jit_stxi_i(lightrec_offset(code_lut) + 4, tmp, tmp3);
5459088b 1574 } else {
8afce295
PC
1575 jit_stxi(lightrec_offset(code_lut) + sizeof(uintptr_t),
1576 tmp, tmp3);
5459088b
PC
1577 }
1578 }
1579
f5ee77ca 1580 if (different_offsets) {
d16005f8
PC
1581 jit_movi(tmp, state->offset_ram);
1582
22eee2ac 1583 to_end = jit_b();
9259d748 1584 jit_patch(to_not_ram);
d16005f8
PC
1585 }
1586
d16005f8
PC
1587 if (state->offset_ram || state->offset_scratch)
1588 jit_movi(tmp, state->offset_scratch);
1589
f5ee77ca 1590 if (different_offsets)
d16005f8
PC
1591 jit_patch(to_end);
1592
1593 if (state->offset_ram || state->offset_scratch)
1594 jit_addr(tmp2, tmp2, tmp);
1595
1596 lightrec_free_reg(reg_cache, tmp);
1597 lightrec_free_reg(reg_cache, tmp3);
878e6cda 1598 lightrec_free_reg(reg_cache, reg_imm);
d16005f8 1599
9259d748 1600 rt = lightrec_alloc_reg_in(reg_cache, _jit, in_reg, 0);
3107c849 1601 src_reg = rt;
02487de7 1602
9259d748 1603 if (is_big_endian() && swap_code && in_reg) {
02487de7
PC
1604 tmp = lightrec_alloc_reg_temp(reg_cache, _jit);
1605
1606 jit_new_node_ww(swap_code, tmp, rt);
3107c849 1607 src_reg = tmp;
5459088b 1608
3107c849 1609 lightrec_free_reg(reg_cache, rt);
02487de7 1610 }
d16005f8 1611
3107c849
PC
1612 if (c.i.op == OP_META_SWU)
1613 jit_unstr(tmp2, src_reg, LIGHTNING_UNALIGNED_32BIT);
1614 else
1615 jit_new_node_www(code, 0, tmp2, src_reg);
1616
1617 lightrec_free_reg(reg_cache, src_reg);
d16005f8
PC
1618 lightrec_free_reg(reg_cache, tmp2);
1619}
1620
98fa08a5 1621static void rec_store(struct lightrec_cstate *state,
02487de7
PC
1622 const struct block *block, u16 offset,
1623 jit_code_t code, jit_code_t swap_code)
d16005f8 1624{
03535202 1625 u32 flags = block->opcode_list[offset].flags;
9259d748 1626 u32 mode = LIGHTREC_FLAGS_GET_IO_MODE(flags);
03535202 1627 bool no_invalidate = op_flag_no_invalidate(flags) ||
684432ad 1628 (state->state->opt_flags & LIGHTREC_OPT_INV_DMA_ONLY);
9259d748
PC
1629 union code c = block->opcode_list[offset].c;
1630 bool is_swc2 = c.i.op == OP_SWC2;
1631
1632 if (is_swc2) {
1633 switch (mode) {
1634 case LIGHTREC_IO_RAM:
1635 case LIGHTREC_IO_SCRATCH:
1636 case LIGHTREC_IO_DIRECT:
1637 case LIGHTREC_IO_DIRECT_HW:
cb72ea13 1638 rec_cp2_do_mfc2(state, block, offset, c.i.rt, REG_TEMP);
9259d748
PC
1639 break;
1640 default:
1641 break;
1642 }
1643 }
22eee2ac 1644
9259d748 1645 switch (mode) {
22eee2ac 1646 case LIGHTREC_IO_RAM:
02487de7
PC
1647 rec_store_ram(state, block, offset, code,
1648 swap_code, !no_invalidate);
22eee2ac
PC
1649 break;
1650 case LIGHTREC_IO_SCRATCH:
02487de7 1651 rec_store_scratch(state, block, offset, code, swap_code);
22eee2ac
PC
1652 break;
1653 case LIGHTREC_IO_DIRECT:
02487de7
PC
1654 if (no_invalidate) {
1655 rec_store_direct_no_invalidate(state, block, offset,
1656 code, swap_code);
1657 } else {
1658 rec_store_direct(state, block, offset, code, swap_code);
1659 }
22eee2ac 1660 break;
ba3814c1
PC
1661 case LIGHTREC_IO_DIRECT_HW:
1662 rec_store_io(state, block, offset, code, swap_code);
1663 break;
22eee2ac 1664 default:
98fa08a5 1665 rec_io(state, block, offset, true, false);
9259d748 1666 return;
d16005f8 1667 }
9259d748
PC
1668
1669 if (is_swc2)
cb72ea13 1670 lightrec_discard_reg_if_loaded(state->reg_cache, REG_TEMP);
d16005f8
PC
1671}
1672
98fa08a5
PC
1673static void rec_SB(struct lightrec_cstate *state,
1674 const struct block *block, u16 offset)
d16005f8
PC
1675{
1676 _jit_name(block->_jit, __func__);
02487de7 1677 rec_store(state, block, offset, jit_code_stxi_c, 0);
d16005f8
PC
1678}
1679
98fa08a5
PC
1680static void rec_SH(struct lightrec_cstate *state,
1681 const struct block *block, u16 offset)
d16005f8
PC
1682{
1683 _jit_name(block->_jit, __func__);
02487de7
PC
1684 rec_store(state, block, offset,
1685 jit_code_stxi_s, jit_code_bswapr_us);
d16005f8
PC
1686}
1687
98fa08a5
PC
1688static void rec_SW(struct lightrec_cstate *state,
1689 const struct block *block, u16 offset)
1690
d16005f8 1691{
9259d748
PC
1692 union code c = block->opcode_list[offset].c;
1693
1694 _jit_name(block->_jit, c.i.op == OP_SWC2 ? "rec_SWC2" : "rec_SW");
02487de7
PC
1695 rec_store(state, block, offset,
1696 jit_code_stxi_i, jit_code_bswapr_ui);
d16005f8
PC
1697}
1698
98fa08a5
PC
1699static void rec_SWL(struct lightrec_cstate *state,
1700 const struct block *block, u16 offset)
d16005f8
PC
1701{
1702 _jit_name(block->_jit, __func__);
98fa08a5 1703 rec_io(state, block, offset, true, false);
d16005f8
PC
1704}
1705
98fa08a5
PC
1706static void rec_SWR(struct lightrec_cstate *state,
1707 const struct block *block, u16 offset)
d16005f8
PC
1708{
1709 _jit_name(block->_jit, __func__);
98fa08a5 1710 rec_io(state, block, offset, true, false);
d16005f8
PC
1711}
1712
22eee2ac 1713static void rec_load_memory(struct lightrec_cstate *cstate,
02487de7
PC
1714 const struct block *block, u16 offset,
1715 jit_code_t code, jit_code_t swap_code, bool is_unsigned,
22eee2ac
PC
1716 uintptr_t addr_offset, u32 addr_mask)
1717{
878e6cda 1718 struct lightrec_state *state = cstate->state;
22eee2ac
PC
1719 struct regcache *reg_cache = cstate->reg_cache;
1720 struct opcode *op = &block->opcode_list[offset];
cb72ea13 1721 bool load_delay = op_flag_load_delay(op->flags) && !cstate->no_load_delay;
22eee2ac 1722 jit_state_t *_jit = block->_jit;
9259d748 1723 u8 rs, rt, out_reg, addr_reg, flags = REG_EXT;
03535202 1724 bool no_mask = op_flag_no_mask(op->flags);
22eee2ac 1725 union code c = op->c;
02487de7 1726 s16 imm;
22eee2ac 1727
cb72ea13
PC
1728 if (load_delay || c.i.op == OP_LWC2)
1729 out_reg = REG_TEMP;
9259d748
PC
1730 else if (c.i.rt)
1731 out_reg = c.i.rt;
1732 else
22eee2ac
PC
1733 return;
1734
1735 if (is_unsigned)
1736 flags |= REG_ZEXT;
1737
1738 rs = lightrec_alloc_reg_in(reg_cache, _jit, c.i.rs, 0);
9259d748 1739 rt = lightrec_alloc_reg_out(reg_cache, _jit, out_reg, flags);
22eee2ac 1740
5459088b 1741 if ((op->i.op == OP_META_LWU && c.i.imm)
878e6cda 1742 || (!state->mirrors_mapped && c.i.imm && !no_mask)) {
02487de7 1743 jit_addi(rt, rs, (s16)c.i.imm);
22eee2ac 1744 addr_reg = rt;
02487de7 1745 imm = 0;
22eee2ac
PC
1746 } else {
1747 addr_reg = rs;
02487de7
PC
1748 imm = (s16)c.i.imm;
1749 }
1750
5459088b
PC
1751 if (op->i.op == OP_META_LWU)
1752 imm = LIGHTNING_UNALIGNED_32BIT;
1753
02487de7 1754 if (!no_mask) {
878e6cda 1755 rec_and_mask(cstate, _jit, rt, addr_reg, addr_mask);
02487de7 1756 addr_reg = rt;
22eee2ac
PC
1757 }
1758
1759 if (addr_offset) {
878e6cda 1760 rec_add_offset(cstate, _jit, rt, addr_reg, addr_offset);
22eee2ac
PC
1761 addr_reg = rt;
1762 }
1763
02487de7
PC
1764 jit_new_node_www(code, rt, addr_reg, imm);
1765
1766 if (is_big_endian() && swap_code) {
1767 jit_new_node_ww(swap_code, rt, rt);
1768
1769 if (c.i.op == OP_LH)
1770 jit_extr_s(rt, rt);
1771 else if (c.i.op == OP_LW && __WORDSIZE == 64)
1772 jit_extr_i(rt, rt);
1773 }
22eee2ac
PC
1774
1775 lightrec_free_reg(reg_cache, rs);
1776 lightrec_free_reg(reg_cache, rt);
1777}
1778
1779static void rec_load_ram(struct lightrec_cstate *cstate,
02487de7
PC
1780 const struct block *block, u16 offset,
1781 jit_code_t code, jit_code_t swap_code, bool is_unsigned)
22eee2ac
PC
1782{
1783 _jit_note(block->_jit, __FILE__, __LINE__);
1784
02487de7
PC
1785 rec_load_memory(cstate, block, offset, code, swap_code, is_unsigned,
1786 cstate->state->offset_ram, rec_ram_mask(cstate->state));
22eee2ac
PC
1787}
1788
1789static void rec_load_bios(struct lightrec_cstate *cstate,
02487de7
PC
1790 const struct block *block, u16 offset,
1791 jit_code_t code, jit_code_t swap_code, bool is_unsigned)
22eee2ac
PC
1792{
1793 _jit_note(block->_jit, __FILE__, __LINE__);
1794
02487de7 1795 rec_load_memory(cstate, block, offset, code, swap_code, is_unsigned,
22eee2ac
PC
1796 cstate->state->offset_bios, 0x1fffffff);
1797}
1798
1799static void rec_load_scratch(struct lightrec_cstate *cstate,
02487de7
PC
1800 const struct block *block, u16 offset,
1801 jit_code_t code, jit_code_t swap_code, bool is_unsigned)
22eee2ac
PC
1802{
1803 _jit_note(block->_jit, __FILE__, __LINE__);
1804
02487de7 1805 rec_load_memory(cstate, block, offset, code, swap_code, is_unsigned,
22eee2ac
PC
1806 cstate->state->offset_scratch, 0x1fffffff);
1807}
1808
ba3814c1
PC
1809static void rec_load_io(struct lightrec_cstate *cstate,
1810 const struct block *block, u16 offset,
1811 jit_code_t code, jit_code_t swap_code, bool is_unsigned)
1812{
1813 _jit_note(block->_jit, __FILE__, __LINE__);
1814
1815 rec_load_memory(cstate, block, offset, code, swap_code, is_unsigned,
13b02197 1816 cstate->state->offset_io, rec_io_mask(cstate->state));
ba3814c1
PC
1817}
1818
02487de7
PC
1819static void rec_load_direct(struct lightrec_cstate *cstate,
1820 const struct block *block, u16 offset,
1821 jit_code_t code, jit_code_t swap_code,
1822 bool is_unsigned)
d16005f8 1823{
f5ee77ca 1824 const struct lightrec_state *state = cstate->state;
98fa08a5 1825 struct regcache *reg_cache = cstate->reg_cache;
cb72ea13
PC
1826 struct opcode *op = &block->opcode_list[offset];
1827 bool load_delay = op_flag_load_delay(op->flags) && !cstate->no_load_delay;
d16005f8 1828 jit_state_t *_jit = block->_jit;
98fa08a5 1829 jit_node_t *to_not_ram, *to_not_bios, *to_end, *to_end2;
9259d748 1830 u8 tmp, rs, rt, out_reg, addr_reg, flags = REG_EXT;
f5ee77ca 1831 bool different_offsets = state->offset_bios != state->offset_scratch;
cb72ea13 1832 union code c = op->c;
684432ad
PC
1833 s32 addr_mask;
1834 u32 reg_imm;
1835 s8 offt_reg;
d16005f8
PC
1836 s16 imm;
1837
cb72ea13
PC
1838 if (load_delay || c.i.op == OP_LWC2)
1839 out_reg = REG_TEMP;
9259d748
PC
1840 else if (c.i.rt)
1841 out_reg = c.i.rt;
1842 else
d16005f8
PC
1843 return;
1844
98fa08a5
PC
1845 if (is_unsigned)
1846 flags |= REG_ZEXT;
1847
d16005f8 1848 jit_note(__FILE__, __LINE__);
98fa08a5 1849 rs = lightrec_alloc_reg_in(reg_cache, _jit, c.i.rs, 0);
9259d748 1850 rt = lightrec_alloc_reg_out(reg_cache, _jit, out_reg, flags);
d16005f8
PC
1851
1852 if ((state->offset_ram == state->offset_bios &&
1853 state->offset_ram == state->offset_scratch &&
5459088b
PC
1854 state->mirrors_mapped && c.i.op != OP_META_LWU)
1855 || !c.i.imm) {
d16005f8 1856 addr_reg = rs;
98fa08a5 1857 imm = (s16)c.i.imm;
d16005f8 1858 } else {
98fa08a5 1859 jit_addi(rt, rs, (s16)c.i.imm);
d16005f8
PC
1860 addr_reg = rt;
1861 imm = 0;
1862
98fa08a5 1863 if (c.i.rs != c.i.rt)
d16005f8
PC
1864 lightrec_free_reg(reg_cache, rs);
1865 }
1866
5459088b
PC
1867 if (op->i.op == OP_META_LWU)
1868 imm = LIGHTNING_UNALIGNED_32BIT;
1869
d16005f8
PC
1870 tmp = lightrec_alloc_reg_temp(reg_cache, _jit);
1871
1872 if (state->offset_ram == state->offset_bios &&
1873 state->offset_ram == state->offset_scratch) {
684432ad
PC
1874 if (!state->mirrors_mapped)
1875 addr_mask = 0x1f800000 | (RAM_SIZE - 1);
1876 else
1877 addr_mask = 0x1fffffff;
1878
d16005f8 1879 if (!state->mirrors_mapped) {
3107c849
PC
1880 reg_imm = lightrec_alloc_reg_temp_with_value(reg_cache, _jit,
1881 addr_mask);
d16005f8
PC
1882 jit_andi(tmp, addr_reg, BIT(28));
1883 jit_rshi_u(tmp, tmp, 28 - 22);
684432ad 1884 jit_orr(tmp, tmp, reg_imm);
d16005f8 1885 jit_andr(rt, addr_reg, tmp);
3107c849
PC
1886
1887 lightrec_free_reg(reg_cache, reg_imm);
d16005f8 1888 } else {
3107c849 1889 rec_and_mask(cstate, _jit, rt, addr_reg, addr_mask);
d16005f8
PC
1890 }
1891
684432ad
PC
1892 if (state->offset_ram) {
1893 offt_reg = lightrec_get_reg_with_value(reg_cache,
1894 state->offset_ram);
1895 if (offt_reg < 0) {
1896 jit_movi(tmp, state->offset_ram);
1897 lightrec_temp_set_value(reg_cache, tmp,
1898 state->offset_ram);
1899 } else {
1900 lightrec_free_reg(reg_cache, tmp);
1901 tmp = offt_reg;
1902 }
1903 }
d16005f8
PC
1904 } else {
1905 to_not_ram = jit_bmsi(addr_reg, BIT(28));
1906
1907 /* Convert to KUNSEG and avoid RAM mirrors */
1908 jit_andi(rt, addr_reg, RAM_SIZE - 1);
1909
1910 if (state->offset_ram)
1911 jit_movi(tmp, state->offset_ram);
1912
22eee2ac 1913 to_end = jit_b();
d16005f8
PC
1914
1915 jit_patch(to_not_ram);
1916
f5ee77ca 1917 if (different_offsets)
d16005f8
PC
1918 to_not_bios = jit_bmci(addr_reg, BIT(22));
1919
1920 /* Convert to KUNSEG */
1921 jit_andi(rt, addr_reg, 0x1fc00000 | (BIOS_SIZE - 1));
1922
1923 jit_movi(tmp, state->offset_bios);
1924
f5ee77ca 1925 if (different_offsets) {
22eee2ac 1926 to_end2 = jit_b();
d16005f8
PC
1927
1928 jit_patch(to_not_bios);
1929
1930 /* Convert to KUNSEG */
1931 jit_andi(rt, addr_reg, 0x1f800fff);
1932
1933 if (state->offset_scratch)
1934 jit_movi(tmp, state->offset_scratch);
1935
1936 jit_patch(to_end2);
1937 }
1938
1939 jit_patch(to_end);
1940 }
1941
1942 if (state->offset_ram || state->offset_bios || state->offset_scratch)
1943 jit_addr(rt, rt, tmp);
1944
1945 jit_new_node_www(code, rt, rt, imm);
1946
02487de7
PC
1947 if (is_big_endian() && swap_code) {
1948 jit_new_node_ww(swap_code, rt, rt);
1949
1950 if (c.i.op == OP_LH)
1951 jit_extr_s(rt, rt);
1952 else if (c.i.op == OP_LW && __WORDSIZE == 64)
1953 jit_extr_i(rt, rt);
1954 }
1955
d16005f8
PC
1956 lightrec_free_reg(reg_cache, addr_reg);
1957 lightrec_free_reg(reg_cache, rt);
1958 lightrec_free_reg(reg_cache, tmp);
1959}
1960
98fa08a5 1961static void rec_load(struct lightrec_cstate *state, const struct block *block,
02487de7
PC
1962 u16 offset, jit_code_t code, jit_code_t swap_code,
1963 bool is_unsigned)
d16005f8 1964{
9259d748
PC
1965 const struct opcode *op = &block->opcode_list[offset];
1966 u32 flags = op->flags;
98fa08a5 1967
22eee2ac
PC
1968 switch (LIGHTREC_FLAGS_GET_IO_MODE(flags)) {
1969 case LIGHTREC_IO_RAM:
02487de7 1970 rec_load_ram(state, block, offset, code, swap_code, is_unsigned);
22eee2ac
PC
1971 break;
1972 case LIGHTREC_IO_BIOS:
02487de7 1973 rec_load_bios(state, block, offset, code, swap_code, is_unsigned);
22eee2ac
PC
1974 break;
1975 case LIGHTREC_IO_SCRATCH:
02487de7 1976 rec_load_scratch(state, block, offset, code, swap_code, is_unsigned);
22eee2ac 1977 break;
ba3814c1
PC
1978 case LIGHTREC_IO_DIRECT_HW:
1979 rec_load_io(state, block, offset, code, swap_code, is_unsigned);
1980 break;
22eee2ac 1981 case LIGHTREC_IO_DIRECT:
02487de7 1982 rec_load_direct(state, block, offset, code, swap_code, is_unsigned);
22eee2ac
PC
1983 break;
1984 default:
98fa08a5 1985 rec_io(state, block, offset, false, true);
9259d748
PC
1986 return;
1987 }
1988
1989 if (op->i.op == OP_LWC2) {
cb72ea13
PC
1990 rec_cp2_do_mtc2(state, block, offset, op->i.rt, REG_TEMP);
1991 lightrec_discard_reg_if_loaded(state->reg_cache, REG_TEMP);
22eee2ac 1992 }
d16005f8
PC
1993}
1994
98fa08a5 1995static void rec_LB(struct lightrec_cstate *state, const struct block *block, u16 offset)
d16005f8
PC
1996{
1997 _jit_name(block->_jit, __func__);
02487de7 1998 rec_load(state, block, offset, jit_code_ldxi_c, 0, false);
d16005f8
PC
1999}
2000
98fa08a5 2001static void rec_LBU(struct lightrec_cstate *state, const struct block *block, u16 offset)
d16005f8
PC
2002{
2003 _jit_name(block->_jit, __func__);
02487de7 2004 rec_load(state, block, offset, jit_code_ldxi_uc, 0, true);
d16005f8
PC
2005}
2006
98fa08a5 2007static void rec_LH(struct lightrec_cstate *state, const struct block *block, u16 offset)
d16005f8 2008{
ba3814c1
PC
2009 jit_code_t code = is_big_endian() ? jit_code_ldxi_us : jit_code_ldxi_s;
2010
d16005f8 2011 _jit_name(block->_jit, __func__);
ba3814c1 2012 rec_load(state, block, offset, code, jit_code_bswapr_us, false);
d16005f8
PC
2013}
2014
98fa08a5 2015static void rec_LHU(struct lightrec_cstate *state, const struct block *block, u16 offset)
d16005f8
PC
2016{
2017 _jit_name(block->_jit, __func__);
02487de7 2018 rec_load(state, block, offset, jit_code_ldxi_us, jit_code_bswapr_us, true);
d16005f8
PC
2019}
2020
98fa08a5 2021static void rec_LWL(struct lightrec_cstate *state, const struct block *block, u16 offset)
d16005f8
PC
2022{
2023 _jit_name(block->_jit, __func__);
98fa08a5 2024 rec_io(state, block, offset, true, true);
d16005f8
PC
2025}
2026
98fa08a5 2027static void rec_LWR(struct lightrec_cstate *state, const struct block *block, u16 offset)
d16005f8
PC
2028{
2029 _jit_name(block->_jit, __func__);
98fa08a5 2030 rec_io(state, block, offset, true, true);
d16005f8
PC
2031}
2032
98fa08a5 2033static void rec_LW(struct lightrec_cstate *state, const struct block *block, u16 offset)
d16005f8 2034{
9259d748 2035 union code c = block->opcode_list[offset].c;
ba3814c1
PC
2036 jit_code_t code;
2037
2038 if (is_big_endian() && __WORDSIZE == 64)
2039 code = jit_code_ldxi_ui;
2040 else
2041 code = jit_code_ldxi_i;
2042
9259d748 2043 _jit_name(block->_jit, c.i.op == OP_LWC2 ? "rec_LWC2" : "rec_LW");
ba3814c1 2044 rec_load(state, block, offset, code, jit_code_bswapr_ui, false);
d16005f8
PC
2045}
2046
e26c79a8
PC
2047static void rec_exit_early(struct lightrec_cstate *state,
2048 const struct block *block, u16 offset,
2049 u32 exit_code, u32 pc)
d16005f8 2050{
ba3814c1
PC
2051 struct regcache *reg_cache = state->reg_cache;
2052 jit_state_t *_jit = block->_jit;
2053 u8 tmp;
2054
98fa08a5 2055 _jit_note(block->_jit, __FILE__, __LINE__);
d16005f8 2056
ba3814c1
PC
2057 tmp = lightrec_alloc_reg_temp(reg_cache, _jit);
2058
2059 jit_movi(tmp, exit_code);
8afce295 2060 jit_stxi_i(lightrec_offset(exit_flags), LIGHTREC_REG_STATE, tmp);
ba3814c1 2061
8afce295 2062 jit_ldxi_i(tmp, LIGHTREC_REG_STATE, lightrec_offset(target_cycle));
cb72ea13
PC
2063 jit_subr(tmp, tmp, LIGHTREC_REG_CYCLE);
2064 jit_movi(LIGHTREC_REG_CYCLE, 0);
8afce295
PC
2065 jit_stxi_i(lightrec_offset(target_cycle), LIGHTREC_REG_STATE, tmp);
2066 jit_stxi_i(lightrec_offset(current_cycle), LIGHTREC_REG_STATE, tmp);
cb72ea13 2067
ba3814c1 2068 lightrec_free_reg(reg_cache, tmp);
d16005f8 2069
e26c79a8 2070 lightrec_emit_end_of_block(state, block, offset, -1, pc, 31, 0, true);
d16005f8
PC
2071}
2072
98fa08a5
PC
2073static void rec_special_SYSCALL(struct lightrec_cstate *state,
2074 const struct block *block, u16 offset)
d16005f8
PC
2075{
2076 _jit_name(block->_jit, __func__);
e26c79a8
PC
2077
2078 /* TODO: the return address should be "pc - 4" if we're a delay slot */
2079 rec_exit_early(state, block, offset, LIGHTREC_EXIT_SYSCALL,
2080 get_ds_pc(block, offset, 0));
d16005f8
PC
2081}
2082
98fa08a5
PC
2083static void rec_special_BREAK(struct lightrec_cstate *state,
2084 const struct block *block, u16 offset)
d16005f8
PC
2085{
2086 _jit_name(block->_jit, __func__);
e26c79a8
PC
2087 rec_exit_early(state, block, offset, LIGHTREC_EXIT_BREAK,
2088 get_ds_pc(block, offset, 0));
d16005f8
PC
2089}
2090
fdf33147
PC
2091static void rec_mfc(struct lightrec_cstate *state, const struct block *block, u16 offset)
2092{
2093 struct regcache *reg_cache = state->reg_cache;
2094 union code c = block->opcode_list[offset].c;
2095 jit_state_t *_jit = block->_jit;
2096
2097 jit_note(__FILE__, __LINE__);
9259d748
PC
2098
2099 if (c.i.op != OP_SWC2)
2100 lightrec_clean_reg_if_loaded(reg_cache, _jit, c.i.rt, true);
fdf33147
PC
2101
2102 call_to_c_wrapper(state, block, c.opcode, C_WRAPPER_MFC);
2103}
2104
fd58fa32 2105static void rec_mtc(struct lightrec_cstate *state, const struct block *block, u16 offset)
98fa08a5
PC
2106{
2107 struct regcache *reg_cache = state->reg_cache;
2108 union code c = block->opcode_list[offset].c;
2109 jit_state_t *_jit = block->_jit;
d16005f8 2110
98fa08a5
PC
2111 jit_note(__FILE__, __LINE__);
2112 lightrec_clean_reg_if_loaded(reg_cache, _jit, c.i.rs, false);
2113 lightrec_clean_reg_if_loaded(reg_cache, _jit, c.i.rt, false);
cb72ea13 2114 lightrec_clean_reg_if_loaded(reg_cache, _jit, REG_TEMP, false);
d16005f8 2115
ba3814c1 2116 call_to_c_wrapper(state, block, c.opcode, C_WRAPPER_MTC);
d16005f8 2117
98fa08a5 2118 if (c.i.op == OP_CP0 &&
03535202 2119 !op_flag_no_ds(block->opcode_list[offset].flags) &&
98fa08a5
PC
2120 (c.r.rd == 12 || c.r.rd == 13))
2121 lightrec_emit_end_of_block(state, block, offset, -1,
2122 get_ds_pc(block, offset, 1),
2123 0, 0, true);
d16005f8
PC
2124}
2125
98fa08a5
PC
2126static void
2127rec_mfc0(struct lightrec_cstate *state, const struct block *block, u16 offset)
d16005f8 2128{
d16005f8 2129 struct regcache *reg_cache = state->reg_cache;
98fa08a5 2130 union code c = block->opcode_list[offset].c;
d16005f8 2131 jit_state_t *_jit = block->_jit;
98fa08a5 2132 u8 rt;
d16005f8
PC
2133
2134 jit_note(__FILE__, __LINE__);
2135
98fa08a5 2136 rt = lightrec_alloc_reg_out(reg_cache, _jit, c.i.rt, REG_EXT);
d16005f8 2137
8afce295 2138 jit_ldxi_i(rt, LIGHTREC_REG_STATE, lightrec_offset(regs.cp0[c.r.rd]));
d16005f8 2139
98fa08a5
PC
2140 lightrec_free_reg(reg_cache, rt);
2141}
d16005f8 2142
cb72ea13
PC
2143static bool block_uses_icache(const struct lightrec_cstate *state,
2144 const struct block *block)
98fa08a5 2145{
cb72ea13 2146 const struct lightrec_mem_map *map = &state->state->maps[PSX_MAP_KERNEL_USER_RAM];
98fa08a5 2147 u32 pc = kunseg(block->pc);
d16005f8 2148
cb72ea13
PC
2149 if (pc < map->pc || pc >= map->pc + map->length)
2150 return false;
2151
2152 return (block->pc >> 28) < 0xa;
d16005f8
PC
2153}
2154
98fa08a5
PC
2155static void
2156rec_mtc0(struct lightrec_cstate *state, const struct block *block, u16 offset)
d16005f8 2157{
98fa08a5
PC
2158 struct regcache *reg_cache = state->reg_cache;
2159 const union code c = block->opcode_list[offset].c;
2160 jit_state_t *_jit = block->_jit;
fd58fa32 2161 u8 rt, tmp = 0, tmp2, status;
0cf41071 2162 jit_node_t *to_end;
98fa08a5
PC
2163
2164 jit_note(__FILE__, __LINE__);
2165
2166 switch(c.r.rd) {
2167 case 1:
2168 case 4:
2169 case 8:
2170 case 14:
2171 case 15:
2172 /* Those registers are read-only */
2173 return;
2174 default:
2175 break;
2176 }
2177
cb72ea13
PC
2178 if (!block_uses_icache(state, block) && c.r.rd == 12) {
2179 /* If we are not running code from the RAM through kuseg or
2180 * kseg0, handle writes to the Status register in C; as the
2181 * code may toggle bit 16 which isolates the cache. Code
2182 * running from kuseg or kseg0 in RAM cannot do that. */
98fa08a5
PC
2183 rec_mtc(state, block, offset);
2184 return;
2185 }
2186
2187 rt = lightrec_alloc_reg_in(reg_cache, _jit, c.i.rt, 0);
2188
8afce295
PC
2189 if (c.r.rd != 13)
2190 jit_stxi_i(lightrec_offset(regs.cp0[c.r.rd]), LIGHTREC_REG_STATE, rt);
98fa08a5
PC
2191
2192 if (c.r.rd == 12 || c.r.rd == 13) {
2193 tmp = lightrec_alloc_reg_temp(reg_cache, _jit);
8afce295 2194 jit_ldxi_i(tmp, LIGHTREC_REG_STATE, lightrec_offset(regs.cp0[13]));
fd58fa32
PC
2195
2196 tmp2 = lightrec_alloc_reg_temp(reg_cache, _jit);
98fa08a5
PC
2197 }
2198
2199 if (c.r.rd == 12) {
2200 status = rt;
2201 } else if (c.r.rd == 13) {
98fa08a5
PC
2202 /* Cause = (Cause & ~0x0300) | (value & 0x0300) */
2203 jit_andi(tmp2, rt, 0x0300);
2204 jit_ori(tmp, tmp, 0x0300);
2205 jit_xori(tmp, tmp, 0x0300);
2206 jit_orr(tmp, tmp, tmp2);
8afce295
PC
2207 jit_ldxi_i(tmp2, LIGHTREC_REG_STATE, lightrec_offset(regs.cp0[12]));
2208 jit_stxi_i(lightrec_offset(regs.cp0[13]), LIGHTREC_REG_STATE, tmp);
98fa08a5
PC
2209 status = tmp2;
2210 }
2211
2212 if (c.r.rd == 12 || c.r.rd == 13) {
2213 /* Exit dynarec in case there's a software interrupt.
2214 * exit_flags = !!(status & tmp & 0x0300) & status; */
2215 jit_andr(tmp, tmp, status);
2216 jit_andi(tmp, tmp, 0x0300);
2217 jit_nei(tmp, tmp, 0);
2218 jit_andr(tmp, tmp, status);
fd58fa32
PC
2219 }
2220
2221 if (c.r.rd == 12) {
2222 /* Exit dynarec in case we unmask a hardware interrupt.
2223 * exit_flags = !(~status & 0x401) */
2224
2225 jit_comr(tmp2, status);
2226 jit_andi(tmp2, tmp2, 0x401);
2227 jit_eqi(tmp2, tmp2, 0);
2228 jit_orr(tmp, tmp, tmp2);
2229 }
2230
0cf41071
PC
2231 lightrec_free_reg(reg_cache, rt);
2232
fd58fa32 2233 if (c.r.rd == 12 || c.r.rd == 13) {
0cf41071 2234 to_end = jit_beqi(tmp, 0);
98fa08a5 2235
8afce295 2236 jit_ldxi_i(tmp2, LIGHTREC_REG_STATE, lightrec_offset(target_cycle));
0cf41071
PC
2237 jit_subr(tmp2, tmp2, LIGHTREC_REG_CYCLE);
2238 jit_movi(LIGHTREC_REG_CYCLE, 0);
8afce295
PC
2239 jit_stxi_i(lightrec_offset(target_cycle), LIGHTREC_REG_STATE, tmp2);
2240 jit_stxi_i(lightrec_offset(current_cycle), LIGHTREC_REG_STATE, tmp2);
98fa08a5 2241
0cf41071
PC
2242
2243 jit_patch(to_end);
2244 }
98fa08a5 2245
03535202 2246 if (!op_flag_no_ds(block->opcode_list[offset].flags) &&
13b02197 2247 (c.r.rd == 12 || c.r.rd == 13)) {
684432ad 2248 state->cycles += lightrec_cycles_of_opcode(state->state, c);
13b02197
PC
2249 lightrec_emit_eob(state, block, offset + 1);
2250 }
d16005f8
PC
2251}
2252
98fa08a5
PC
2253static void rec_cp0_MFC0(struct lightrec_cstate *state,
2254 const struct block *block, u16 offset)
d16005f8
PC
2255{
2256 _jit_name(block->_jit, __func__);
98fa08a5 2257 rec_mfc0(state, block, offset);
d16005f8
PC
2258}
2259
98fa08a5
PC
2260static void rec_cp0_CFC0(struct lightrec_cstate *state,
2261 const struct block *block, u16 offset)
d16005f8
PC
2262{
2263 _jit_name(block->_jit, __func__);
98fa08a5 2264 rec_mfc0(state, block, offset);
d16005f8
PC
2265}
2266
98fa08a5
PC
2267static void rec_cp0_MTC0(struct lightrec_cstate *state,
2268 const struct block *block, u16 offset)
d16005f8
PC
2269{
2270 _jit_name(block->_jit, __func__);
98fa08a5 2271 rec_mtc0(state, block, offset);
d16005f8
PC
2272}
2273
98fa08a5
PC
2274static void rec_cp0_CTC0(struct lightrec_cstate *state,
2275 const struct block *block, u16 offset)
d16005f8
PC
2276{
2277 _jit_name(block->_jit, __func__);
98fa08a5 2278 rec_mtc0(state, block, offset);
d16005f8
PC
2279}
2280
02487de7
PC
2281static unsigned int cp2d_i_offset(u8 reg)
2282{
8afce295 2283 return lightrec_offset(regs.cp2d[reg]);
02487de7
PC
2284}
2285
2286static unsigned int cp2d_s_offset(u8 reg)
2287{
2288 return cp2d_i_offset(reg) + is_big_endian() * 2;
2289}
2290
2291static unsigned int cp2c_i_offset(u8 reg)
2292{
8afce295 2293 return lightrec_offset(regs.cp2c[reg]);
02487de7
PC
2294}
2295
2296static unsigned int cp2c_s_offset(u8 reg)
2297{
2298 return cp2c_i_offset(reg) + is_big_endian() * 2;
2299}
2300
9259d748
PC
2301static void rec_cp2_do_mfc2(struct lightrec_cstate *state,
2302 const struct block *block, u16 offset,
2303 u8 reg, u8 out_reg)
d16005f8 2304{
fd58fa32 2305 struct regcache *reg_cache = state->reg_cache;
fd58fa32
PC
2306 jit_state_t *_jit = block->_jit;
2307 const u32 zext_regs = 0x300f0080;
2308 u8 rt, tmp, tmp2, tmp3, out, flags;
fd58fa32
PC
2309 unsigned int i;
2310
d16005f8 2311 _jit_name(block->_jit, __func__);
fd58fa32 2312
fdf33147
PC
2313 if (state->state->ops.cop2_notify) {
2314 /* We must call cop2_notify, handle that in C. */
2315 rec_mfc(state, block, offset);
2316 return;
2317 }
2318
fd58fa32 2319 flags = (zext_regs & BIT(reg)) ? REG_ZEXT : REG_EXT;
9259d748
PC
2320 rt = lightrec_alloc_reg_out(reg_cache, _jit, out_reg, flags);
2321
2322 if (reg == 15)
2323 reg = 14;
fd58fa32
PC
2324
2325 switch (reg) {
2326 case 1:
2327 case 3:
2328 case 5:
2329 case 8:
2330 case 9:
2331 case 10:
2332 case 11:
02487de7 2333 jit_ldxi_s(rt, LIGHTREC_REG_STATE, cp2d_s_offset(reg));
fd58fa32
PC
2334 break;
2335 case 7:
2336 case 16:
2337 case 17:
2338 case 18:
2339 case 19:
02487de7 2340 jit_ldxi_us(rt, LIGHTREC_REG_STATE, cp2d_s_offset(reg));
fd58fa32
PC
2341 break;
2342 case 28:
2343 case 29:
2344 tmp = lightrec_alloc_reg_temp(reg_cache, _jit);
2345 tmp2 = lightrec_alloc_reg_temp(reg_cache, _jit);
2346 tmp3 = lightrec_alloc_reg_temp(reg_cache, _jit);
2347
2348 for (i = 0; i < 3; i++) {
2349 out = i == 0 ? rt : tmp;
2350
02487de7 2351 jit_ldxi_s(tmp, LIGHTREC_REG_STATE, cp2d_s_offset(9 + i));
fd58fa32
PC
2352 jit_movi(tmp2, 0x1f);
2353 jit_rshi(out, tmp, 7);
2354
2355 jit_ltr(tmp3, tmp2, out);
2356 jit_movnr(out, tmp2, tmp3);
2357
2358 jit_gei(tmp2, out, 0);
2359 jit_movzr(out, tmp2, tmp2);
2360
2361 if (i > 0) {
2362 jit_lshi(tmp, tmp, 5 * i);
2363 jit_orr(rt, rt, tmp);
2364 }
2365 }
2366
2367
2368 lightrec_free_reg(reg_cache, tmp);
2369 lightrec_free_reg(reg_cache, tmp2);
2370 lightrec_free_reg(reg_cache, tmp3);
2371 break;
2372 default:
02487de7 2373 jit_ldxi_i(rt, LIGHTREC_REG_STATE, cp2d_i_offset(reg));
fd58fa32
PC
2374 break;
2375 }
2376
2377 lightrec_free_reg(reg_cache, rt);
d16005f8
PC
2378}
2379
9259d748
PC
2380static void rec_cp2_basic_MFC2(struct lightrec_cstate *state,
2381 const struct block *block, u16 offset)
2382{
2383 const union code c = block->opcode_list[offset].c;
2384
2385 rec_cp2_do_mfc2(state, block, offset, c.r.rd, c.r.rt);
2386}
2387
98fa08a5
PC
2388static void rec_cp2_basic_CFC2(struct lightrec_cstate *state,
2389 const struct block *block, u16 offset)
d16005f8 2390{
fd58fa32
PC
2391 struct regcache *reg_cache = state->reg_cache;
2392 const union code c = block->opcode_list[offset].c;
2393 jit_state_t *_jit = block->_jit;
2394 u8 rt;
2395
d16005f8 2396 _jit_name(block->_jit, __func__);
fd58fa32 2397
fdf33147
PC
2398 if (state->state->ops.cop2_notify) {
2399 /* We must call cop2_notify, handle that in C. */
2400 rec_mfc(state, block, offset);
2401 return;
2402 }
2403
fd58fa32
PC
2404 switch (c.r.rd) {
2405 case 4:
2406 case 12:
2407 case 20:
2408 case 26:
2409 case 27:
2410 case 29:
2411 case 30:
2412 rt = lightrec_alloc_reg_out(reg_cache, _jit, c.r.rt, REG_EXT);
02487de7 2413 jit_ldxi_s(rt, LIGHTREC_REG_STATE, cp2c_s_offset(c.r.rd));
fd58fa32
PC
2414 break;
2415 default:
2416 rt = lightrec_alloc_reg_out(reg_cache, _jit, c.r.rt, REG_ZEXT);
0cf41071 2417 jit_ldxi_ui(rt, LIGHTREC_REG_STATE, cp2c_i_offset(c.r.rd));
fd58fa32
PC
2418 break;
2419 }
2420
2421 lightrec_free_reg(reg_cache, rt);
d16005f8
PC
2422}
2423
9259d748
PC
2424static void rec_cp2_do_mtc2(struct lightrec_cstate *state,
2425 const struct block *block, u16 offset,
2426 u8 reg, u8 in_reg)
d16005f8 2427{
fd58fa32 2428 struct regcache *reg_cache = state->reg_cache;
fd58fa32 2429 jit_state_t *_jit = block->_jit;
fd58fa32
PC
2430 u8 rt, tmp, tmp2, flags = 0;
2431
d16005f8 2432 _jit_name(block->_jit, __func__);
fd58fa32 2433
fdf33147
PC
2434 if (state->state->ops.cop2_notify) {
2435 /* We must call cop2_notify, handle that in C. */
2436 rec_mtc(state, block, offset);
2437 return;
2438 }
2439
9259d748 2440 if (reg == 31)
fd58fa32
PC
2441 return;
2442
9259d748 2443 if (reg == 30)
fd58fa32
PC
2444 flags |= REG_EXT;
2445
9259d748 2446 rt = lightrec_alloc_reg_in(reg_cache, _jit, in_reg, flags);
fd58fa32 2447
9259d748 2448 switch (reg) {
fd58fa32
PC
2449 case 15:
2450 tmp = lightrec_alloc_reg_temp(reg_cache, _jit);
02487de7 2451 jit_ldxi_i(tmp, LIGHTREC_REG_STATE, cp2d_i_offset(13));
fd58fa32
PC
2452
2453 tmp2 = lightrec_alloc_reg_temp(reg_cache, _jit);
02487de7 2454 jit_ldxi_i(tmp2, LIGHTREC_REG_STATE, cp2d_i_offset(14));
fd58fa32 2455
02487de7
PC
2456 jit_stxi_i(cp2d_i_offset(12), LIGHTREC_REG_STATE, tmp);
2457 jit_stxi_i(cp2d_i_offset(13), LIGHTREC_REG_STATE, tmp2);
2458 jit_stxi_i(cp2d_i_offset(14), LIGHTREC_REG_STATE, rt);
fd58fa32
PC
2459
2460 lightrec_free_reg(reg_cache, tmp);
2461 lightrec_free_reg(reg_cache, tmp2);
2462 break;
2463 case 28:
2464 tmp = lightrec_alloc_reg_temp(reg_cache, _jit);
2465
2466 jit_lshi(tmp, rt, 7);
2467 jit_andi(tmp, tmp, 0xf80);
02487de7 2468 jit_stxi_s(cp2d_s_offset(9), LIGHTREC_REG_STATE, tmp);
fd58fa32
PC
2469
2470 jit_lshi(tmp, rt, 2);
2471 jit_andi(tmp, tmp, 0xf80);
02487de7 2472 jit_stxi_s(cp2d_s_offset(10), LIGHTREC_REG_STATE, tmp);
fd58fa32
PC
2473
2474 jit_rshi(tmp, rt, 3);
2475 jit_andi(tmp, tmp, 0xf80);
02487de7 2476 jit_stxi_s(cp2d_s_offset(11), LIGHTREC_REG_STATE, tmp);
fd58fa32
PC
2477
2478 lightrec_free_reg(reg_cache, tmp);
2479 break;
2480 case 30:
2481 tmp = lightrec_alloc_reg_temp(reg_cache, _jit);
fd58fa32
PC
2482
2483 /* if (rt < 0) rt = ~rt; */
2484 jit_rshi(tmp, rt, 31);
2485 jit_xorr(tmp, rt, tmp);
2486
cb72ea13
PC
2487 /* Count leading zeros */
2488 jit_clzr(tmp, tmp);
2489 if (__WORDSIZE != 32)
2490 jit_subi(tmp, tmp, __WORDSIZE - 32);
fd58fa32 2491
cb72ea13 2492 jit_stxi_i(cp2d_i_offset(31), LIGHTREC_REG_STATE, tmp);
fd58fa32
PC
2493
2494 lightrec_free_reg(reg_cache, tmp);
cb72ea13 2495 fallthrough;
fd58fa32 2496 default:
9259d748 2497 jit_stxi_i(cp2d_i_offset(reg), LIGHTREC_REG_STATE, rt);
fd58fa32
PC
2498 break;
2499 }
2500
2501 lightrec_free_reg(reg_cache, rt);
d16005f8
PC
2502}
2503
9259d748
PC
2504static void rec_cp2_basic_MTC2(struct lightrec_cstate *state,
2505 const struct block *block, u16 offset)
2506{
2507 const union code c = block->opcode_list[offset].c;
2508
2509 rec_cp2_do_mtc2(state, block, offset, c.r.rd, c.r.rt);
2510}
2511
98fa08a5
PC
2512static void rec_cp2_basic_CTC2(struct lightrec_cstate *state,
2513 const struct block *block, u16 offset)
d16005f8 2514{
fd58fa32
PC
2515 struct regcache *reg_cache = state->reg_cache;
2516 const union code c = block->opcode_list[offset].c;
2517 jit_state_t *_jit = block->_jit;
2518 u8 rt, tmp, tmp2;
2519
98fa08a5 2520 _jit_name(block->_jit, __func__);
fd58fa32 2521
fdf33147
PC
2522 if (state->state->ops.cop2_notify) {
2523 /* We must call cop2_notify, handle that in C. */
2524 rec_mtc(state, block, offset);
2525 return;
2526 }
2527
fd58fa32
PC
2528 rt = lightrec_alloc_reg_in(reg_cache, _jit, c.r.rt, 0);
2529
2530 switch (c.r.rd) {
2531 case 4:
2532 case 12:
2533 case 20:
2534 case 26:
2535 case 27:
2536 case 29:
2537 case 30:
02487de7 2538 jit_stxi_s(cp2c_s_offset(c.r.rd), LIGHTREC_REG_STATE, rt);
fd58fa32
PC
2539 break;
2540 case 31:
2541 tmp = lightrec_alloc_reg_temp(reg_cache, _jit);
2542 tmp2 = lightrec_alloc_reg_temp(reg_cache, _jit);
2543
2544 jit_andi(tmp, rt, 0x7f87e000);
2545 jit_nei(tmp, tmp, 0);
2546 jit_lshi(tmp, tmp, 31);
2547
2548 jit_andi(tmp2, rt, 0x7ffff000);
2549 jit_orr(tmp, tmp2, tmp);
2550
02487de7 2551 jit_stxi_i(cp2c_i_offset(31), LIGHTREC_REG_STATE, tmp);
fd58fa32
PC
2552
2553 lightrec_free_reg(reg_cache, tmp);
2554 lightrec_free_reg(reg_cache, tmp2);
2555 break;
2556
2557 default:
02487de7 2558 jit_stxi_i(cp2c_i_offset(c.r.rd), LIGHTREC_REG_STATE, rt);
fd58fa32
PC
2559 }
2560
2561 lightrec_free_reg(reg_cache, rt);
d16005f8
PC
2562}
2563
98fa08a5
PC
2564static void rec_cp0_RFE(struct lightrec_cstate *state,
2565 const struct block *block, u16 offset)
d16005f8 2566{
98fa08a5 2567 struct regcache *reg_cache = state->reg_cache;
d16005f8 2568 jit_state_t *_jit = block->_jit;
98fa08a5 2569 u8 status, tmp;
d16005f8
PC
2570
2571 jit_name(__func__);
2572 jit_note(__FILE__, __LINE__);
2573
98fa08a5 2574 status = lightrec_alloc_reg_temp(reg_cache, _jit);
8afce295 2575 jit_ldxi_i(status, LIGHTREC_REG_STATE, lightrec_offset(regs.cp0[12]));
d16005f8 2576
98fa08a5 2577 tmp = lightrec_alloc_reg_temp(reg_cache, _jit);
d16005f8 2578
98fa08a5
PC
2579 /* status = ((status >> 2) & 0xf) | status & ~0xf; */
2580 jit_rshi(tmp, status, 2);
2581 jit_andi(tmp, tmp, 0xf);
2582 jit_andi(status, status, ~0xful);
2583 jit_orr(status, status, tmp);
2584
8afce295
PC
2585 jit_ldxi_i(tmp, LIGHTREC_REG_STATE, lightrec_offset(regs.cp0[13]));
2586 jit_stxi_i(lightrec_offset(regs.cp0[12]), LIGHTREC_REG_STATE, status);
98fa08a5
PC
2587
2588 /* Exit dynarec in case there's a software interrupt.
2589 * exit_flags = !!(status & cause & 0x0300) & status; */
2590 jit_andr(tmp, tmp, status);
2591 jit_andi(tmp, tmp, 0x0300);
2592 jit_nei(tmp, tmp, 0);
2593 jit_andr(tmp, tmp, status);
8afce295 2594 jit_stxi_i(lightrec_offset(exit_flags), LIGHTREC_REG_STATE, tmp);
98fa08a5
PC
2595
2596 lightrec_free_reg(reg_cache, status);
d16005f8 2597 lightrec_free_reg(reg_cache, tmp);
d16005f8
PC
2598}
2599
98fa08a5
PC
2600static void rec_CP(struct lightrec_cstate *state,
2601 const struct block *block, u16 offset)
d16005f8 2602{
98fa08a5 2603 union code c = block->opcode_list[offset].c;
d16005f8
PC
2604 jit_state_t *_jit = block->_jit;
2605
2606 jit_name(__func__);
2607 jit_note(__FILE__, __LINE__);
2608
ba3814c1 2609 call_to_c_wrapper(state, block, c.opcode, C_WRAPPER_CP);
d16005f8
PC
2610}
2611
98fa08a5
PC
2612static void rec_meta_MOV(struct lightrec_cstate *state,
2613 const struct block *block, u16 offset)
d16005f8 2614{
d16005f8 2615 struct regcache *reg_cache = state->reg_cache;
9259d748
PC
2616 const struct opcode *op = &block->opcode_list[offset];
2617 union code c = op->c;
d16005f8 2618 jit_state_t *_jit = block->_jit;
9259d748 2619 bool unload_rd;
684432ad 2620 bool unload_rs, discard_rs;
d16005f8
PC
2621 u8 rs, rd;
2622
2623 _jit_name(block->_jit, __func__);
2624 jit_note(__FILE__, __LINE__);
9259d748 2625
684432ad
PC
2626 unload_rs = OPT_EARLY_UNLOAD
2627 && LIGHTREC_FLAGS_GET_RS(op->flags) == LIGHTREC_REG_UNLOAD;
2628 discard_rs = OPT_EARLY_UNLOAD
2629 && LIGHTREC_FLAGS_GET_RS(op->flags) == LIGHTREC_REG_DISCARD;
2630
2631 if ((unload_rs || discard_rs) && c.m.rs) {
2632 /* If the source register is going to be unloaded or discarded,
2633 * then we can simply mark its host register as now pointing to
2634 * the destination register. */
2635 pr_debug("Remap %s to %s at offset 0x%x\n",
2636 lightrec_reg_name(c.m.rs), lightrec_reg_name(c.m.rd),
2637 offset << 2);
2638 rs = lightrec_alloc_reg_in(reg_cache, _jit, c.m.rs, 0);
2639 lightrec_remap_reg(reg_cache, _jit, rs, c.m.rd, discard_rs);
2640 lightrec_free_reg(reg_cache, rs);
2641 return;
2642 }
2643
9259d748
PC
2644 unload_rd = OPT_EARLY_UNLOAD
2645 && LIGHTREC_FLAGS_GET_RD(op->flags) == LIGHTREC_REG_UNLOAD;
2646
8afce295 2647 if (unload_rd) {
9259d748
PC
2648 /* If the destination register will be unloaded right after the
2649 * MOV meta-opcode, we don't actually need to write any host
2650 * register - we can just store the source register directly to
2651 * the register cache, at the offset corresponding to the
2652 * destination register. */
cb72ea13
PC
2653 lightrec_discard_reg_if_loaded(reg_cache, c.m.rd);
2654
2655 rs = lightrec_alloc_reg_in(reg_cache, _jit, c.m.rs, 0);
9259d748 2656
8afce295 2657 jit_stxi_i(lightrec_offset(regs.gpr) + (c.m.rd << 2), LIGHTREC_REG_STATE, rs);
d16005f8 2658
98fa08a5 2659 lightrec_free_reg(reg_cache, rs);
9259d748 2660 } else {
cb72ea13
PC
2661 if (c.m.rs)
2662 rs = lightrec_alloc_reg_in(reg_cache, _jit, c.m.rs, 0);
2663
2664 rd = lightrec_alloc_reg_out(reg_cache, _jit, c.m.rd, REG_EXT);
9259d748 2665
cb72ea13 2666 if (c.m.rs == 0) {
9259d748 2667 jit_movi(rd, 0);
cb72ea13 2668 } else {
9259d748 2669 jit_extr_i(rd, rs);
cb72ea13
PC
2670 lightrec_free_reg(reg_cache, rs);
2671 }
9259d748
PC
2672
2673 lightrec_free_reg(reg_cache, rd);
2674 }
d16005f8
PC
2675}
2676
98fa08a5
PC
2677static void rec_meta_EXTC_EXTS(struct lightrec_cstate *state,
2678 const struct block *block,
2679 u16 offset)
d16005f8 2680{
98fa08a5
PC
2681 struct regcache *reg_cache = state->reg_cache;
2682 union code c = block->opcode_list[offset].c;
d16005f8 2683 jit_state_t *_jit = block->_jit;
cb72ea13 2684 u8 rs, rd;
d16005f8 2685
98fa08a5 2686 _jit_name(block->_jit, __func__);
d16005f8
PC
2687 jit_note(__FILE__, __LINE__);
2688
684432ad
PC
2689 rec_alloc_rs_rd(reg_cache, _jit, &block->opcode_list[offset],
2690 c.m.rs, c.m.rd, 0, REG_EXT, &rs, &rd);
d16005f8 2691
cb72ea13
PC
2692 if (c.m.op == OP_META_EXTC)
2693 jit_extr_c(rd, rs);
98fa08a5 2694 else
cb72ea13 2695 jit_extr_s(rd, rs);
d16005f8 2696
98fa08a5 2697 lightrec_free_reg(reg_cache, rs);
cb72ea13 2698 lightrec_free_reg(reg_cache, rd);
d16005f8
PC
2699}
2700
ba3814c1
PC
2701static void rec_meta_MULT2(struct lightrec_cstate *state,
2702 const struct block *block,
2703 u16 offset)
2704{
2705 struct regcache *reg_cache = state->reg_cache;
2706 union code c = block->opcode_list[offset].c;
2707 jit_state_t *_jit = block->_jit;
2708 u8 reg_lo = get_mult_div_lo(c);
2709 u8 reg_hi = get_mult_div_hi(c);
2710 u32 flags = block->opcode_list[offset].flags;
2711 bool is_signed = c.i.op == OP_META_MULT2;
2712 u8 rs, lo, hi, rflags = 0, hiflags = 0;
0cf41071 2713 unsigned int i;
ba3814c1
PC
2714
2715 if (!op_flag_no_hi(flags) && c.r.op < 32) {
2716 rflags = is_signed ? REG_EXT : REG_ZEXT;
2717 hiflags = is_signed ? REG_EXT : (REG_EXT | REG_ZEXT);
2718 }
2719
2720 _jit_name(block->_jit, __func__);
2721 jit_note(__FILE__, __LINE__);
2722
2723 rs = lightrec_alloc_reg_in(reg_cache, _jit, c.i.rs, rflags);
2724
0cf41071
PC
2725 /*
2726 * We must handle the case where one of the output registers is our rs
2727 * input register. Thanksfully, computing LO/HI can be done in any
2728 * order. Here, we make sure that the computation that overwrites the
2729 * input register is always performed last.
2730 */
2731 for (i = 0; i < 2; i++) {
2732 if ((!i ^ (reg_lo == c.i.rs)) && !op_flag_no_lo(flags)) {
2733 lo = lightrec_alloc_reg_out(reg_cache, _jit, reg_lo, 0);
2734
2735 if (c.r.op < 32)
2736 jit_lshi(lo, rs, c.r.op);
2737 else
2738 jit_movi(lo, 0);
ba3814c1 2739
0cf41071
PC
2740 lightrec_free_reg(reg_cache, lo);
2741 continue;
2742 }
ba3814c1 2743
0cf41071
PC
2744 if ((!!i ^ (reg_lo == c.i.rs)) && !op_flag_no_hi(flags)) {
2745 hi = lightrec_alloc_reg_out(reg_cache, _jit,
2746 reg_hi, hiflags);
ba3814c1 2747
f5ee77ca 2748 if (c.r.op >= 32) {
0cf41071 2749 jit_lshi(hi, rs, c.r.op - 32);
f5ee77ca
PC
2750 } else if (is_signed) {
2751 if (c.r.op)
2752 jit_rshi(hi, rs, 32 - c.r.op);
2753 else
2754 jit_rshi(hi, rs, 31);
2755 } else {
2756 if (c.r.op)
2757 jit_rshi_u(hi, rs, 32 - c.r.op);
2758 else
2759 jit_movi(hi, 0);
2760 }
ba3814c1 2761
0cf41071
PC
2762 lightrec_free_reg(reg_cache, hi);
2763 }
ba3814c1
PC
2764 }
2765
2766 lightrec_free_reg(reg_cache, rs);
2767
2768 _jit_name(block->_jit, __func__);
2769 jit_note(__FILE__, __LINE__);
2770}
2771
cb72ea13
PC
2772static void rec_meta_COM(struct lightrec_cstate *state,
2773 const struct block *block, u16 offset)
2774{
2775 struct regcache *reg_cache = state->reg_cache;
2776 union code c = block->opcode_list[offset].c;
2777 jit_state_t *_jit = block->_jit;
2778 u8 rd, rs, flags;
2779
2780 jit_note(__FILE__, __LINE__);
684432ad
PC
2781
2782 rec_alloc_rs_rd(reg_cache, _jit, &block->opcode_list[offset],
2783 c.m.rs, c.m.rd, 0, 0, &rs, &rd);
cb72ea13
PC
2784
2785 flags = lightrec_get_reg_in_flags(reg_cache, rs);
2786
2787 lightrec_set_reg_out_flags(reg_cache, rd,
2788 flags & REG_EXT);
2789
2790 jit_comr(rd, rs);
2791
2792 lightrec_free_reg(reg_cache, rs);
2793 lightrec_free_reg(reg_cache, rd);
2794}
2795
5459088b
PC
2796static void rec_meta_LWU(struct lightrec_cstate *state,
2797 const struct block *block,
2798 u16 offset)
2799{
2800 jit_code_t code;
2801
2802 if (is_big_endian() && __WORDSIZE == 64)
2803 code = jit_code_unldr_u;
2804 else
2805 code = jit_code_unldr;
2806
2807 _jit_name(block->_jit, __func__);
2808 rec_load(state, block, offset, code, jit_code_bswapr_ui, false);
2809}
2810
2811static void rec_meta_SWU(struct lightrec_cstate *state,
2812 const struct block *block,
2813 u16 offset)
2814{
2815 _jit_name(block->_jit, __func__);
2816 rec_store(state, block, offset, jit_code_unstr, jit_code_bswapr_ui);
2817}
2818
e26c79a8
PC
2819static void unknown_opcode(struct lightrec_cstate *state,
2820 const struct block *block, u16 offset)
2821{
2822 rec_exit_early(state, block, offset, LIGHTREC_EXIT_UNKNOWN_OP,
2823 block->pc + (offset << 2));
2824}
2825
d16005f8 2826static const lightrec_rec_func_t rec_standard[64] = {
98fa08a5 2827 SET_DEFAULT_ELM(rec_standard, unknown_opcode),
d16005f8
PC
2828 [OP_SPECIAL] = rec_SPECIAL,
2829 [OP_REGIMM] = rec_REGIMM,
2830 [OP_J] = rec_J,
2831 [OP_JAL] = rec_JAL,
2832 [OP_BEQ] = rec_BEQ,
2833 [OP_BNE] = rec_BNE,
2834 [OP_BLEZ] = rec_BLEZ,
2835 [OP_BGTZ] = rec_BGTZ,
2836 [OP_ADDI] = rec_ADDI,
2837 [OP_ADDIU] = rec_ADDIU,
2838 [OP_SLTI] = rec_SLTI,
2839 [OP_SLTIU] = rec_SLTIU,
2840 [OP_ANDI] = rec_ANDI,
2841 [OP_ORI] = rec_ORI,
2842 [OP_XORI] = rec_XORI,
2843 [OP_LUI] = rec_LUI,
2844 [OP_CP0] = rec_CP0,
2845 [OP_CP2] = rec_CP2,
2846 [OP_LB] = rec_LB,
2847 [OP_LH] = rec_LH,
2848 [OP_LWL] = rec_LWL,
2849 [OP_LW] = rec_LW,
2850 [OP_LBU] = rec_LBU,
2851 [OP_LHU] = rec_LHU,
2852 [OP_LWR] = rec_LWR,
2853 [OP_SB] = rec_SB,
2854 [OP_SH] = rec_SH,
2855 [OP_SWL] = rec_SWL,
2856 [OP_SW] = rec_SW,
2857 [OP_SWR] = rec_SWR,
9259d748
PC
2858 [OP_LWC2] = rec_LW,
2859 [OP_SWC2] = rec_SW,
d16005f8 2860
cb72ea13 2861 [OP_META] = rec_META,
ba3814c1
PC
2862 [OP_META_MULT2] = rec_meta_MULT2,
2863 [OP_META_MULTU2] = rec_meta_MULT2,
5459088b
PC
2864 [OP_META_LWU] = rec_meta_LWU,
2865 [OP_META_SWU] = rec_meta_SWU,
d16005f8
PC
2866};
2867
2868static const lightrec_rec_func_t rec_special[64] = {
98fa08a5 2869 SET_DEFAULT_ELM(rec_special, unknown_opcode),
d16005f8
PC
2870 [OP_SPECIAL_SLL] = rec_special_SLL,
2871 [OP_SPECIAL_SRL] = rec_special_SRL,
2872 [OP_SPECIAL_SRA] = rec_special_SRA,
2873 [OP_SPECIAL_SLLV] = rec_special_SLLV,
2874 [OP_SPECIAL_SRLV] = rec_special_SRLV,
2875 [OP_SPECIAL_SRAV] = rec_special_SRAV,
2876 [OP_SPECIAL_JR] = rec_special_JR,
2877 [OP_SPECIAL_JALR] = rec_special_JALR,
2878 [OP_SPECIAL_SYSCALL] = rec_special_SYSCALL,
2879 [OP_SPECIAL_BREAK] = rec_special_BREAK,
2880 [OP_SPECIAL_MFHI] = rec_special_MFHI,
2881 [OP_SPECIAL_MTHI] = rec_special_MTHI,
2882 [OP_SPECIAL_MFLO] = rec_special_MFLO,
2883 [OP_SPECIAL_MTLO] = rec_special_MTLO,
2884 [OP_SPECIAL_MULT] = rec_special_MULT,
2885 [OP_SPECIAL_MULTU] = rec_special_MULTU,
2886 [OP_SPECIAL_DIV] = rec_special_DIV,
2887 [OP_SPECIAL_DIVU] = rec_special_DIVU,
2888 [OP_SPECIAL_ADD] = rec_special_ADD,
2889 [OP_SPECIAL_ADDU] = rec_special_ADDU,
2890 [OP_SPECIAL_SUB] = rec_special_SUB,
2891 [OP_SPECIAL_SUBU] = rec_special_SUBU,
2892 [OP_SPECIAL_AND] = rec_special_AND,
2893 [OP_SPECIAL_OR] = rec_special_OR,
2894 [OP_SPECIAL_XOR] = rec_special_XOR,
2895 [OP_SPECIAL_NOR] = rec_special_NOR,
2896 [OP_SPECIAL_SLT] = rec_special_SLT,
2897 [OP_SPECIAL_SLTU] = rec_special_SLTU,
2898};
2899
2900static const lightrec_rec_func_t rec_regimm[64] = {
98fa08a5 2901 SET_DEFAULT_ELM(rec_regimm, unknown_opcode),
d16005f8
PC
2902 [OP_REGIMM_BLTZ] = rec_regimm_BLTZ,
2903 [OP_REGIMM_BGEZ] = rec_regimm_BGEZ,
2904 [OP_REGIMM_BLTZAL] = rec_regimm_BLTZAL,
2905 [OP_REGIMM_BGEZAL] = rec_regimm_BGEZAL,
2906};
2907
2908static const lightrec_rec_func_t rec_cp0[64] = {
98fa08a5 2909 SET_DEFAULT_ELM(rec_cp0, rec_CP),
d16005f8
PC
2910 [OP_CP0_MFC0] = rec_cp0_MFC0,
2911 [OP_CP0_CFC0] = rec_cp0_CFC0,
2912 [OP_CP0_MTC0] = rec_cp0_MTC0,
2913 [OP_CP0_CTC0] = rec_cp0_CTC0,
2914 [OP_CP0_RFE] = rec_cp0_RFE,
2915};
2916
2917static const lightrec_rec_func_t rec_cp2_basic[64] = {
98fa08a5 2918 SET_DEFAULT_ELM(rec_cp2_basic, rec_CP),
d16005f8
PC
2919 [OP_CP2_BASIC_MFC2] = rec_cp2_basic_MFC2,
2920 [OP_CP2_BASIC_CFC2] = rec_cp2_basic_CFC2,
2921 [OP_CP2_BASIC_MTC2] = rec_cp2_basic_MTC2,
2922 [OP_CP2_BASIC_CTC2] = rec_cp2_basic_CTC2,
2923};
2924
cb72ea13
PC
2925static const lightrec_rec_func_t rec_meta[64] = {
2926 SET_DEFAULT_ELM(rec_meta, unknown_opcode),
2927 [OP_META_MOV] = rec_meta_MOV,
2928 [OP_META_EXTC] = rec_meta_EXTC_EXTS,
2929 [OP_META_EXTS] = rec_meta_EXTC_EXTS,
2930 [OP_META_COM] = rec_meta_COM,
2931};
2932
98fa08a5
PC
2933static void rec_SPECIAL(struct lightrec_cstate *state,
2934 const struct block *block, u16 offset)
d16005f8 2935{
98fa08a5
PC
2936 union code c = block->opcode_list[offset].c;
2937 lightrec_rec_func_t f = rec_special[c.r.op];
2938
2939 if (!HAS_DEFAULT_ELM && unlikely(!f))
2940 unknown_opcode(state, block, offset);
d16005f8 2941 else
98fa08a5 2942 (*f)(state, block, offset);
d16005f8
PC
2943}
2944
98fa08a5
PC
2945static void rec_REGIMM(struct lightrec_cstate *state,
2946 const struct block *block, u16 offset)
d16005f8 2947{
98fa08a5
PC
2948 union code c = block->opcode_list[offset].c;
2949 lightrec_rec_func_t f = rec_regimm[c.r.rt];
2950
2951 if (!HAS_DEFAULT_ELM && unlikely(!f))
2952 unknown_opcode(state, block, offset);
d16005f8 2953 else
98fa08a5 2954 (*f)(state, block, offset);
d16005f8
PC
2955}
2956
98fa08a5
PC
2957static void rec_CP0(struct lightrec_cstate *state,
2958 const struct block *block, u16 offset)
d16005f8 2959{
98fa08a5
PC
2960 union code c = block->opcode_list[offset].c;
2961 lightrec_rec_func_t f = rec_cp0[c.r.rs];
2962
2963 if (!HAS_DEFAULT_ELM && unlikely(!f))
2964 rec_CP(state, block, offset);
d16005f8 2965 else
98fa08a5 2966 (*f)(state, block, offset);
d16005f8
PC
2967}
2968
98fa08a5
PC
2969static void rec_CP2(struct lightrec_cstate *state,
2970 const struct block *block, u16 offset)
d16005f8 2971{
98fa08a5
PC
2972 union code c = block->opcode_list[offset].c;
2973
2974 if (c.r.op == OP_CP2_BASIC) {
2975 lightrec_rec_func_t f = rec_cp2_basic[c.r.rs];
2976
2977 if (HAS_DEFAULT_ELM || likely(f)) {
2978 (*f)(state, block, offset);
d16005f8
PC
2979 return;
2980 }
2981 }
2982
98fa08a5 2983 rec_CP(state, block, offset);
d16005f8
PC
2984}
2985
cb72ea13
PC
2986static void rec_META(struct lightrec_cstate *state,
2987 const struct block *block, u16 offset)
2988{
2989 union code c = block->opcode_list[offset].c;
2990 lightrec_rec_func_t f = rec_meta[c.m.op];
2991
2992 if (!HAS_DEFAULT_ELM && unlikely(!f))
2993 unknown_opcode(state, block, offset);
2994 else
2995 (*f)(state, block, offset);
2996}
2997
98fa08a5
PC
2998void lightrec_rec_opcode(struct lightrec_cstate *state,
2999 const struct block *block, u16 offset)
d16005f8 3000{
98fa08a5
PC
3001 struct regcache *reg_cache = state->reg_cache;
3002 struct lightrec_branch_target *target;
3003 const struct opcode *op = &block->opcode_list[offset];
3004 jit_state_t *_jit = block->_jit;
3005 lightrec_rec_func_t f;
03535202 3006 u16 unload_offset;
98fa08a5 3007
03535202
PC
3008 if (op_flag_sync(op->flags)) {
3009 if (state->cycles)
3010 jit_subi(LIGHTREC_REG_CYCLE, LIGHTREC_REG_CYCLE, state->cycles);
98fa08a5
PC
3011 state->cycles = 0;
3012
3013 lightrec_storeback_regs(reg_cache, _jit);
3014 lightrec_regcache_reset(reg_cache);
3015
3016 pr_debug("Adding branch target at offset 0x%x\n", offset << 2);
3017 target = &state->targets[state->nb_targets++];
3018 target->offset = offset;
3019 target->label = jit_indirect();
3020 }
3021
3022 if (likely(op->opcode)) {
3023 f = rec_standard[op->i.op];
3024
3025 if (!HAS_DEFAULT_ELM && unlikely(!f))
3026 unknown_opcode(state, block, offset);
3027 else
3028 (*f)(state, block, offset);
3029 }
3030
03535202
PC
3031 if (OPT_EARLY_UNLOAD) {
3032 unload_offset = offset +
3033 (has_delay_slot(op->c) && !op_flag_no_ds(op->flags));
3034
3035 lightrec_do_early_unload(state, block, unload_offset);
98fa08a5 3036 }
cb72ea13
PC
3037
3038 state->no_load_delay = false;
d16005f8 3039}