Update lightrec 20220910 (#686)
[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
682 /* E(rd) = (E(rs) & E(rt)) | (E(rt) & !Z(rt)) | (E(rs) & !Z(rs)) */
683 if ((REG_EXT & flags_rs & flags_rt) ||
ba3814c1
PC
684 ((flags_rt & (REG_EXT | REG_ZEXT)) == REG_EXT) ||
685 ((flags_rs & (REG_EXT | REG_ZEXT)) == REG_EXT))
98fa08a5
PC
686 flags_rd |= REG_EXT;
687
688 lightrec_set_reg_out_flags(reg_cache, rd, flags_rd);
689
690 jit_orr(rd, rs, rt);
691
692 if (nor)
693 jit_comr(rd, rd);
694
695 lightrec_free_reg(reg_cache, rs);
696 lightrec_free_reg(reg_cache, rt);
697 lightrec_free_reg(reg_cache, rd);
698}
699
700static void rec_special_OR(struct lightrec_cstate *state,
701 const struct block *block, u16 offset)
d16005f8
PC
702{
703 _jit_name(block->_jit, __func__);
98fa08a5 704 rec_special_or_nor(state, block, offset, false);
d16005f8
PC
705}
706
98fa08a5
PC
707static void rec_special_NOR(struct lightrec_cstate *state,
708 const struct block *block, u16 offset)
d16005f8
PC
709{
710 _jit_name(block->_jit, __func__);
98fa08a5 711 rec_special_or_nor(state, block, offset, true);
d16005f8
PC
712}
713
98fa08a5
PC
714static void rec_special_XOR(struct lightrec_cstate *state,
715 const struct block *block, u16 offset)
d16005f8 716{
98fa08a5
PC
717 struct regcache *reg_cache = state->reg_cache;
718 union code c = block->opcode_list[offset].c;
d16005f8 719 jit_state_t *_jit = block->_jit;
98fa08a5 720 u8 rd, rt, rs, flags_rs, flags_rt, flags_rd;
d16005f8 721
98fa08a5
PC
722 _jit_name(block->_jit, __func__);
723
724 jit_note(__FILE__, __LINE__);
725 rs = lightrec_alloc_reg_in(reg_cache, _jit, c.r.rs, 0);
726 rt = lightrec_alloc_reg_in(reg_cache, _jit, c.r.rt, 0);
727 rd = lightrec_alloc_reg_out(reg_cache, _jit, c.r.rd, 0);
d16005f8 728
98fa08a5
PC
729 flags_rs = lightrec_get_reg_in_flags(reg_cache, rs);
730 flags_rt = lightrec_get_reg_in_flags(reg_cache, rt);
d16005f8 731
98fa08a5
PC
732 /* Z(rd) = Z(rs) & Z(rt) */
733 flags_rd = REG_ZEXT & flags_rs & flags_rt;
734
735 /* E(rd) = E(rs) & E(rt) */
736 flags_rd |= REG_EXT & flags_rs & flags_rt;
737
738 lightrec_set_reg_out_flags(reg_cache, rd, flags_rd);
739
740 jit_xorr(rd, rs, rt);
741
742 lightrec_free_reg(reg_cache, rs);
743 lightrec_free_reg(reg_cache, rt);
d16005f8
PC
744 lightrec_free_reg(reg_cache, rd);
745}
746
98fa08a5
PC
747static void rec_special_SLTU(struct lightrec_cstate *state,
748 const struct block *block, u16 offset)
d16005f8
PC
749{
750 _jit_name(block->_jit, __func__);
98fa08a5 751 rec_alu_special(state, block, offset, jit_code_ltr_u, true);
d16005f8
PC
752}
753
98fa08a5
PC
754static void rec_special_SLT(struct lightrec_cstate *state,
755 const struct block *block, u16 offset)
d16005f8
PC
756{
757 _jit_name(block->_jit, __func__);
98fa08a5 758 rec_alu_special(state, block, offset, jit_code_ltr, true);
d16005f8
PC
759}
760
98fa08a5
PC
761static void rec_special_SLLV(struct lightrec_cstate *state,
762 const struct block *block, u16 offset)
d16005f8
PC
763{
764 _jit_name(block->_jit, __func__);
98fa08a5 765 rec_alu_shiftv(state, block, offset, jit_code_lshr);
d16005f8
PC
766}
767
98fa08a5
PC
768static void rec_special_SRLV(struct lightrec_cstate *state,
769 const struct block *block, u16 offset)
d16005f8
PC
770{
771 _jit_name(block->_jit, __func__);
98fa08a5 772 rec_alu_shiftv(state, block, offset, jit_code_rshr_u);
d16005f8
PC
773}
774
98fa08a5
PC
775static void rec_special_SRAV(struct lightrec_cstate *state,
776 const struct block *block, u16 offset)
d16005f8
PC
777{
778 _jit_name(block->_jit, __func__);
98fa08a5 779 rec_alu_shiftv(state, block, offset, jit_code_rshr);
d16005f8
PC
780}
781
98fa08a5
PC
782static void rec_alu_shift(struct lightrec_cstate *state, const struct block *block,
783 u16 offset, jit_code_t code)
d16005f8 784{
98fa08a5
PC
785 struct regcache *reg_cache = state->reg_cache;
786 union code c = block->opcode_list[offset].c;
d16005f8 787 jit_state_t *_jit = block->_jit;
98fa08a5 788 u8 rd, rt, flags = 0;
d16005f8
PC
789
790 jit_note(__FILE__, __LINE__);
791
98fa08a5
PC
792 if (code == jit_code_rshi)
793 flags = REG_EXT;
794 else if (code == jit_code_rshi_u)
795 flags = REG_ZEXT;
d16005f8 796
98fa08a5
PC
797 rt = lightrec_alloc_reg_in(reg_cache, _jit, c.r.rt, flags);
798
799 /* Input reg is zero-extended, if we SRL at least by one bit, we know
800 * the output reg will be both zero-extended and sign-extended. */
801 if (code == jit_code_rshi_u && c.r.imm)
802 flags |= REG_EXT;
803 rd = lightrec_alloc_reg_out(reg_cache, _jit, c.r.rd, flags);
804
805 jit_new_node_www(code, rd, rt, c.r.imm);
d16005f8
PC
806
807 lightrec_free_reg(reg_cache, rt);
808 lightrec_free_reg(reg_cache, rd);
809}
810
98fa08a5
PC
811static void rec_special_SLL(struct lightrec_cstate *state,
812 const struct block *block, u16 offset)
d16005f8
PC
813{
814 _jit_name(block->_jit, __func__);
98fa08a5 815 rec_alu_shift(state, block, offset, jit_code_lshi);
d16005f8
PC
816}
817
98fa08a5
PC
818static void rec_special_SRL(struct lightrec_cstate *state,
819 const struct block *block, u16 offset)
d16005f8
PC
820{
821 _jit_name(block->_jit, __func__);
98fa08a5 822 rec_alu_shift(state, block, offset, jit_code_rshi_u);
d16005f8
PC
823}
824
98fa08a5
PC
825static void rec_special_SRA(struct lightrec_cstate *state,
826 const struct block *block, u16 offset)
d16005f8
PC
827{
828 _jit_name(block->_jit, __func__);
98fa08a5 829 rec_alu_shift(state, block, offset, jit_code_rshi);
d16005f8
PC
830}
831
98fa08a5
PC
832static void rec_alu_mult(struct lightrec_cstate *state,
833 const struct block *block, u16 offset, bool is_signed)
d16005f8 834{
98fa08a5
PC
835 struct regcache *reg_cache = state->reg_cache;
836 union code c = block->opcode_list[offset].c;
03535202 837 u32 flags = block->opcode_list[offset].flags;
98fa08a5
PC
838 u8 reg_lo = get_mult_div_lo(c);
839 u8 reg_hi = get_mult_div_hi(c);
d16005f8 840 jit_state_t *_jit = block->_jit;
98fa08a5 841 u8 lo, hi, rs, rt, rflags = 0;
d16005f8
PC
842
843 jit_note(__FILE__, __LINE__);
844
98fa08a5
PC
845 if (is_signed)
846 rflags = REG_EXT;
847 else
848 rflags = REG_ZEXT;
849
850 rs = lightrec_alloc_reg_in(reg_cache, _jit, c.r.rs, rflags);
851 rt = lightrec_alloc_reg_in(reg_cache, _jit, c.r.rt, rflags);
852
03535202 853 if (!op_flag_no_lo(flags))
98fa08a5
PC
854 lo = lightrec_alloc_reg_out(reg_cache, _jit, reg_lo, 0);
855 else if (__WORDSIZE == 32)
856 lo = lightrec_alloc_reg_temp(reg_cache, _jit);
857
03535202 858 if (!op_flag_no_hi(flags))
98fa08a5
PC
859 hi = lightrec_alloc_reg_out(reg_cache, _jit, reg_hi, REG_EXT);
860
861 if (__WORDSIZE == 32) {
862 /* On 32-bit systems, do a 32*32->64 bit operation, or a 32*32->32 bit
863 * operation if the MULT was detected a 32-bit only. */
03535202 864 if (!op_flag_no_hi(flags)) {
98fa08a5
PC
865 if (is_signed)
866 jit_qmulr(lo, hi, rs, rt);
867 else
868 jit_qmulr_u(lo, hi, rs, rt);
869 } else {
870 jit_mulr(lo, rs, rt);
871 }
d16005f8 872 } else {
98fa08a5 873 /* On 64-bit systems, do a 64*64->64 bit operation. */
03535202 874 if (op_flag_no_lo(flags)) {
98fa08a5
PC
875 jit_mulr(hi, rs, rt);
876 jit_rshi(hi, hi, 32);
877 } else {
878 jit_mulr(lo, rs, rt);
d16005f8 879
98fa08a5 880 /* The 64-bit output value is in $lo, store the upper 32 bits in $hi */
03535202 881 if (!op_flag_no_hi(flags))
98fa08a5
PC
882 jit_rshi(hi, lo, 32);
883 }
d16005f8
PC
884 }
885
d16005f8
PC
886 lightrec_free_reg(reg_cache, rs);
887 lightrec_free_reg(reg_cache, rt);
03535202 888 if (!op_flag_no_lo(flags) || __WORDSIZE == 32)
98fa08a5 889 lightrec_free_reg(reg_cache, lo);
03535202 890 if (!op_flag_no_hi(flags))
d16005f8
PC
891 lightrec_free_reg(reg_cache, hi);
892}
893
98fa08a5
PC
894static void rec_alu_div(struct lightrec_cstate *state,
895 const struct block *block, u16 offset, bool is_signed)
d16005f8 896{
98fa08a5
PC
897 struct regcache *reg_cache = state->reg_cache;
898 union code c = block->opcode_list[offset].c;
03535202
PC
899 u32 flags = block->opcode_list[offset].flags;
900 bool no_check = op_flag_no_div_check(flags);
98fa08a5
PC
901 u8 reg_lo = get_mult_div_lo(c);
902 u8 reg_hi = get_mult_div_hi(c);
d16005f8
PC
903 jit_state_t *_jit = block->_jit;
904 jit_node_t *branch, *to_end;
fd58fa32 905 u8 lo = 0, hi = 0, rs, rt, rflags = 0;
d16005f8
PC
906
907 jit_note(__FILE__, __LINE__);
d16005f8 908
98fa08a5
PC
909 if (is_signed)
910 rflags = REG_EXT;
911 else
912 rflags = REG_ZEXT;
913
914 rs = lightrec_alloc_reg_in(reg_cache, _jit, c.r.rs, rflags);
915 rt = lightrec_alloc_reg_in(reg_cache, _jit, c.r.rt, rflags);
916
03535202 917 if (!op_flag_no_lo(flags))
98fa08a5
PC
918 lo = lightrec_alloc_reg_out(reg_cache, _jit, reg_lo, 0);
919
03535202 920 if (!op_flag_no_hi(flags))
98fa08a5 921 hi = lightrec_alloc_reg_out(reg_cache, _jit, reg_hi, 0);
d16005f8
PC
922
923 /* Jump to special handler if dividing by zero */
98fa08a5
PC
924 if (!no_check)
925 branch = jit_beqi(rt, 0);
d16005f8 926
03535202 927 if (op_flag_no_lo(flags)) {
98fa08a5
PC
928 if (is_signed)
929 jit_remr(hi, rs, rt);
930 else
931 jit_remr_u(hi, rs, rt);
03535202 932 } else if (op_flag_no_hi(flags)) {
98fa08a5
PC
933 if (is_signed)
934 jit_divr(lo, rs, rt);
935 else
936 jit_divr_u(lo, rs, rt);
d16005f8 937 } else {
98fa08a5
PC
938 if (is_signed)
939 jit_qdivr(lo, hi, rs, rt);
940 else
941 jit_qdivr_u(lo, hi, rs, rt);
d16005f8 942 }
d16005f8 943
98fa08a5 944 if (!no_check) {
98fa08a5 945 /* Jump above the div-by-zero handler */
22eee2ac 946 to_end = jit_b();
d16005f8 947
98fa08a5
PC
948 jit_patch(branch);
949
03535202 950 if (!op_flag_no_lo(flags)) {
98fa08a5
PC
951 if (is_signed) {
952 jit_lti(lo, rs, 0);
953 jit_lshi(lo, lo, 1);
954 jit_subi(lo, lo, 1);
955 } else {
956 jit_movi(lo, 0xffffffff);
957 }
958 }
d16005f8 959
03535202 960 if (!op_flag_no_hi(flags))
98fa08a5 961 jit_movr(hi, rs);
d16005f8 962
98fa08a5
PC
963 jit_patch(to_end);
964 }
d16005f8
PC
965
966 lightrec_free_reg(reg_cache, rs);
967 lightrec_free_reg(reg_cache, rt);
98fa08a5 968
03535202 969 if (!op_flag_no_lo(flags))
98fa08a5
PC
970 lightrec_free_reg(reg_cache, lo);
971
03535202 972 if (!op_flag_no_hi(flags))
98fa08a5 973 lightrec_free_reg(reg_cache, hi);
d16005f8
PC
974}
975
98fa08a5
PC
976static void rec_special_MULT(struct lightrec_cstate *state,
977 const struct block *block, u16 offset)
d16005f8
PC
978{
979 _jit_name(block->_jit, __func__);
98fa08a5 980 rec_alu_mult(state, block, offset, true);
d16005f8
PC
981}
982
98fa08a5
PC
983static void rec_special_MULTU(struct lightrec_cstate *state,
984 const struct block *block, u16 offset)
d16005f8
PC
985{
986 _jit_name(block->_jit, __func__);
98fa08a5 987 rec_alu_mult(state, block, offset, false);
d16005f8
PC
988}
989
98fa08a5
PC
990static void rec_special_DIV(struct lightrec_cstate *state,
991 const struct block *block, u16 offset)
d16005f8
PC
992{
993 _jit_name(block->_jit, __func__);
98fa08a5 994 rec_alu_div(state, block, offset, true);
d16005f8
PC
995}
996
98fa08a5
PC
997static void rec_special_DIVU(struct lightrec_cstate *state,
998 const struct block *block, u16 offset)
d16005f8
PC
999{
1000 _jit_name(block->_jit, __func__);
98fa08a5 1001 rec_alu_div(state, block, offset, false);
d16005f8
PC
1002}
1003
98fa08a5
PC
1004static void rec_alu_mv_lo_hi(struct lightrec_cstate *state,
1005 const struct block *block, u8 dst, u8 src)
d16005f8 1006{
98fa08a5 1007 struct regcache *reg_cache = state->reg_cache;
d16005f8
PC
1008 jit_state_t *_jit = block->_jit;
1009
1010 jit_note(__FILE__, __LINE__);
98fa08a5
PC
1011 src = lightrec_alloc_reg_in(reg_cache, _jit, src, 0);
1012 dst = lightrec_alloc_reg_out(reg_cache, _jit, dst, REG_EXT);
d16005f8 1013
d16005f8 1014 jit_extr_i(dst, src);
d16005f8
PC
1015
1016 lightrec_free_reg(reg_cache, src);
1017 lightrec_free_reg(reg_cache, dst);
1018}
1019
98fa08a5
PC
1020static void rec_special_MFHI(struct lightrec_cstate *state,
1021 const struct block *block, u16 offset)
d16005f8 1022{
98fa08a5
PC
1023 union code c = block->opcode_list[offset].c;
1024
d16005f8 1025 _jit_name(block->_jit, __func__);
98fa08a5 1026 rec_alu_mv_lo_hi(state, block, c.r.rd, REG_HI);
d16005f8
PC
1027}
1028
98fa08a5
PC
1029static void rec_special_MTHI(struct lightrec_cstate *state,
1030 const struct block *block, u16 offset)
d16005f8 1031{
98fa08a5
PC
1032 union code c = block->opcode_list[offset].c;
1033
d16005f8 1034 _jit_name(block->_jit, __func__);
98fa08a5 1035 rec_alu_mv_lo_hi(state, block, REG_HI, c.r.rs);
d16005f8
PC
1036}
1037
98fa08a5
PC
1038static void rec_special_MFLO(struct lightrec_cstate *state,
1039 const struct block *block, u16 offset)
d16005f8 1040{
98fa08a5
PC
1041 union code c = block->opcode_list[offset].c;
1042
d16005f8 1043 _jit_name(block->_jit, __func__);
98fa08a5 1044 rec_alu_mv_lo_hi(state, block, c.r.rd, REG_LO);
d16005f8
PC
1045}
1046
98fa08a5
PC
1047static void rec_special_MTLO(struct lightrec_cstate *state,
1048 const struct block *block, u16 offset)
d16005f8 1049{
98fa08a5
PC
1050 union code c = block->opcode_list[offset].c;
1051
d16005f8 1052 _jit_name(block->_jit, __func__);
98fa08a5 1053 rec_alu_mv_lo_hi(state, block, REG_LO, c.r.rs);
d16005f8
PC
1054}
1055
ba3814c1
PC
1056static void call_to_c_wrapper(struct lightrec_cstate *state,
1057 const struct block *block, u32 arg,
1058 enum c_wrappers wrapper)
d16005f8 1059{
98fa08a5 1060 struct regcache *reg_cache = state->reg_cache;
d16005f8 1061 jit_state_t *_jit = block->_jit;
ba3814c1 1062 s8 tmp, tmp2;
d16005f8 1063
ba3814c1
PC
1064 /* Make sure JIT_R1 is not mapped; it will be used in the C wrapper. */
1065 tmp2 = lightrec_alloc_reg(reg_cache, _jit, JIT_R1);
d16005f8 1066
ba3814c1
PC
1067 tmp = lightrec_get_reg_with_value(reg_cache,
1068 (intptr_t) state->state->wrappers_eps[wrapper]);
1069 if (tmp < 0) {
1070 tmp = lightrec_alloc_reg_temp(reg_cache, _jit);
1071 jit_ldxi(tmp, LIGHTREC_REG_STATE,
1072 offsetof(struct lightrec_state, wrappers_eps[wrapper]));
1073
1074 lightrec_temp_set_value(reg_cache, tmp,
1075 (intptr_t) state->state->wrappers_eps[wrapper]);
22eee2ac
PC
1076 }
1077
ba3814c1
PC
1078 lightrec_free_reg(reg_cache, tmp2);
1079
1080#ifdef __mips__
1081 /* On MIPS, register t9 is always used as the target register for JALR.
1082 * Therefore if it does not contain the target address we must
1083 * invalidate it. */
1084 if (tmp != _T9)
1085 lightrec_unload_reg(reg_cache, _jit, _T9);
1086#endif
1087
1088 jit_prepare();
1089 jit_pushargi(arg);
1090
22eee2ac 1091 lightrec_regcache_mark_live(reg_cache, _jit);
98fa08a5 1092 jit_callr(tmp);
d16005f8 1093
98fa08a5 1094 lightrec_free_reg(reg_cache, tmp);
98fa08a5
PC
1095 lightrec_regcache_mark_live(reg_cache, _jit);
1096}
1097
1098static void rec_io(struct lightrec_cstate *state,
1099 const struct block *block, u16 offset,
1100 bool load_rt, bool read_rt)
1101{
1102 struct regcache *reg_cache = state->reg_cache;
1103 jit_state_t *_jit = block->_jit;
1104 union code c = block->opcode_list[offset].c;
03535202 1105 u32 flags = block->opcode_list[offset].flags;
22eee2ac 1106 bool is_tagged = LIGHTREC_FLAGS_GET_IO_MODE(flags);
98fa08a5 1107 u32 lut_entry;
d16005f8 1108
98fa08a5 1109 jit_note(__FILE__, __LINE__);
d16005f8 1110
98fa08a5
PC
1111 lightrec_clean_reg_if_loaded(reg_cache, _jit, c.i.rs, false);
1112
1113 if (read_rt && likely(c.i.rt))
1114 lightrec_clean_reg_if_loaded(reg_cache, _jit, c.i.rt, true);
d16005f8 1115 else if (load_rt)
98fa08a5 1116 lightrec_clean_reg_if_loaded(reg_cache, _jit, c.i.rt, false);
d16005f8
PC
1117
1118 if (is_tagged) {
ba3814c1 1119 call_to_c_wrapper(state, block, c.opcode, C_WRAPPER_RW);
d16005f8 1120 } else {
98fa08a5
PC
1121 lut_entry = lightrec_get_lut_entry(block);
1122 call_to_c_wrapper(state, block, (lut_entry << 16) | offset,
ba3814c1 1123 C_WRAPPER_RW_GENERIC);
d16005f8 1124 }
d16005f8
PC
1125}
1126
02487de7
PC
1127static u32 rec_ram_mask(struct lightrec_state *state)
1128{
1129 return (RAM_SIZE << (state->mirrors_mapped * 2)) - 1;
1130}
1131
22eee2ac
PC
1132static void rec_store_memory(struct lightrec_cstate *cstate,
1133 const struct block *block,
1134 u16 offset, jit_code_t code,
02487de7 1135 jit_code_t swap_code,
22eee2ac
PC
1136 uintptr_t addr_offset, u32 addr_mask,
1137 bool invalidate)
1138{
02487de7 1139 const struct lightrec_state *state = cstate->state;
22eee2ac
PC
1140 struct regcache *reg_cache = cstate->reg_cache;
1141 struct opcode *op = &block->opcode_list[offset];
1142 jit_state_t *_jit = block->_jit;
1143 union code c = op->c;
1144 u8 rs, rt, tmp, tmp2, tmp3, addr_reg, addr_reg2;
1145 s16 imm = (s16)c.i.imm;
02487de7 1146 s32 simm = (s32)imm << (1 - lut_is_32bit(state));
22eee2ac 1147 s32 lut_offt = offsetof(struct lightrec_state, code_lut);
03535202 1148 bool no_mask = op_flag_no_mask(op->flags);
02487de7
PC
1149 bool add_imm = c.i.imm &&
1150 ((!state->mirrors_mapped && !no_mask) || (invalidate &&
1151 ((imm & 0x3) || simm + lut_offt != (s16)(simm + lut_offt))));
ba3814c1 1152 bool need_tmp = !no_mask || addr_offset || add_imm || invalidate;
22eee2ac
PC
1153
1154 rt = lightrec_alloc_reg_in(reg_cache, _jit, c.i.rt, 0);
1155 rs = lightrec_alloc_reg_in(reg_cache, _jit, c.i.rs, 0);
1156 if (need_tmp)
1157 tmp = lightrec_alloc_reg_temp(reg_cache, _jit);
1158
1159 addr_reg = rs;
1160
1161 if (add_imm) {
1162 jit_addi(tmp, addr_reg, (s16)c.i.imm);
1163 addr_reg = tmp;
1164 imm = 0;
1165 } else if (simm) {
1166 lut_offt += simm;
1167 }
1168
1169 if (!no_mask) {
1170 jit_andi(tmp, addr_reg, addr_mask);
1171 addr_reg = tmp;
1172 }
1173
22eee2ac 1174 if (addr_offset) {
ba3814c1 1175 tmp2 = lightrec_alloc_reg_temp(reg_cache, _jit);
22eee2ac
PC
1176 jit_addi(tmp2, addr_reg, addr_offset);
1177 addr_reg2 = tmp2;
1178 } else {
1179 addr_reg2 = addr_reg;
1180 }
1181
02487de7
PC
1182 if (is_big_endian() && swap_code && c.i.rt) {
1183 tmp3 = lightrec_alloc_reg_temp(reg_cache, _jit);
1184
1185 jit_new_node_ww(swap_code, tmp3, rt);
1186 jit_new_node_www(code, imm, addr_reg2, tmp3);
1187
1188 lightrec_free_reg(reg_cache, tmp3);
1189 } else {
1190 jit_new_node_www(code, imm, addr_reg2, rt);
1191 }
1192
22eee2ac
PC
1193 lightrec_free_reg(reg_cache, rt);
1194
1195 if (invalidate) {
1196 tmp3 = lightrec_alloc_reg_in(reg_cache, _jit, 0, 0);
1197
1198 if (c.i.op != OP_SW) {
ba3814c1
PC
1199 jit_andi(tmp, addr_reg, ~3);
1200 addr_reg = tmp;
22eee2ac
PC
1201 }
1202
02487de7 1203 if (!lut_is_32bit(state)) {
ba3814c1
PC
1204 jit_lshi(tmp, addr_reg, 1);
1205 addr_reg = tmp;
22eee2ac
PC
1206 }
1207
02487de7
PC
1208 if (addr_reg == rs && c.i.rs == 0) {
1209 addr_reg = LIGHTREC_REG_STATE;
1210 } else {
ba3814c1
PC
1211 jit_addr(tmp, addr_reg, LIGHTREC_REG_STATE);
1212 addr_reg = tmp;
22eee2ac
PC
1213 }
1214
02487de7
PC
1215 if (lut_is_32bit(state))
1216 jit_stxi_i(lut_offt, addr_reg, tmp3);
1217 else
1218 jit_stxi(lut_offt, addr_reg, tmp3);
22eee2ac
PC
1219
1220 lightrec_free_reg(reg_cache, tmp3);
1221 }
1222
ba3814c1 1223 if (addr_offset)
22eee2ac
PC
1224 lightrec_free_reg(reg_cache, tmp2);
1225 if (need_tmp)
1226 lightrec_free_reg(reg_cache, tmp);
1227 lightrec_free_reg(reg_cache, rs);
1228}
1229
1230static void rec_store_ram(struct lightrec_cstate *cstate,
1231 const struct block *block,
1232 u16 offset, jit_code_t code,
02487de7 1233 jit_code_t swap_code, bool invalidate)
22eee2ac 1234{
02487de7
PC
1235 struct lightrec_state *state = cstate->state;
1236
22eee2ac
PC
1237 _jit_note(block->_jit, __FILE__, __LINE__);
1238
02487de7
PC
1239 return rec_store_memory(cstate, block, offset, code, swap_code,
1240 state->offset_ram, rec_ram_mask(state),
1241 invalidate);
22eee2ac
PC
1242}
1243
1244static void rec_store_scratch(struct lightrec_cstate *cstate,
02487de7
PC
1245 const struct block *block, u16 offset,
1246 jit_code_t code, jit_code_t swap_code)
22eee2ac
PC
1247{
1248 _jit_note(block->_jit, __FILE__, __LINE__);
1249
02487de7 1250 return rec_store_memory(cstate, block, offset, code, swap_code,
22eee2ac
PC
1251 cstate->state->offset_scratch,
1252 0x1fffffff, false);
1253}
1254
ba3814c1
PC
1255static void rec_store_io(struct lightrec_cstate *cstate,
1256 const struct block *block, u16 offset,
1257 jit_code_t code, jit_code_t swap_code)
1258{
1259 _jit_note(block->_jit, __FILE__, __LINE__);
1260
1261 return rec_store_memory(cstate, block, offset, code, swap_code,
1262 cstate->state->offset_io,
1263 0x1fffffff, false);
1264}
1265
98fa08a5
PC
1266static void rec_store_direct_no_invalidate(struct lightrec_cstate *cstate,
1267 const struct block *block,
02487de7
PC
1268 u16 offset, jit_code_t code,
1269 jit_code_t swap_code)
d16005f8 1270{
98fa08a5
PC
1271 struct lightrec_state *state = cstate->state;
1272 struct regcache *reg_cache = cstate->reg_cache;
1273 union code c = block->opcode_list[offset].c;
d16005f8
PC
1274 jit_state_t *_jit = block->_jit;
1275 jit_node_t *to_not_ram, *to_end;
1276 u8 tmp, tmp2, rs, rt;
1277 s16 imm;
1278
1279 jit_note(__FILE__, __LINE__);
98fa08a5 1280 rs = lightrec_alloc_reg_in(reg_cache, _jit, c.i.rs, 0);
d16005f8 1281 tmp = lightrec_alloc_reg_temp(reg_cache, _jit);
98fa08a5
PC
1282
1283 if (state->offset_ram || state->offset_scratch)
1284 tmp2 = lightrec_alloc_reg_temp(reg_cache, _jit);
d16005f8
PC
1285
1286 /* Convert to KUNSEG and avoid RAM mirrors */
1287 if (state->mirrors_mapped) {
98fa08a5 1288 imm = (s16)c.i.imm;
d16005f8 1289 jit_andi(tmp, rs, 0x1f800000 | (4 * RAM_SIZE - 1));
98fa08a5 1290 } else if (c.i.imm) {
d16005f8 1291 imm = 0;
98fa08a5 1292 jit_addi(tmp, rs, (s16)c.i.imm);
d16005f8
PC
1293 jit_andi(tmp, tmp, 0x1f800000 | (RAM_SIZE - 1));
1294 } else {
1295 imm = 0;
1296 jit_andi(tmp, rs, 0x1f800000 | (RAM_SIZE - 1));
1297 }
1298
1299 lightrec_free_reg(reg_cache, rs);
1300
1301 if (state->offset_ram != state->offset_scratch) {
1302 to_not_ram = jit_bmsi(tmp, BIT(28));
1303
1304 jit_movi(tmp2, state->offset_ram);
1305
22eee2ac 1306 to_end = jit_b();
d16005f8
PC
1307 jit_patch(to_not_ram);
1308
1309 jit_movi(tmp2, state->offset_scratch);
1310 jit_patch(to_end);
1311 } else if (state->offset_ram) {
1312 jit_movi(tmp2, state->offset_ram);
1313 }
1314
98fa08a5 1315 if (state->offset_ram || state->offset_scratch) {
d16005f8 1316 jit_addr(tmp, tmp, tmp2);
98fa08a5
PC
1317 lightrec_free_reg(reg_cache, tmp2);
1318 }
d16005f8 1319
ba3814c1
PC
1320 rt = lightrec_alloc_reg_in(reg_cache, _jit, c.i.rt, 0);
1321
02487de7
PC
1322 if (is_big_endian() && swap_code && c.i.rt) {
1323 tmp2 = lightrec_alloc_reg_temp(reg_cache, _jit);
1324
1325 jit_new_node_ww(swap_code, tmp2, rt);
1326 jit_new_node_www(code, imm, tmp, tmp2);
1327
1328 lightrec_free_reg(reg_cache, tmp2);
1329 } else {
1330 jit_new_node_www(code, imm, tmp, rt);
1331 }
d16005f8
PC
1332
1333 lightrec_free_reg(reg_cache, rt);
1334 lightrec_free_reg(reg_cache, tmp);
1335}
1336
98fa08a5 1337static void rec_store_direct(struct lightrec_cstate *cstate, const struct block *block,
02487de7 1338 u16 offset, jit_code_t code, jit_code_t swap_code)
d16005f8 1339{
98fa08a5
PC
1340 struct lightrec_state *state = cstate->state;
1341 u32 ram_size = state->mirrors_mapped ? RAM_SIZE * 4 : RAM_SIZE;
1342 struct regcache *reg_cache = cstate->reg_cache;
1343 union code c = block->opcode_list[offset].c;
d16005f8 1344 jit_state_t *_jit = block->_jit;
98fa08a5 1345 jit_node_t *to_not_ram, *to_end;
d16005f8
PC
1346 u8 tmp, tmp2, tmp3, rs, rt;
1347
1348 jit_note(__FILE__, __LINE__);
1349
98fa08a5 1350 rs = lightrec_alloc_reg_in(reg_cache, _jit, c.i.rs, 0);
d16005f8 1351 tmp2 = lightrec_alloc_reg_temp(reg_cache, _jit);
98fa08a5 1352 tmp3 = lightrec_alloc_reg_in(reg_cache, _jit, 0, 0);
d16005f8
PC
1353
1354 /* Convert to KUNSEG and avoid RAM mirrors */
98fa08a5
PC
1355 if (c.i.imm) {
1356 jit_addi(tmp2, rs, (s16)c.i.imm);
1357 jit_andi(tmp2, tmp2, 0x1f800000 | (ram_size - 1));
d16005f8 1358 } else {
98fa08a5 1359 jit_andi(tmp2, rs, 0x1f800000 | (ram_size - 1));
d16005f8
PC
1360 }
1361
1362 lightrec_free_reg(reg_cache, rs);
1363 tmp = lightrec_alloc_reg_temp(reg_cache, _jit);
1364
98fa08a5
PC
1365 to_not_ram = jit_bgti(tmp2, ram_size);
1366
d16005f8
PC
1367 /* Compute the offset to the code LUT */
1368 jit_andi(tmp, tmp2, (RAM_SIZE - 1) & ~3);
02487de7 1369 if (!lut_is_32bit(state))
98fa08a5 1370 jit_lshi(tmp, tmp, 1);
d16005f8
PC
1371 jit_addr(tmp, LIGHTREC_REG_STATE, tmp);
1372
1373 /* Write NULL to the code LUT to invalidate any block that's there */
02487de7
PC
1374 if (lut_is_32bit(state))
1375 jit_stxi_i(offsetof(struct lightrec_state, code_lut), tmp, tmp3);
1376 else
1377 jit_stxi(offsetof(struct lightrec_state, code_lut), tmp, tmp3);
d16005f8
PC
1378
1379 if (state->offset_ram != state->offset_scratch) {
1380 jit_movi(tmp, state->offset_ram);
1381
22eee2ac 1382 to_end = jit_b();
d16005f8
PC
1383 }
1384
1385 jit_patch(to_not_ram);
1386
1387 if (state->offset_ram || state->offset_scratch)
1388 jit_movi(tmp, state->offset_scratch);
1389
1390 if (state->offset_ram != state->offset_scratch)
1391 jit_patch(to_end);
1392
1393 if (state->offset_ram || state->offset_scratch)
1394 jit_addr(tmp2, tmp2, tmp);
1395
1396 lightrec_free_reg(reg_cache, tmp);
1397 lightrec_free_reg(reg_cache, tmp3);
1398
98fa08a5 1399 rt = lightrec_alloc_reg_in(reg_cache, _jit, c.i.rt, 0);
02487de7
PC
1400
1401 if (is_big_endian() && swap_code && c.i.rt) {
1402 tmp = lightrec_alloc_reg_temp(reg_cache, _jit);
1403
1404 jit_new_node_ww(swap_code, tmp, rt);
1405 jit_new_node_www(code, 0, tmp2, tmp);
1406
1407 lightrec_free_reg(reg_cache, tmp);
1408 } else {
1409 jit_new_node_www(code, 0, tmp2, rt);
1410 }
d16005f8
PC
1411
1412 lightrec_free_reg(reg_cache, rt);
1413 lightrec_free_reg(reg_cache, tmp2);
1414}
1415
98fa08a5 1416static void rec_store(struct lightrec_cstate *state,
02487de7
PC
1417 const struct block *block, u16 offset,
1418 jit_code_t code, jit_code_t swap_code)
d16005f8 1419{
03535202
PC
1420 u32 flags = block->opcode_list[offset].flags;
1421 bool no_invalidate = op_flag_no_invalidate(flags) ||
22eee2ac
PC
1422 state->state->invalidate_from_dma_only;
1423
1424 switch (LIGHTREC_FLAGS_GET_IO_MODE(flags)) {
1425 case LIGHTREC_IO_RAM:
02487de7
PC
1426 rec_store_ram(state, block, offset, code,
1427 swap_code, !no_invalidate);
22eee2ac
PC
1428 break;
1429 case LIGHTREC_IO_SCRATCH:
02487de7 1430 rec_store_scratch(state, block, offset, code, swap_code);
22eee2ac
PC
1431 break;
1432 case LIGHTREC_IO_DIRECT:
02487de7
PC
1433 if (no_invalidate) {
1434 rec_store_direct_no_invalidate(state, block, offset,
1435 code, swap_code);
1436 } else {
1437 rec_store_direct(state, block, offset, code, swap_code);
1438 }
22eee2ac 1439 break;
ba3814c1
PC
1440 case LIGHTREC_IO_DIRECT_HW:
1441 rec_store_io(state, block, offset, code, swap_code);
1442 break;
22eee2ac 1443 default:
98fa08a5 1444 rec_io(state, block, offset, true, false);
22eee2ac 1445 break;
d16005f8
PC
1446 }
1447}
1448
98fa08a5
PC
1449static void rec_SB(struct lightrec_cstate *state,
1450 const struct block *block, u16 offset)
d16005f8
PC
1451{
1452 _jit_name(block->_jit, __func__);
02487de7 1453 rec_store(state, block, offset, jit_code_stxi_c, 0);
d16005f8
PC
1454}
1455
98fa08a5
PC
1456static void rec_SH(struct lightrec_cstate *state,
1457 const struct block *block, u16 offset)
d16005f8
PC
1458{
1459 _jit_name(block->_jit, __func__);
02487de7
PC
1460 rec_store(state, block, offset,
1461 jit_code_stxi_s, jit_code_bswapr_us);
d16005f8
PC
1462}
1463
98fa08a5
PC
1464static void rec_SW(struct lightrec_cstate *state,
1465 const struct block *block, u16 offset)
1466
d16005f8
PC
1467{
1468 _jit_name(block->_jit, __func__);
02487de7
PC
1469 rec_store(state, block, offset,
1470 jit_code_stxi_i, jit_code_bswapr_ui);
d16005f8
PC
1471}
1472
98fa08a5
PC
1473static void rec_SWL(struct lightrec_cstate *state,
1474 const struct block *block, u16 offset)
d16005f8
PC
1475{
1476 _jit_name(block->_jit, __func__);
98fa08a5 1477 rec_io(state, block, offset, true, false);
d16005f8
PC
1478}
1479
98fa08a5
PC
1480static void rec_SWR(struct lightrec_cstate *state,
1481 const struct block *block, u16 offset)
d16005f8
PC
1482{
1483 _jit_name(block->_jit, __func__);
98fa08a5 1484 rec_io(state, block, offset, true, false);
d16005f8
PC
1485}
1486
98fa08a5
PC
1487static void rec_SWC2(struct lightrec_cstate *state,
1488 const struct block *block, u16 offset)
d16005f8
PC
1489{
1490 _jit_name(block->_jit, __func__);
98fa08a5 1491 rec_io(state, block, offset, false, false);
d16005f8
PC
1492}
1493
22eee2ac 1494static void rec_load_memory(struct lightrec_cstate *cstate,
02487de7
PC
1495 const struct block *block, u16 offset,
1496 jit_code_t code, jit_code_t swap_code, bool is_unsigned,
22eee2ac
PC
1497 uintptr_t addr_offset, u32 addr_mask)
1498{
1499 struct regcache *reg_cache = cstate->reg_cache;
1500 struct opcode *op = &block->opcode_list[offset];
1501 jit_state_t *_jit = block->_jit;
1502 u8 rs, rt, addr_reg, flags = REG_EXT;
03535202 1503 bool no_mask = op_flag_no_mask(op->flags);
22eee2ac 1504 union code c = op->c;
02487de7 1505 s16 imm;
22eee2ac
PC
1506
1507 if (!c.i.rt)
1508 return;
1509
1510 if (is_unsigned)
1511 flags |= REG_ZEXT;
1512
1513 rs = lightrec_alloc_reg_in(reg_cache, _jit, c.i.rs, 0);
1514 rt = lightrec_alloc_reg_out(reg_cache, _jit, c.i.rt, flags);
1515
02487de7
PC
1516 if (!cstate->state->mirrors_mapped && c.i.imm && !no_mask) {
1517 jit_addi(rt, rs, (s16)c.i.imm);
22eee2ac 1518 addr_reg = rt;
02487de7 1519 imm = 0;
22eee2ac
PC
1520 } else {
1521 addr_reg = rs;
02487de7
PC
1522 imm = (s16)c.i.imm;
1523 }
1524
1525 if (!no_mask) {
1526 jit_andi(rt, addr_reg, addr_mask);
1527 addr_reg = rt;
22eee2ac
PC
1528 }
1529
1530 if (addr_offset) {
1531 jit_addi(rt, addr_reg, addr_offset);
1532 addr_reg = rt;
1533 }
1534
02487de7
PC
1535 jit_new_node_www(code, rt, addr_reg, imm);
1536
1537 if (is_big_endian() && swap_code) {
1538 jit_new_node_ww(swap_code, rt, rt);
1539
1540 if (c.i.op == OP_LH)
1541 jit_extr_s(rt, rt);
1542 else if (c.i.op == OP_LW && __WORDSIZE == 64)
1543 jit_extr_i(rt, rt);
1544 }
22eee2ac
PC
1545
1546 lightrec_free_reg(reg_cache, rs);
1547 lightrec_free_reg(reg_cache, rt);
1548}
1549
1550static void rec_load_ram(struct lightrec_cstate *cstate,
02487de7
PC
1551 const struct block *block, u16 offset,
1552 jit_code_t code, jit_code_t swap_code, bool is_unsigned)
22eee2ac
PC
1553{
1554 _jit_note(block->_jit, __FILE__, __LINE__);
1555
02487de7
PC
1556 rec_load_memory(cstate, block, offset, code, swap_code, is_unsigned,
1557 cstate->state->offset_ram, rec_ram_mask(cstate->state));
22eee2ac
PC
1558}
1559
1560static void rec_load_bios(struct lightrec_cstate *cstate,
02487de7
PC
1561 const struct block *block, u16 offset,
1562 jit_code_t code, jit_code_t swap_code, bool is_unsigned)
22eee2ac
PC
1563{
1564 _jit_note(block->_jit, __FILE__, __LINE__);
1565
02487de7 1566 rec_load_memory(cstate, block, offset, code, swap_code, is_unsigned,
22eee2ac
PC
1567 cstate->state->offset_bios, 0x1fffffff);
1568}
1569
1570static void rec_load_scratch(struct lightrec_cstate *cstate,
02487de7
PC
1571 const struct block *block, u16 offset,
1572 jit_code_t code, jit_code_t swap_code, bool is_unsigned)
22eee2ac
PC
1573{
1574 _jit_note(block->_jit, __FILE__, __LINE__);
1575
02487de7 1576 rec_load_memory(cstate, block, offset, code, swap_code, is_unsigned,
22eee2ac
PC
1577 cstate->state->offset_scratch, 0x1fffffff);
1578}
1579
ba3814c1
PC
1580static void rec_load_io(struct lightrec_cstate *cstate,
1581 const struct block *block, u16 offset,
1582 jit_code_t code, jit_code_t swap_code, bool is_unsigned)
1583{
1584 _jit_note(block->_jit, __FILE__, __LINE__);
1585
1586 rec_load_memory(cstate, block, offset, code, swap_code, is_unsigned,
1587 cstate->state->offset_io, 0x1fffffff);
1588}
1589
02487de7
PC
1590static void rec_load_direct(struct lightrec_cstate *cstate,
1591 const struct block *block, u16 offset,
1592 jit_code_t code, jit_code_t swap_code,
1593 bool is_unsigned)
d16005f8 1594{
98fa08a5
PC
1595 struct lightrec_state *state = cstate->state;
1596 struct regcache *reg_cache = cstate->reg_cache;
1597 union code c = block->opcode_list[offset].c;
d16005f8 1598 jit_state_t *_jit = block->_jit;
98fa08a5
PC
1599 jit_node_t *to_not_ram, *to_not_bios, *to_end, *to_end2;
1600 u8 tmp, rs, rt, addr_reg, flags = REG_EXT;
d16005f8
PC
1601 s16 imm;
1602
98fa08a5 1603 if (!c.i.rt)
d16005f8
PC
1604 return;
1605
98fa08a5
PC
1606 if (is_unsigned)
1607 flags |= REG_ZEXT;
1608
d16005f8 1609 jit_note(__FILE__, __LINE__);
98fa08a5
PC
1610 rs = lightrec_alloc_reg_in(reg_cache, _jit, c.i.rs, 0);
1611 rt = lightrec_alloc_reg_out(reg_cache, _jit, c.i.rt, flags);
d16005f8
PC
1612
1613 if ((state->offset_ram == state->offset_bios &&
1614 state->offset_ram == state->offset_scratch &&
98fa08a5 1615 state->mirrors_mapped) || !c.i.imm) {
d16005f8 1616 addr_reg = rs;
98fa08a5 1617 imm = (s16)c.i.imm;
d16005f8 1618 } else {
98fa08a5 1619 jit_addi(rt, rs, (s16)c.i.imm);
d16005f8
PC
1620 addr_reg = rt;
1621 imm = 0;
1622
98fa08a5 1623 if (c.i.rs != c.i.rt)
d16005f8
PC
1624 lightrec_free_reg(reg_cache, rs);
1625 }
1626
1627 tmp = lightrec_alloc_reg_temp(reg_cache, _jit);
1628
1629 if (state->offset_ram == state->offset_bios &&
1630 state->offset_ram == state->offset_scratch) {
1631 if (!state->mirrors_mapped) {
1632 jit_andi(tmp, addr_reg, BIT(28));
1633 jit_rshi_u(tmp, tmp, 28 - 22);
1634 jit_ori(tmp, tmp, 0x1f800000 | (RAM_SIZE - 1));
1635 jit_andr(rt, addr_reg, tmp);
1636 } else {
1637 jit_andi(rt, addr_reg, 0x1fffffff);
1638 }
1639
1640 if (state->offset_ram)
1641 jit_movi(tmp, state->offset_ram);
1642 } else {
1643 to_not_ram = jit_bmsi(addr_reg, BIT(28));
1644
1645 /* Convert to KUNSEG and avoid RAM mirrors */
1646 jit_andi(rt, addr_reg, RAM_SIZE - 1);
1647
1648 if (state->offset_ram)
1649 jit_movi(tmp, state->offset_ram);
1650
22eee2ac 1651 to_end = jit_b();
d16005f8
PC
1652
1653 jit_patch(to_not_ram);
1654
1655 if (state->offset_bios != state->offset_scratch)
1656 to_not_bios = jit_bmci(addr_reg, BIT(22));
1657
1658 /* Convert to KUNSEG */
1659 jit_andi(rt, addr_reg, 0x1fc00000 | (BIOS_SIZE - 1));
1660
1661 jit_movi(tmp, state->offset_bios);
1662
1663 if (state->offset_bios != state->offset_scratch) {
22eee2ac 1664 to_end2 = jit_b();
d16005f8
PC
1665
1666 jit_patch(to_not_bios);
1667
1668 /* Convert to KUNSEG */
1669 jit_andi(rt, addr_reg, 0x1f800fff);
1670
1671 if (state->offset_scratch)
1672 jit_movi(tmp, state->offset_scratch);
1673
1674 jit_patch(to_end2);
1675 }
1676
1677 jit_patch(to_end);
1678 }
1679
1680 if (state->offset_ram || state->offset_bios || state->offset_scratch)
1681 jit_addr(rt, rt, tmp);
1682
1683 jit_new_node_www(code, rt, rt, imm);
1684
02487de7
PC
1685 if (is_big_endian() && swap_code) {
1686 jit_new_node_ww(swap_code, rt, rt);
1687
1688 if (c.i.op == OP_LH)
1689 jit_extr_s(rt, rt);
1690 else if (c.i.op == OP_LW && __WORDSIZE == 64)
1691 jit_extr_i(rt, rt);
1692 }
1693
d16005f8
PC
1694 lightrec_free_reg(reg_cache, addr_reg);
1695 lightrec_free_reg(reg_cache, rt);
1696 lightrec_free_reg(reg_cache, tmp);
1697}
1698
98fa08a5 1699static void rec_load(struct lightrec_cstate *state, const struct block *block,
02487de7
PC
1700 u16 offset, jit_code_t code, jit_code_t swap_code,
1701 bool is_unsigned)
d16005f8 1702{
03535202 1703 u32 flags = block->opcode_list[offset].flags;
98fa08a5 1704
22eee2ac
PC
1705 switch (LIGHTREC_FLAGS_GET_IO_MODE(flags)) {
1706 case LIGHTREC_IO_RAM:
02487de7 1707 rec_load_ram(state, block, offset, code, swap_code, is_unsigned);
22eee2ac
PC
1708 break;
1709 case LIGHTREC_IO_BIOS:
02487de7 1710 rec_load_bios(state, block, offset, code, swap_code, is_unsigned);
22eee2ac
PC
1711 break;
1712 case LIGHTREC_IO_SCRATCH:
02487de7 1713 rec_load_scratch(state, block, offset, code, swap_code, is_unsigned);
22eee2ac 1714 break;
ba3814c1
PC
1715 case LIGHTREC_IO_DIRECT_HW:
1716 rec_load_io(state, block, offset, code, swap_code, is_unsigned);
1717 break;
22eee2ac 1718 case LIGHTREC_IO_DIRECT:
02487de7 1719 rec_load_direct(state, block, offset, code, swap_code, is_unsigned);
22eee2ac
PC
1720 break;
1721 default:
98fa08a5 1722 rec_io(state, block, offset, false, true);
22eee2ac
PC
1723 break;
1724 }
d16005f8
PC
1725}
1726
98fa08a5 1727static void rec_LB(struct lightrec_cstate *state, const struct block *block, u16 offset)
d16005f8
PC
1728{
1729 _jit_name(block->_jit, __func__);
02487de7 1730 rec_load(state, block, offset, jit_code_ldxi_c, 0, false);
d16005f8
PC
1731}
1732
98fa08a5 1733static void rec_LBU(struct lightrec_cstate *state, const struct block *block, u16 offset)
d16005f8
PC
1734{
1735 _jit_name(block->_jit, __func__);
02487de7 1736 rec_load(state, block, offset, jit_code_ldxi_uc, 0, true);
d16005f8
PC
1737}
1738
98fa08a5 1739static void rec_LH(struct lightrec_cstate *state, const struct block *block, u16 offset)
d16005f8 1740{
ba3814c1
PC
1741 jit_code_t code = is_big_endian() ? jit_code_ldxi_us : jit_code_ldxi_s;
1742
d16005f8 1743 _jit_name(block->_jit, __func__);
ba3814c1 1744 rec_load(state, block, offset, code, jit_code_bswapr_us, false);
d16005f8
PC
1745}
1746
98fa08a5 1747static void rec_LHU(struct lightrec_cstate *state, const struct block *block, u16 offset)
d16005f8
PC
1748{
1749 _jit_name(block->_jit, __func__);
02487de7 1750 rec_load(state, block, offset, jit_code_ldxi_us, jit_code_bswapr_us, true);
d16005f8
PC
1751}
1752
98fa08a5 1753static void rec_LWL(struct lightrec_cstate *state, const struct block *block, u16 offset)
d16005f8
PC
1754{
1755 _jit_name(block->_jit, __func__);
98fa08a5 1756 rec_io(state, block, offset, true, true);
d16005f8
PC
1757}
1758
98fa08a5 1759static void rec_LWR(struct lightrec_cstate *state, const struct block *block, u16 offset)
d16005f8
PC
1760{
1761 _jit_name(block->_jit, __func__);
98fa08a5 1762 rec_io(state, block, offset, true, true);
d16005f8
PC
1763}
1764
98fa08a5 1765static void rec_LW(struct lightrec_cstate *state, const struct block *block, u16 offset)
d16005f8 1766{
ba3814c1
PC
1767 jit_code_t code;
1768
1769 if (is_big_endian() && __WORDSIZE == 64)
1770 code = jit_code_ldxi_ui;
1771 else
1772 code = jit_code_ldxi_i;
1773
d16005f8 1774 _jit_name(block->_jit, __func__);
ba3814c1 1775 rec_load(state, block, offset, code, jit_code_bswapr_ui, false);
d16005f8
PC
1776}
1777
98fa08a5 1778static void rec_LWC2(struct lightrec_cstate *state, const struct block *block, u16 offset)
d16005f8
PC
1779{
1780 _jit_name(block->_jit, __func__);
98fa08a5 1781 rec_io(state, block, offset, false, false);
d16005f8
PC
1782}
1783
98fa08a5 1784static void rec_break_syscall(struct lightrec_cstate *state,
ba3814c1
PC
1785 const struct block *block, u16 offset,
1786 u32 exit_code)
d16005f8 1787{
ba3814c1
PC
1788 struct regcache *reg_cache = state->reg_cache;
1789 jit_state_t *_jit = block->_jit;
1790 u8 tmp;
1791
98fa08a5 1792 _jit_note(block->_jit, __FILE__, __LINE__);
d16005f8 1793
ba3814c1
PC
1794 tmp = lightrec_alloc_reg_temp(reg_cache, _jit);
1795
1796 jit_movi(tmp, exit_code);
1797 jit_stxi_i(offsetof(struct lightrec_state, exit_flags),
1798 LIGHTREC_REG_STATE, tmp);
1799
1800 lightrec_free_reg(reg_cache, tmp);
d16005f8
PC
1801
1802 /* TODO: the return address should be "pc - 4" if we're a delay slot */
98fa08a5
PC
1803 lightrec_emit_end_of_block(state, block, offset, -1,
1804 get_ds_pc(block, offset, 0),
1805 31, 0, true);
d16005f8
PC
1806}
1807
98fa08a5
PC
1808static void rec_special_SYSCALL(struct lightrec_cstate *state,
1809 const struct block *block, u16 offset)
d16005f8
PC
1810{
1811 _jit_name(block->_jit, __func__);
ba3814c1 1812 rec_break_syscall(state, block, offset, LIGHTREC_EXIT_SYSCALL);
d16005f8
PC
1813}
1814
98fa08a5
PC
1815static void rec_special_BREAK(struct lightrec_cstate *state,
1816 const struct block *block, u16 offset)
d16005f8
PC
1817{
1818 _jit_name(block->_jit, __func__);
ba3814c1 1819 rec_break_syscall(state, block, offset, LIGHTREC_EXIT_BREAK);
d16005f8
PC
1820}
1821
fd58fa32 1822static void rec_mtc(struct lightrec_cstate *state, const struct block *block, u16 offset)
98fa08a5
PC
1823{
1824 struct regcache *reg_cache = state->reg_cache;
1825 union code c = block->opcode_list[offset].c;
1826 jit_state_t *_jit = block->_jit;
d16005f8 1827
98fa08a5
PC
1828 jit_note(__FILE__, __LINE__);
1829 lightrec_clean_reg_if_loaded(reg_cache, _jit, c.i.rs, false);
1830 lightrec_clean_reg_if_loaded(reg_cache, _jit, c.i.rt, false);
d16005f8 1831
ba3814c1 1832 call_to_c_wrapper(state, block, c.opcode, C_WRAPPER_MTC);
d16005f8 1833
98fa08a5 1834 if (c.i.op == OP_CP0 &&
03535202 1835 !op_flag_no_ds(block->opcode_list[offset].flags) &&
98fa08a5
PC
1836 (c.r.rd == 12 || c.r.rd == 13))
1837 lightrec_emit_end_of_block(state, block, offset, -1,
1838 get_ds_pc(block, offset, 1),
1839 0, 0, true);
d16005f8
PC
1840}
1841
98fa08a5
PC
1842static void
1843rec_mfc0(struct lightrec_cstate *state, const struct block *block, u16 offset)
d16005f8 1844{
d16005f8 1845 struct regcache *reg_cache = state->reg_cache;
98fa08a5 1846 union code c = block->opcode_list[offset].c;
d16005f8 1847 jit_state_t *_jit = block->_jit;
98fa08a5 1848 u8 rt;
d16005f8
PC
1849
1850 jit_note(__FILE__, __LINE__);
1851
98fa08a5 1852 rt = lightrec_alloc_reg_out(reg_cache, _jit, c.i.rt, REG_EXT);
d16005f8 1853
98fa08a5
PC
1854 jit_ldxi_i(rt, LIGHTREC_REG_STATE,
1855 offsetof(struct lightrec_state, regs.cp0[c.r.rd]));
d16005f8 1856
98fa08a5
PC
1857 lightrec_free_reg(reg_cache, rt);
1858}
d16005f8 1859
98fa08a5
PC
1860static bool block_in_bios(const struct lightrec_cstate *state,
1861 const struct block *block)
1862{
1863 const struct lightrec_mem_map *bios = &state->state->maps[PSX_MAP_BIOS];
1864 u32 pc = kunseg(block->pc);
d16005f8 1865
98fa08a5 1866 return pc >= bios->pc && pc < bios->pc + bios->length;
d16005f8
PC
1867}
1868
98fa08a5
PC
1869static void
1870rec_mtc0(struct lightrec_cstate *state, const struct block *block, u16 offset)
d16005f8 1871{
98fa08a5
PC
1872 struct regcache *reg_cache = state->reg_cache;
1873 const union code c = block->opcode_list[offset].c;
1874 jit_state_t *_jit = block->_jit;
fd58fa32 1875 u8 rt, tmp = 0, tmp2, status;
98fa08a5
PC
1876
1877 jit_note(__FILE__, __LINE__);
1878
1879 switch(c.r.rd) {
1880 case 1:
1881 case 4:
1882 case 8:
1883 case 14:
1884 case 15:
1885 /* Those registers are read-only */
1886 return;
1887 default:
1888 break;
1889 }
1890
1891 if (block_in_bios(state, block) && c.r.rd == 12) {
1892 /* If we are running code from the BIOS, handle writes to the
1893 * Status register in C. BIOS code may toggle bit 16 which will
1894 * map/unmap the RAM, while game code cannot do that. */
1895 rec_mtc(state, block, offset);
1896 return;
1897 }
1898
1899 rt = lightrec_alloc_reg_in(reg_cache, _jit, c.i.rt, 0);
1900
1901 if (c.r.rd != 13) {
1902 jit_stxi_i(offsetof(struct lightrec_state, regs.cp0[c.r.rd]),
1903 LIGHTREC_REG_STATE, rt);
1904 }
1905
1906 if (c.r.rd == 12 || c.r.rd == 13) {
1907 tmp = lightrec_alloc_reg_temp(reg_cache, _jit);
1908 jit_ldxi_i(tmp, LIGHTREC_REG_STATE,
1909 offsetof(struct lightrec_state, regs.cp0[13]));
fd58fa32
PC
1910
1911 tmp2 = lightrec_alloc_reg_temp(reg_cache, _jit);
98fa08a5
PC
1912 }
1913
1914 if (c.r.rd == 12) {
1915 status = rt;
1916 } else if (c.r.rd == 13) {
98fa08a5
PC
1917 /* Cause = (Cause & ~0x0300) | (value & 0x0300) */
1918 jit_andi(tmp2, rt, 0x0300);
1919 jit_ori(tmp, tmp, 0x0300);
1920 jit_xori(tmp, tmp, 0x0300);
1921 jit_orr(tmp, tmp, tmp2);
1922 jit_ldxi_i(tmp2, LIGHTREC_REG_STATE,
1923 offsetof(struct lightrec_state, regs.cp0[12]));
1924 jit_stxi_i(offsetof(struct lightrec_state, regs.cp0[13]),
1925 LIGHTREC_REG_STATE, tmp);
1926 status = tmp2;
1927 }
1928
1929 if (c.r.rd == 12 || c.r.rd == 13) {
1930 /* Exit dynarec in case there's a software interrupt.
1931 * exit_flags = !!(status & tmp & 0x0300) & status; */
1932 jit_andr(tmp, tmp, status);
1933 jit_andi(tmp, tmp, 0x0300);
1934 jit_nei(tmp, tmp, 0);
1935 jit_andr(tmp, tmp, status);
fd58fa32
PC
1936 }
1937
1938 if (c.r.rd == 12) {
1939 /* Exit dynarec in case we unmask a hardware interrupt.
1940 * exit_flags = !(~status & 0x401) */
1941
1942 jit_comr(tmp2, status);
1943 jit_andi(tmp2, tmp2, 0x401);
1944 jit_eqi(tmp2, tmp2, 0);
1945 jit_orr(tmp, tmp, tmp2);
1946 }
1947
1948 if (c.r.rd == 12 || c.r.rd == 13) {
98fa08a5
PC
1949 jit_stxi_i(offsetof(struct lightrec_state, exit_flags),
1950 LIGHTREC_REG_STATE, tmp);
1951
1952 lightrec_free_reg(reg_cache, tmp);
98fa08a5 1953 lightrec_free_reg(reg_cache, tmp2);
fd58fa32 1954 }
98fa08a5
PC
1955
1956 lightrec_free_reg(reg_cache, rt);
1957
03535202 1958 if (!op_flag_no_ds(block->opcode_list[offset].flags) &&
98fa08a5
PC
1959 (c.r.rd == 12 || c.r.rd == 13))
1960 lightrec_emit_eob(state, block, offset + 1, true);
d16005f8
PC
1961}
1962
98fa08a5
PC
1963static void rec_cp0_MFC0(struct lightrec_cstate *state,
1964 const struct block *block, u16 offset)
d16005f8
PC
1965{
1966 _jit_name(block->_jit, __func__);
98fa08a5 1967 rec_mfc0(state, block, offset);
d16005f8
PC
1968}
1969
98fa08a5
PC
1970static void rec_cp0_CFC0(struct lightrec_cstate *state,
1971 const struct block *block, u16 offset)
d16005f8
PC
1972{
1973 _jit_name(block->_jit, __func__);
98fa08a5 1974 rec_mfc0(state, block, offset);
d16005f8
PC
1975}
1976
98fa08a5
PC
1977static void rec_cp0_MTC0(struct lightrec_cstate *state,
1978 const struct block *block, u16 offset)
d16005f8
PC
1979{
1980 _jit_name(block->_jit, __func__);
98fa08a5 1981 rec_mtc0(state, block, offset);
d16005f8
PC
1982}
1983
98fa08a5
PC
1984static void rec_cp0_CTC0(struct lightrec_cstate *state,
1985 const struct block *block, u16 offset)
d16005f8
PC
1986{
1987 _jit_name(block->_jit, __func__);
98fa08a5 1988 rec_mtc0(state, block, offset);
d16005f8
PC
1989}
1990
02487de7
PC
1991static unsigned int cp2d_i_offset(u8 reg)
1992{
1993 return offsetof(struct lightrec_state, regs.cp2d[reg]);
1994}
1995
1996static unsigned int cp2d_s_offset(u8 reg)
1997{
1998 return cp2d_i_offset(reg) + is_big_endian() * 2;
1999}
2000
2001static unsigned int cp2c_i_offset(u8 reg)
2002{
2003 return offsetof(struct lightrec_state, regs.cp2c[reg]);
2004}
2005
2006static unsigned int cp2c_s_offset(u8 reg)
2007{
2008 return cp2c_i_offset(reg) + is_big_endian() * 2;
2009}
2010
98fa08a5
PC
2011static void rec_cp2_basic_MFC2(struct lightrec_cstate *state,
2012 const struct block *block, u16 offset)
d16005f8 2013{
fd58fa32
PC
2014 struct regcache *reg_cache = state->reg_cache;
2015 const union code c = block->opcode_list[offset].c;
2016 jit_state_t *_jit = block->_jit;
2017 const u32 zext_regs = 0x300f0080;
2018 u8 rt, tmp, tmp2, tmp3, out, flags;
2019 u8 reg = c.r.rd == 15 ? 14 : c.r.rd;
2020 unsigned int i;
2021
d16005f8 2022 _jit_name(block->_jit, __func__);
fd58fa32
PC
2023
2024 flags = (zext_regs & BIT(reg)) ? REG_ZEXT : REG_EXT;
2025 rt = lightrec_alloc_reg_out(reg_cache, _jit, c.r.rt, flags);
2026
2027 switch (reg) {
2028 case 1:
2029 case 3:
2030 case 5:
2031 case 8:
2032 case 9:
2033 case 10:
2034 case 11:
02487de7 2035 jit_ldxi_s(rt, LIGHTREC_REG_STATE, cp2d_s_offset(reg));
fd58fa32
PC
2036 break;
2037 case 7:
2038 case 16:
2039 case 17:
2040 case 18:
2041 case 19:
02487de7 2042 jit_ldxi_us(rt, LIGHTREC_REG_STATE, cp2d_s_offset(reg));
fd58fa32
PC
2043 break;
2044 case 28:
2045 case 29:
2046 tmp = lightrec_alloc_reg_temp(reg_cache, _jit);
2047 tmp2 = lightrec_alloc_reg_temp(reg_cache, _jit);
2048 tmp3 = lightrec_alloc_reg_temp(reg_cache, _jit);
2049
2050 for (i = 0; i < 3; i++) {
2051 out = i == 0 ? rt : tmp;
2052
02487de7 2053 jit_ldxi_s(tmp, LIGHTREC_REG_STATE, cp2d_s_offset(9 + i));
fd58fa32
PC
2054 jit_movi(tmp2, 0x1f);
2055 jit_rshi(out, tmp, 7);
2056
2057 jit_ltr(tmp3, tmp2, out);
2058 jit_movnr(out, tmp2, tmp3);
2059
2060 jit_gei(tmp2, out, 0);
2061 jit_movzr(out, tmp2, tmp2);
2062
2063 if (i > 0) {
2064 jit_lshi(tmp, tmp, 5 * i);
2065 jit_orr(rt, rt, tmp);
2066 }
2067 }
2068
2069
2070 lightrec_free_reg(reg_cache, tmp);
2071 lightrec_free_reg(reg_cache, tmp2);
2072 lightrec_free_reg(reg_cache, tmp3);
2073 break;
2074 default:
02487de7 2075 jit_ldxi_i(rt, LIGHTREC_REG_STATE, cp2d_i_offset(reg));
fd58fa32
PC
2076 break;
2077 }
2078
2079 lightrec_free_reg(reg_cache, rt);
d16005f8
PC
2080}
2081
98fa08a5
PC
2082static void rec_cp2_basic_CFC2(struct lightrec_cstate *state,
2083 const struct block *block, u16 offset)
d16005f8 2084{
fd58fa32
PC
2085 struct regcache *reg_cache = state->reg_cache;
2086 const union code c = block->opcode_list[offset].c;
2087 jit_state_t *_jit = block->_jit;
2088 u8 rt;
2089
d16005f8 2090 _jit_name(block->_jit, __func__);
fd58fa32
PC
2091
2092 switch (c.r.rd) {
2093 case 4:
2094 case 12:
2095 case 20:
2096 case 26:
2097 case 27:
2098 case 29:
2099 case 30:
2100 rt = lightrec_alloc_reg_out(reg_cache, _jit, c.r.rt, REG_EXT);
02487de7 2101 jit_ldxi_s(rt, LIGHTREC_REG_STATE, cp2c_s_offset(c.r.rd));
fd58fa32
PC
2102 break;
2103 default:
2104 rt = lightrec_alloc_reg_out(reg_cache, _jit, c.r.rt, REG_ZEXT);
02487de7 2105 jit_ldxi_i(rt, LIGHTREC_REG_STATE, cp2c_i_offset(c.r.rd));
fd58fa32
PC
2106 break;
2107 }
2108
2109 lightrec_free_reg(reg_cache, rt);
d16005f8
PC
2110}
2111
98fa08a5
PC
2112static void rec_cp2_basic_MTC2(struct lightrec_cstate *state,
2113 const struct block *block, u16 offset)
d16005f8 2114{
fd58fa32
PC
2115 struct regcache *reg_cache = state->reg_cache;
2116 const union code c = block->opcode_list[offset].c;
2117 jit_state_t *_jit = block->_jit;
2118 jit_node_t *loop, *to_loop;
2119 u8 rt, tmp, tmp2, flags = 0;
2120
d16005f8 2121 _jit_name(block->_jit, __func__);
fd58fa32
PC
2122
2123 if (c.r.rd == 31)
2124 return;
2125
2126 if (c.r.rd == 30)
2127 flags |= REG_EXT;
2128
2129 rt = lightrec_alloc_reg_in(reg_cache, _jit, c.r.rt, flags);
2130
2131 switch (c.r.rd) {
2132 case 15:
2133 tmp = lightrec_alloc_reg_temp(reg_cache, _jit);
02487de7 2134 jit_ldxi_i(tmp, LIGHTREC_REG_STATE, cp2d_i_offset(13));
fd58fa32
PC
2135
2136 tmp2 = lightrec_alloc_reg_temp(reg_cache, _jit);
02487de7 2137 jit_ldxi_i(tmp2, LIGHTREC_REG_STATE, cp2d_i_offset(14));
fd58fa32 2138
02487de7
PC
2139 jit_stxi_i(cp2d_i_offset(12), LIGHTREC_REG_STATE, tmp);
2140 jit_stxi_i(cp2d_i_offset(13), LIGHTREC_REG_STATE, tmp2);
2141 jit_stxi_i(cp2d_i_offset(14), LIGHTREC_REG_STATE, rt);
fd58fa32
PC
2142
2143 lightrec_free_reg(reg_cache, tmp);
2144 lightrec_free_reg(reg_cache, tmp2);
2145 break;
2146 case 28:
2147 tmp = lightrec_alloc_reg_temp(reg_cache, _jit);
2148
2149 jit_lshi(tmp, rt, 7);
2150 jit_andi(tmp, tmp, 0xf80);
02487de7 2151 jit_stxi_s(cp2d_s_offset(9), LIGHTREC_REG_STATE, tmp);
fd58fa32
PC
2152
2153 jit_lshi(tmp, rt, 2);
2154 jit_andi(tmp, tmp, 0xf80);
02487de7 2155 jit_stxi_s(cp2d_s_offset(10), LIGHTREC_REG_STATE, tmp);
fd58fa32
PC
2156
2157 jit_rshi(tmp, rt, 3);
2158 jit_andi(tmp, tmp, 0xf80);
02487de7 2159 jit_stxi_s(cp2d_s_offset(11), LIGHTREC_REG_STATE, tmp);
fd58fa32
PC
2160
2161 lightrec_free_reg(reg_cache, tmp);
2162 break;
2163 case 30:
2164 tmp = lightrec_alloc_reg_temp(reg_cache, _jit);
2165 tmp2 = lightrec_alloc_reg_temp(reg_cache, _jit);
2166
2167 /* if (rt < 0) rt = ~rt; */
2168 jit_rshi(tmp, rt, 31);
2169 jit_xorr(tmp, rt, tmp);
2170
2171 /* We know the sign bit is 0. Left-shift by 1 to start the algorithm */
2172 jit_lshi(tmp, tmp, 1);
2173 jit_movi(tmp2, 33);
2174
2175 /* Decrement tmp2 and right-shift the value by 1 until it equals zero */
2176 loop = jit_label();
2177 jit_subi(tmp2, tmp2, 1);
2178 jit_rshi_u(tmp, tmp, 1);
2179 to_loop = jit_bnei(tmp, 0);
2180
2181 jit_patch_at(to_loop, loop);
2182
02487de7
PC
2183 jit_stxi_i(cp2d_i_offset(31), LIGHTREC_REG_STATE, tmp2);
2184 jit_stxi_i(cp2d_i_offset(30), LIGHTREC_REG_STATE, rt);
fd58fa32
PC
2185
2186 lightrec_free_reg(reg_cache, tmp);
2187 lightrec_free_reg(reg_cache, tmp2);
2188 break;
2189 default:
02487de7 2190 jit_stxi_i(cp2d_i_offset(c.r.rd), LIGHTREC_REG_STATE, rt);
fd58fa32
PC
2191 break;
2192 }
2193
2194 lightrec_free_reg(reg_cache, rt);
d16005f8
PC
2195}
2196
98fa08a5
PC
2197static void rec_cp2_basic_CTC2(struct lightrec_cstate *state,
2198 const struct block *block, u16 offset)
d16005f8 2199{
fd58fa32
PC
2200 struct regcache *reg_cache = state->reg_cache;
2201 const union code c = block->opcode_list[offset].c;
2202 jit_state_t *_jit = block->_jit;
2203 u8 rt, tmp, tmp2;
2204
98fa08a5 2205 _jit_name(block->_jit, __func__);
fd58fa32
PC
2206
2207 rt = lightrec_alloc_reg_in(reg_cache, _jit, c.r.rt, 0);
2208
2209 switch (c.r.rd) {
2210 case 4:
2211 case 12:
2212 case 20:
2213 case 26:
2214 case 27:
2215 case 29:
2216 case 30:
02487de7 2217 jit_stxi_s(cp2c_s_offset(c.r.rd), LIGHTREC_REG_STATE, rt);
fd58fa32
PC
2218 break;
2219 case 31:
2220 tmp = lightrec_alloc_reg_temp(reg_cache, _jit);
2221 tmp2 = lightrec_alloc_reg_temp(reg_cache, _jit);
2222
2223 jit_andi(tmp, rt, 0x7f87e000);
2224 jit_nei(tmp, tmp, 0);
2225 jit_lshi(tmp, tmp, 31);
2226
2227 jit_andi(tmp2, rt, 0x7ffff000);
2228 jit_orr(tmp, tmp2, tmp);
2229
02487de7 2230 jit_stxi_i(cp2c_i_offset(31), LIGHTREC_REG_STATE, tmp);
fd58fa32
PC
2231
2232 lightrec_free_reg(reg_cache, tmp);
2233 lightrec_free_reg(reg_cache, tmp2);
2234 break;
2235
2236 default:
02487de7 2237 jit_stxi_i(cp2c_i_offset(c.r.rd), LIGHTREC_REG_STATE, rt);
fd58fa32
PC
2238 }
2239
2240 lightrec_free_reg(reg_cache, rt);
d16005f8
PC
2241}
2242
98fa08a5
PC
2243static void rec_cp0_RFE(struct lightrec_cstate *state,
2244 const struct block *block, u16 offset)
d16005f8 2245{
98fa08a5 2246 struct regcache *reg_cache = state->reg_cache;
d16005f8 2247 jit_state_t *_jit = block->_jit;
98fa08a5 2248 u8 status, tmp;
d16005f8
PC
2249
2250 jit_name(__func__);
2251 jit_note(__FILE__, __LINE__);
2252
98fa08a5
PC
2253 status = lightrec_alloc_reg_temp(reg_cache, _jit);
2254 jit_ldxi_i(status, LIGHTREC_REG_STATE,
2255 offsetof(struct lightrec_state, regs.cp0[12]));
d16005f8 2256
98fa08a5 2257 tmp = lightrec_alloc_reg_temp(reg_cache, _jit);
d16005f8 2258
98fa08a5
PC
2259 /* status = ((status >> 2) & 0xf) | status & ~0xf; */
2260 jit_rshi(tmp, status, 2);
2261 jit_andi(tmp, tmp, 0xf);
2262 jit_andi(status, status, ~0xful);
2263 jit_orr(status, status, tmp);
2264
2265 jit_ldxi_i(tmp, LIGHTREC_REG_STATE,
2266 offsetof(struct lightrec_state, regs.cp0[13]));
2267 jit_stxi_i(offsetof(struct lightrec_state, regs.cp0[12]),
2268 LIGHTREC_REG_STATE, status);
2269
2270 /* Exit dynarec in case there's a software interrupt.
2271 * exit_flags = !!(status & cause & 0x0300) & status; */
2272 jit_andr(tmp, tmp, status);
2273 jit_andi(tmp, tmp, 0x0300);
2274 jit_nei(tmp, tmp, 0);
2275 jit_andr(tmp, tmp, status);
2276 jit_stxi_i(offsetof(struct lightrec_state, exit_flags),
2277 LIGHTREC_REG_STATE, tmp);
2278
2279 lightrec_free_reg(reg_cache, status);
d16005f8 2280 lightrec_free_reg(reg_cache, tmp);
d16005f8
PC
2281}
2282
98fa08a5
PC
2283static void rec_CP(struct lightrec_cstate *state,
2284 const struct block *block, u16 offset)
d16005f8 2285{
98fa08a5 2286 union code c = block->opcode_list[offset].c;
d16005f8
PC
2287 jit_state_t *_jit = block->_jit;
2288
2289 jit_name(__func__);
2290 jit_note(__FILE__, __LINE__);
2291
ba3814c1 2292 call_to_c_wrapper(state, block, c.opcode, C_WRAPPER_CP);
d16005f8
PC
2293}
2294
98fa08a5
PC
2295static void rec_meta_MOV(struct lightrec_cstate *state,
2296 const struct block *block, u16 offset)
d16005f8 2297{
d16005f8 2298 struct regcache *reg_cache = state->reg_cache;
98fa08a5 2299 union code c = block->opcode_list[offset].c;
d16005f8
PC
2300 jit_state_t *_jit = block->_jit;
2301 u8 rs, rd;
2302
2303 _jit_name(block->_jit, __func__);
2304 jit_note(__FILE__, __LINE__);
98fa08a5
PC
2305 if (c.r.rs)
2306 rs = lightrec_alloc_reg_in(reg_cache, _jit, c.r.rs, 0);
2307 rd = lightrec_alloc_reg_out(reg_cache, _jit, c.r.rd, REG_EXT);
d16005f8 2308
98fa08a5 2309 if (c.r.rs == 0)
d16005f8 2310 jit_movi(rd, 0);
98fa08a5 2311 else
d16005f8 2312 jit_extr_i(rd, rs);
d16005f8 2313
98fa08a5
PC
2314 if (c.r.rs)
2315 lightrec_free_reg(reg_cache, rs);
2316 lightrec_free_reg(reg_cache, rd);
d16005f8
PC
2317}
2318
98fa08a5
PC
2319static void rec_meta_EXTC_EXTS(struct lightrec_cstate *state,
2320 const struct block *block,
2321 u16 offset)
d16005f8 2322{
98fa08a5
PC
2323 struct regcache *reg_cache = state->reg_cache;
2324 union code c = block->opcode_list[offset].c;
d16005f8 2325 jit_state_t *_jit = block->_jit;
98fa08a5 2326 u8 rs, rt;
d16005f8 2327
98fa08a5 2328 _jit_name(block->_jit, __func__);
d16005f8
PC
2329 jit_note(__FILE__, __LINE__);
2330
98fa08a5
PC
2331 rs = lightrec_alloc_reg_in(reg_cache, _jit, c.i.rs, 0);
2332 rt = lightrec_alloc_reg_out(reg_cache, _jit, c.i.rt, REG_EXT);
d16005f8 2333
98fa08a5
PC
2334 if (c.i.op == OP_META_EXTC)
2335 jit_extr_c(rt, rs);
2336 else
2337 jit_extr_s(rt, rs);
d16005f8 2338
98fa08a5
PC
2339 lightrec_free_reg(reg_cache, rs);
2340 lightrec_free_reg(reg_cache, rt);
d16005f8
PC
2341}
2342
ba3814c1
PC
2343static void rec_meta_MULT2(struct lightrec_cstate *state,
2344 const struct block *block,
2345 u16 offset)
2346{
2347 struct regcache *reg_cache = state->reg_cache;
2348 union code c = block->opcode_list[offset].c;
2349 jit_state_t *_jit = block->_jit;
2350 u8 reg_lo = get_mult_div_lo(c);
2351 u8 reg_hi = get_mult_div_hi(c);
2352 u32 flags = block->opcode_list[offset].flags;
2353 bool is_signed = c.i.op == OP_META_MULT2;
2354 u8 rs, lo, hi, rflags = 0, hiflags = 0;
2355
2356 if (!op_flag_no_hi(flags) && c.r.op < 32) {
2357 rflags = is_signed ? REG_EXT : REG_ZEXT;
2358 hiflags = is_signed ? REG_EXT : (REG_EXT | REG_ZEXT);
2359 }
2360
2361 _jit_name(block->_jit, __func__);
2362 jit_note(__FILE__, __LINE__);
2363
2364 rs = lightrec_alloc_reg_in(reg_cache, _jit, c.i.rs, rflags);
2365
2366 if (!op_flag_no_lo(flags)) {
2367 lo = lightrec_alloc_reg_out(reg_cache, _jit, reg_lo, 0);
2368
2369 if (c.r.op < 32)
2370 jit_lshi(lo, rs, c.r.op);
2371 else
2372 jit_movi(lo, 0);
2373
2374 lightrec_free_reg(reg_cache, lo);
2375 }
2376
2377 if (!op_flag_no_hi(flags)) {
2378 hi = lightrec_alloc_reg_out(reg_cache, _jit, reg_hi, hiflags);
2379
2380 if (c.r.op >= 32)
2381 jit_lshi(hi, rs, c.r.op - 32);
2382 else if (is_signed)
2383 jit_rshi(hi, rs, 32 - c.r.op);
2384 else
2385 jit_rshi_u(hi, rs, 32 - c.r.op);
2386
2387 lightrec_free_reg(reg_cache, hi);
2388 }
2389
2390 lightrec_free_reg(reg_cache, rs);
2391
2392 _jit_name(block->_jit, __func__);
2393 jit_note(__FILE__, __LINE__);
2394}
2395
d16005f8 2396static const lightrec_rec_func_t rec_standard[64] = {
98fa08a5 2397 SET_DEFAULT_ELM(rec_standard, unknown_opcode),
d16005f8
PC
2398 [OP_SPECIAL] = rec_SPECIAL,
2399 [OP_REGIMM] = rec_REGIMM,
2400 [OP_J] = rec_J,
2401 [OP_JAL] = rec_JAL,
2402 [OP_BEQ] = rec_BEQ,
2403 [OP_BNE] = rec_BNE,
2404 [OP_BLEZ] = rec_BLEZ,
2405 [OP_BGTZ] = rec_BGTZ,
2406 [OP_ADDI] = rec_ADDI,
2407 [OP_ADDIU] = rec_ADDIU,
2408 [OP_SLTI] = rec_SLTI,
2409 [OP_SLTIU] = rec_SLTIU,
2410 [OP_ANDI] = rec_ANDI,
2411 [OP_ORI] = rec_ORI,
2412 [OP_XORI] = rec_XORI,
2413 [OP_LUI] = rec_LUI,
2414 [OP_CP0] = rec_CP0,
2415 [OP_CP2] = rec_CP2,
2416 [OP_LB] = rec_LB,
2417 [OP_LH] = rec_LH,
2418 [OP_LWL] = rec_LWL,
2419 [OP_LW] = rec_LW,
2420 [OP_LBU] = rec_LBU,
2421 [OP_LHU] = rec_LHU,
2422 [OP_LWR] = rec_LWR,
2423 [OP_SB] = rec_SB,
2424 [OP_SH] = rec_SH,
2425 [OP_SWL] = rec_SWL,
2426 [OP_SW] = rec_SW,
2427 [OP_SWR] = rec_SWR,
2428 [OP_LWC2] = rec_LWC2,
2429 [OP_SWC2] = rec_SWC2,
2430
d16005f8 2431 [OP_META_MOV] = rec_meta_MOV,
98fa08a5
PC
2432 [OP_META_EXTC] = rec_meta_EXTC_EXTS,
2433 [OP_META_EXTS] = rec_meta_EXTC_EXTS,
ba3814c1
PC
2434 [OP_META_MULT2] = rec_meta_MULT2,
2435 [OP_META_MULTU2] = rec_meta_MULT2,
d16005f8
PC
2436};
2437
2438static const lightrec_rec_func_t rec_special[64] = {
98fa08a5 2439 SET_DEFAULT_ELM(rec_special, unknown_opcode),
d16005f8
PC
2440 [OP_SPECIAL_SLL] = rec_special_SLL,
2441 [OP_SPECIAL_SRL] = rec_special_SRL,
2442 [OP_SPECIAL_SRA] = rec_special_SRA,
2443 [OP_SPECIAL_SLLV] = rec_special_SLLV,
2444 [OP_SPECIAL_SRLV] = rec_special_SRLV,
2445 [OP_SPECIAL_SRAV] = rec_special_SRAV,
2446 [OP_SPECIAL_JR] = rec_special_JR,
2447 [OP_SPECIAL_JALR] = rec_special_JALR,
2448 [OP_SPECIAL_SYSCALL] = rec_special_SYSCALL,
2449 [OP_SPECIAL_BREAK] = rec_special_BREAK,
2450 [OP_SPECIAL_MFHI] = rec_special_MFHI,
2451 [OP_SPECIAL_MTHI] = rec_special_MTHI,
2452 [OP_SPECIAL_MFLO] = rec_special_MFLO,
2453 [OP_SPECIAL_MTLO] = rec_special_MTLO,
2454 [OP_SPECIAL_MULT] = rec_special_MULT,
2455 [OP_SPECIAL_MULTU] = rec_special_MULTU,
2456 [OP_SPECIAL_DIV] = rec_special_DIV,
2457 [OP_SPECIAL_DIVU] = rec_special_DIVU,
2458 [OP_SPECIAL_ADD] = rec_special_ADD,
2459 [OP_SPECIAL_ADDU] = rec_special_ADDU,
2460 [OP_SPECIAL_SUB] = rec_special_SUB,
2461 [OP_SPECIAL_SUBU] = rec_special_SUBU,
2462 [OP_SPECIAL_AND] = rec_special_AND,
2463 [OP_SPECIAL_OR] = rec_special_OR,
2464 [OP_SPECIAL_XOR] = rec_special_XOR,
2465 [OP_SPECIAL_NOR] = rec_special_NOR,
2466 [OP_SPECIAL_SLT] = rec_special_SLT,
2467 [OP_SPECIAL_SLTU] = rec_special_SLTU,
2468};
2469
2470static const lightrec_rec_func_t rec_regimm[64] = {
98fa08a5 2471 SET_DEFAULT_ELM(rec_regimm, unknown_opcode),
d16005f8
PC
2472 [OP_REGIMM_BLTZ] = rec_regimm_BLTZ,
2473 [OP_REGIMM_BGEZ] = rec_regimm_BGEZ,
2474 [OP_REGIMM_BLTZAL] = rec_regimm_BLTZAL,
2475 [OP_REGIMM_BGEZAL] = rec_regimm_BGEZAL,
2476};
2477
2478static const lightrec_rec_func_t rec_cp0[64] = {
98fa08a5 2479 SET_DEFAULT_ELM(rec_cp0, rec_CP),
d16005f8
PC
2480 [OP_CP0_MFC0] = rec_cp0_MFC0,
2481 [OP_CP0_CFC0] = rec_cp0_CFC0,
2482 [OP_CP0_MTC0] = rec_cp0_MTC0,
2483 [OP_CP0_CTC0] = rec_cp0_CTC0,
2484 [OP_CP0_RFE] = rec_cp0_RFE,
2485};
2486
2487static const lightrec_rec_func_t rec_cp2_basic[64] = {
98fa08a5 2488 SET_DEFAULT_ELM(rec_cp2_basic, rec_CP),
d16005f8
PC
2489 [OP_CP2_BASIC_MFC2] = rec_cp2_basic_MFC2,
2490 [OP_CP2_BASIC_CFC2] = rec_cp2_basic_CFC2,
2491 [OP_CP2_BASIC_MTC2] = rec_cp2_basic_MTC2,
2492 [OP_CP2_BASIC_CTC2] = rec_cp2_basic_CTC2,
2493};
2494
98fa08a5
PC
2495static void rec_SPECIAL(struct lightrec_cstate *state,
2496 const struct block *block, u16 offset)
d16005f8 2497{
98fa08a5
PC
2498 union code c = block->opcode_list[offset].c;
2499 lightrec_rec_func_t f = rec_special[c.r.op];
2500
2501 if (!HAS_DEFAULT_ELM && unlikely(!f))
2502 unknown_opcode(state, block, offset);
d16005f8 2503 else
98fa08a5 2504 (*f)(state, block, offset);
d16005f8
PC
2505}
2506
98fa08a5
PC
2507static void rec_REGIMM(struct lightrec_cstate *state,
2508 const struct block *block, u16 offset)
d16005f8 2509{
98fa08a5
PC
2510 union code c = block->opcode_list[offset].c;
2511 lightrec_rec_func_t f = rec_regimm[c.r.rt];
2512
2513 if (!HAS_DEFAULT_ELM && unlikely(!f))
2514 unknown_opcode(state, block, offset);
d16005f8 2515 else
98fa08a5 2516 (*f)(state, block, offset);
d16005f8
PC
2517}
2518
98fa08a5
PC
2519static void rec_CP0(struct lightrec_cstate *state,
2520 const struct block *block, u16 offset)
d16005f8 2521{
98fa08a5
PC
2522 union code c = block->opcode_list[offset].c;
2523 lightrec_rec_func_t f = rec_cp0[c.r.rs];
2524
2525 if (!HAS_DEFAULT_ELM && unlikely(!f))
2526 rec_CP(state, block, offset);
d16005f8 2527 else
98fa08a5 2528 (*f)(state, block, offset);
d16005f8
PC
2529}
2530
98fa08a5
PC
2531static void rec_CP2(struct lightrec_cstate *state,
2532 const struct block *block, u16 offset)
d16005f8 2533{
98fa08a5
PC
2534 union code c = block->opcode_list[offset].c;
2535
2536 if (c.r.op == OP_CP2_BASIC) {
2537 lightrec_rec_func_t f = rec_cp2_basic[c.r.rs];
2538
2539 if (HAS_DEFAULT_ELM || likely(f)) {
2540 (*f)(state, block, offset);
d16005f8
PC
2541 return;
2542 }
2543 }
2544
98fa08a5 2545 rec_CP(state, block, offset);
d16005f8
PC
2546}
2547
98fa08a5
PC
2548void lightrec_rec_opcode(struct lightrec_cstate *state,
2549 const struct block *block, u16 offset)
d16005f8 2550{
98fa08a5
PC
2551 struct regcache *reg_cache = state->reg_cache;
2552 struct lightrec_branch_target *target;
2553 const struct opcode *op = &block->opcode_list[offset];
2554 jit_state_t *_jit = block->_jit;
2555 lightrec_rec_func_t f;
03535202 2556 u16 unload_offset;
98fa08a5 2557
03535202
PC
2558 if (op_flag_sync(op->flags)) {
2559 if (state->cycles)
2560 jit_subi(LIGHTREC_REG_CYCLE, LIGHTREC_REG_CYCLE, state->cycles);
98fa08a5
PC
2561 state->cycles = 0;
2562
2563 lightrec_storeback_regs(reg_cache, _jit);
2564 lightrec_regcache_reset(reg_cache);
2565
2566 pr_debug("Adding branch target at offset 0x%x\n", offset << 2);
2567 target = &state->targets[state->nb_targets++];
2568 target->offset = offset;
2569 target->label = jit_indirect();
2570 }
2571
2572 if (likely(op->opcode)) {
2573 f = rec_standard[op->i.op];
2574
2575 if (!HAS_DEFAULT_ELM && unlikely(!f))
2576 unknown_opcode(state, block, offset);
2577 else
2578 (*f)(state, block, offset);
2579 }
2580
03535202
PC
2581 if (OPT_EARLY_UNLOAD) {
2582 unload_offset = offset +
2583 (has_delay_slot(op->c) && !op_flag_no_ds(op->flags));
2584
2585 lightrec_do_early_unload(state, block, unload_offset);
98fa08a5 2586 }
d16005f8 2587}