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 != &reg[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 != &reg[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