1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2 * Mupen64plus - cached_interp.c *
3 * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
4 * Copyright (C) 2002 Hacktarux *
5 * *
6 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 2 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the *
18 * Free Software Foundation, Inc., *
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
20 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
21
22 #include <stdint.h>
23 #include <stdlib.h>
24
25 #define __STDC_FORMAT_MACROS
26 #ifdef _MSC_VER
27 #define PRIx32 "x"
28 #define PRIX32 "X"
29 #else
30 #include <inttypes.h>
31 #endif
32 #include <string.h>
33
34 #include "api/callbacks.h"
35 #include "api/debugger.h"
36 #include "api/m64p_types.h"
37 #include "cached_interp.h"
38 #include "cp0_private.h"
39 #include "cp1_private.h"
40 #include "exception.h"
41 #include "interrupt.h"
42 #include "macros.h"
43 #include "main/main.h"
44 #include "memory/memory.h"
45 #include "ops.h"
46 #include "r4300.h"
47 #include "recomp.h"
48 #include "tlb.h"
49
50 #ifdef DBG
51 #include "debugger/dbg_debugger.h"
52 #include "debugger/dbg_types.h"
53 #endif
54
55 /* global variables */
56 char invalid_code[0x100000];
57 struct precomp_block *blocks[0x100000];
58 struct precomp_block *actual = NULL;
59 uint32_t jump_to_address;
60
61 // -----------------------------------------------------------
62 // Cached interpreter functions (and fallback for dynarec).
63 // -----------------------------------------------------------
64 #ifdef DBG
65 #define UPDATE_DEBUGGER() if (g_DebuggerActive) update_debugger(PC->addr)
66 #else
67 #define UPDATE_DEBUGGER() do { } while(0)
68 #endif
69
70 #define PCADDR PC->addr
71 #define ADD_TO_PC(x) PC += x;
72 #define DECLARE_INSTRUCTION(name) static void name(void)
73
74 #define DECLARE_JUMP(name, destination, condition, link, likely, cop1) \
75 static void name(void) \
76 { \
77 const int take_jump = (condition); \
78 const uint32_t jump_target = (destination); \
79 int64_t *link_register = (link); \
80 if (cop1 && check_cop1_unusable()) return; \
81 if (link_register != ®[0]) \
82 { \
83 *link_register = SE32(PC->addr + 8); \
84 } \
85 if (!likely || take_jump) \
86 { \
87 PC++; \
88 g_dev.r4300.delay_slot=1; \
89 UPDATE_DEBUGGER(); \
90 PC->ops(); \
91 cp0_update_count(); \
92 g_dev.r4300.delay_slot=0; \
93 if (take_jump && !skip_jump) \
94 { \
95 PC=actual->block+((jump_target-actual->start)>>2); \
96 } \
97 } \
98 else \
99 { \
100 PC += 2; \
101 cp0_update_count(); \
102 } \
103 last_addr = PC->addr; \
104 if (next_interrupt <= g_cp0_regs[CP0_COUNT_REG]) gen_interrupt(); \
105 } \
106 static void name##_OUT(void) \
107 { \
108 const int take_jump = (condition); \
109 const uint32_t jump_target = (destination); \
110 int64_t *link_register = (link); \
111 if (cop1 && check_cop1_unusable()) return; \
112 if (link_register != ®[0]) \
113 { \
114 *link_register = SE32(PC->addr + 8); \
115 } \
116 if (!likely || take_jump) \
117 { \
118 PC++; \
119 g_dev.r4300.delay_slot=1; \
120 UPDATE_DEBUGGER(); \
121 PC->ops(); \
122 cp0_update_count(); \
123 g_dev.r4300.delay_slot=0; \
124 if (take_jump && !skip_jump) \
125 { \
126 jump_to(jump_target); \
127 } \
128 } \
129 else \
130 { \
131 PC += 2; \
132 cp0_update_count(); \
133 } \
134 last_addr = PC->addr; \
135 if (next_interrupt <= g_cp0_regs[CP0_COUNT_REG]) gen_interrupt(); \
136 } \
137 static void name##_IDLE(void) \
138 { \
139 const int take_jump = (condition); \
140 int skip; \
141 if (cop1 && check_cop1_unusable()) return; \
142 if (take_jump) \
143 { \
144 cp0_update_count(); \
145 skip = next_interrupt - g_cp0_regs[CP0_COUNT_REG]; \
146 if (skip > 3) g_cp0_regs[CP0_COUNT_REG] += (skip & UINT32_C(0xFFFFFFFC)); \
147 else name(); \
148 } \
149 else name(); \
150 }
151
152 #define CHECK_MEMORY() \
153 if (!invalid_code[address>>12]) \
154 if (blocks[address>>12]->block[(address&0xFFF)/4].ops != \
155 current_instruction_table.NOTCOMPILED) \
156 invalid_code[address>>12] = 1;
157
158 // two functions are defined from the macros above but never used
159 // these prototype declarations will prevent a warning
160 #if defined(__GNUC__)
161 static void JR_IDLE(void) __attribute__((used));
162 static void JALR_IDLE(void) __attribute__((used));
163 #endif
164
165 #include "mips_instructions.def"
166
167 // -----------------------------------------------------------
168 // Flow control 'fake' instructions
169 // -----------------------------------------------------------
FIN_BLOCK(void)170 static void FIN_BLOCK(void)
171 {
172 if (!g_dev.r4300.delay_slot)
173 {
174 jump_to((PC-1)->addr+4);
175 #if 0
176 #ifdef DBG
177 if (g_DebuggerActive) update_debugger(PC->addr);
178 #endif
179 /* Used by dynarec only, check should be unnecessary */
180 #endif
181 PC->ops();
182 if (r4300emu == CORE_DYNAREC) dyna_jump();
183 }
184 else
185 {
186 struct precomp_block *blk = actual;
187 struct precomp_instr *inst = PC;
188 jump_to((PC-1)->addr+4);
189
190 #if 0
191 #ifdef DBG
192 if (g_DebuggerActive) update_debugger(PC->addr);
193 #endif
194 /* Used by dynarec only, check should be unnecessary */
195 #endif
196 if (!skip_jump)
197 {
198 PC->ops();
199 actual = blk;
200 PC = inst+1;
201 }
202 else
203 PC->ops();
204
205 if (r4300emu == CORE_DYNAREC) dyna_jump();
206 }
207 }
208
NOTCOMPILED(void)209 static void NOTCOMPILED(void)
210 {
211 uint32_t *mem = fast_mem_access(blocks[PC->addr>>12]->start);
212 #ifdef CORE_DBG
213 DebugMessage(M64MSG_INFO, "NOTCOMPILED: addr = %x ops = %lx", PC->addr, (long) PC->ops);
214 #endif
215
216 if (mem != NULL)
217 recompile_block(mem, blocks[PC->addr >> 12], PC->addr);
218 else
219 DebugMessage(M64MSG_ERROR, "not compiled exception");
220
221 #if 0
222 #ifdef DBG
223 if (g_DebuggerActive) update_debugger(PC->addr);
224 #endif
225 /* The preceeding update_debugger SHOULD be unnecessary since it should have been
226 called before NOTCOMPILED would have been executed */
227 #endif
228 PC->ops();
229 if (r4300emu == CORE_DYNAREC)
230 dyna_jump();
231 }
232
NOTCOMPILED2(void)233 static void NOTCOMPILED2(void)
234 {
235 NOTCOMPILED();
236 }
237
238 // -----------------------------------------------------------
239 // Cached interpreter instruction table
240 // -----------------------------------------------------------
241 const cpu_instruction_table cached_interpreter_table = {
242 LB,
243 LBU,
244 LH,
245 LHU,
246 LW,
247 LWL,
248 LWR,
249 SB,
250 SH,
251 SW,
252 SWL,
253 SWR,
254
255 LD,
256 LDL,
257 LDR,
258 LL,
259 LWU,
260 SC,
261 SD,
262 SDL,
263 SDR,
264 SYNC,
265
266 ADDI,
267 ADDIU,
268 SLTI,
269 SLTIU,
270 ANDI,
271 ORI,
272 XORI,
273 LUI,
274
275 DADDI,
276 DADDIU,
277
278 ADD,
279 ADDU,
280 SUB,
281 SUBU,
282 SLT,
283 SLTU,
284 AND,
285 OR,
286 XOR,
287 NOR,
288
289 DADD,
290 DADDU,
291 DSUB,
292 DSUBU,
293
294 MULT,
295 MULTU,
296 DIV,
297 DIVU,
298 MFHI,
299 MTHI,
300 MFLO,
301 MTLO,
302
303 DMULT,
304 DMULTU,
305 DDIV,
306 DDIVU,
307
308 J,
309 J_OUT,
310 J_IDLE,
311 JAL,
312 JAL_OUT,
313 JAL_IDLE,
314 // Use the _OUT versions of JR and JALR, since we don't know
315 // until runtime if they're going to jump inside or outside the block
316 JR_OUT,
317 JALR_OUT,
318 BEQ,
319 BEQ_OUT,
320 BEQ_IDLE,
321 BNE,
322 BNE_OUT,
323 BNE_IDLE,
324 BLEZ,
325 BLEZ_OUT,
326 BLEZ_IDLE,
327 BGTZ,
328 BGTZ_OUT,
329 BGTZ_IDLE,
330 BLTZ,
331 BLTZ_OUT,
332 BLTZ_IDLE,
333 BGEZ,
334 BGEZ_OUT,
335 BGEZ_IDLE,
336 BLTZAL,
337 BLTZAL_OUT,
338 BLTZAL_IDLE,
339 BGEZAL,
340 BGEZAL_OUT,
341 BGEZAL_IDLE,
342
343 BEQL,
344 BEQL_OUT,
345 BEQL_IDLE,
346 BNEL,
347 BNEL_OUT,
348 BNEL_IDLE,
349 BLEZL,
350 BLEZL_OUT,
351 BLEZL_IDLE,
352 BGTZL,
353 BGTZL_OUT,
354 BGTZL_IDLE,
355 BLTZL,
356 BLTZL_OUT,
357 BLTZL_IDLE,
358 BGEZL,
359 BGEZL_OUT,
360 BGEZL_IDLE,
361 BLTZALL,
362 BLTZALL_OUT,
363 BLTZALL_IDLE,
364 BGEZALL,
365 BGEZALL_OUT,
366 BGEZALL_IDLE,
367 BC1TL,
368 BC1TL_OUT,
369 BC1TL_IDLE,
370 BC1FL,
371 BC1FL_OUT,
372 BC1FL_IDLE,
373
374 SLL,
375 SRL,
376 SRA,
377 SLLV,
378 SRLV,
379 SRAV,
380
381 DSLL,
382 DSRL,
383 DSRA,
384 DSLLV,
385 DSRLV,
386 DSRAV,
387 DSLL32,
388 DSRL32,
389 DSRA32,
390
391 MTC0,
392 MFC0,
393
394 TLBR,
395 TLBWI,
396 TLBWR,
397 TLBP,
398 CACHE,
399 ERET,
400
401 LWC1,
402 SWC1,
403 MTC1,
404 MFC1,
405 CTC1,
406 CFC1,
407 BC1T,
408 BC1T_OUT,
409 BC1T_IDLE,
410 BC1F,
411 BC1F_OUT,
412 BC1F_IDLE,
413
414 DMFC1,
415 DMTC1,
416 LDC1,
417 SDC1,
418
419 CVT_S_D,
420 CVT_S_W,
421 CVT_S_L,
422 CVT_D_S,
423 CVT_D_W,
424 CVT_D_L,
425 CVT_W_S,
426 CVT_W_D,
427 CVT_L_S,
428 CVT_L_D,
429
430 ROUND_W_S,
431 ROUND_W_D,
432 ROUND_L_S,
433 ROUND_L_D,
434
435 TRUNC_W_S,
436 TRUNC_W_D,
437 TRUNC_L_S,
438 TRUNC_L_D,
439
440 CEIL_W_S,
441 CEIL_W_D,
442 CEIL_L_S,
443 CEIL_L_D,
444
445 FLOOR_W_S,
446 FLOOR_W_D,
447 FLOOR_L_S,
448 FLOOR_L_D,
449
450 ADD_S,
451 ADD_D,
452
453 SUB_S,
454 SUB_D,
455
456 MUL_S,
457 MUL_D,
458
459 DIV_S,
460 DIV_D,
461
462 ABS_S,
463 ABS_D,
464
465 MOV_S,
466 MOV_D,
467
468 NEG_S,
469 NEG_D,
470
471 SQRT_S,
472 SQRT_D,
473
474 C_F_S,
475 C_F_D,
476 C_UN_S,
477 C_UN_D,
478 C_EQ_S,
479 C_EQ_D,
480 C_UEQ_S,
481 C_UEQ_D,
482 C_OLT_S,
483 C_OLT_D,
484 C_ULT_S,
485 C_ULT_D,
486 C_OLE_S,
487 C_OLE_D,
488 C_ULE_S,
489 C_ULE_D,
490 C_SF_S,
491 C_SF_D,
492 C_NGLE_S,
493 C_NGLE_D,
494 C_SEQ_S,
495 C_SEQ_D,
496 C_NGL_S,
497 C_NGL_D,
498 C_LT_S,
499 C_LT_D,
500 C_NGE_S,
501 C_NGE_D,
502 C_LE_S,
503 C_LE_D,
504 C_NGT_S,
505 C_NGT_D,
506
507 SYSCALL,
508
509 TEQ,
510
511 NOP,
512 RESERVED,
513 NI,
514
515 FIN_BLOCK,
516 NOTCOMPILED,
517 NOTCOMPILED2
518 };
519
update_invalid_addr(unsigned int addr)520 static unsigned int update_invalid_addr(unsigned int addr)
521 {
522 if (addr >= 0x80000000 && addr < 0xc0000000)
523 {
524 if (invalid_code[addr>>12]) invalid_code[(addr^0x20000000)>>12] = 1;
525 if (invalid_code[(addr^0x20000000)>>12]) invalid_code[addr>>12] = 1;
526 return addr;
527 }
528 else
529 {
530 unsigned int paddr = virtual_to_physical_address(&g_dev.r4300, addr, 2);
531 if (paddr)
532 {
533 unsigned int beg_paddr = paddr - (addr - (addr&~0xFFF));
534 update_invalid_addr(paddr);
535 if (invalid_code[(beg_paddr+0x000)>>12]) invalid_code[addr>>12] = 1;
536 if (invalid_code[(beg_paddr+0xFFC)>>12]) invalid_code[addr>>12] = 1;
537 if (invalid_code[addr>>12]) invalid_code[(beg_paddr+0x000)>>12] = 1;
538 if (invalid_code[addr>>12]) invalid_code[(beg_paddr+0xFFC)>>12] = 1;
539 }
540 return paddr;
541 }
542 }
543
544 #define addr jump_to_address
jump_to_func(void)545 void jump_to_func(void)
546 {
547 unsigned int paddr;
548 if (skip_jump) return;
549 paddr = update_invalid_addr(addr);
550 if (!paddr) return;
551 actual = blocks[addr>>12];
552 if (invalid_code[addr>>12])
553 {
554 if (!blocks[addr>>12])
555 {
556 blocks[addr>>12] = (struct precomp_block *) malloc(sizeof(struct precomp_block));
557 actual = blocks[addr>>12];
558 blocks[addr>>12]->code = NULL;
559 blocks[addr>>12]->block = NULL;
560 blocks[addr>>12]->jumps_table = NULL;
561 blocks[addr>>12]->riprel_table = NULL;
562 }
563 blocks[addr>>12]->start = addr & ~0xFFF;
564 blocks[addr>>12]->end = (addr & ~0xFFF) + 0x1000;
565 init_block(blocks[addr>>12]);
566 }
567 PC=actual->block+((addr-actual->start)>>2);
568
569 if (r4300emu == CORE_DYNAREC) dyna_jump();
570 }
571 #undef addr
572
init_blocks(void)573 void init_blocks(void)
574 {
575 int i;
576 for (i=0; i<0x100000; i++)
577 {
578 invalid_code[i] = 1;
579 blocks[i] = NULL;
580 }
581 }
582
free_blocks(void)583 void free_blocks(void)
584 {
585 int i;
586 for (i=0; i<0x100000; i++)
587 {
588 if (blocks[i])
589 {
590 free_block(blocks[i]);
591 free(blocks[i]);
592 blocks[i] = NULL;
593 }
594 }
595 }
596
invalidate_cached_code_hacktarux(uint32_t address,size_t size)597 void invalidate_cached_code_hacktarux(uint32_t address, size_t size)
598 {
599 size_t i;
600 uint32_t addr;
601 uint32_t addr_max;
602
603 if (size == 0)
604 {
605 /* invalidate everthing */
606 memset(invalid_code, 1, 0x100000);
607 }
608 else
609 {
610 /* invalidate blocks (if necessary) */
611 addr_max = address+size;
612
613 for(addr = address; addr < addr_max; addr += 4)
614 {
615 i = (addr >> 12);
616
617 if (invalid_code[i] == 0)
618 {
619 if (blocks[i] == NULL
620 || blocks[i]->block[(addr & 0xfff) / 4].ops != current_instruction_table.NOTCOMPILED)
621 {
622 invalid_code[i] = 1;
623 /* go directly to next i */
624 addr &= ~0xfff;
625 addr |= 0xffc;
626 }
627 }
628 else
629 {
630 /* go directly to next i */
631 addr &= ~0xfff;
632 addr |= 0xffc;
633 }
634 }
635 }
636 }
637
638