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