git subrepo pull --force deps/lightning
[pcsx_rearmed.git] / deps / lightrec / lightrec.c
CommitLineData
d16005f8
PC
1/*
2 * Copyright (C) 2014-2020 Paul Cercueil <paul@crapouillou.net>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 */
14
15#include "blockcache.h"
16#include "config.h"
17#include "debug.h"
18#include "disassembler.h"
19#include "emitter.h"
20#include "interpreter.h"
21#include "lightrec.h"
22#include "memmanager.h"
a59e5536 23#include "reaper.h"
d16005f8
PC
24#include "recompiler.h"
25#include "regcache.h"
26#include "optimizer.h"
27
28#include <errno.h>
29#include <lightning.h>
30#include <limits.h>
31#if ENABLE_THREADED_COMPILER
32#include <stdatomic.h>
33#endif
34#include <stdbool.h>
35#include <stddef.h>
36#include <string.h>
37#if ENABLE_TINYMM
38#include <tinymm.h>
39#endif
40
41#define GENMASK(h, l) \
42 (((uintptr_t)-1 << (l)) & ((uintptr_t)-1 >> (__WORDSIZE - 1 - (h))))
43
44static struct block * lightrec_precompile_block(struct lightrec_state *state,
45 u32 pc);
46
a59e5536 47static void lightrec_default_sb(struct lightrec_state *state, u32 opcode,
48 void *host, u32 addr, u8 data)
49{
50 *(u8 *)host = data;
51
52 if (!state->invalidate_from_dma_only)
53 lightrec_invalidate(state, addr, 1);
54}
55
56static void lightrec_default_sh(struct lightrec_state *state, u32 opcode,
57 void *host, u32 addr, u16 data)
58{
59 *(u16 *)host = HTOLE16(data);
60
61 if (!state->invalidate_from_dma_only)
62 lightrec_invalidate(state, addr, 2);
63}
64
65static void lightrec_default_sw(struct lightrec_state *state, u32 opcode,
66 void *host, u32 addr, u32 data)
67{
68 *(u32 *)host = HTOLE32(data);
69
70 if (!state->invalidate_from_dma_only)
71 lightrec_invalidate(state, addr, 4);
72}
73
74static u8 lightrec_default_lb(struct lightrec_state *state,
75 u32 opcode, void *host, u32 addr)
76{
77 return *(u8 *)host;
78}
79
80static u16 lightrec_default_lh(struct lightrec_state *state,
81 u32 opcode, void *host, u32 addr)
82{
83 return LE16TOH(*(u16 *)host);
84}
85
86static u32 lightrec_default_lw(struct lightrec_state *state,
87 u32 opcode, void *host, u32 addr)
88{
89 return LE32TOH(*(u32 *)host);
90}
91
92static const struct lightrec_mem_map_ops lightrec_default_ops = {
93 .sb = lightrec_default_sb,
94 .sh = lightrec_default_sh,
95 .sw = lightrec_default_sw,
96 .lb = lightrec_default_lb,
97 .lh = lightrec_default_lh,
98 .lw = lightrec_default_lw,
99};
100
d16005f8
PC
101static void __segfault_cb(struct lightrec_state *state, u32 addr)
102{
103 lightrec_set_exit_flags(state, LIGHTREC_EXIT_SEGFAULT);
104 pr_err("Segmentation fault in recompiled code: invalid "
105 "load/store at address 0x%08x\n", addr);
106}
107
a59e5536 108static void lightrec_swl(struct lightrec_state *state,
109 const struct lightrec_mem_map_ops *ops,
110 u32 opcode, void *host, u32 addr, u32 data)
d16005f8 111{
a59e5536 112 unsigned int shift = addr & 0x3;
113 unsigned int mask = GENMASK(31, (shift + 1) * 8);
114 u32 old_data;
115
116 /* Align to 32 bits */
117 addr &= ~3;
118 host = (void *)((uintptr_t)host & ~3);
119
120 old_data = ops->lw(state, opcode, host, addr);
121
122 data = (data >> ((3 - shift) * 8)) | (old_data & mask);
123
124 ops->sw(state, opcode, host, addr, data);
125}
126
127static void lightrec_swr(struct lightrec_state *state,
128 const struct lightrec_mem_map_ops *ops,
129 u32 opcode, void *host, u32 addr, u32 data)
130{
131 unsigned int shift = addr & 0x3;
132 unsigned int mask = (1 << (shift * 8)) - 1;
133 u32 old_data;
134
135 /* Align to 32 bits */
136 addr &= ~3;
137 host = (void *)((uintptr_t)host & ~3);
138
139 old_data = ops->lw(state, opcode, host, addr);
140
141 data = (data << (shift * 8)) | (old_data & mask);
142
143 ops->sw(state, opcode, host, addr, data);
144}
145
146static void lightrec_swc2(struct lightrec_state *state, union code op,
147 const struct lightrec_mem_map_ops *ops,
148 void *host, u32 addr)
149{
150 u32 data = state->ops.cop2_ops.mfc(state, op.opcode, op.i.rt);
151
152 ops->sw(state, op.opcode, host, addr, data);
153}
154
155static u32 lightrec_lwl(struct lightrec_state *state,
156 const struct lightrec_mem_map_ops *ops,
157 u32 opcode, void *host, u32 addr, u32 data)
158{
159 unsigned int shift = addr & 0x3;
160 unsigned int mask = (1 << (24 - shift * 8)) - 1;
161 u32 old_data;
162
163 /* Align to 32 bits */
164 addr &= ~3;
165 host = (void *)((uintptr_t)host & ~3);
166
167 old_data = ops->lw(state, opcode, host, addr);
168
169 return (data & mask) | (old_data << (24 - shift * 8));
170}
171
172static u32 lightrec_lwr(struct lightrec_state *state,
173 const struct lightrec_mem_map_ops *ops,
174 u32 opcode, void *host, u32 addr, u32 data)
175{
176 unsigned int shift = addr & 0x3;
177 unsigned int mask = GENMASK(31, 32 - shift * 8);
178 u32 old_data;
179
180 /* Align to 32 bits */
181 addr &= ~3;
182 host = (void *)((uintptr_t)host & ~3);
183
184 old_data = ops->lw(state, opcode, host, addr);
185
186 return (data & mask) | (old_data >> (shift * 8));
187}
188
189static void lightrec_lwc2(struct lightrec_state *state, union code op,
190 const struct lightrec_mem_map_ops *ops,
191 void *host, u32 addr)
192{
193 u32 data = ops->lw(state, op.opcode, host, addr);
194
195 state->ops.cop2_ops.mtc(state, op.opcode, op.i.rt, data);
d16005f8
PC
196}
197
198static void lightrec_invalidate_map(struct lightrec_state *state,
199 const struct lightrec_mem_map *map, u32 addr)
200{
201 if (map == &state->maps[PSX_MAP_KERNEL_USER_RAM])
202 state->code_lut[lut_offset(addr)] = NULL;
203}
204
205static const struct lightrec_mem_map *
206lightrec_get_map(struct lightrec_state *state, u32 kaddr)
207{
208 unsigned int i;
209
210 for (i = 0; i < state->nb_maps; i++) {
211 const struct lightrec_mem_map *map = &state->maps[i];
212
213 if (kaddr >= map->pc && kaddr < map->pc + map->length)
214 return map;
215 }
216
217 return NULL;
218}
219
220u32 lightrec_rw(struct lightrec_state *state, union code op,
221 u32 addr, u32 data, u16 *flags)
222{
223 const struct lightrec_mem_map *map;
a59e5536 224 const struct lightrec_mem_map_ops *ops;
225 u32 kaddr, pc, opcode = op.opcode;
226 void *host;
d16005f8
PC
227
228 addr += (s16) op.i.imm;
229 kaddr = kunseg(addr);
230
231 map = lightrec_get_map(state, kaddr);
232 if (!map) {
233 __segfault_cb(state, addr);
234 return 0;
235 }
236
237 pc = map->pc;
238
a59e5536 239 while (map->mirror_of)
240 map = map->mirror_of;
241
242 host = (void *)((uintptr_t)map->address + kaddr - pc);
243
d16005f8
PC
244 if (unlikely(map->ops)) {
245 if (flags)
246 *flags |= LIGHTREC_HW_IO;
247
a59e5536 248 ops = map->ops;
249 } else {
250 if (flags)
251 *flags |= LIGHTREC_DIRECT_IO;
d16005f8 252
a59e5536 253 ops = &lightrec_default_ops;
254 }
d16005f8
PC
255
256 switch (op.i.op) {
257 case OP_SB:
a59e5536 258 ops->sb(state, opcode, host, addr, (u8) data);
d16005f8
PC
259 return 0;
260 case OP_SH:
a59e5536 261 ops->sh(state, opcode, host, addr, (u16) data);
d16005f8
PC
262 return 0;
263 case OP_SWL:
a59e5536 264 lightrec_swl(state, ops, opcode, host, addr, data);
d16005f8
PC
265 return 0;
266 case OP_SWR:
a59e5536 267 lightrec_swr(state, ops, opcode, host, addr, data);
d16005f8
PC
268 return 0;
269 case OP_SW:
a59e5536 270 ops->sw(state, opcode, host, addr, data);
d16005f8
PC
271 return 0;
272 case OP_SWC2:
a59e5536 273 lightrec_swc2(state, op, ops, host, addr);
d16005f8
PC
274 return 0;
275 case OP_LB:
a59e5536 276 return (s32) (s8) ops->lb(state, opcode, host, addr);
d16005f8 277 case OP_LBU:
a59e5536 278 return ops->lb(state, opcode, host, addr);
d16005f8 279 case OP_LH:
a59e5536 280 return (s32) (s16) ops->lh(state, opcode, host, addr);
d16005f8 281 case OP_LHU:
a59e5536 282 return ops->lh(state, opcode, host, addr);
d16005f8 283 case OP_LWC2:
a59e5536 284 lightrec_lwc2(state, op, ops, host, addr);
d16005f8 285 return 0;
a59e5536 286 case OP_LWL:
287 return lightrec_lwl(state, ops, opcode, host, addr, data);
288 case OP_LWR:
289 return lightrec_lwr(state, ops, opcode, host, addr, data);
d16005f8
PC
290 case OP_LW:
291 default:
a59e5536 292 return ops->lw(state, opcode, host, addr);
d16005f8
PC
293 }
294}
295
296static void lightrec_rw_helper(struct lightrec_state *state,
297 union code op, u16 *flags)
298{
299 u32 ret = lightrec_rw(state, op,
300 state->native_reg_cache[op.i.rs],
301 state->native_reg_cache[op.i.rt], flags);
302
303 switch (op.i.op) {
304 case OP_LB:
305 case OP_LBU:
306 case OP_LH:
307 case OP_LHU:
308 case OP_LWL:
309 case OP_LWR:
310 case OP_LW:
311 if (op.i.rt)
312 state->native_reg_cache[op.i.rt] = ret;
313 default: /* fall-through */
314 break;
315 }
316}
317
318static void lightrec_rw_cb(struct lightrec_state *state, union code op)
319{
320 lightrec_rw_helper(state, op, NULL);
321}
322
323static void lightrec_rw_generic_cb(struct lightrec_state *state,
324 struct opcode *op, struct block *block)
325{
326 bool was_tagged = op->flags & (LIGHTREC_HW_IO | LIGHTREC_DIRECT_IO);
327
328 lightrec_rw_helper(state, op->c, &op->flags);
329
330 if (!was_tagged) {
331 pr_debug("Opcode of block at PC 0x%08x offset 0x%x has been "
332 "tagged - flag for recompilation\n",
333 block->pc, op->offset << 2);
334
a59e5536 335 block->flags |= BLOCK_SHOULD_RECOMPILE;
d16005f8
PC
336 }
337}
338
339u32 lightrec_mfc(struct lightrec_state *state, union code op)
340{
341 bool is_cfc = (op.i.op == OP_CP0 && op.r.rs == OP_CP0_CFC0) ||
342 (op.i.op == OP_CP2 && op.r.rs == OP_CP2_BASIC_CFC2);
a59e5536 343 u32 (*func)(struct lightrec_state *, u32, u8);
d16005f8
PC
344 const struct lightrec_cop_ops *ops;
345
346 if (op.i.op == OP_CP0)
347 ops = &state->ops.cop0_ops;
348 else
349 ops = &state->ops.cop2_ops;
350
351 if (is_cfc)
352 func = ops->cfc;
353 else
354 func = ops->mfc;
355
a59e5536 356 return (*func)(state, op.opcode, op.r.rd);
d16005f8
PC
357}
358
359static void lightrec_mfc_cb(struct lightrec_state *state, union code op)
360{
361 u32 rt = lightrec_mfc(state, op);
362
363 if (op.r.rt)
364 state->native_reg_cache[op.r.rt] = rt;
365}
366
367void lightrec_mtc(struct lightrec_state *state, union code op, u32 data)
368{
369 bool is_ctc = (op.i.op == OP_CP0 && op.r.rs == OP_CP0_CTC0) ||
370 (op.i.op == OP_CP2 && op.r.rs == OP_CP2_BASIC_CTC2);
a59e5536 371 void (*func)(struct lightrec_state *, u32, u8, u32);
d16005f8
PC
372 const struct lightrec_cop_ops *ops;
373
374 if (op.i.op == OP_CP0)
375 ops = &state->ops.cop0_ops;
376 else
377 ops = &state->ops.cop2_ops;
378
379 if (is_ctc)
380 func = ops->ctc;
381 else
382 func = ops->mtc;
383
a59e5536 384 (*func)(state, op.opcode, op.r.rd, data);
d16005f8
PC
385}
386
387static void lightrec_mtc_cb(struct lightrec_state *state, union code op)
388{
389 lightrec_mtc(state, op, state->native_reg_cache[op.r.rt]);
390}
391
392static void lightrec_rfe_cb(struct lightrec_state *state, union code op)
393{
394 u32 status;
395
396 /* Read CP0 Status register (r12) */
a59e5536 397 status = state->ops.cop0_ops.mfc(state, op.opcode, 12);
d16005f8
PC
398
399 /* Switch the bits */
400 status = ((status & 0x3c) >> 2) | (status & ~0xf);
401
402 /* Write it back */
a59e5536 403 state->ops.cop0_ops.ctc(state, op.opcode, 12, status);
d16005f8
PC
404}
405
406static void lightrec_cp_cb(struct lightrec_state *state, union code op)
407{
408 void (*func)(struct lightrec_state *, u32);
409
410 if ((op.opcode >> 25) & 1)
411 func = state->ops.cop2_ops.op;
412 else
413 func = state->ops.cop0_ops.op;
414
415 (*func)(state, op.opcode);
416}
417
418static void lightrec_syscall_cb(struct lightrec_state *state, union code op)
419{
420 lightrec_set_exit_flags(state, LIGHTREC_EXIT_SYSCALL);
421}
422
423static void lightrec_break_cb(struct lightrec_state *state, union code op)
424{
425 lightrec_set_exit_flags(state, LIGHTREC_EXIT_BREAK);
426}
427
428struct block * lightrec_get_block(struct lightrec_state *state, u32 pc)
429{
430 struct block *block = lightrec_find_block(state->block_cache, pc);
431
432 if (block && lightrec_block_is_outdated(block)) {
433 pr_debug("Block at PC 0x%08x is outdated!\n", block->pc);
434
435 /* Make sure the recompiler isn't processing the block we'll
436 * destroy */
437 if (ENABLE_THREADED_COMPILER)
438 lightrec_recompiler_remove(state->rec, block);
439
440 lightrec_unregister_block(state->block_cache, block);
a59e5536 441 remove_from_code_lut(state->block_cache, block);
d16005f8
PC
442 lightrec_free_block(block);
443 block = NULL;
444 }
445
446 if (!block) {
447 block = lightrec_precompile_block(state, pc);
448 if (!block) {
449 pr_err("Unable to recompile block at PC 0x%x\n", pc);
450 lightrec_set_exit_flags(state, LIGHTREC_EXIT_SEGFAULT);
451 return NULL;
452 }
453
454 lightrec_register_block(state->block_cache, block);
455 }
456
457 return block;
458}
459
460static void * get_next_block_func(struct lightrec_state *state, u32 pc)
461{
462 struct block *block;
463 bool should_recompile;
464 void *func;
465
466 for (;;) {
467 func = state->code_lut[lut_offset(pc)];
468 if (func && func != state->get_next_block)
469 return func;
470
471 block = lightrec_get_block(state, pc);
472
473 if (unlikely(!block))
474 return NULL;
475
a59e5536 476 should_recompile = block->flags & BLOCK_SHOULD_RECOMPILE &&
477 !(block->flags & BLOCK_IS_DEAD);
d16005f8
PC
478
479 if (unlikely(should_recompile)) {
a59e5536 480 pr_debug("Block at PC 0x%08x should recompile\n", pc);
d16005f8 481
d16005f8 482 lightrec_unregister(MEM_FOR_CODE, block->code_size);
a59e5536 483
484 if (ENABLE_THREADED_COMPILER)
485 lightrec_recompiler_add(state->rec, block);
486 else
487 lightrec_compile_block(block);
d16005f8
PC
488 }
489
490 if (ENABLE_THREADED_COMPILER && likely(!should_recompile))
491 func = lightrec_recompiler_run_first_pass(block, &pc);
492 else
493 func = block->function;
494
495 if (likely(func))
496 return func;
497
498 /* Block wasn't compiled yet - run the interpreter */
499 if (!ENABLE_THREADED_COMPILER &&
500 ((ENABLE_FIRST_PASS && likely(!should_recompile)) ||
501 unlikely(block->flags & BLOCK_NEVER_COMPILE)))
502 pc = lightrec_emulate_block(block, pc);
503
504 if (likely(!(block->flags & BLOCK_NEVER_COMPILE))) {
505 /* Then compile it using the profiled data */
506 if (ENABLE_THREADED_COMPILER)
507 lightrec_recompiler_add(state->rec, block);
508 else
509 lightrec_compile_block(block);
510 }
511
512 if (state->exit_flags != LIGHTREC_EXIT_NORMAL ||
513 state->current_cycle >= state->target_cycle) {
514 state->next_pc = pc;
515 return NULL;
516 }
517 }
518}
519
520static s32 c_generic_function_wrapper(struct lightrec_state *state,
521 s32 cycles_delta,
522 void (*f)(struct lightrec_state *,
523 struct opcode *,
524 struct block *),
525 struct opcode *op, struct block *block)
526{
527 state->current_cycle = state->target_cycle - cycles_delta;
528
529 (*f)(state, op, block);
530
531 return state->target_cycle - state->current_cycle;
532}
533
534static s32 c_function_wrapper(struct lightrec_state *state, s32 cycles_delta,
535 void (*f)(struct lightrec_state *, union code),
536 union code op)
537{
538 state->current_cycle = state->target_cycle - cycles_delta;
539
540 (*f)(state, op);
541
542 return state->target_cycle - state->current_cycle;
543}
544
545static struct block * generate_wrapper(struct lightrec_state *state,
546 void *f, bool generic)
547{
548 struct block *block;
549 jit_state_t *_jit;
550 unsigned int i;
551 int stack_ptr;
552 jit_word_t code_size;
553 jit_node_t *to_tramp, *to_fn_epilog;
554
555 block = lightrec_malloc(state, MEM_FOR_IR, sizeof(*block));
556 if (!block)
557 goto err_no_mem;
558
559 _jit = jit_new_state();
560 if (!_jit)
561 goto err_free_block;
562
563 jit_name("RW wrapper");
564 jit_note(__FILE__, __LINE__);
565
566 /* Wrapper entry point */
567 jit_prolog();
568
569 stack_ptr = jit_allocai(sizeof(uintptr_t) * NUM_TEMPS);
570
571 for (i = 0; i < NUM_TEMPS; i++)
572 jit_stxi(stack_ptr + i * sizeof(uintptr_t), JIT_FP, JIT_R(i));
573
574 /* Jump to the trampoline */
575 to_tramp = jit_jmpi();
576
577 /* The trampoline will jump back here */
578 to_fn_epilog = jit_label();
579
580 for (i = 0; i < NUM_TEMPS; i++)
581 jit_ldxi(JIT_R(i), JIT_FP, stack_ptr + i * sizeof(uintptr_t));
582
583 jit_ret();
584 jit_epilog();
585
586 /* Trampoline entry point.
587 * The sole purpose of the trampoline is to cheese Lightning not to
588 * save/restore the callee-saved register LIGHTREC_REG_CYCLE, since we
589 * do want to return to the caller with this register modified. */
590 jit_prolog();
591 jit_tramp(256);
592 jit_patch(to_tramp);
593
594 jit_prepare();
595 jit_pushargr(LIGHTREC_REG_STATE);
596 jit_pushargr(LIGHTREC_REG_CYCLE);
597 jit_pushargi((uintptr_t)f);
598 jit_pushargr(JIT_R0);
599 if (generic) {
600 jit_pushargr(JIT_R1);
601 jit_finishi(c_generic_function_wrapper);
602 } else {
603 jit_finishi(c_function_wrapper);
604 }
605
606#if __WORDSIZE == 64
607 jit_retval_i(LIGHTREC_REG_CYCLE);
608#else
609 jit_retval(LIGHTREC_REG_CYCLE);
610#endif
611
612 jit_patch_at(jit_jmpi(), to_fn_epilog);
613 jit_epilog();
614
615 block->state = state;
616 block->_jit = _jit;
617 block->function = jit_emit();
618 block->opcode_list = NULL;
619 block->flags = 0;
620 block->nb_ops = 0;
621
622 jit_get_code(&code_size);
623 lightrec_register(MEM_FOR_CODE, code_size);
624
625 block->code_size = code_size;
626
627 if (ENABLE_DISASSEMBLER) {
628 pr_debug("Wrapper block:\n");
629 jit_disassemble();
630 }
631
632 jit_clear_state();
633 return block;
634
635err_free_block:
636 lightrec_free(state, MEM_FOR_IR, sizeof(*block), block);
637err_no_mem:
638 pr_err("Unable to compile wrapper: Out of memory\n");
639 return NULL;
640}
641
642static struct block * generate_dispatcher(struct lightrec_state *state)
643{
644 struct block *block;
645 jit_state_t *_jit;
646 jit_node_t *to_end, *to_end2, *to_c, *loop, *addr, *addr2;
647 unsigned int i;
648 u32 offset, ram_len;
649 jit_word_t code_size;
650
651 block = lightrec_malloc(state, MEM_FOR_IR, sizeof(*block));
652 if (!block)
653 goto err_no_mem;
654
655 _jit = jit_new_state();
656 if (!_jit)
657 goto err_free_block;
658
659 jit_name("dispatcher");
660 jit_note(__FILE__, __LINE__);
661
662 jit_prolog();
663 jit_frame(256);
664
665 jit_getarg(JIT_R0, jit_arg());
666#if __WORDSIZE == 64
667 jit_getarg_i(LIGHTREC_REG_CYCLE, jit_arg());
668#else
669 jit_getarg(LIGHTREC_REG_CYCLE, jit_arg());
670#endif
671
672 /* Force all callee-saved registers to be pushed on the stack */
673 for (i = 0; i < NUM_REGS; i++)
674 jit_movr(JIT_V(i), JIT_V(i));
675
676 /* Pass lightrec_state structure to blocks, using the last callee-saved
677 * register that Lightning provides */
678 jit_movi(LIGHTREC_REG_STATE, (intptr_t) state);
679
680 loop = jit_label();
681
682 /* Call the block's code */
683 jit_jmpr(JIT_R0);
684
685 /* The block will jump here, with the number of cycles remaining in
686 * LIGHTREC_REG_CYCLE */
687 addr2 = jit_indirect();
688
689 /* Jump to end if state->target_cycle < state->current_cycle */
690 to_end = jit_blei(LIGHTREC_REG_CYCLE, 0);
691
692 /* Convert next PC to KUNSEG and avoid mirrors */
693 ram_len = state->maps[PSX_MAP_KERNEL_USER_RAM].length;
694 jit_andi(JIT_R0, JIT_V0, 0x10000000 | (ram_len - 1));
695 to_c = jit_bgei(JIT_R0, ram_len);
696
697 /* Fast path: code is running from RAM, use the code LUT */
698#if __WORDSIZE == 64
699 jit_lshi(JIT_R0, JIT_R0, 1);
700#endif
701 jit_addr(JIT_R0, JIT_R0, LIGHTREC_REG_STATE);
702 jit_ldxi(JIT_R0, JIT_R0, offsetof(struct lightrec_state, code_lut));
703
704 /* If we get non-NULL, loop */
705 jit_patch_at(jit_bnei(JIT_R0, 0), loop);
706
707 /* Slow path: call C function get_next_block_func() */
708 jit_patch(to_c);
709
710 if (ENABLE_FIRST_PASS) {
711 /* We may call the interpreter - update state->current_cycle */
712 jit_ldxi_i(JIT_R2, LIGHTREC_REG_STATE,
713 offsetof(struct lightrec_state, target_cycle));
714 jit_subr(JIT_R1, JIT_R2, LIGHTREC_REG_CYCLE);
715 jit_stxi_i(offsetof(struct lightrec_state, current_cycle),
716 LIGHTREC_REG_STATE, JIT_R1);
717 }
718
719 /* The code LUT will be set to this address when the block at the target
720 * PC has been preprocessed but not yet compiled by the threaded
721 * recompiler */
722 addr = jit_indirect();
723
724 /* Get the next block */
725 jit_prepare();
726 jit_pushargr(LIGHTREC_REG_STATE);
727 jit_pushargr(JIT_V0);
728 jit_finishi(&get_next_block_func);
729 jit_retval(JIT_R0);
730
731 if (ENABLE_FIRST_PASS) {
732 /* The interpreter may have updated state->current_cycle and
733 * state->target_cycle - recalc the delta */
734 jit_ldxi_i(JIT_R1, LIGHTREC_REG_STATE,
735 offsetof(struct lightrec_state, current_cycle));
736 jit_ldxi_i(JIT_R2, LIGHTREC_REG_STATE,
737 offsetof(struct lightrec_state, target_cycle));
738 jit_subr(LIGHTREC_REG_CYCLE, JIT_R2, JIT_R1);
739 }
740
741 /* If we get non-NULL, loop */
742 jit_patch_at(jit_bnei(JIT_R0, 0), loop);
743
744 to_end2 = jit_jmpi();
745
746 /* When exiting, the recompiled code will jump to that address */
747 jit_note(__FILE__, __LINE__);
748 jit_patch(to_end);
749
750 /* Store back the next_pc to the lightrec_state structure */
751 offset = offsetof(struct lightrec_state, next_pc);
752 jit_stxi_i(offset, LIGHTREC_REG_STATE, JIT_V0);
753
754 jit_patch(to_end2);
755
756 jit_retr(LIGHTREC_REG_CYCLE);
757 jit_epilog();
758
759 block->state = state;
760 block->_jit = _jit;
761 block->function = jit_emit();
762 block->opcode_list = NULL;
763 block->flags = 0;
764 block->nb_ops = 0;
765
766 jit_get_code(&code_size);
767 lightrec_register(MEM_FOR_CODE, code_size);
768
769 block->code_size = code_size;
770
771 state->eob_wrapper_func = jit_address(addr2);
772 state->get_next_block = jit_address(addr);
773
774 if (ENABLE_DISASSEMBLER) {
775 pr_debug("Dispatcher block:\n");
776 jit_disassemble();
777 }
778
779 /* We're done! */
780 jit_clear_state();
781 return block;
782
783err_free_block:
784 lightrec_free(state, MEM_FOR_IR, sizeof(*block), block);
785err_no_mem:
786 pr_err("Unable to compile dispatcher: Out of memory\n");
787 return NULL;
788}
789
790union code lightrec_read_opcode(struct lightrec_state *state, u32 pc)
791{
792 u32 addr, kunseg_pc = kunseg(pc);
793 const u32 *code;
794 const struct lightrec_mem_map *map = lightrec_get_map(state, kunseg_pc);
795
796 addr = kunseg_pc - map->pc;
797
798 while (map->mirror_of)
799 map = map->mirror_of;
800
801 code = map->address + addr;
802
803 return (union code) *code;
804}
805
806static struct block * lightrec_precompile_block(struct lightrec_state *state,
807 u32 pc)
808{
809 struct opcode *list;
810 struct block *block;
811 const u32 *code;
812 u32 addr, kunseg_pc = kunseg(pc);
813 const struct lightrec_mem_map *map = lightrec_get_map(state, kunseg_pc);
814 unsigned int length;
815
816 if (!map)
817 return NULL;
818
819 addr = kunseg_pc - map->pc;
820
821 while (map->mirror_of)
822 map = map->mirror_of;
823
824 code = map->address + addr;
825
826 block = lightrec_malloc(state, MEM_FOR_IR, sizeof(*block));
827 if (!block) {
828 pr_err("Unable to recompile block: Out of memory\n");
829 return NULL;
830 }
831
832 list = lightrec_disassemble(state, code, &length);
833 if (!list) {
834 lightrec_free(state, MEM_FOR_IR, sizeof(*block), block);
835 return NULL;
836 }
837
838 block->pc = pc;
839 block->state = state;
840 block->_jit = NULL;
841 block->function = NULL;
842 block->opcode_list = list;
843 block->map = map;
844 block->next = NULL;
845 block->flags = 0;
846 block->code_size = 0;
847#if ENABLE_THREADED_COMPILER
848 block->op_list_freed = (atomic_flag)ATOMIC_FLAG_INIT;
849#endif
850 block->nb_ops = length / sizeof(u32);
851
852 lightrec_optimize(block);
853
854 length = block->nb_ops * sizeof(u32);
855
856 lightrec_register(MEM_FOR_MIPS_CODE, length);
857
858 if (ENABLE_DISASSEMBLER) {
859 pr_debug("Disassembled block at PC: 0x%x\n", block->pc);
860 lightrec_print_disassembly(block, code, length);
861 }
862
863 pr_debug("Block size: %lu opcodes\n", block->nb_ops);
864
865 /* If the first opcode is an 'impossible' branch, never compile the
866 * block */
867 if (list->flags & LIGHTREC_EMULATE_BRANCH)
868 block->flags |= BLOCK_NEVER_COMPILE;
869
870 block->hash = lightrec_calculate_block_hash(block);
871
a59e5536 872 pr_debug("Recompile count: %u\n", state->nb_precompile++);
873
d16005f8
PC
874 return block;
875}
876
877static bool lightrec_block_is_fully_tagged(struct block *block)
878{
879 struct opcode *op;
880
881 for (op = block->opcode_list; op; op = op->next) {
882 /* Verify that all load/stores of the opcode list
883 * Check all loads/stores of the opcode list and mark the
884 * block as fully compiled if they all have been tagged. */
885 switch (op->c.i.op) {
886 case OP_LB:
887 case OP_LH:
888 case OP_LWL:
889 case OP_LW:
890 case OP_LBU:
891 case OP_LHU:
892 case OP_LWR:
893 case OP_SB:
894 case OP_SH:
895 case OP_SWL:
896 case OP_SW:
897 case OP_SWR:
898 case OP_LWC2:
899 case OP_SWC2:
900 if (!(op->flags & (LIGHTREC_DIRECT_IO |
901 LIGHTREC_HW_IO)))
902 return false;
903 default: /* fall-through */
904 continue;
905 }
906 }
907
908 return true;
909}
910
a59e5536 911static void lightrec_reap_block(void *data)
912{
913 struct block *block = data;
914
915 pr_debug("Reap dead block at PC 0x%08x\n", block->pc);
916 lightrec_free_block(block);
917}
918
919static void lightrec_reap_jit(void *data)
920{
921 _jit_destroy_state(data);
922}
923
d16005f8
PC
924int lightrec_compile_block(struct block *block)
925{
926 struct lightrec_state *state = block->state;
a59e5536 927 struct lightrec_branch_target *target;
d16005f8 928 bool op_list_freed = false, fully_tagged = false;
a59e5536 929 struct block *block2;
d16005f8 930 struct opcode *elm;
a59e5536 931 jit_state_t *_jit, *oldjit;
d16005f8
PC
932 jit_node_t *start_of_block;
933 bool skip_next = false;
934 jit_word_t code_size;
935 unsigned int i, j;
a59e5536 936 u32 next_pc, offset;
d16005f8
PC
937
938 fully_tagged = lightrec_block_is_fully_tagged(block);
939 if (fully_tagged)
940 block->flags |= BLOCK_FULLY_TAGGED;
941
942 _jit = jit_new_state();
943 if (!_jit)
944 return -ENOMEM;
945
a59e5536 946 oldjit = block->_jit;
d16005f8
PC
947 block->_jit = _jit;
948
949 lightrec_regcache_reset(state->reg_cache);
950 state->cycles = 0;
951 state->nb_branches = 0;
952 state->nb_local_branches = 0;
953 state->nb_targets = 0;
954
955 jit_prolog();
956 jit_tramp(256);
957
958 start_of_block = jit_label();
959
960 for (elm = block->opcode_list; elm; elm = elm->next) {
961 next_pc = block->pc + elm->offset * sizeof(u32);
962
963 if (skip_next) {
964 skip_next = false;
965 continue;
966 }
967
968 state->cycles += lightrec_cycles_of_opcode(elm->c);
969
970 if (elm->flags & LIGHTREC_EMULATE_BRANCH) {
971 pr_debug("Branch at offset 0x%x will be emulated\n",
972 elm->offset << 2);
973 lightrec_emit_eob(block, elm, next_pc);
974 skip_next = !(elm->flags & LIGHTREC_NO_DS);
975 } else if (elm->opcode) {
976 lightrec_rec_opcode(block, elm, next_pc);
977 skip_next = has_delay_slot(elm->c) &&
978 !(elm->flags & LIGHTREC_NO_DS);
979#if _WIN32
980 /* FIXME: GNU Lightning on Windows seems to use our
981 * mapped registers as temporaries. Until the actual bug
982 * is found and fixed, unconditionally mark our
983 * registers as live here. */
984 lightrec_regcache_mark_live(state->reg_cache, _jit);
985#endif
986 }
987 }
988
989 for (i = 0; i < state->nb_branches; i++)
990 jit_patch(state->branches[i]);
991
992 for (i = 0; i < state->nb_local_branches; i++) {
993 struct lightrec_branch *branch = &state->local_branches[i];
994
995 pr_debug("Patch local branch to offset 0x%x\n",
996 branch->target << 2);
997
998 if (branch->target == 0) {
999 jit_patch_at(branch->branch, start_of_block);
1000 continue;
1001 }
1002
1003 for (j = 0; j < state->nb_targets; j++) {
1004 if (state->targets[j].offset == branch->target) {
1005 jit_patch_at(branch->branch,
1006 state->targets[j].label);
1007 break;
1008 }
1009 }
1010
1011 if (j == state->nb_targets)
1012 pr_err("Unable to find branch target\n");
1013 }
1014
1015 jit_ldxi(JIT_R0, LIGHTREC_REG_STATE,
1016 offsetof(struct lightrec_state, eob_wrapper_func));
1017
1018 jit_jmpr(JIT_R0);
1019
1020 jit_ret();
1021 jit_epilog();
1022
1023 block->function = jit_emit();
a59e5536 1024 block->flags &= ~BLOCK_SHOULD_RECOMPILE;
d16005f8
PC
1025
1026 /* Add compiled function to the LUT */
1027 state->code_lut[lut_offset(block->pc)] = block->function;
1028
a59e5536 1029 /* Fill code LUT with the block's entry points */
1030 for (i = 0; i < state->nb_targets; i++) {
1031 target = &state->targets[i];
1032
1033 if (target->offset) {
1034 offset = lut_offset(block->pc) + target->offset;
1035 state->code_lut[offset] = jit_address(target->label);
1036 }
1037 }
1038
1039 /* Detect old blocks that have been covered by the new one */
1040 for (i = 0; i < state->nb_targets; i++) {
1041 target = &state->targets[i];
1042
1043 if (!target->offset)
1044 continue;
1045
1046 offset = block->pc + target->offset * sizeof(u32);
1047 block2 = lightrec_find_block(state->block_cache, offset);
1048 if (block2) {
1049 /* No need to check if block2 is compilable - it must
1050 * be, otherwise block wouldn't be compilable either */
1051
1052 block2->flags |= BLOCK_IS_DEAD;
1053
1054 pr_debug("Reap block 0x%08x as it's covered by block "
1055 "0x%08x\n", block2->pc, block->pc);
1056
1057 lightrec_unregister_block(state->block_cache, block2);
1058
1059 if (ENABLE_THREADED_COMPILER) {
1060 lightrec_recompiler_remove(state->rec, block2);
1061 lightrec_reaper_add(state->reaper,
1062 lightrec_reap_block,
1063 block2);
1064 } else {
1065 lightrec_free_block(block2);
1066 }
1067 }
1068 }
1069
d16005f8
PC
1070 jit_get_code(&code_size);
1071 lightrec_register(MEM_FOR_CODE, code_size);
1072
1073 block->code_size = code_size;
1074
1075 if (ENABLE_DISASSEMBLER) {
1076 pr_debug("Compiling block at PC: 0x%x\n", block->pc);
1077 jit_disassemble();
1078 }
1079
1080 jit_clear_state();
1081
1082#if ENABLE_THREADED_COMPILER
1083 if (fully_tagged)
1084 op_list_freed = atomic_flag_test_and_set(&block->op_list_freed);
1085#endif
1086 if (fully_tagged && !op_list_freed) {
1087 pr_debug("Block PC 0x%08x is fully tagged"
1088 " - free opcode list\n", block->pc);
1089 lightrec_free_opcode_list(state, block->opcode_list);
1090 block->opcode_list = NULL;
1091 }
1092
a59e5536 1093 if (oldjit) {
1094 pr_debug("Block 0x%08x recompiled, reaping old jit context.\n",
1095 block->pc);
1096
1097 if (ENABLE_THREADED_COMPILER)
1098 lightrec_reaper_add(state->reaper,
1099 lightrec_reap_jit, oldjit);
1100 else
1101 _jit_destroy_state(oldjit);
1102 }
1103
d16005f8
PC
1104 return 0;
1105}
1106
1107u32 lightrec_execute(struct lightrec_state *state, u32 pc, u32 target_cycle)
1108{
1109 s32 (*func)(void *, s32) = (void *)state->dispatcher->function;
1110 void *block_trace;
1111 s32 cycles_delta;
1112
1113 state->exit_flags = LIGHTREC_EXIT_NORMAL;
1114
1115 /* Handle the cycle counter overflowing */
1116 if (unlikely(target_cycle < state->current_cycle))
1117 target_cycle = UINT_MAX;
1118
1119 state->target_cycle = target_cycle;
1120
1121 block_trace = get_next_block_func(state, pc);
1122 if (block_trace) {
1123 cycles_delta = state->target_cycle - state->current_cycle;
1124
1125 cycles_delta = (*func)(block_trace, cycles_delta);
1126
1127 state->current_cycle = state->target_cycle - cycles_delta;
1128 }
1129
a59e5536 1130 if (ENABLE_THREADED_COMPILER)
1131 lightrec_reaper_reap(state->reaper);
1132
d16005f8
PC
1133 return state->next_pc;
1134}
1135
1136u32 lightrec_execute_one(struct lightrec_state *state, u32 pc)
1137{
1138 return lightrec_execute(state, pc, state->current_cycle);
1139}
1140
1141u32 lightrec_run_interpreter(struct lightrec_state *state, u32 pc)
1142{
1143 struct block *block = lightrec_get_block(state, pc);
1144 if (!block)
1145 return 0;
1146
1147 state->exit_flags = LIGHTREC_EXIT_NORMAL;
1148
1149 return lightrec_emulate_block(block, pc);
1150}
1151
1152void lightrec_free_block(struct block *block)
1153{
1154 lightrec_unregister(MEM_FOR_MIPS_CODE, block->nb_ops * sizeof(u32));
1155 if (block->opcode_list)
1156 lightrec_free_opcode_list(block->state, block->opcode_list);
1157 if (block->_jit)
1158 _jit_destroy_state(block->_jit);
1159 lightrec_unregister(MEM_FOR_CODE, block->code_size);
1160 lightrec_free(block->state, MEM_FOR_IR, sizeof(*block), block);
1161}
1162
1163struct lightrec_state * lightrec_init(char *argv0,
1164 const struct lightrec_mem_map *map,
1165 size_t nb,
1166 const struct lightrec_ops *ops)
1167{
1168 struct lightrec_state *state;
1169
1170 /* Sanity-check ops */
1171 if (!ops ||
1172 !ops->cop0_ops.mfc || !ops->cop0_ops.cfc || !ops->cop0_ops.mtc ||
1173 !ops->cop0_ops.ctc || !ops->cop0_ops.op ||
1174 !ops->cop2_ops.mfc || !ops->cop2_ops.cfc || !ops->cop2_ops.mtc ||
1175 !ops->cop2_ops.ctc || !ops->cop2_ops.op) {
1176 pr_err("Missing callbacks in lightrec_ops structure\n");
1177 return NULL;
1178 }
1179
1180 init_jit(argv0);
1181
1182 state = calloc(1, sizeof(*state) +
1183 sizeof(*state->code_lut) * CODE_LUT_SIZE);
1184 if (!state)
1185 goto err_finish_jit;
1186
1187 lightrec_register(MEM_FOR_LIGHTREC, sizeof(*state) +
1188 sizeof(*state->code_lut) * CODE_LUT_SIZE);
1189
1190#if ENABLE_TINYMM
1191 state->tinymm = tinymm_init(malloc, free, 4096);
1192 if (!state->tinymm)
1193 goto err_free_state;
1194#endif
1195
1196 state->block_cache = lightrec_blockcache_init(state);
1197 if (!state->block_cache)
1198 goto err_free_tinymm;
1199
1200 state->reg_cache = lightrec_regcache_init(state);
1201 if (!state->reg_cache)
1202 goto err_free_block_cache;
1203
1204 if (ENABLE_THREADED_COMPILER) {
1205 state->rec = lightrec_recompiler_init(state);
1206 if (!state->rec)
1207 goto err_free_reg_cache;
a59e5536 1208
1209 state->reaper = lightrec_reaper_init(state);
1210 if (!state->reaper)
1211 goto err_free_recompiler;
d16005f8
PC
1212 }
1213
1214 state->nb_maps = nb;
1215 state->maps = map;
1216
1217 memcpy(&state->ops, ops, sizeof(*ops));
1218
1219 state->dispatcher = generate_dispatcher(state);
1220 if (!state->dispatcher)
a59e5536 1221 goto err_free_reaper;
d16005f8
PC
1222
1223 state->rw_generic_wrapper = generate_wrapper(state,
1224 lightrec_rw_generic_cb,
1225 true);
1226 if (!state->rw_generic_wrapper)
1227 goto err_free_dispatcher;
1228
1229 state->rw_wrapper = generate_wrapper(state, lightrec_rw_cb, false);
1230 if (!state->rw_wrapper)
1231 goto err_free_generic_rw_wrapper;
1232
1233 state->mfc_wrapper = generate_wrapper(state, lightrec_mfc_cb, false);
1234 if (!state->mfc_wrapper)
1235 goto err_free_rw_wrapper;
1236
1237 state->mtc_wrapper = generate_wrapper(state, lightrec_mtc_cb, false);
1238 if (!state->mtc_wrapper)
1239 goto err_free_mfc_wrapper;
1240
1241 state->rfe_wrapper = generate_wrapper(state, lightrec_rfe_cb, false);
1242 if (!state->rfe_wrapper)
1243 goto err_free_mtc_wrapper;
1244
1245 state->cp_wrapper = generate_wrapper(state, lightrec_cp_cb, false);
1246 if (!state->cp_wrapper)
1247 goto err_free_rfe_wrapper;
1248
1249 state->syscall_wrapper = generate_wrapper(state, lightrec_syscall_cb,
1250 false);
1251 if (!state->syscall_wrapper)
1252 goto err_free_cp_wrapper;
1253
1254 state->break_wrapper = generate_wrapper(state, lightrec_break_cb,
1255 false);
1256 if (!state->break_wrapper)
1257 goto err_free_syscall_wrapper;
1258
1259 state->rw_generic_func = state->rw_generic_wrapper->function;
1260 state->rw_func = state->rw_wrapper->function;
1261 state->mfc_func = state->mfc_wrapper->function;
1262 state->mtc_func = state->mtc_wrapper->function;
1263 state->rfe_func = state->rfe_wrapper->function;
1264 state->cp_func = state->cp_wrapper->function;
1265 state->syscall_func = state->syscall_wrapper->function;
1266 state->break_func = state->break_wrapper->function;
1267
1268 map = &state->maps[PSX_MAP_BIOS];
1269 state->offset_bios = (uintptr_t)map->address - map->pc;
1270
1271 map = &state->maps[PSX_MAP_SCRATCH_PAD];
1272 state->offset_scratch = (uintptr_t)map->address - map->pc;
1273
1274 map = &state->maps[PSX_MAP_KERNEL_USER_RAM];
1275 state->offset_ram = (uintptr_t)map->address - map->pc;
1276
1277 if (state->maps[PSX_MAP_MIRROR1].address == map->address + 0x200000 &&
1278 state->maps[PSX_MAP_MIRROR2].address == map->address + 0x400000 &&
1279 state->maps[PSX_MAP_MIRROR3].address == map->address + 0x600000)
1280 state->mirrors_mapped = true;
1281
1282 return state;
1283
1284err_free_syscall_wrapper:
1285 lightrec_free_block(state->syscall_wrapper);
1286err_free_cp_wrapper:
1287 lightrec_free_block(state->cp_wrapper);
1288err_free_rfe_wrapper:
1289 lightrec_free_block(state->rfe_wrapper);
1290err_free_mtc_wrapper:
1291 lightrec_free_block(state->mtc_wrapper);
1292err_free_mfc_wrapper:
1293 lightrec_free_block(state->mfc_wrapper);
1294err_free_rw_wrapper:
1295 lightrec_free_block(state->rw_wrapper);
1296err_free_generic_rw_wrapper:
1297 lightrec_free_block(state->rw_generic_wrapper);
1298err_free_dispatcher:
1299 lightrec_free_block(state->dispatcher);
a59e5536 1300err_free_reaper:
1301 if (ENABLE_THREADED_COMPILER)
1302 lightrec_reaper_destroy(state->reaper);
d16005f8
PC
1303err_free_recompiler:
1304 if (ENABLE_THREADED_COMPILER)
1305 lightrec_free_recompiler(state->rec);
1306err_free_reg_cache:
1307 lightrec_free_regcache(state->reg_cache);
1308err_free_block_cache:
1309 lightrec_free_block_cache(state->block_cache);
1310err_free_tinymm:
1311#if ENABLE_TINYMM
1312 tinymm_shutdown(state->tinymm);
1313err_free_state:
1314#endif
1315 lightrec_unregister(MEM_FOR_LIGHTREC, sizeof(*state) +
1316 sizeof(*state->code_lut) * CODE_LUT_SIZE);
1317 free(state);
1318err_finish_jit:
1319 finish_jit();
1320 return NULL;
1321}
1322
1323void lightrec_destroy(struct lightrec_state *state)
1324{
a59e5536 1325 if (ENABLE_THREADED_COMPILER) {
d16005f8 1326 lightrec_free_recompiler(state->rec);
a59e5536 1327 lightrec_reaper_destroy(state->reaper);
1328 }
d16005f8
PC
1329
1330 lightrec_free_regcache(state->reg_cache);
1331 lightrec_free_block_cache(state->block_cache);
1332 lightrec_free_block(state->dispatcher);
1333 lightrec_free_block(state->rw_generic_wrapper);
1334 lightrec_free_block(state->rw_wrapper);
1335 lightrec_free_block(state->mfc_wrapper);
1336 lightrec_free_block(state->mtc_wrapper);
1337 lightrec_free_block(state->rfe_wrapper);
1338 lightrec_free_block(state->cp_wrapper);
1339 lightrec_free_block(state->syscall_wrapper);
1340 lightrec_free_block(state->break_wrapper);
1341 finish_jit();
1342
1343#if ENABLE_TINYMM
1344 tinymm_shutdown(state->tinymm);
1345#endif
1346 lightrec_unregister(MEM_FOR_LIGHTREC, sizeof(*state) +
1347 sizeof(*state->code_lut) * CODE_LUT_SIZE);
1348 free(state);
1349}
1350
1351void lightrec_invalidate(struct lightrec_state *state, u32 addr, u32 len)
1352{
1353 u32 kaddr = kunseg(addr & ~0x3);
1354 const struct lightrec_mem_map *map = lightrec_get_map(state, kaddr);
1355
1356 if (map) {
1357 while (map->mirror_of)
1358 map = map->mirror_of;
1359
1360 if (map != &state->maps[PSX_MAP_KERNEL_USER_RAM])
1361 return;
1362
1363 /* Handle mirrors */
1364 kaddr &= (state->maps[PSX_MAP_KERNEL_USER_RAM].length - 1);
1365
1366 for (; len > 4; len -= 4, kaddr += 4)
1367 lightrec_invalidate_map(state, map, kaddr);
1368
1369 lightrec_invalidate_map(state, map, kaddr);
1370 }
1371}
1372
1373void lightrec_invalidate_all(struct lightrec_state *state)
1374{
1375 memset(state->code_lut, 0, sizeof(*state->code_lut) * CODE_LUT_SIZE);
1376}
1377
1378void lightrec_set_invalidate_mode(struct lightrec_state *state, bool dma_only)
1379{
1380 if (state->invalidate_from_dma_only != dma_only)
1381 lightrec_invalidate_all(state);
1382
1383 state->invalidate_from_dma_only = dma_only;
1384}
1385
1386void lightrec_set_exit_flags(struct lightrec_state *state, u32 flags)
1387{
1388 if (flags != LIGHTREC_EXIT_NORMAL) {
1389 state->exit_flags |= flags;
1390 state->target_cycle = state->current_cycle;
1391 }
1392}
1393
1394u32 lightrec_exit_flags(struct lightrec_state *state)
1395{
1396 return state->exit_flags;
1397}
1398
1399void lightrec_dump_registers(struct lightrec_state *state, u32 regs[34])
1400{
1401 memcpy(regs, state->native_reg_cache, sizeof(state->native_reg_cache));
1402}
1403
1404void lightrec_restore_registers(struct lightrec_state *state, u32 regs[34])
1405{
1406 memcpy(state->native_reg_cache, regs, sizeof(state->native_reg_cache));
1407}
1408
1409u32 lightrec_current_cycle_count(const struct lightrec_state *state)
1410{
1411 return state->current_cycle;
1412}
1413
1414void lightrec_reset_cycle_count(struct lightrec_state *state, u32 cycles)
1415{
1416 state->current_cycle = cycles;
1417
1418 if (state->target_cycle < cycles)
1419 state->target_cycle = cycles;
1420}
1421
1422void lightrec_set_target_cycle_count(struct lightrec_state *state, u32 cycles)
1423{
1424 if (state->exit_flags == LIGHTREC_EXIT_NORMAL) {
1425 if (cycles < state->current_cycle)
1426 cycles = state->current_cycle;
1427
1428 state->target_cycle = cycles;
1429 }
1430}