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