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 | */ | |
a59e5536 | 153 | cause = (*state->ops.cop0_ops.cfc)(state, op->c.opcode, 13); |
154 | epc = (*state->ops.cop0_ops.cfc)(state, op->c.opcode, 14); | |
d16005f8 PC |
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 "); | |
a59e5536 | 221 | inter->cycles += lightrec_cycles_of_opcode(op_next); |
222 | old_rs = reg_cache[op_next.r.rs]; | |
d16005f8 PC |
223 | } else { |
224 | new_op.c = op_next; | |
225 | new_op.flags = 0; | |
226 | new_op.offset = 0; | |
227 | new_op.next = NULL; | |
228 | inter2.op = &new_op; | |
229 | ||
230 | /* Execute the first opcode of the next block */ | |
231 | (*int_standard[inter2.op->i.op])(&inter2); | |
232 | ||
233 | if (save_rs) { | |
234 | new_rs = reg_cache[op->r.rs]; | |
235 | reg_cache[op->r.rs] = old_rs; | |
236 | } | |
237 | ||
238 | inter->cycles += lightrec_cycles_of_opcode(op_next); | |
239 | } | |
240 | } else { | |
241 | next_pc = inter->block->pc | |
242 | + (inter->op->offset + 2) * sizeof(u32); | |
243 | } | |
244 | ||
245 | inter2.block = inter->block; | |
246 | inter2.op = op; | |
247 | inter2.cycles = inter->cycles; | |
248 | ||
249 | if (dummy_ld) | |
250 | new_rt = reg_cache[op->r.rt]; | |
251 | ||
252 | /* Execute delay slot opcode */ | |
a59e5536 | 253 | ds_next_pc = (*int_standard[inter2.op->i.op])(&inter2); |
254 | ||
255 | if (branch_at_addr) { | |
256 | if (op_next.i.op == OP_SPECIAL) | |
257 | /* TODO: Handle JALR setting $ra */ | |
258 | ds_next_pc = old_rs; | |
259 | else if (op_next.i.op == OP_J || op_next.i.op == OP_JAL) | |
260 | /* TODO: Handle JAL setting $ra */ | |
261 | ds_next_pc = (pc & 0xf0000000) | (op_next.j.imm << 2); | |
262 | else | |
263 | ds_next_pc = pc + 4 + ((s16)op_next.i.imm << 2); | |
264 | } | |
d16005f8 PC |
265 | |
266 | if (branch_at_addr && !branch_taken) { | |
267 | /* If the branch at the target of the branch opcode is not | |
268 | * taken, we jump to its delay slot */ | |
269 | next_pc = pc + sizeof(u32); | |
a59e5536 | 270 | } else if (branch_at_addr || (!branch && branch_in_ds)) { |
d16005f8 PC |
271 | next_pc = ds_next_pc; |
272 | } | |
273 | ||
274 | if (save_rs) | |
275 | reg_cache[op->r.rs] = new_rs; | |
276 | if (dummy_ld) | |
277 | reg_cache[op->r.rt] = new_rt; | |
278 | ||
279 | inter->cycles += lightrec_cycles_of_opcode(op->c); | |
280 | ||
281 | if (branch_at_addr && branch_taken) { | |
282 | /* If the branch at the target of the branch opcode is taken, | |
283 | * we execute its delay slot here, and jump to its target | |
284 | * address. */ | |
285 | op_next = lightrec_read_opcode(state, pc + 4); | |
286 | ||
287 | new_op.c = op_next; | |
288 | new_op.flags = 0; | |
289 | new_op.offset = sizeof(u32); | |
290 | new_op.next = NULL; | |
291 | inter2.op = &new_op; | |
292 | inter2.block = NULL; | |
293 | ||
294 | inter->cycles += lightrec_cycles_of_opcode(op_next); | |
295 | ||
296 | pr_debug("Running delay slot of branch at target of impossible " | |
297 | "branch\n"); | |
298 | (*int_standard[inter2.op->i.op])(&inter2); | |
299 | } | |
300 | ||
301 | return next_pc; | |
302 | } | |
303 | ||
304 | static u32 int_unimplemented(struct interpreter *inter) | |
305 | { | |
306 | pr_warn("Unimplemented opcode 0x%08x\n", inter->op->opcode); | |
307 | ||
308 | return jump_next(inter); | |
309 | } | |
310 | ||
311 | static u32 int_jump(struct interpreter *inter, bool link) | |
312 | { | |
313 | struct lightrec_state *state = inter->state; | |
314 | u32 old_pc = inter->block->pc + inter->op->offset * sizeof(u32); | |
315 | u32 pc = (old_pc & 0xf0000000) | (inter->op->j.imm << 2); | |
316 | ||
317 | if (link) | |
318 | state->native_reg_cache[31] = old_pc + 8; | |
319 | ||
320 | if (inter->op->flags & LIGHTREC_NO_DS) | |
321 | return pc; | |
322 | ||
323 | return int_delay_slot(inter, pc, true); | |
324 | } | |
325 | ||
326 | static u32 int_J(struct interpreter *inter) | |
327 | { | |
328 | return int_jump(inter, false); | |
329 | } | |
330 | ||
331 | static u32 int_JAL(struct interpreter *inter) | |
332 | { | |
333 | return int_jump(inter, true); | |
334 | } | |
335 | ||
336 | static u32 int_jumpr(struct interpreter *inter, u8 link_reg) | |
337 | { | |
338 | struct lightrec_state *state = inter->state; | |
339 | u32 old_pc, next_pc = state->native_reg_cache[inter->op->r.rs]; | |
340 | ||
341 | if (link_reg) { | |
342 | old_pc = inter->block->pc + inter->op->offset * sizeof(u32); | |
343 | state->native_reg_cache[link_reg] = old_pc + 8; | |
344 | } | |
345 | ||
346 | if (inter->op->flags & LIGHTREC_NO_DS) | |
347 | return next_pc; | |
348 | ||
349 | return int_delay_slot(inter, next_pc, true); | |
350 | } | |
351 | ||
352 | static u32 int_special_JR(struct interpreter *inter) | |
353 | { | |
354 | return int_jumpr(inter, 0); | |
355 | } | |
356 | ||
357 | static u32 int_special_JALR(struct interpreter *inter) | |
358 | { | |
359 | return int_jumpr(inter, inter->op->r.rd); | |
360 | } | |
361 | ||
362 | static u32 int_do_branch(struct interpreter *inter, u32 old_pc, u32 next_pc) | |
363 | { | |
364 | if (!inter->delay_slot && | |
365 | (inter->op->flags & LIGHTREC_LOCAL_BRANCH) && | |
366 | (s16)inter->op->c.i.imm >= 0) { | |
367 | next_pc = old_pc + ((1 + (s16)inter->op->c.i.imm) << 2); | |
368 | next_pc = lightrec_emulate_block(inter->block, next_pc); | |
369 | } | |
370 | ||
371 | return next_pc; | |
372 | } | |
373 | ||
374 | static u32 int_branch(struct interpreter *inter, u32 pc, | |
375 | union code code, bool branch) | |
376 | { | |
377 | u32 next_pc = pc + 4 + ((s16)code.i.imm << 2); | |
378 | ||
379 | update_cycles_before_branch(inter); | |
380 | ||
381 | if (inter->op->flags & LIGHTREC_NO_DS) { | |
382 | if (branch) | |
383 | return int_do_branch(inter, pc, next_pc); | |
384 | else | |
385 | return jump_next(inter); | |
386 | } | |
387 | ||
388 | if (!inter->delay_slot) | |
389 | next_pc = int_delay_slot(inter, next_pc, branch); | |
390 | ||
391 | if (branch) | |
392 | return int_do_branch(inter, pc, next_pc); | |
393 | ||
394 | if (inter->op->flags & LIGHTREC_EMULATE_BRANCH) | |
395 | return pc + 8; | |
396 | else | |
397 | return jump_after_branch(inter); | |
398 | } | |
399 | ||
400 | static u32 int_beq(struct interpreter *inter, bool bne) | |
401 | { | |
402 | u32 rs, rt, old_pc = inter->block->pc + inter->op->offset * sizeof(u32); | |
403 | ||
404 | rs = inter->state->native_reg_cache[inter->op->i.rs]; | |
405 | rt = inter->state->native_reg_cache[inter->op->i.rt]; | |
406 | ||
407 | return int_branch(inter, old_pc, inter->op->c, (rs == rt) ^ bne); | |
408 | } | |
409 | ||
410 | static u32 int_BEQ(struct interpreter *inter) | |
411 | { | |
412 | return int_beq(inter, false); | |
413 | } | |
414 | ||
415 | static u32 int_BNE(struct interpreter *inter) | |
416 | { | |
417 | return int_beq(inter, true); | |
418 | } | |
419 | ||
420 | static u32 int_bgez(struct interpreter *inter, bool link, bool lt, bool regimm) | |
421 | { | |
422 | u32 old_pc = inter->block->pc + inter->op->offset * sizeof(u32); | |
423 | s32 rs; | |
424 | ||
425 | if (link) | |
426 | inter->state->native_reg_cache[31] = old_pc + 8; | |
427 | ||
428 | rs = (s32)inter->state->native_reg_cache[inter->op->i.rs]; | |
429 | ||
430 | return int_branch(inter, old_pc, inter->op->c, | |
431 | ((regimm && !rs) || rs > 0) ^ lt); | |
432 | } | |
433 | ||
434 | static u32 int_regimm_BLTZ(struct interpreter *inter) | |
435 | { | |
436 | return int_bgez(inter, false, true, true); | |
437 | } | |
438 | ||
439 | static u32 int_regimm_BGEZ(struct interpreter *inter) | |
440 | { | |
441 | return int_bgez(inter, false, false, true); | |
442 | } | |
443 | ||
444 | static u32 int_regimm_BLTZAL(struct interpreter *inter) | |
445 | { | |
446 | return int_bgez(inter, true, true, true); | |
447 | } | |
448 | ||
449 | static u32 int_regimm_BGEZAL(struct interpreter *inter) | |
450 | { | |
451 | return int_bgez(inter, true, false, true); | |
452 | } | |
453 | ||
454 | static u32 int_BLEZ(struct interpreter *inter) | |
455 | { | |
456 | return int_bgez(inter, false, true, false); | |
457 | } | |
458 | ||
459 | static u32 int_BGTZ(struct interpreter *inter) | |
460 | { | |
461 | return int_bgez(inter, false, false, false); | |
462 | } | |
463 | ||
464 | static u32 int_cfc(struct interpreter *inter) | |
465 | { | |
466 | struct lightrec_state *state = inter->state; | |
467 | const struct opcode *op = inter->op; | |
468 | u32 val; | |
469 | ||
470 | val = lightrec_mfc(state, op->c); | |
471 | ||
472 | if (likely(op->r.rt)) | |
473 | state->native_reg_cache[op->r.rt] = val; | |
474 | ||
475 | return jump_next(inter); | |
476 | } | |
477 | ||
478 | static u32 int_ctc(struct interpreter *inter) | |
479 | { | |
480 | struct lightrec_state *state = inter->state; | |
481 | const struct opcode *op = inter->op; | |
482 | ||
483 | lightrec_mtc(state, op->c, state->native_reg_cache[op->r.rt]); | |
484 | ||
485 | /* If we have a MTC0 or CTC0 to CP0 register 12 (Status) or 13 (Cause), | |
486 | * return early so that the emulator will be able to check software | |
487 | * interrupt status. */ | |
a59e5536 | 488 | if (!(inter->op->flags & LIGHTREC_NO_DS) && |
489 | op->i.op == OP_CP0 && (op->r.rd == 12 || op->r.rd == 13)) | |
d16005f8 PC |
490 | return inter->block->pc + (op->offset + 1) * sizeof(u32); |
491 | else | |
492 | return jump_next(inter); | |
493 | } | |
494 | ||
495 | static u32 int_cp0_RFE(struct interpreter *inter) | |
496 | { | |
497 | struct lightrec_state *state = inter->state; | |
498 | u32 status; | |
499 | ||
500 | /* Read CP0 Status register (r12) */ | |
a59e5536 | 501 | status = state->ops.cop0_ops.mfc(state, inter->op->c.opcode, 12); |
d16005f8 PC |
502 | |
503 | /* Switch the bits */ | |
504 | status = ((status & 0x3c) >> 2) | (status & ~0xf); | |
505 | ||
506 | /* Write it back */ | |
a59e5536 | 507 | state->ops.cop0_ops.ctc(state, inter->op->c.opcode, 12, status); |
d16005f8 PC |
508 | |
509 | return jump_next(inter); | |
510 | } | |
511 | ||
512 | static u32 int_CP(struct interpreter *inter) | |
513 | { | |
514 | struct lightrec_state *state = inter->state; | |
515 | const struct lightrec_cop_ops *ops; | |
516 | const struct opcode *op = inter->op; | |
517 | ||
518 | if ((op->j.imm >> 25) & 1) | |
519 | ops = &state->ops.cop2_ops; | |
520 | else | |
521 | ops = &state->ops.cop0_ops; | |
522 | ||
523 | (*ops->op)(state, (op->j.imm) & ~(1 << 25)); | |
524 | ||
525 | return jump_next(inter); | |
526 | } | |
527 | ||
528 | static u32 int_ADDI(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] = reg_cache[op->rs] + (s32)(s16)op->imm; | |
535 | ||
536 | return jump_next(inter); | |
537 | } | |
538 | ||
539 | static u32 int_SLTI(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] = (s32)reg_cache[op->rs] < (s32)(s16)op->imm; | |
546 | ||
547 | return jump_next(inter); | |
548 | } | |
549 | ||
550 | static u32 int_SLTIU(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] < (u32)(s32)(s16)op->imm; | |
557 | ||
558 | return jump_next(inter); | |
559 | } | |
560 | ||
561 | static u32 int_ANDI(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_ORI(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_XORI(struct interpreter *inter) | |
584 | { | |
585 | u32 *reg_cache = inter->state->native_reg_cache; | |
586 | struct opcode_i *op = &inter->op->i; | |
587 | ||
588 | if (likely(op->rt)) | |
589 | reg_cache[op->rt] = reg_cache[op->rs] ^ op->imm; | |
590 | ||
591 | return jump_next(inter); | |
592 | } | |
593 | ||
594 | static u32 int_LUI(struct interpreter *inter) | |
595 | { | |
596 | struct opcode_i *op = &inter->op->i; | |
597 | ||
598 | inter->state->native_reg_cache[op->rt] = op->imm << 16; | |
599 | ||
600 | return jump_next(inter); | |
601 | } | |
602 | ||
603 | static u32 int_io(struct interpreter *inter, bool is_load) | |
604 | { | |
605 | struct opcode_i *op = &inter->op->i; | |
606 | u32 *reg_cache = inter->state->native_reg_cache; | |
607 | u32 val; | |
608 | ||
609 | val = lightrec_rw(inter->state, inter->op->c, | |
610 | reg_cache[op->rs], reg_cache[op->rt], | |
611 | &inter->op->flags); | |
612 | ||
613 | if (is_load && op->rt) | |
614 | reg_cache[op->rt] = val; | |
615 | ||
616 | return jump_next(inter); | |
617 | } | |
618 | ||
619 | static u32 int_load(struct interpreter *inter) | |
620 | { | |
621 | return int_io(inter, true); | |
622 | } | |
623 | ||
624 | static u32 int_store(struct interpreter *inter) | |
625 | { | |
626 | u32 next_pc; | |
627 | ||
628 | if (likely(!(inter->op->flags & LIGHTREC_SMC))) | |
629 | return int_io(inter, false); | |
630 | ||
631 | lightrec_rw(inter->state, inter->op->c, | |
632 | inter->state->native_reg_cache[inter->op->i.rs], | |
633 | inter->state->native_reg_cache[inter->op->i.rt], | |
634 | &inter->op->flags); | |
635 | ||
636 | next_pc = inter->block->pc + (inter->op->offset + 1) * 4; | |
637 | ||
638 | /* Invalidate next PC, to force the rest of the block to be rebuilt */ | |
639 | lightrec_invalidate(inter->state, next_pc, 4); | |
640 | ||
641 | return next_pc; | |
642 | } | |
643 | ||
644 | static u32 int_LWC2(struct interpreter *inter) | |
645 | { | |
646 | return int_io(inter, false); | |
647 | } | |
648 | ||
649 | static u32 int_special_SLL(struct interpreter *inter) | |
650 | { | |
651 | struct opcode *op = inter->op; | |
652 | u32 rt; | |
653 | ||
654 | if (op->opcode) { /* Handle NOPs */ | |
655 | rt = inter->state->native_reg_cache[op->r.rt]; | |
656 | inter->state->native_reg_cache[op->r.rd] = rt << op->r.imm; | |
657 | } | |
658 | ||
659 | return jump_next(inter); | |
660 | } | |
661 | ||
662 | static u32 int_special_SRL(struct interpreter *inter) | |
663 | { | |
664 | struct opcode *op = inter->op; | |
665 | u32 rt = inter->state->native_reg_cache[op->r.rt]; | |
666 | ||
667 | inter->state->native_reg_cache[op->r.rd] = rt >> op->r.imm; | |
668 | ||
669 | return jump_next(inter); | |
670 | } | |
671 | ||
672 | static u32 int_special_SRA(struct interpreter *inter) | |
673 | { | |
674 | struct opcode *op = inter->op; | |
675 | s32 rt = inter->state->native_reg_cache[op->r.rt]; | |
676 | ||
677 | inter->state->native_reg_cache[op->r.rd] = rt >> op->r.imm; | |
678 | ||
679 | return jump_next(inter); | |
680 | } | |
681 | ||
682 | static u32 int_special_SLLV(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_SRLV(struct interpreter *inter) | |
694 | { | |
695 | struct opcode *op = inter->op; | |
696 | u32 rs = inter->state->native_reg_cache[op->r.rs]; | |
697 | u32 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_special_SRAV(struct interpreter *inter) | |
705 | { | |
706 | struct opcode *op = inter->op; | |
707 | u32 rs = inter->state->native_reg_cache[op->r.rs]; | |
708 | s32 rt = inter->state->native_reg_cache[op->r.rt]; | |
709 | ||
710 | inter->state->native_reg_cache[op->r.rd] = rt >> (rs & 0x1f); | |
711 | ||
712 | return jump_next(inter); | |
713 | } | |
714 | ||
715 | static u32 int_syscall_break(struct interpreter *inter) | |
716 | { | |
717 | ||
718 | if (inter->op->r.op == OP_SPECIAL_BREAK) | |
719 | inter->state->exit_flags |= LIGHTREC_EXIT_BREAK; | |
720 | else | |
721 | inter->state->exit_flags |= LIGHTREC_EXIT_SYSCALL; | |
722 | ||
723 | return inter->block->pc + inter->op->offset * sizeof(u32); | |
724 | } | |
725 | ||
726 | static u32 int_special_MFHI(struct interpreter *inter) | |
727 | { | |
728 | u32 *reg_cache = inter->state->native_reg_cache; | |
729 | struct opcode_r *op = &inter->op->r; | |
730 | ||
731 | if (likely(op->rd)) | |
732 | reg_cache[op->rd] = reg_cache[REG_HI]; | |
733 | ||
734 | return jump_next(inter); | |
735 | } | |
736 | ||
737 | static u32 int_special_MTHI(struct interpreter *inter) | |
738 | { | |
739 | u32 *reg_cache = inter->state->native_reg_cache; | |
740 | ||
741 | reg_cache[REG_HI] = reg_cache[inter->op->r.rs]; | |
742 | ||
743 | return jump_next(inter); | |
744 | } | |
745 | ||
746 | static u32 int_special_MFLO(struct interpreter *inter) | |
747 | { | |
748 | u32 *reg_cache = inter->state->native_reg_cache; | |
749 | struct opcode_r *op = &inter->op->r; | |
750 | ||
751 | if (likely(op->rd)) | |
752 | reg_cache[op->rd] = reg_cache[REG_LO]; | |
753 | ||
754 | return jump_next(inter); | |
755 | } | |
756 | ||
757 | static u32 int_special_MTLO(struct interpreter *inter) | |
758 | { | |
759 | u32 *reg_cache = inter->state->native_reg_cache; | |
760 | ||
761 | reg_cache[REG_LO] = reg_cache[inter->op->r.rs]; | |
762 | ||
763 | return jump_next(inter); | |
764 | } | |
765 | ||
766 | static u32 int_special_MULT(struct interpreter *inter) | |
767 | { | |
768 | u32 *reg_cache = inter->state->native_reg_cache; | |
769 | s32 rs = reg_cache[inter->op->r.rs]; | |
770 | s32 rt = reg_cache[inter->op->r.rt]; | |
771 | u64 res = (s64)rs * (s64)rt; | |
772 | ||
773 | if (!(inter->op->flags & LIGHTREC_MULT32)) | |
774 | reg_cache[REG_HI] = res >> 32; | |
775 | reg_cache[REG_LO] = res; | |
776 | ||
777 | return jump_next(inter); | |
778 | } | |
779 | ||
780 | static u32 int_special_MULTU(struct interpreter *inter) | |
781 | { | |
782 | u32 *reg_cache = inter->state->native_reg_cache; | |
783 | u32 rs = reg_cache[inter->op->r.rs]; | |
784 | u32 rt = reg_cache[inter->op->r.rt]; | |
785 | u64 res = (u64)rs * (u64)rt; | |
786 | ||
787 | if (!(inter->op->flags & LIGHTREC_MULT32)) | |
788 | reg_cache[REG_HI] = res >> 32; | |
789 | reg_cache[REG_LO] = res; | |
790 | ||
791 | return jump_next(inter); | |
792 | } | |
793 | ||
794 | static u32 int_special_DIV(struct interpreter *inter) | |
795 | { | |
796 | u32 *reg_cache = inter->state->native_reg_cache; | |
797 | s32 rs = reg_cache[inter->op->r.rs]; | |
798 | s32 rt = reg_cache[inter->op->r.rt]; | |
799 | u32 lo, hi; | |
800 | ||
801 | if (rt == 0) { | |
802 | hi = rs; | |
803 | lo = (rs < 0) * 2 - 1; | |
f533290e EC |
804 | } else if ((rs == 0x80000000) && (rt == 0xFFFFFFFF)) { |
805 | lo = rs; | |
806 | hi = 0; | |
d16005f8 PC |
807 | } else { |
808 | lo = rs / rt; | |
809 | hi = rs % rt; | |
810 | } | |
811 | ||
812 | reg_cache[REG_HI] = hi; | |
813 | reg_cache[REG_LO] = lo; | |
814 | ||
815 | return jump_next(inter); | |
816 | } | |
817 | ||
818 | static u32 int_special_DIVU(struct interpreter *inter) | |
819 | { | |
820 | u32 *reg_cache = inter->state->native_reg_cache; | |
821 | u32 rs = reg_cache[inter->op->r.rs]; | |
822 | u32 rt = reg_cache[inter->op->r.rt]; | |
823 | u32 lo, hi; | |
824 | ||
825 | if (rt == 0) { | |
826 | hi = rs; | |
827 | lo = (u32)-1; | |
828 | } else { | |
829 | lo = rs / rt; | |
830 | hi = rs % rt; | |
831 | } | |
832 | ||
833 | reg_cache[REG_HI] = hi; | |
834 | reg_cache[REG_LO] = lo; | |
835 | ||
836 | return jump_next(inter); | |
837 | } | |
838 | ||
839 | static u32 int_special_ADD(struct interpreter *inter) | |
840 | { | |
841 | u32 *reg_cache = inter->state->native_reg_cache; | |
842 | struct opcode_r *op = &inter->op->r; | |
843 | s32 rs = reg_cache[op->rs]; | |
844 | s32 rt = reg_cache[op->rt]; | |
845 | ||
846 | if (likely(op->rd)) | |
847 | reg_cache[op->rd] = rs + rt; | |
848 | ||
849 | return jump_next(inter); | |
850 | } | |
851 | ||
852 | static u32 int_special_SUB(struct interpreter *inter) | |
853 | { | |
854 | u32 *reg_cache = inter->state->native_reg_cache; | |
855 | struct opcode_r *op = &inter->op->r; | |
856 | u32 rs = reg_cache[op->rs]; | |
857 | u32 rt = reg_cache[op->rt]; | |
858 | ||
859 | if (likely(op->rd)) | |
860 | reg_cache[op->rd] = rs - rt; | |
861 | ||
862 | return jump_next(inter); | |
863 | } | |
864 | ||
865 | static u32 int_special_AND(struct interpreter *inter) | |
866 | { | |
867 | u32 *reg_cache = inter->state->native_reg_cache; | |
868 | struct opcode_r *op = &inter->op->r; | |
869 | u32 rs = reg_cache[op->rs]; | |
870 | u32 rt = reg_cache[op->rt]; | |
871 | ||
872 | if (likely(op->rd)) | |
873 | reg_cache[op->rd] = rs & rt; | |
874 | ||
875 | return jump_next(inter); | |
876 | } | |
877 | ||
878 | static u32 int_special_OR(struct interpreter *inter) | |
879 | { | |
880 | u32 *reg_cache = inter->state->native_reg_cache; | |
881 | struct opcode_r *op = &inter->op->r; | |
882 | u32 rs = reg_cache[op->rs]; | |
883 | u32 rt = reg_cache[op->rt]; | |
884 | ||
885 | if (likely(op->rd)) | |
886 | reg_cache[op->rd] = rs | rt; | |
887 | ||
888 | return jump_next(inter); | |
889 | } | |
890 | ||
891 | static u32 int_special_XOR(struct interpreter *inter) | |
892 | { | |
893 | u32 *reg_cache = inter->state->native_reg_cache; | |
894 | struct opcode_r *op = &inter->op->r; | |
895 | u32 rs = reg_cache[op->rs]; | |
896 | u32 rt = reg_cache[op->rt]; | |
897 | ||
898 | if (likely(op->rd)) | |
899 | reg_cache[op->rd] = rs ^ rt; | |
900 | ||
901 | return jump_next(inter); | |
902 | } | |
903 | ||
904 | static u32 int_special_NOR(struct interpreter *inter) | |
905 | { | |
906 | u32 *reg_cache = inter->state->native_reg_cache; | |
907 | struct opcode_r *op = &inter->op->r; | |
908 | u32 rs = reg_cache[op->rs]; | |
909 | u32 rt = reg_cache[op->rt]; | |
910 | ||
911 | if (likely(op->rd)) | |
912 | reg_cache[op->rd] = ~(rs | rt); | |
913 | ||
914 | return jump_next(inter); | |
915 | } | |
916 | ||
917 | static u32 int_special_SLT(struct interpreter *inter) | |
918 | { | |
919 | u32 *reg_cache = inter->state->native_reg_cache; | |
920 | struct opcode_r *op = &inter->op->r; | |
921 | s32 rs = reg_cache[op->rs]; | |
922 | s32 rt = reg_cache[op->rt]; | |
923 | ||
924 | if (likely(op->rd)) | |
925 | reg_cache[op->rd] = rs < rt; | |
926 | ||
927 | return jump_next(inter); | |
928 | } | |
929 | ||
930 | static u32 int_special_SLTU(struct interpreter *inter) | |
931 | { | |
932 | u32 *reg_cache = inter->state->native_reg_cache; | |
933 | struct opcode_r *op = &inter->op->r; | |
934 | u32 rs = reg_cache[op->rs]; | |
935 | u32 rt = reg_cache[op->rt]; | |
936 | ||
937 | if (likely(op->rd)) | |
938 | reg_cache[op->rd] = rs < rt; | |
939 | ||
940 | return jump_next(inter); | |
941 | } | |
942 | ||
943 | static u32 int_META_SKIP(struct interpreter *inter) | |
944 | { | |
945 | return jump_skip(inter); | |
946 | } | |
947 | ||
948 | static u32 int_META_MOV(struct interpreter *inter) | |
949 | { | |
950 | u32 *reg_cache = inter->state->native_reg_cache; | |
951 | struct opcode_r *op = &inter->op->r; | |
952 | ||
953 | if (likely(op->rd)) | |
954 | reg_cache[op->rd] = reg_cache[op->rs]; | |
955 | ||
956 | return jump_next(inter); | |
957 | } | |
958 | ||
959 | static u32 int_META_SYNC(struct interpreter *inter) | |
960 | { | |
961 | inter->state->current_cycle += inter->cycles; | |
962 | inter->cycles = 0; | |
963 | ||
964 | return jump_skip(inter); | |
965 | } | |
966 | ||
967 | static const lightrec_int_func_t int_standard[64] = { | |
968 | [OP_SPECIAL] = int_SPECIAL, | |
969 | [OP_REGIMM] = int_REGIMM, | |
970 | [OP_J] = int_J, | |
971 | [OP_JAL] = int_JAL, | |
972 | [OP_BEQ] = int_BEQ, | |
973 | [OP_BNE] = int_BNE, | |
974 | [OP_BLEZ] = int_BLEZ, | |
975 | [OP_BGTZ] = int_BGTZ, | |
976 | [OP_ADDI] = int_ADDI, | |
977 | [OP_ADDIU] = int_ADDI, | |
978 | [OP_SLTI] = int_SLTI, | |
979 | [OP_SLTIU] = int_SLTIU, | |
980 | [OP_ANDI] = int_ANDI, | |
981 | [OP_ORI] = int_ORI, | |
982 | [OP_XORI] = int_XORI, | |
983 | [OP_LUI] = int_LUI, | |
984 | [OP_CP0] = int_CP0, | |
985 | [OP_CP2] = int_CP2, | |
986 | [OP_LB] = int_load, | |
987 | [OP_LH] = int_load, | |
988 | [OP_LWL] = int_load, | |
989 | [OP_LW] = int_load, | |
990 | [OP_LBU] = int_load, | |
991 | [OP_LHU] = int_load, | |
992 | [OP_LWR] = int_load, | |
993 | [OP_SB] = int_store, | |
994 | [OP_SH] = int_store, | |
995 | [OP_SWL] = int_store, | |
996 | [OP_SW] = int_store, | |
997 | [OP_SWR] = int_store, | |
998 | [OP_LWC2] = int_LWC2, | |
999 | [OP_SWC2] = int_store, | |
1000 | ||
1001 | [OP_META_REG_UNLOAD] = int_META_SKIP, | |
1002 | [OP_META_BEQZ] = int_BEQ, | |
1003 | [OP_META_BNEZ] = int_BNE, | |
1004 | [OP_META_MOV] = int_META_MOV, | |
1005 | [OP_META_SYNC] = int_META_SYNC, | |
1006 | }; | |
1007 | ||
1008 | static const lightrec_int_func_t int_special[64] = { | |
1009 | [OP_SPECIAL_SLL] = int_special_SLL, | |
1010 | [OP_SPECIAL_SRL] = int_special_SRL, | |
1011 | [OP_SPECIAL_SRA] = int_special_SRA, | |
1012 | [OP_SPECIAL_SLLV] = int_special_SLLV, | |
1013 | [OP_SPECIAL_SRLV] = int_special_SRLV, | |
1014 | [OP_SPECIAL_SRAV] = int_special_SRAV, | |
1015 | [OP_SPECIAL_JR] = int_special_JR, | |
1016 | [OP_SPECIAL_JALR] = int_special_JALR, | |
1017 | [OP_SPECIAL_SYSCALL] = int_syscall_break, | |
1018 | [OP_SPECIAL_BREAK] = int_syscall_break, | |
1019 | [OP_SPECIAL_MFHI] = int_special_MFHI, | |
1020 | [OP_SPECIAL_MTHI] = int_special_MTHI, | |
1021 | [OP_SPECIAL_MFLO] = int_special_MFLO, | |
1022 | [OP_SPECIAL_MTLO] = int_special_MTLO, | |
1023 | [OP_SPECIAL_MULT] = int_special_MULT, | |
1024 | [OP_SPECIAL_MULTU] = int_special_MULTU, | |
1025 | [OP_SPECIAL_DIV] = int_special_DIV, | |
1026 | [OP_SPECIAL_DIVU] = int_special_DIVU, | |
1027 | [OP_SPECIAL_ADD] = int_special_ADD, | |
1028 | [OP_SPECIAL_ADDU] = int_special_ADD, | |
1029 | [OP_SPECIAL_SUB] = int_special_SUB, | |
1030 | [OP_SPECIAL_SUBU] = int_special_SUB, | |
1031 | [OP_SPECIAL_AND] = int_special_AND, | |
1032 | [OP_SPECIAL_OR] = int_special_OR, | |
1033 | [OP_SPECIAL_XOR] = int_special_XOR, | |
1034 | [OP_SPECIAL_NOR] = int_special_NOR, | |
1035 | [OP_SPECIAL_SLT] = int_special_SLT, | |
1036 | [OP_SPECIAL_SLTU] = int_special_SLTU, | |
1037 | }; | |
1038 | ||
1039 | static const lightrec_int_func_t int_regimm[64] = { | |
1040 | [OP_REGIMM_BLTZ] = int_regimm_BLTZ, | |
1041 | [OP_REGIMM_BGEZ] = int_regimm_BGEZ, | |
1042 | [OP_REGIMM_BLTZAL] = int_regimm_BLTZAL, | |
1043 | [OP_REGIMM_BGEZAL] = int_regimm_BGEZAL, | |
1044 | }; | |
1045 | ||
1046 | static const lightrec_int_func_t int_cp0[64] = { | |
1047 | [OP_CP0_MFC0] = int_cfc, | |
1048 | [OP_CP0_CFC0] = int_cfc, | |
1049 | [OP_CP0_MTC0] = int_ctc, | |
1050 | [OP_CP0_CTC0] = int_ctc, | |
1051 | [OP_CP0_RFE] = int_cp0_RFE, | |
1052 | }; | |
1053 | ||
1054 | static const lightrec_int_func_t int_cp2_basic[64] = { | |
1055 | [OP_CP2_BASIC_MFC2] = int_cfc, | |
1056 | [OP_CP2_BASIC_CFC2] = int_cfc, | |
1057 | [OP_CP2_BASIC_MTC2] = int_ctc, | |
1058 | [OP_CP2_BASIC_CTC2] = int_ctc, | |
1059 | }; | |
1060 | ||
1061 | static u32 int_SPECIAL(struct interpreter *inter) | |
1062 | { | |
1063 | lightrec_int_func_t f = int_special[inter->op->r.op]; | |
1064 | if (likely(f)) | |
1065 | return execute(f, inter); | |
1066 | else | |
1067 | return int_unimplemented(inter); | |
1068 | } | |
1069 | ||
1070 | static u32 int_REGIMM(struct interpreter *inter) | |
1071 | { | |
1072 | lightrec_int_func_t f = int_regimm[inter->op->r.rt]; | |
1073 | if (likely(f)) | |
1074 | return execute(f, inter); | |
1075 | else | |
1076 | return int_unimplemented(inter); | |
1077 | } | |
1078 | ||
1079 | static u32 int_CP0(struct interpreter *inter) | |
1080 | { | |
1081 | lightrec_int_func_t f = int_cp0[inter->op->r.rs]; | |
1082 | if (likely(f)) | |
1083 | return execute(f, inter); | |
1084 | else | |
1085 | return int_CP(inter); | |
1086 | } | |
1087 | ||
1088 | static u32 int_CP2(struct interpreter *inter) | |
1089 | { | |
1090 | if (inter->op->r.op == OP_CP2_BASIC) { | |
1091 | lightrec_int_func_t f = int_cp2_basic[inter->op->r.rs]; | |
1092 | if (likely(f)) | |
1093 | return execute(f, inter); | |
1094 | } | |
1095 | ||
1096 | return int_CP(inter); | |
1097 | } | |
1098 | ||
1099 | static u32 lightrec_int_op(struct interpreter *inter) | |
1100 | { | |
1101 | return execute(int_standard[inter->op->i.op], inter); | |
1102 | } | |
1103 | ||
1104 | static u32 lightrec_emulate_block_list(struct block *block, struct opcode *op) | |
1105 | { | |
1106 | struct interpreter inter; | |
1107 | u32 pc; | |
1108 | ||
1109 | inter.block = block; | |
1110 | inter.state = block->state; | |
1111 | inter.op = op; | |
1112 | inter.cycles = 0; | |
1113 | inter.delay_slot = false; | |
1114 | ||
1115 | pc = lightrec_int_op(&inter); | |
1116 | ||
1117 | /* Add the cycles of the last branch */ | |
1118 | inter.cycles += lightrec_cycles_of_opcode(inter.op->c); | |
1119 | ||
1120 | block->state->current_cycle += inter.cycles; | |
1121 | ||
1122 | return pc; | |
1123 | } | |
1124 | ||
1125 | u32 lightrec_emulate_block(struct block *block, u32 pc) | |
1126 | { | |
1127 | u32 offset = (kunseg(pc) - kunseg(block->pc)) >> 2; | |
1128 | struct opcode *op; | |
1129 | ||
1130 | for (op = block->opcode_list; | |
1131 | op && (op->offset < offset); op = op->next); | |
1132 | if (op) | |
1133 | return lightrec_emulate_block_list(block, op); | |
1134 | ||
1135 | pr_err("PC 0x%x is outside block at PC 0x%x\n", pc, block->pc); | |
1136 | ||
1137 | return 0; | |
1138 | } |