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