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