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