Update lightrec 20220716 (#672)
[pcsx_rearmed.git] / deps / lightrec / interpreter.c
CommitLineData
98fa08a5 1// SPDX-License-Identifier: LGPL-2.1-or-later
d16005f8 2/*
98fa08a5 3 * Copyright (C) 2019-2021 Paul Cercueil <paul@crapouillou.net>
d16005f8
PC
4 */
5
6#include "disassembler.h"
7#include "interpreter.h"
8#include "lightrec-private.h"
9#include "optimizer.h"
10#include "regcache.h"
11
12#include <stdbool.h>
13
14struct interpreter;
15
16static u32 int_CP0(struct interpreter *inter);
17static u32 int_CP2(struct interpreter *inter);
18static u32 int_SPECIAL(struct interpreter *inter);
19static u32 int_REGIMM(struct interpreter *inter);
20static u32 int_branch(struct interpreter *inter, u32 pc,
21 union code code, bool branch);
22
23typedef u32 (*lightrec_int_func_t)(struct interpreter *inter);
24
25static const lightrec_int_func_t int_standard[64];
26
27struct interpreter {
28 struct lightrec_state *state;
29 struct block *block;
30 struct opcode *op;
31 u32 cycles;
32 bool delay_slot;
98fa08a5 33 u16 offset;
d16005f8
PC
34};
35
98fa08a5
PC
36static u32 int_get_branch_pc(const struct interpreter *inter)
37{
38 return get_branch_pc(inter->block, inter->offset, 0);
39}
40
41static inline u32 int_get_ds_pc(const struct interpreter *inter, s16 imm)
42{
43 return get_ds_pc(inter->block, inter->offset, imm);
44}
45
46static inline struct opcode *next_op(const struct interpreter *inter)
47{
48 return &inter->block->opcode_list[inter->offset + 1];
49}
50
d16005f8
PC
51static inline u32 execute(lightrec_int_func_t func, struct interpreter *inter)
52{
53 return (*func)(inter);
54}
55
98fa08a5
PC
56static inline u32 lightrec_int_op(struct interpreter *inter)
57{
58 return execute(int_standard[inter->op->i.op], inter);
59}
60
d16005f8
PC
61static inline u32 jump_skip(struct interpreter *inter)
62{
98fa08a5
PC
63 inter->op = next_op(inter);
64 inter->offset++;
d16005f8 65
03535202 66 if (op_flag_sync(inter->op->flags)) {
98fa08a5
PC
67 inter->state->current_cycle += inter->cycles;
68 inter->cycles = 0;
69 }
70
71 return lightrec_int_op(inter);
d16005f8
PC
72}
73
74static inline u32 jump_next(struct interpreter *inter)
75{
76 inter->cycles += lightrec_cycles_of_opcode(inter->op->c);
77
78 if (unlikely(inter->delay_slot))
79 return 0;
80
81 return jump_skip(inter);
82}
83
84static inline u32 jump_after_branch(struct interpreter *inter)
85{
86 inter->cycles += lightrec_cycles_of_opcode(inter->op->c);
87
88 if (unlikely(inter->delay_slot))
89 return 0;
90
98fa08a5
PC
91 inter->op = next_op(inter);
92 inter->offset++;
d16005f8
PC
93
94 return jump_skip(inter);
95}
96
97static void update_cycles_before_branch(struct interpreter *inter)
98{
99 u32 cycles;
100
101 if (!inter->delay_slot) {
102 cycles = lightrec_cycles_of_opcode(inter->op->c);
103
03535202
PC
104 if (!op_flag_no_ds(inter->op->flags) &&
105 has_delay_slot(inter->op->c))
98fa08a5 106 cycles += lightrec_cycles_of_opcode(next_op(inter)->c);
d16005f8
PC
107
108 inter->cycles += cycles;
109 inter->state->current_cycle += inter->cycles;
110 inter->cycles = -cycles;
111 }
112}
113
114static bool is_branch_taken(const u32 *reg_cache, union code op)
115{
116 switch (op.i.op) {
117 case OP_SPECIAL:
118 return op.r.op == OP_SPECIAL_JR || op.r.op == OP_SPECIAL_JALR;
119 case OP_J:
120 case OP_JAL:
121 return true;
122 case OP_BEQ:
d16005f8
PC
123 return reg_cache[op.r.rs] == reg_cache[op.r.rt];
124 case OP_BNE:
d16005f8
PC
125 return reg_cache[op.r.rs] != reg_cache[op.r.rt];
126 case OP_REGIMM:
127 switch (op.r.rt) {
128 case OP_REGIMM_BLTZ:
129 case OP_REGIMM_BLTZAL:
130 return (s32)reg_cache[op.r.rs] < 0;
131 case OP_REGIMM_BGEZ:
132 case OP_REGIMM_BGEZAL:
133 return (s32)reg_cache[op.r.rs] >= 0;
134 }
135 default:
136 break;
137 }
138
139 return false;
140}
141
142static u32 int_delay_slot(struct interpreter *inter, u32 pc, bool branch)
143{
144 struct lightrec_state *state = inter->state;
98fa08a5
PC
145 u32 *reg_cache = state->regs.gpr;
146 struct opcode new_op, *op = next_op(inter);
d16005f8
PC
147 union code op_next;
148 struct interpreter inter2 = {
149 .state = state,
150 .cycles = inter->cycles,
151 .delay_slot = true,
152 .block = NULL,
153 };
154 bool run_first_op = false, dummy_ld = false, save_rs = false,
155 load_in_ds, branch_in_ds = false, branch_at_addr = false,
156 branch_taken;
157 u32 old_rs, new_rs, new_rt;
158 u32 next_pc, ds_next_pc;
159 u32 cause, epc;
160
161 if (op->i.op == OP_CP0 && op->r.rs == OP_CP0_RFE) {
162 /* When an IRQ happens, the PSX exception handlers (when done)
163 * will jump back to the instruction that was executed right
164 * before the IRQ, unless it was a GTE opcode; in that case, it
165 * jumps to the instruction right after.
166 * Since we will never handle the IRQ right after a GTE opcode,
167 * but on branch boundaries, we need to adjust the return
168 * address so that the GTE opcode is effectively executed.
169 */
98fa08a5
PC
170 cause = state->regs.cp0[13];
171 epc = state->regs.cp0[14];
d16005f8
PC
172
173 if (!(cause & 0x7c) && epc == pc - 4)
174 pc -= 4;
175 }
176
177 if (inter->delay_slot) {
178 /* The branch opcode was in a delay slot of another branch
179 * opcode. Just return the target address of the second
180 * branch. */
181 return pc;
182 }
183
184 /* An opcode located in the delay slot performing a delayed read
185 * requires special handling; we will always resort to using the
186 * interpreter in that case.
187 * Same goes for when we have a branch in a delay slot of another
188 * branch. */
189 load_in_ds = load_in_delay_slot(op->c);
190 branch_in_ds = has_delay_slot(op->c);
191
192 if (branch) {
193 if (load_in_ds || branch_in_ds)
194 op_next = lightrec_read_opcode(state, pc);
195
196 if (load_in_ds) {
197 /* Verify that the next block actually reads the
198 * destination register of the delay slot opcode. */
199 run_first_op = opcode_reads_register(op_next, op->r.rt);
200 }
201
202 if (branch_in_ds) {
203 run_first_op = true;
204 next_pc = pc + 4;
205 }
206
207 if (load_in_ds && run_first_op) {
208 next_pc = pc + 4;
209
210 /* If the first opcode of the next block writes the
211 * regiser used as the address for the load, we need to
212 * reset to the old value after it has been executed,
213 * then restore the new value after the delay slot
214 * opcode has been executed. */
215 save_rs = opcode_reads_register(op->c, op->r.rs) &&
216 opcode_writes_register(op_next, op->r.rs);
217 if (save_rs)
218 old_rs = reg_cache[op->r.rs];
219
220 /* If both the first opcode of the next block and the
221 * delay slot opcode write to the same register, the
222 * value written by the delay slot opcode is
223 * discarded. */
224 dummy_ld = opcode_writes_register(op_next, op->r.rt);
225 }
226
227 if (!run_first_op) {
228 next_pc = pc;
229 } else if (has_delay_slot(op_next)) {
230 /* The first opcode of the next block is a branch, so we
231 * cannot execute it here, because of the load delay.
232 * Just check whether or not the branch would be taken,
233 * and save that info into the interpreter struct. */
234 branch_at_addr = true;
235 branch_taken = is_branch_taken(reg_cache, op_next);
236 pr_debug("Target of impossible branch is a branch, "
237 "%staken.\n", branch_taken ? "" : "not ");
a59e5536 238 inter->cycles += lightrec_cycles_of_opcode(op_next);
239 old_rs = reg_cache[op_next.r.rs];
d16005f8
PC
240 } else {
241 new_op.c = op_next;
242 new_op.flags = 0;
d16005f8
PC
243 inter2.op = &new_op;
244
245 /* Execute the first opcode of the next block */
98fa08a5 246 lightrec_int_op(&inter2);
d16005f8
PC
247
248 if (save_rs) {
249 new_rs = reg_cache[op->r.rs];
250 reg_cache[op->r.rs] = old_rs;
251 }
252
253 inter->cycles += lightrec_cycles_of_opcode(op_next);
254 }
255 } else {
98fa08a5 256 next_pc = int_get_ds_pc(inter, 2);
d16005f8
PC
257 }
258
259 inter2.block = inter->block;
260 inter2.op = op;
261 inter2.cycles = inter->cycles;
262
263 if (dummy_ld)
264 new_rt = reg_cache[op->r.rt];
265
266 /* Execute delay slot opcode */
98fa08a5 267 ds_next_pc = lightrec_int_op(&inter2);
a59e5536 268
269 if (branch_at_addr) {
270 if (op_next.i.op == OP_SPECIAL)
271 /* TODO: Handle JALR setting $ra */
272 ds_next_pc = old_rs;
273 else if (op_next.i.op == OP_J || op_next.i.op == OP_JAL)
274 /* TODO: Handle JAL setting $ra */
275 ds_next_pc = (pc & 0xf0000000) | (op_next.j.imm << 2);
276 else
277 ds_next_pc = pc + 4 + ((s16)op_next.i.imm << 2);
278 }
d16005f8
PC
279
280 if (branch_at_addr && !branch_taken) {
281 /* If the branch at the target of the branch opcode is not
282 * taken, we jump to its delay slot */
283 next_pc = pc + sizeof(u32);
a59e5536 284 } else if (branch_at_addr || (!branch && branch_in_ds)) {
d16005f8
PC
285 next_pc = ds_next_pc;
286 }
287
288 if (save_rs)
289 reg_cache[op->r.rs] = new_rs;
290 if (dummy_ld)
291 reg_cache[op->r.rt] = new_rt;
292
293 inter->cycles += lightrec_cycles_of_opcode(op->c);
294
295 if (branch_at_addr && branch_taken) {
296 /* If the branch at the target of the branch opcode is taken,
297 * we execute its delay slot here, and jump to its target
298 * address. */
299 op_next = lightrec_read_opcode(state, pc + 4);
300
301 new_op.c = op_next;
302 new_op.flags = 0;
d16005f8
PC
303 inter2.op = &new_op;
304 inter2.block = NULL;
305
306 inter->cycles += lightrec_cycles_of_opcode(op_next);
307
308 pr_debug("Running delay slot of branch at target of impossible "
309 "branch\n");
98fa08a5 310 lightrec_int_op(&inter2);
d16005f8
PC
311 }
312
313 return next_pc;
314}
315
316static u32 int_unimplemented(struct interpreter *inter)
317{
318 pr_warn("Unimplemented opcode 0x%08x\n", inter->op->opcode);
319
320 return jump_next(inter);
321}
322
323static u32 int_jump(struct interpreter *inter, bool link)
324{
325 struct lightrec_state *state = inter->state;
98fa08a5 326 u32 old_pc = int_get_branch_pc(inter);
d16005f8
PC
327 u32 pc = (old_pc & 0xf0000000) | (inter->op->j.imm << 2);
328
329 if (link)
98fa08a5 330 state->regs.gpr[31] = old_pc + 8;
d16005f8 331
03535202 332 if (op_flag_no_ds(inter->op->flags))
d16005f8
PC
333 return pc;
334
335 return int_delay_slot(inter, pc, true);
336}
337
338static u32 int_J(struct interpreter *inter)
339{
340 return int_jump(inter, false);
341}
342
343static u32 int_JAL(struct interpreter *inter)
344{
345 return int_jump(inter, true);
346}
347
348static u32 int_jumpr(struct interpreter *inter, u8 link_reg)
349{
350 struct lightrec_state *state = inter->state;
03535202
PC
351 u32 old_pc = int_get_branch_pc(inter);
352 u32 next_pc = state->regs.gpr[inter->op->r.rs];
d16005f8 353
03535202
PC
354 if (op_flag_emulate_branch(inter->op->flags) && inter->offset) {
355 inter->cycles -= lightrec_cycles_of_opcode(inter->op->c);
356 return old_pc;
d16005f8
PC
357 }
358
03535202
PC
359 if (link_reg)
360 state->regs.gpr[link_reg] = old_pc + 8;
361
362 if (op_flag_no_ds(inter->op->flags))
d16005f8
PC
363 return next_pc;
364
365 return int_delay_slot(inter, next_pc, true);
366}
367
368static u32 int_special_JR(struct interpreter *inter)
369{
370 return int_jumpr(inter, 0);
371}
372
373static u32 int_special_JALR(struct interpreter *inter)
374{
375 return int_jumpr(inter, inter->op->r.rd);
376}
377
378static u32 int_do_branch(struct interpreter *inter, u32 old_pc, u32 next_pc)
379{
03535202 380 if (!inter->delay_slot && op_flag_local_branch(inter->op->flags) &&
d16005f8
PC
381 (s16)inter->op->c.i.imm >= 0) {
382 next_pc = old_pc + ((1 + (s16)inter->op->c.i.imm) << 2);
98fa08a5 383 next_pc = lightrec_emulate_block(inter->state, inter->block, next_pc);
d16005f8
PC
384 }
385
386 return next_pc;
387}
388
389static u32 int_branch(struct interpreter *inter, u32 pc,
390 union code code, bool branch)
391{
392 u32 next_pc = pc + 4 + ((s16)code.i.imm << 2);
393
03535202
PC
394 if (op_flag_emulate_branch(inter->op->flags) && inter->offset) {
395 inter->cycles -= lightrec_cycles_of_opcode(inter->op->c);
396 return pc;
397 }
398
d16005f8
PC
399 update_cycles_before_branch(inter);
400
03535202 401 if (op_flag_no_ds(inter->op->flags)) {
d16005f8
PC
402 if (branch)
403 return int_do_branch(inter, pc, next_pc);
404 else
405 return jump_next(inter);
406 }
407
408 if (!inter->delay_slot)
409 next_pc = int_delay_slot(inter, next_pc, branch);
410
411 if (branch)
412 return int_do_branch(inter, pc, next_pc);
413
03535202 414 if (op_flag_emulate_branch(inter->op->flags))
d16005f8
PC
415 return pc + 8;
416 else
417 return jump_after_branch(inter);
418}
419
420static u32 int_beq(struct interpreter *inter, bool bne)
421{
98fa08a5 422 u32 rs, rt, old_pc = int_get_branch_pc(inter);
d16005f8 423
98fa08a5
PC
424 rs = inter->state->regs.gpr[inter->op->i.rs];
425 rt = inter->state->regs.gpr[inter->op->i.rt];
d16005f8
PC
426
427 return int_branch(inter, old_pc, inter->op->c, (rs == rt) ^ bne);
428}
429
430static u32 int_BEQ(struct interpreter *inter)
431{
432 return int_beq(inter, false);
433}
434
435static u32 int_BNE(struct interpreter *inter)
436{
437 return int_beq(inter, true);
438}
439
440static u32 int_bgez(struct interpreter *inter, bool link, bool lt, bool regimm)
441{
98fa08a5 442 u32 old_pc = int_get_branch_pc(inter);
d16005f8
PC
443 s32 rs;
444
445 if (link)
98fa08a5 446 inter->state->regs.gpr[31] = old_pc + 8;
d16005f8 447
98fa08a5 448 rs = (s32)inter->state->regs.gpr[inter->op->i.rs];
d16005f8
PC
449
450 return int_branch(inter, old_pc, inter->op->c,
451 ((regimm && !rs) || rs > 0) ^ lt);
452}
453
454static u32 int_regimm_BLTZ(struct interpreter *inter)
455{
456 return int_bgez(inter, false, true, true);
457}
458
459static u32 int_regimm_BGEZ(struct interpreter *inter)
460{
461 return int_bgez(inter, false, false, true);
462}
463
464static u32 int_regimm_BLTZAL(struct interpreter *inter)
465{
466 return int_bgez(inter, true, true, true);
467}
468
469static u32 int_regimm_BGEZAL(struct interpreter *inter)
470{
471 return int_bgez(inter, true, false, true);
472}
473
474static u32 int_BLEZ(struct interpreter *inter)
475{
476 return int_bgez(inter, false, true, false);
477}
478
479static u32 int_BGTZ(struct interpreter *inter)
480{
481 return int_bgez(inter, false, false, false);
482}
483
484static u32 int_cfc(struct interpreter *inter)
485{
486 struct lightrec_state *state = inter->state;
487 const struct opcode *op = inter->op;
488 u32 val;
489
490 val = lightrec_mfc(state, op->c);
491
492 if (likely(op->r.rt))
98fa08a5 493 state->regs.gpr[op->r.rt] = val;
d16005f8
PC
494
495 return jump_next(inter);
496}
497
498static u32 int_ctc(struct interpreter *inter)
499{
500 struct lightrec_state *state = inter->state;
501 const struct opcode *op = inter->op;
502
98fa08a5 503 lightrec_mtc(state, op->c, state->regs.gpr[op->r.rt]);
d16005f8
PC
504
505 /* If we have a MTC0 or CTC0 to CP0 register 12 (Status) or 13 (Cause),
506 * return early so that the emulator will be able to check software
507 * interrupt status. */
03535202 508 if (!op_flag_no_ds(inter->op->flags) &&
a59e5536 509 op->i.op == OP_CP0 && (op->r.rd == 12 || op->r.rd == 13))
98fa08a5 510 return int_get_ds_pc(inter, 1);
d16005f8
PC
511 else
512 return jump_next(inter);
513}
514
515static u32 int_cp0_RFE(struct interpreter *inter)
516{
98fa08a5 517 lightrec_rfe(inter->state);
d16005f8
PC
518
519 return jump_next(inter);
520}
521
522static u32 int_CP(struct interpreter *inter)
523{
98fa08a5 524 lightrec_cp(inter->state, inter->op->c);
d16005f8
PC
525
526 return jump_next(inter);
527}
528
529static u32 int_ADDI(struct interpreter *inter)
530{
98fa08a5 531 u32 *reg_cache = inter->state->regs.gpr;
d16005f8
PC
532 struct opcode_i *op = &inter->op->i;
533
534 if (likely(op->rt))
535 reg_cache[op->rt] = reg_cache[op->rs] + (s32)(s16)op->imm;
536
537 return jump_next(inter);
538}
539
540static u32 int_SLTI(struct interpreter *inter)
541{
98fa08a5 542 u32 *reg_cache = inter->state->regs.gpr;
d16005f8
PC
543 struct opcode_i *op = &inter->op->i;
544
545 if (likely(op->rt))
546 reg_cache[op->rt] = (s32)reg_cache[op->rs] < (s32)(s16)op->imm;
547
548 return jump_next(inter);
549}
550
551static u32 int_SLTIU(struct interpreter *inter)
552{
98fa08a5 553 u32 *reg_cache = inter->state->regs.gpr;
d16005f8
PC
554 struct opcode_i *op = &inter->op->i;
555
556 if (likely(op->rt))
557 reg_cache[op->rt] = reg_cache[op->rs] < (u32)(s32)(s16)op->imm;
558
559 return jump_next(inter);
560}
561
562static u32 int_ANDI(struct interpreter *inter)
563{
98fa08a5 564 u32 *reg_cache = inter->state->regs.gpr;
d16005f8
PC
565 struct opcode_i *op = &inter->op->i;
566
567 if (likely(op->rt))
568 reg_cache[op->rt] = reg_cache[op->rs] & op->imm;
569
570 return jump_next(inter);
571}
572
573static u32 int_ORI(struct interpreter *inter)
574{
98fa08a5 575 u32 *reg_cache = inter->state->regs.gpr;
d16005f8
PC
576 struct opcode_i *op = &inter->op->i;
577
578 if (likely(op->rt))
579 reg_cache[op->rt] = reg_cache[op->rs] | op->imm;
580
581 return jump_next(inter);
582}
583
584static u32 int_XORI(struct interpreter *inter)
585{
98fa08a5 586 u32 *reg_cache = inter->state->regs.gpr;
d16005f8
PC
587 struct opcode_i *op = &inter->op->i;
588
589 if (likely(op->rt))
590 reg_cache[op->rt] = reg_cache[op->rs] ^ op->imm;
591
592 return jump_next(inter);
593}
594
595static u32 int_LUI(struct interpreter *inter)
596{
597 struct opcode_i *op = &inter->op->i;
598
98fa08a5 599 inter->state->regs.gpr[op->rt] = op->imm << 16;
d16005f8
PC
600
601 return jump_next(inter);
602}
603
604static u32 int_io(struct interpreter *inter, bool is_load)
605{
606 struct opcode_i *op = &inter->op->i;
98fa08a5 607 u32 *reg_cache = inter->state->regs.gpr;
d16005f8
PC
608 u32 val;
609
610 val = lightrec_rw(inter->state, inter->op->c,
611 reg_cache[op->rs], reg_cache[op->rt],
98fa08a5 612 &inter->op->flags, inter->block);
d16005f8
PC
613
614 if (is_load && op->rt)
615 reg_cache[op->rt] = val;
616
617 return jump_next(inter);
618}
619
620static u32 int_load(struct interpreter *inter)
621{
622 return int_io(inter, true);
623}
624
625static u32 int_store(struct interpreter *inter)
626{
627 u32 next_pc;
628
03535202 629 if (likely(!op_flag_smc(inter->op->flags)))
d16005f8
PC
630 return int_io(inter, false);
631
632 lightrec_rw(inter->state, inter->op->c,
98fa08a5
PC
633 inter->state->regs.gpr[inter->op->i.rs],
634 inter->state->regs.gpr[inter->op->i.rt],
635 &inter->op->flags, inter->block);
d16005f8 636
98fa08a5 637 next_pc = int_get_ds_pc(inter, 1);
d16005f8
PC
638
639 /* Invalidate next PC, to force the rest of the block to be rebuilt */
640 lightrec_invalidate(inter->state, next_pc, 4);
641
642 return next_pc;
643}
644
645static u32 int_LWC2(struct interpreter *inter)
646{
647 return int_io(inter, false);
648}
649
650static u32 int_special_SLL(struct interpreter *inter)
651{
652 struct opcode *op = inter->op;
653 u32 rt;
654
655 if (op->opcode) { /* Handle NOPs */
98fa08a5
PC
656 rt = inter->state->regs.gpr[op->r.rt];
657 inter->state->regs.gpr[op->r.rd] = rt << op->r.imm;
d16005f8
PC
658 }
659
660 return jump_next(inter);
661}
662
663static u32 int_special_SRL(struct interpreter *inter)
664{
665 struct opcode *op = inter->op;
98fa08a5 666 u32 rt = inter->state->regs.gpr[op->r.rt];
d16005f8 667
98fa08a5 668 inter->state->regs.gpr[op->r.rd] = rt >> op->r.imm;
d16005f8
PC
669
670 return jump_next(inter);
671}
672
673static u32 int_special_SRA(struct interpreter *inter)
674{
675 struct opcode *op = inter->op;
98fa08a5 676 s32 rt = inter->state->regs.gpr[op->r.rt];
d16005f8 677
98fa08a5 678 inter->state->regs.gpr[op->r.rd] = rt >> op->r.imm;
d16005f8
PC
679
680 return jump_next(inter);
681}
682
683static u32 int_special_SLLV(struct interpreter *inter)
684{
685 struct opcode *op = inter->op;
98fa08a5
PC
686 u32 rs = inter->state->regs.gpr[op->r.rs];
687 u32 rt = inter->state->regs.gpr[op->r.rt];
d16005f8 688
98fa08a5 689 inter->state->regs.gpr[op->r.rd] = rt << (rs & 0x1f);
d16005f8
PC
690
691 return jump_next(inter);
692}
693
694static u32 int_special_SRLV(struct interpreter *inter)
695{
696 struct opcode *op = inter->op;
98fa08a5
PC
697 u32 rs = inter->state->regs.gpr[op->r.rs];
698 u32 rt = inter->state->regs.gpr[op->r.rt];
d16005f8 699
98fa08a5 700 inter->state->regs.gpr[op->r.rd] = rt >> (rs & 0x1f);
d16005f8
PC
701
702 return jump_next(inter);
703}
704
705static u32 int_special_SRAV(struct interpreter *inter)
706{
707 struct opcode *op = inter->op;
98fa08a5
PC
708 u32 rs = inter->state->regs.gpr[op->r.rs];
709 s32 rt = inter->state->regs.gpr[op->r.rt];
d16005f8 710
98fa08a5 711 inter->state->regs.gpr[op->r.rd] = rt >> (rs & 0x1f);
d16005f8
PC
712
713 return jump_next(inter);
714}
715
716static u32 int_syscall_break(struct interpreter *inter)
717{
718
719 if (inter->op->r.op == OP_SPECIAL_BREAK)
720 inter->state->exit_flags |= LIGHTREC_EXIT_BREAK;
721 else
722 inter->state->exit_flags |= LIGHTREC_EXIT_SYSCALL;
723
98fa08a5 724 return int_get_ds_pc(inter, 0);
d16005f8
PC
725}
726
727static u32 int_special_MFHI(struct interpreter *inter)
728{
98fa08a5 729 u32 *reg_cache = inter->state->regs.gpr;
d16005f8
PC
730 struct opcode_r *op = &inter->op->r;
731
732 if (likely(op->rd))
733 reg_cache[op->rd] = reg_cache[REG_HI];
734
735 return jump_next(inter);
736}
737
738static u32 int_special_MTHI(struct interpreter *inter)
739{
98fa08a5 740 u32 *reg_cache = inter->state->regs.gpr;
d16005f8
PC
741
742 reg_cache[REG_HI] = reg_cache[inter->op->r.rs];
743
744 return jump_next(inter);
745}
746
747static u32 int_special_MFLO(struct interpreter *inter)
748{
98fa08a5 749 u32 *reg_cache = inter->state->regs.gpr;
d16005f8
PC
750 struct opcode_r *op = &inter->op->r;
751
752 if (likely(op->rd))
753 reg_cache[op->rd] = reg_cache[REG_LO];
754
755 return jump_next(inter);
756}
757
758static u32 int_special_MTLO(struct interpreter *inter)
759{
98fa08a5 760 u32 *reg_cache = inter->state->regs.gpr;
d16005f8
PC
761
762 reg_cache[REG_LO] = reg_cache[inter->op->r.rs];
763
764 return jump_next(inter);
765}
766
767static u32 int_special_MULT(struct interpreter *inter)
768{
98fa08a5 769 u32 *reg_cache = inter->state->regs.gpr;
d16005f8
PC
770 s32 rs = reg_cache[inter->op->r.rs];
771 s32 rt = reg_cache[inter->op->r.rt];
98fa08a5
PC
772 u8 reg_lo = get_mult_div_lo(inter->op->c);
773 u8 reg_hi = get_mult_div_hi(inter->op->c);
d16005f8
PC
774 u64 res = (s64)rs * (s64)rt;
775
03535202 776 if (!op_flag_no_hi(inter->op->flags))
98fa08a5 777 reg_cache[reg_hi] = res >> 32;
03535202 778 if (!op_flag_no_lo(inter->op->flags))
98fa08a5 779 reg_cache[reg_lo] = res;
d16005f8
PC
780
781 return jump_next(inter);
782}
783
784static u32 int_special_MULTU(struct interpreter *inter)
785{
98fa08a5 786 u32 *reg_cache = inter->state->regs.gpr;
d16005f8
PC
787 u32 rs = reg_cache[inter->op->r.rs];
788 u32 rt = reg_cache[inter->op->r.rt];
98fa08a5
PC
789 u8 reg_lo = get_mult_div_lo(inter->op->c);
790 u8 reg_hi = get_mult_div_hi(inter->op->c);
d16005f8
PC
791 u64 res = (u64)rs * (u64)rt;
792
03535202 793 if (!op_flag_no_hi(inter->op->flags))
98fa08a5 794 reg_cache[reg_hi] = res >> 32;
03535202 795 if (!op_flag_no_lo(inter->op->flags))
98fa08a5 796 reg_cache[reg_lo] = res;
d16005f8
PC
797
798 return jump_next(inter);
799}
800
801static u32 int_special_DIV(struct interpreter *inter)
802{
98fa08a5 803 u32 *reg_cache = inter->state->regs.gpr;
d16005f8
PC
804 s32 rs = reg_cache[inter->op->r.rs];
805 s32 rt = reg_cache[inter->op->r.rt];
98fa08a5
PC
806 u8 reg_lo = get_mult_div_lo(inter->op->c);
807 u8 reg_hi = get_mult_div_hi(inter->op->c);
d16005f8
PC
808 u32 lo, hi;
809
810 if (rt == 0) {
811 hi = rs;
812 lo = (rs < 0) * 2 - 1;
813 } else {
814 lo = rs / rt;
815 hi = rs % rt;
816 }
817
03535202 818 if (!op_flag_no_hi(inter->op->flags))
98fa08a5 819 reg_cache[reg_hi] = hi;
03535202 820 if (!op_flag_no_lo(inter->op->flags))
98fa08a5 821 reg_cache[reg_lo] = lo;
d16005f8
PC
822
823 return jump_next(inter);
824}
825
826static u32 int_special_DIVU(struct interpreter *inter)
827{
98fa08a5 828 u32 *reg_cache = inter->state->regs.gpr;
d16005f8
PC
829 u32 rs = reg_cache[inter->op->r.rs];
830 u32 rt = reg_cache[inter->op->r.rt];
98fa08a5
PC
831 u8 reg_lo = get_mult_div_lo(inter->op->c);
832 u8 reg_hi = get_mult_div_hi(inter->op->c);
d16005f8
PC
833 u32 lo, hi;
834
835 if (rt == 0) {
836 hi = rs;
837 lo = (u32)-1;
838 } else {
839 lo = rs / rt;
840 hi = rs % rt;
841 }
842
03535202 843 if (!op_flag_no_hi(inter->op->flags))
98fa08a5 844 reg_cache[reg_hi] = hi;
03535202 845 if (!op_flag_no_lo(inter->op->flags))
98fa08a5 846 reg_cache[reg_lo] = lo;
d16005f8
PC
847
848 return jump_next(inter);
849}
850
851static u32 int_special_ADD(struct interpreter *inter)
852{
98fa08a5 853 u32 *reg_cache = inter->state->regs.gpr;
d16005f8
PC
854 struct opcode_r *op = &inter->op->r;
855 s32 rs = reg_cache[op->rs];
856 s32 rt = reg_cache[op->rt];
857
858 if (likely(op->rd))
859 reg_cache[op->rd] = rs + rt;
860
861 return jump_next(inter);
862}
863
864static u32 int_special_SUB(struct interpreter *inter)
865{
98fa08a5 866 u32 *reg_cache = inter->state->regs.gpr;
d16005f8
PC
867 struct opcode_r *op = &inter->op->r;
868 u32 rs = reg_cache[op->rs];
869 u32 rt = reg_cache[op->rt];
870
871 if (likely(op->rd))
872 reg_cache[op->rd] = rs - rt;
873
874 return jump_next(inter);
875}
876
877static u32 int_special_AND(struct interpreter *inter)
878{
98fa08a5 879 u32 *reg_cache = inter->state->regs.gpr;
d16005f8
PC
880 struct opcode_r *op = &inter->op->r;
881 u32 rs = reg_cache[op->rs];
882 u32 rt = reg_cache[op->rt];
883
884 if (likely(op->rd))
885 reg_cache[op->rd] = rs & rt;
886
887 return jump_next(inter);
888}
889
890static u32 int_special_OR(struct interpreter *inter)
891{
98fa08a5 892 u32 *reg_cache = inter->state->regs.gpr;
d16005f8
PC
893 struct opcode_r *op = &inter->op->r;
894 u32 rs = reg_cache[op->rs];
895 u32 rt = reg_cache[op->rt];
896
897 if (likely(op->rd))
898 reg_cache[op->rd] = rs | rt;
899
900 return jump_next(inter);
901}
902
903static u32 int_special_XOR(struct interpreter *inter)
904{
98fa08a5 905 u32 *reg_cache = inter->state->regs.gpr;
d16005f8
PC
906 struct opcode_r *op = &inter->op->r;
907 u32 rs = reg_cache[op->rs];
908 u32 rt = reg_cache[op->rt];
909
910 if (likely(op->rd))
911 reg_cache[op->rd] = rs ^ rt;
912
913 return jump_next(inter);
914}
915
916static u32 int_special_NOR(struct interpreter *inter)
917{
98fa08a5 918 u32 *reg_cache = inter->state->regs.gpr;
d16005f8
PC
919 struct opcode_r *op = &inter->op->r;
920 u32 rs = reg_cache[op->rs];
921 u32 rt = reg_cache[op->rt];
922
923 if (likely(op->rd))
924 reg_cache[op->rd] = ~(rs | rt);
925
926 return jump_next(inter);
927}
928
929static u32 int_special_SLT(struct interpreter *inter)
930{
98fa08a5 931 u32 *reg_cache = inter->state->regs.gpr;
d16005f8
PC
932 struct opcode_r *op = &inter->op->r;
933 s32 rs = reg_cache[op->rs];
934 s32 rt = reg_cache[op->rt];
935
936 if (likely(op->rd))
937 reg_cache[op->rd] = rs < rt;
938
939 return jump_next(inter);
940}
941
942static u32 int_special_SLTU(struct interpreter *inter)
943{
98fa08a5 944 u32 *reg_cache = inter->state->regs.gpr;
d16005f8
PC
945 struct opcode_r *op = &inter->op->r;
946 u32 rs = reg_cache[op->rs];
947 u32 rt = reg_cache[op->rt];
948
949 if (likely(op->rd))
950 reg_cache[op->rd] = rs < rt;
951
952 return jump_next(inter);
953}
954
d16005f8
PC
955static u32 int_META_MOV(struct interpreter *inter)
956{
98fa08a5 957 u32 *reg_cache = inter->state->regs.gpr;
d16005f8
PC
958 struct opcode_r *op = &inter->op->r;
959
960 if (likely(op->rd))
961 reg_cache[op->rd] = reg_cache[op->rs];
962
963 return jump_next(inter);
964}
965
98fa08a5 966static u32 int_META_EXTC(struct interpreter *inter)
d16005f8 967{
98fa08a5
PC
968 u32 *reg_cache = inter->state->regs.gpr;
969 struct opcode_i *op = &inter->op->i;
d16005f8 970
98fa08a5
PC
971 if (likely(op->rt))
972 reg_cache[op->rt] = (u32)(s32)(s8)reg_cache[op->rs];
973
974 return jump_next(inter);
975}
976
977static u32 int_META_EXTS(struct interpreter *inter)
978{
979 u32 *reg_cache = inter->state->regs.gpr;
980 struct opcode_i *op = &inter->op->i;
981
982 if (likely(op->rt))
983 reg_cache[op->rt] = (u32)(s32)(s16)reg_cache[op->rs];
984
985 return jump_next(inter);
d16005f8
PC
986}
987
988static const lightrec_int_func_t int_standard[64] = {
98fa08a5 989 SET_DEFAULT_ELM(int_standard, int_unimplemented),
d16005f8
PC
990 [OP_SPECIAL] = int_SPECIAL,
991 [OP_REGIMM] = int_REGIMM,
992 [OP_J] = int_J,
993 [OP_JAL] = int_JAL,
994 [OP_BEQ] = int_BEQ,
995 [OP_BNE] = int_BNE,
996 [OP_BLEZ] = int_BLEZ,
997 [OP_BGTZ] = int_BGTZ,
998 [OP_ADDI] = int_ADDI,
999 [OP_ADDIU] = int_ADDI,
1000 [OP_SLTI] = int_SLTI,
1001 [OP_SLTIU] = int_SLTIU,
1002 [OP_ANDI] = int_ANDI,
1003 [OP_ORI] = int_ORI,
1004 [OP_XORI] = int_XORI,
1005 [OP_LUI] = int_LUI,
1006 [OP_CP0] = int_CP0,
1007 [OP_CP2] = int_CP2,
1008 [OP_LB] = int_load,
1009 [OP_LH] = int_load,
1010 [OP_LWL] = int_load,
1011 [OP_LW] = int_load,
1012 [OP_LBU] = int_load,
1013 [OP_LHU] = int_load,
1014 [OP_LWR] = int_load,
1015 [OP_SB] = int_store,
1016 [OP_SH] = int_store,
1017 [OP_SWL] = int_store,
1018 [OP_SW] = int_store,
1019 [OP_SWR] = int_store,
1020 [OP_LWC2] = int_LWC2,
1021 [OP_SWC2] = int_store,
1022
d16005f8 1023 [OP_META_MOV] = int_META_MOV,
98fa08a5
PC
1024 [OP_META_EXTC] = int_META_EXTC,
1025 [OP_META_EXTS] = int_META_EXTS,
d16005f8
PC
1026};
1027
1028static const lightrec_int_func_t int_special[64] = {
98fa08a5 1029 SET_DEFAULT_ELM(int_special, int_unimplemented),
d16005f8
PC
1030 [OP_SPECIAL_SLL] = int_special_SLL,
1031 [OP_SPECIAL_SRL] = int_special_SRL,
1032 [OP_SPECIAL_SRA] = int_special_SRA,
1033 [OP_SPECIAL_SLLV] = int_special_SLLV,
1034 [OP_SPECIAL_SRLV] = int_special_SRLV,
1035 [OP_SPECIAL_SRAV] = int_special_SRAV,
1036 [OP_SPECIAL_JR] = int_special_JR,
1037 [OP_SPECIAL_JALR] = int_special_JALR,
1038 [OP_SPECIAL_SYSCALL] = int_syscall_break,
1039 [OP_SPECIAL_BREAK] = int_syscall_break,
1040 [OP_SPECIAL_MFHI] = int_special_MFHI,
1041 [OP_SPECIAL_MTHI] = int_special_MTHI,
1042 [OP_SPECIAL_MFLO] = int_special_MFLO,
1043 [OP_SPECIAL_MTLO] = int_special_MTLO,
1044 [OP_SPECIAL_MULT] = int_special_MULT,
1045 [OP_SPECIAL_MULTU] = int_special_MULTU,
1046 [OP_SPECIAL_DIV] = int_special_DIV,
1047 [OP_SPECIAL_DIVU] = int_special_DIVU,
1048 [OP_SPECIAL_ADD] = int_special_ADD,
1049 [OP_SPECIAL_ADDU] = int_special_ADD,
1050 [OP_SPECIAL_SUB] = int_special_SUB,
1051 [OP_SPECIAL_SUBU] = int_special_SUB,
1052 [OP_SPECIAL_AND] = int_special_AND,
1053 [OP_SPECIAL_OR] = int_special_OR,
1054 [OP_SPECIAL_XOR] = int_special_XOR,
1055 [OP_SPECIAL_NOR] = int_special_NOR,
1056 [OP_SPECIAL_SLT] = int_special_SLT,
1057 [OP_SPECIAL_SLTU] = int_special_SLTU,
1058};
1059
1060static const lightrec_int_func_t int_regimm[64] = {
98fa08a5 1061 SET_DEFAULT_ELM(int_regimm, int_unimplemented),
d16005f8
PC
1062 [OP_REGIMM_BLTZ] = int_regimm_BLTZ,
1063 [OP_REGIMM_BGEZ] = int_regimm_BGEZ,
1064 [OP_REGIMM_BLTZAL] = int_regimm_BLTZAL,
1065 [OP_REGIMM_BGEZAL] = int_regimm_BGEZAL,
1066};
1067
1068static const lightrec_int_func_t int_cp0[64] = {
98fa08a5 1069 SET_DEFAULT_ELM(int_cp0, int_CP),
d16005f8
PC
1070 [OP_CP0_MFC0] = int_cfc,
1071 [OP_CP0_CFC0] = int_cfc,
1072 [OP_CP0_MTC0] = int_ctc,
1073 [OP_CP0_CTC0] = int_ctc,
1074 [OP_CP0_RFE] = int_cp0_RFE,
1075};
1076
1077static const lightrec_int_func_t int_cp2_basic[64] = {
98fa08a5 1078 SET_DEFAULT_ELM(int_cp2_basic, int_CP),
d16005f8
PC
1079 [OP_CP2_BASIC_MFC2] = int_cfc,
1080 [OP_CP2_BASIC_CFC2] = int_cfc,
1081 [OP_CP2_BASIC_MTC2] = int_ctc,
1082 [OP_CP2_BASIC_CTC2] = int_ctc,
1083};
1084
1085static u32 int_SPECIAL(struct interpreter *inter)
1086{
1087 lightrec_int_func_t f = int_special[inter->op->r.op];
98fa08a5
PC
1088
1089 if (!HAS_DEFAULT_ELM && unlikely(!f))
d16005f8 1090 return int_unimplemented(inter);
98fa08a5
PC
1091
1092 return execute(f, inter);
d16005f8
PC
1093}
1094
1095static u32 int_REGIMM(struct interpreter *inter)
1096{
1097 lightrec_int_func_t f = int_regimm[inter->op->r.rt];
98fa08a5
PC
1098
1099 if (!HAS_DEFAULT_ELM && unlikely(!f))
d16005f8 1100 return int_unimplemented(inter);
98fa08a5
PC
1101
1102 return execute(f, inter);
d16005f8
PC
1103}
1104
1105static u32 int_CP0(struct interpreter *inter)
1106{
1107 lightrec_int_func_t f = int_cp0[inter->op->r.rs];
98fa08a5
PC
1108
1109 if (!HAS_DEFAULT_ELM && unlikely(!f))
d16005f8 1110 return int_CP(inter);
98fa08a5
PC
1111
1112 return execute(f, inter);
d16005f8
PC
1113}
1114
1115static u32 int_CP2(struct interpreter *inter)
1116{
1117 if (inter->op->r.op == OP_CP2_BASIC) {
1118 lightrec_int_func_t f = int_cp2_basic[inter->op->r.rs];
98fa08a5 1119 if (HAS_DEFAULT_ELM || likely(f))
d16005f8
PC
1120 return execute(f, inter);
1121 }
1122
1123 return int_CP(inter);
1124}
1125
98fa08a5
PC
1126static u32 lightrec_emulate_block_list(struct lightrec_state *state,
1127 struct block *block, u32 offset)
d16005f8
PC
1128{
1129 struct interpreter inter;
1130 u32 pc;
1131
1132 inter.block = block;
98fa08a5
PC
1133 inter.state = state;
1134 inter.offset = offset;
1135 inter.op = &block->opcode_list[offset];
d16005f8
PC
1136 inter.cycles = 0;
1137 inter.delay_slot = false;
1138
1139 pc = lightrec_int_op(&inter);
1140
1141 /* Add the cycles of the last branch */
1142 inter.cycles += lightrec_cycles_of_opcode(inter.op->c);
1143
98fa08a5 1144 state->current_cycle += inter.cycles;
d16005f8
PC
1145
1146 return pc;
1147}
1148
98fa08a5 1149u32 lightrec_emulate_block(struct lightrec_state *state, struct block *block, u32 pc)
d16005f8
PC
1150{
1151 u32 offset = (kunseg(pc) - kunseg(block->pc)) >> 2;
d16005f8 1152
98fa08a5
PC
1153 if (offset < block->nb_ops)
1154 return lightrec_emulate_block_list(state, block, offset);
d16005f8
PC
1155
1156 pr_err("PC 0x%x is outside block at PC 0x%x\n", pc, block->pc);
1157
1158 return 0;
1159}