X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=source%2Fmupen64plus-core%2Fsrc%2Fr4300%2Fr4300.c;fp=source%2Fmupen64plus-core%2Fsrc%2Fr4300%2Fr4300.c;h=9a64fdb480602359359ba7e41fc6f7945fe1852a;hb=451ab91e3827a6384981b3300e2a7000d2eaba58;hp=0000000000000000000000000000000000000000;hpb=a2ab25365b5b0dddbee476d695d8a31151407581;p=mupen64plus-pandora.git diff --git a/source/mupen64plus-core/src/r4300/r4300.c b/source/mupen64plus-core/src/r4300/r4300.c new file mode 100644 index 0000000..9a64fdb --- /dev/null +++ b/source/mupen64plus-core/src/r4300/r4300.c @@ -0,0 +1,1100 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - r4300.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include +#include + +#include "api/m64p_types.h" +#include "api/callbacks.h" +#include "api/debugger.h" +#include "memory/memory.h" +#include "main/main.h" +#include "main/rom.h" + +#include "r4300.h" +#include "ops.h" +#include "exception.h" +#include "interupt.h" +#include "macros.h" +#include "recomp.h" +#include "recomph.h" +#include "new_dynarec/new_dynarec.h" + +#ifdef DBG +#include "debugger/dbg_types.h" +#include "debugger/debugger.h" +#endif + +unsigned int r4300emu = 0; +int no_compiled_jump = 0; +int llbit, rompause; +#if NEW_DYNAREC != NEW_DYNAREC_ARM +int stop; +long long int reg[32], hi, lo; +unsigned int reg_cop0[32]; +float *reg_cop1_simple[32]; +double *reg_cop1_double[32]; +int FCR0, FCR31; +unsigned int next_interupt; +precomp_instr *PC; +#endif +long long int local_rs; +long long int reg_cop1_fgr_64[32]; +tlb tlb_e[32]; +unsigned int delay_slot, skip_jump = 0, dyna_interp = 0, last_addr; +unsigned long long int debug_count = 0; +unsigned int CIC_Chip; +char invalid_code[0x100000]; + +precomp_block *blocks[0x100000], *actual; +int rounding_mode = 0x33F, trunc_mode = 0xF3F, round_mode = 0x33F, + ceil_mode = 0xB3F, floor_mode = 0x73F; + +// ----------------------------------------------------------- +// Cached interpreter functions (and fallback for dynarec). +// ----------------------------------------------------------- +#ifdef DBG +#define UPDATE_DEBUGGER() if (g_DebuggerActive) update_debugger(PC->addr) +#else +#define UPDATE_DEBUGGER() do { } while(0) +#endif + +#define PCADDR PC->addr +#define ADD_TO_PC(x) PC += x; +#define DECLARE_INSTRUCTION(name) static void name(void) + +#define DECLARE_JUMP(name, destination, condition, link, likely, cop1) \ + static void name(void) \ + { \ + const int take_jump = (condition); \ + const unsigned int jump_target = (destination); \ + long long int *link_register = (link); \ + if (cop1 && check_cop1_unusable()) return; \ + if (!likely || take_jump) \ + { \ + PC++; \ + delay_slot=1; \ + UPDATE_DEBUGGER(); \ + PC->ops(); \ + update_count(); \ + delay_slot=0; \ + if (take_jump && !skip_jump) \ + { \ + if (link_register != ®[0]) \ + { \ + *link_register=PC->addr; \ + sign_extended(*link_register); \ + } \ + PC=actual->block+((jump_target-actual->start)>>2); \ + } \ + } \ + else \ + { \ + PC += 2; \ + update_count(); \ + } \ + last_addr = PC->addr; \ + if (next_interupt <= Count) gen_interupt(); \ + } \ + static void name##_OUT(void) \ + { \ + const int take_jump = (condition); \ + const unsigned int jump_target = (destination); \ + long long int *link_register = (link); \ + if (cop1 && check_cop1_unusable()) return; \ + if (!likely || take_jump) \ + { \ + PC++; \ + delay_slot=1; \ + UPDATE_DEBUGGER(); \ + PC->ops(); \ + update_count(); \ + delay_slot=0; \ + if (take_jump && !skip_jump) \ + { \ + if (link_register != ®[0]) \ + { \ + *link_register=PC->addr; \ + sign_extended(*link_register); \ + } \ + jump_to(jump_target); \ + } \ + } \ + else \ + { \ + PC += 2; \ + update_count(); \ + } \ + last_addr = PC->addr; \ + if (next_interupt <= Count) gen_interupt(); \ + } \ + static void name##_IDLE(void) \ + { \ + const int take_jump = (condition); \ + int skip; \ + if (cop1 && check_cop1_unusable()) return; \ + if (take_jump) \ + { \ + update_count(); \ + skip = next_interupt - Count; \ + if (skip > 3) Count += (skip & 0xFFFFFFFC); \ + else name(); \ + } \ + else name(); \ + } + +#define CHECK_MEMORY() \ + if (!invalid_code[address>>12]) \ + if (blocks[address>>12]->block[(address&0xFFF)/4].ops != \ + current_instruction_table.NOTCOMPILED) \ + invalid_code[address>>12] = 1; + +#include "interpreter.def" + +// two functions are defined from the macros above but never used +// these prototype declarations will prevent a warning +#if defined(__GNUC__) + void JR_IDLE(void) __attribute__((used)); + void JALR_IDLE(void) __attribute__((used)); +#endif + +// ----------------------------------------------------------- +// Flow control 'fake' instructions +// ----------------------------------------------------------- +static void FIN_BLOCK(void) +{ + if (!delay_slot) + { + jump_to((PC-1)->addr+4); +/*#ifdef DBG + if (g_DebuggerActive) update_debugger(PC->addr); +#endif +Used by dynarec only, check should be unnecessary +*/ + PC->ops(); + if (r4300emu == CORE_DYNAREC) dyna_jump(); + } + else + { + precomp_block *blk = actual; + precomp_instr *inst = PC; + jump_to((PC-1)->addr+4); + +/*#ifdef DBG + if (g_DebuggerActive) update_debugger(PC->addr); +#endif +Used by dynarec only, check should be unnecessary +*/ + if (!skip_jump) + { + PC->ops(); + actual = blk; + PC = inst+1; + } + else + PC->ops(); + + if (r4300emu == CORE_DYNAREC) dyna_jump(); + } +} + +static void NOTCOMPILED(void) +{ + unsigned int *mem = fast_mem_access(blocks[PC->addr>>12]->start); +#ifdef CORE_DBG + DebugMessage(M64MSG_INFO, "NOTCOMPILED: addr = %x ops = %lx", PC->addr, (long) PC->ops); +#endif + + if (mem != NULL) + recompile_block((int *)mem, blocks[PC->addr >> 12], PC->addr); + else + DebugMessage(M64MSG_ERROR, "not compiled exception"); + +/*#ifdef DBG + if (g_DebuggerActive) update_debugger(PC->addr); +#endif +The preceeding update_debugger SHOULD be unnecessary since it should have been +called before NOTCOMPILED would have been executed +*/ + PC->ops(); + if (r4300emu == CORE_DYNAREC) + dyna_jump(); +} + +static void NOTCOMPILED2(void) +{ + NOTCOMPILED(); +} + +// ----------------------------------------------------------- +// Cached interpreter instruction table +// ----------------------------------------------------------- +const cpu_instruction_table cached_interpreter_table = { + LB, + LBU, + LH, + LHU, + LW, + LWL, + LWR, + SB, + SH, + SW, + SWL, + SWR, + + LD, + LDL, + LDR, + LL, + LWU, + SC, + SD, + SDL, + SDR, + SYNC, + + ADDI, + ADDIU, + SLTI, + SLTIU, + ANDI, + ORI, + XORI, + LUI, + + DADDI, + DADDIU, + + ADD, + ADDU, + SUB, + SUBU, + SLT, + SLTU, + AND, + OR, + XOR, + NOR, + + DADD, + DADDU, + DSUB, + DSUBU, + + MULT, + MULTU, + DIV, + DIVU, + MFHI, + MTHI, + MFLO, + MTLO, + + DMULT, + DMULTU, + DDIV, + DDIVU, + + J, + J_OUT, + J_IDLE, + JAL, + JAL_OUT, + JAL_IDLE, + // Use the _OUT versions of JR and JALR, since we don't know + // until runtime if they're going to jump inside or outside the block + JR_OUT, + JALR_OUT, + BEQ, + BEQ_OUT, + BEQ_IDLE, + BNE, + BNE_OUT, + BNE_IDLE, + BLEZ, + BLEZ_OUT, + BLEZ_IDLE, + BGTZ, + BGTZ_OUT, + BGTZ_IDLE, + BLTZ, + BLTZ_OUT, + BLTZ_IDLE, + BGEZ, + BGEZ_OUT, + BGEZ_IDLE, + BLTZAL, + BLTZAL_OUT, + BLTZAL_IDLE, + BGEZAL, + BGEZAL_OUT, + BGEZAL_IDLE, + + BEQL, + BEQL_OUT, + BEQL_IDLE, + BNEL, + BNEL_OUT, + BNEL_IDLE, + BLEZL, + BLEZL_OUT, + BLEZL_IDLE, + BGTZL, + BGTZL_OUT, + BGTZL_IDLE, + BLTZL, + BLTZL_OUT, + BLTZL_IDLE, + BGEZL, + BGEZL_OUT, + BGEZL_IDLE, + BLTZALL, + BLTZALL_OUT, + BLTZALL_IDLE, + BGEZALL, + BGEZALL_OUT, + BGEZALL_IDLE, + BC1TL, + BC1TL_OUT, + BC1TL_IDLE, + BC1FL, + BC1FL_OUT, + BC1FL_IDLE, + + SLL, + SRL, + SRA, + SLLV, + SRLV, + SRAV, + + DSLL, + DSRL, + DSRA, + DSLLV, + DSRLV, + DSRAV, + DSLL32, + DSRL32, + DSRA32, + + MTC0, + MFC0, + + TLBR, + TLBWI, + TLBWR, + TLBP, + CACHE, + ERET, + + LWC1, + SWC1, + MTC1, + MFC1, + CTC1, + CFC1, + BC1T, + BC1T_OUT, + BC1T_IDLE, + BC1F, + BC1F_OUT, + BC1F_IDLE, + + DMFC1, + DMTC1, + LDC1, + SDC1, + + CVT_S_D, + CVT_S_W, + CVT_S_L, + CVT_D_S, + CVT_D_W, + CVT_D_L, + CVT_W_S, + CVT_W_D, + CVT_L_S, + CVT_L_D, + + ROUND_W_S, + ROUND_W_D, + ROUND_L_S, + ROUND_L_D, + + TRUNC_W_S, + TRUNC_W_D, + TRUNC_L_S, + TRUNC_L_D, + + CEIL_W_S, + CEIL_W_D, + CEIL_L_S, + CEIL_L_D, + + FLOOR_W_S, + FLOOR_W_D, + FLOOR_L_S, + FLOOR_L_D, + + ADD_S, + ADD_D, + + SUB_S, + SUB_D, + + MUL_S, + MUL_D, + + DIV_S, + DIV_D, + + ABS_S, + ABS_D, + + MOV_S, + MOV_D, + + NEG_S, + NEG_D, + + SQRT_S, + SQRT_D, + + C_F_S, + C_F_D, + C_UN_S, + C_UN_D, + C_EQ_S, + C_EQ_D, + C_UEQ_S, + C_UEQ_D, + C_OLT_S, + C_OLT_D, + C_ULT_S, + C_ULT_D, + C_OLE_S, + C_OLE_D, + C_ULE_S, + C_ULE_D, + C_SF_S, + C_SF_D, + C_NGLE_S, + C_NGLE_D, + C_SEQ_S, + C_SEQ_D, + C_NGL_S, + C_NGL_D, + C_LT_S, + C_LT_D, + C_NGE_S, + C_NGE_D, + C_LE_S, + C_LE_D, + C_NGT_S, + C_NGT_D, + + SYSCALL, + + TEQ, + + NOP, + RESERVED, + NI, + + FIN_BLOCK, + NOTCOMPILED, + NOTCOMPILED2 +}; + +cpu_instruction_table current_instruction_table; + +static unsigned int update_invalid_addr(unsigned int addr) +{ + if (addr >= 0x80000000 && addr < 0xa0000000) + { + if (invalid_code[addr>>12]) invalid_code[(addr+0x20000000)>>12] = 1; + if (invalid_code[(addr+0x20000000)>>12]) invalid_code[addr>>12] = 1; + return addr; + } + else if (addr >= 0xa0000000 && addr < 0xc0000000) + { + if (invalid_code[addr>>12]) invalid_code[(addr-0x20000000)>>12] = 1; + if (invalid_code[(addr-0x20000000)>>12]) invalid_code[addr>>12] = 1; + return addr; + } + else + { + unsigned int paddr = virtual_to_physical_address(addr, 2); + if (paddr) + { + unsigned int beg_paddr = paddr - (addr - (addr&~0xFFF)); + update_invalid_addr(paddr); + if (invalid_code[(beg_paddr+0x000)>>12]) invalid_code[addr>>12] = 1; + if (invalid_code[(beg_paddr+0xFFC)>>12]) invalid_code[addr>>12] = 1; + if (invalid_code[addr>>12]) invalid_code[(beg_paddr+0x000)>>12] = 1; + if (invalid_code[addr>>12]) invalid_code[(beg_paddr+0xFFC)>>12] = 1; + } + return paddr; + } +} + +#define addr jump_to_address +unsigned int jump_to_address; +void jump_to_func(void) +{ + unsigned int paddr; + if (skip_jump) return; + paddr = update_invalid_addr(addr); + if (!paddr) return; + actual = blocks[addr>>12]; + if (invalid_code[addr>>12]) + { + if (!blocks[addr>>12]) + { + blocks[addr>>12] = (precomp_block *) malloc(sizeof(precomp_block)); + actual = blocks[addr>>12]; + blocks[addr>>12]->code = NULL; + blocks[addr>>12]->block = NULL; + blocks[addr>>12]->jumps_table = NULL; + blocks[addr>>12]->riprel_table = NULL; + } + blocks[addr>>12]->start = addr & ~0xFFF; + blocks[addr>>12]->end = (addr & ~0xFFF) + 0x1000; + init_block(blocks[addr>>12]); + } + PC=actual->block+((addr-actual->start)>>2); + + if (r4300emu == CORE_DYNAREC) dyna_jump(); +} +#undef addr + +void generic_jump_to(unsigned int address) +{ + if (r4300emu == CORE_PURE_INTERPRETER) + PC->addr = address; + else { +#ifdef NEW_DYNAREC + if (r4300emu == CORE_DYNAREC) + last_addr = pcaddr; + else + jump_to(address); +#else + jump_to(address); +#endif + } +} + +/* Refer to Figure 6-2 on page 155 and explanation on page B-11 + of MIPS R4000 Microprocessor User's Manual (Second Edition) + by Joe Heinrich. +*/ +void shuffle_fpr_data(int oldStatus, int newStatus) +{ +#if defined(M64P_BIG_ENDIAN) + const int isBigEndian = 1; +#else + const int isBigEndian = 0; +#endif + + if ((newStatus & 0x04000000) != (oldStatus & 0x04000000)) + { + int i; + int temp_fgr_32[32]; + + // pack or unpack the FGR register data + if (newStatus & 0x04000000) + { // switching into 64-bit mode + // retrieve 32 FPR values from packed 32-bit FGR registers + for (i = 0; i < 32; i++) + { + temp_fgr_32[i] = *((int *) ®_cop1_fgr_64[i>>1] + ((i & 1) ^ isBigEndian)); + } + // unpack them into 32 64-bit registers, taking the high 32-bits from their temporary place in the upper 16 FGRs + for (i = 0; i < 32; i++) + { + int high32 = *((int *) ®_cop1_fgr_64[(i>>1)+16] + (i & 1)); + *((int *) ®_cop1_fgr_64[i] + isBigEndian) = temp_fgr_32[i]; + *((int *) ®_cop1_fgr_64[i] + (isBigEndian^1)) = high32; + } + } + else + { // switching into 32-bit mode + // retrieve the high 32 bits from each 64-bit FGR register and store in temp array + for (i = 0; i < 32; i++) + { + temp_fgr_32[i] = *((int *) ®_cop1_fgr_64[i] + (isBigEndian^1)); + } + // take the low 32 bits from each register and pack them together into 64-bit pairs + for (i = 0; i < 16; i++) + { + unsigned int least32 = *((unsigned int *) ®_cop1_fgr_64[i*2] + isBigEndian); + unsigned int most32 = *((unsigned int *) ®_cop1_fgr_64[i*2+1] + isBigEndian); + reg_cop1_fgr_64[i] = ((unsigned long long) most32 << 32) | (unsigned long long) least32; + } + // store the high bits in the upper 16 FGRs, which wont be accessible in 32-bit mode + for (i = 0; i < 32; i++) + { + *((int *) ®_cop1_fgr_64[(i>>1)+16] + (i & 1)) = temp_fgr_32[i]; + } + } + } +} + +void set_fpr_pointers(int newStatus) +{ + int i; +#if defined(M64P_BIG_ENDIAN) + const int isBigEndian = 1; +#else + const int isBigEndian = 0; +#endif + + // update the FPR register pointers + if (newStatus & 0x04000000) + { + for (i = 0; i < 32; i++) + { + reg_cop1_double[i] = (double*) ®_cop1_fgr_64[i]; + reg_cop1_simple[i] = ((float*) ®_cop1_fgr_64[i]) + isBigEndian; + } + } + else + { + for (i = 0; i < 32; i++) + { + reg_cop1_double[i] = (double*) ®_cop1_fgr_64[i>>1]; + reg_cop1_simple[i] = ((float*) ®_cop1_fgr_64[i>>1]) + ((i & 1) ^ isBigEndian); + } + } +} + +int check_cop1_unusable(void) +{ + if (!(Status & 0x20000000)) + { + Cause = (11 << 2) | 0x10000000; + exception_general(); + return 1; + } + return 0; +} + +void update_count(void) +{ +#ifdef NEW_DYNAREC + if (r4300emu != CORE_DYNAREC) + { +#endif + Count = Count + (PC->addr - last_addr)/2; + last_addr = PC->addr; +#ifdef NEW_DYNAREC + } +#endif + +#ifdef COMPARE_CORE + if (delay_slot) + CoreCompareCallback(); +#endif +/*#ifdef DBG + if (g_DebuggerActive && !delay_slot) update_debugger(PC->addr); +#endif +*/ +} + +void init_blocks(void) +{ + int i; + for (i=0; i<0x100000; i++) + { + invalid_code[i] = 1; + blocks[i] = NULL; + } +} + +void free_blocks(void) +{ + int i; + for (i=0; i<0x100000; i++) + { + if (blocks[i]) + { + free_block(blocks[i]); + free(blocks[i]); + blocks[i] = NULL; + } + } +} + +/* this hard reset function simulates the boot-up state of the R4300 CPU */ +void r4300_reset_hard(void) +{ + unsigned int i; + + // clear r4300 registers and TLB entries + for (i = 0; i < 32; i++) + { + reg[i]=0; + reg_cop0[i]=0; + reg_cop1_fgr_64[i]=0; + + // --------------tlb------------------------ + tlb_e[i].mask=0; + tlb_e[i].vpn2=0; + tlb_e[i].g=0; + tlb_e[i].asid=0; + tlb_e[i].pfn_even=0; + tlb_e[i].c_even=0; + tlb_e[i].d_even=0; + tlb_e[i].v_even=0; + tlb_e[i].pfn_odd=0; + tlb_e[i].c_odd=0; + tlb_e[i].d_odd=0; + tlb_e[i].v_odd=0; + tlb_e[i].r=0; + //tlb_e[i].check_parity_mask=0x1000; + + tlb_e[i].start_even=0; + tlb_e[i].end_even=0; + tlb_e[i].phys_even=0; + tlb_e[i].start_odd=0; + tlb_e[i].end_odd=0; + tlb_e[i].phys_odd=0; + } + for (i=0; i<0x100000; i++) + { + tlb_LUT_r[i] = 0; + tlb_LUT_w[i] = 0; + } + llbit=0; + hi=0; + lo=0; + FCR0=0x511; + FCR31=0; + + // set COP0 registers + Random = 31; + Status= 0x34000000; + set_fpr_pointers(Status); + Config= 0x6e463; + PRevID = 0xb00; + Count = 0x5000; + Cause = 0x5C; + Context = 0x7FFFF0; + EPC = 0xFFFFFFFF; + BadVAddr = 0xFFFFFFFF; + ErrorEPC = 0xFFFFFFFF; + + rounding_mode = 0x33F; +} + +/* this soft reset function simulates the actions of the PIF ROM, which may vary by region + * TODO: accurately simulate the effects of the PIF ROM in the case of a soft reset + * (e.g. Goldeneye crashes) */ +void r4300_reset_soft(void) +{ + long long CRC = 0; + unsigned int i; + + // copy boot code from ROM to SP_DMEM + memcpy((char *)SP_DMEM+0x40, rom+0x40, 0xFC0); + + // the following values are extracted from the pj64 source code + // thanks to Zilmar and Jabo + + reg[6] = 0xFFFFFFFFA4001F0CLL; + reg[7] = 0xFFFFFFFFA4001F08LL; + reg[8] = 0x00000000000000C0LL; + reg[10]= 0x0000000000000040LL; + reg[11]= 0xFFFFFFFFA4000040LL; + reg[29]= 0xFFFFFFFFA4001FF0LL; + + // figure out which ROM type is loaded + for (i = 0x40/4; i < (0x1000/4); i++) + CRC += SP_DMEM[i]; + switch(CRC) { + case 0x000000D0027FDF31LL: + case 0x000000CFFB631223LL: + CIC_Chip = 1; + break; + case 0x000000D057C85244LL: + CIC_Chip = 2; + break; + case 0x000000D6497E414BLL: + CIC_Chip = 3; + break; + case 0x0000011A49F60E96LL: + CIC_Chip = 5; + break; + case 0x000000D6D5BE5580LL: + CIC_Chip = 6; + break; + default: + CIC_Chip = 2; + } + + switch(ROM_PARAMS.systemtype) + { + case SYSTEM_PAL: + switch (CIC_Chip) { + case 2: + reg[5] = 0xFFFFFFFFC0F1D859LL; + reg[14]= 0x000000002DE108EALL; + break; + case 3: + reg[5] = 0xFFFFFFFFD4646273LL; + reg[14]= 0x000000001AF99984LL; + break; + case 5: + SP_IMEM[1] = 0xBDA807FC; + reg[5] = 0xFFFFFFFFDECAAAD1LL; + reg[14]= 0x000000000CF85C13LL; + reg[24]= 0x0000000000000002LL; + break; + case 6: + reg[5] = 0xFFFFFFFFB04DC903LL; + reg[14]= 0x000000001AF99984LL; + reg[24]= 0x0000000000000002LL; + break; + } + reg[23]= 0x0000000000000006LL; + reg[31]= 0xFFFFFFFFA4001554LL; + break; + case SYSTEM_NTSC: + default: + switch (CIC_Chip) { + case 2: + reg[5] = 0xFFFFFFFFC95973D5LL; + reg[14]= 0x000000002449A366LL; + break; + case 3: + reg[5] = 0xFFFFFFFF95315A28LL; + reg[14]= 0x000000005BACA1DFLL; + break; + case 5: + SP_IMEM[1] = 0x8DA807FC; + reg[5] = 0x000000005493FB9ALL; + reg[14]= 0xFFFFFFFFC2C20384LL; + break; + case 6: + reg[5] = 0xFFFFFFFFE067221FLL; + reg[14]= 0x000000005CD2B70FLL; + break; + } + reg[20]= 0x0000000000000001LL; + reg[24]= 0x0000000000000003LL; + reg[31]= 0xFFFFFFFFA4001550LL; + } + switch (CIC_Chip) { + case 1: + reg[22]= 0x000000000000003FLL; + break; + case 2: + reg[1] = 0x0000000000000001LL; + reg[2] = 0x000000000EBDA536LL; + reg[3] = 0x000000000EBDA536LL; + reg[4] = 0x000000000000A536LL; + reg[12]= 0xFFFFFFFFED10D0B3LL; + reg[13]= 0x000000001402A4CCLL; + reg[15]= 0x000000003103E121LL; + reg[22]= 0x000000000000003FLL; + reg[25]= 0xFFFFFFFF9DEBB54FLL; + break; + case 3: + reg[1] = 0x0000000000000001LL; + reg[2] = 0x0000000049A5EE96LL; + reg[3] = 0x0000000049A5EE96LL; + reg[4] = 0x000000000000EE96LL; + reg[12]= 0xFFFFFFFFCE9DFBF7LL; + reg[13]= 0xFFFFFFFFCE9DFBF7LL; + reg[15]= 0x0000000018B63D28LL; + reg[22]= 0x0000000000000078LL; + reg[25]= 0xFFFFFFFF825B21C9LL; + break; + case 5: + SP_IMEM[0] = 0x3C0DBFC0; + SP_IMEM[2] = 0x25AD07C0; + SP_IMEM[3] = 0x31080080; + SP_IMEM[4] = 0x5500FFFC; + SP_IMEM[5] = 0x3C0DBFC0; + SP_IMEM[6] = 0x8DA80024; + SP_IMEM[7] = 0x3C0BB000; + reg[2] = 0xFFFFFFFFF58B0FBFLL; + reg[3] = 0xFFFFFFFFF58B0FBFLL; + reg[4] = 0x0000000000000FBFLL; + reg[12]= 0xFFFFFFFF9651F81ELL; + reg[13]= 0x000000002D42AAC5LL; + reg[15]= 0x0000000056584D60LL; + reg[22]= 0x0000000000000091LL; + reg[25]= 0xFFFFFFFFCDCE565FLL; + break; + case 6: + reg[2] = 0xFFFFFFFFA95930A4LL; + reg[3] = 0xFFFFFFFFA95930A4LL; + reg[4] = 0x00000000000030A4LL; + reg[12]= 0xFFFFFFFFBCB59510LL; + reg[13]= 0xFFFFFFFFBCB59510LL; + reg[15]= 0x000000007A3C07F4LL; + reg[22]= 0x0000000000000085LL; + reg[25]= 0x00000000465E3F72LL; + break; + } + +} + +#if !defined(NO_ASM) +static void dynarec_setup_code(void) +{ + // The dynarec jumps here after we call dyna_start and it prepares + // Here we need to prepare the initial code block and jump to it + jump_to(0xa4000040); + + // Prevent segfault on failed jump_to + if (!actual->block || !actual->code) + dyna_stop(); +} +#endif + +void r4300_execute(void) +{ +#if defined(COUNT_INSTR) || (defined(DYNAREC) && defined(PROFILE_R4300)) + unsigned int i; +#endif + + current_instruction_table = cached_interpreter_table; + + debug_count = 0; + delay_slot=0; + stop = 0; + rompause = 0; + + /* clear instruction counters */ +#if defined(COUNT_INSTR) + for (i = 0; i < 131; i++) + instr_count[i] = 0; +#endif + + last_addr = 0xa4000040; + next_interupt = 624999; + init_interupt(); + + if (r4300emu == CORE_PURE_INTERPRETER) + { + DebugMessage(M64MSG_INFO, "Starting R4300 emulator: Pure Interpreter"); + r4300emu = CORE_PURE_INTERPRETER; + pure_interpreter(); + } +#if defined(DYNAREC) + else if (r4300emu >= 2) + { + DebugMessage(M64MSG_INFO, "Starting R4300 emulator: Dynamic Recompiler"); + r4300emu = CORE_DYNAREC; + init_blocks(); + +#ifdef NEW_DYNAREC + new_dynarec_init(); + new_dyna_start(); + new_dynarec_cleanup(); +#else + dyna_start(dynarec_setup_code); + PC++; +#endif +#if defined(PROFILE_R4300) + pfProfile = fopen("instructionaddrs.dat", "ab"); + for (i=0; i<0x100000; i++) + if (invalid_code[i] == 0 && blocks[i] != NULL && blocks[i]->code != NULL && blocks[i]->block != NULL) + { + unsigned char *x86addr; + int mipsop; + // store final code length for this block + mipsop = -1; /* -1 == end of x86 code block */ + x86addr = blocks[i]->code + blocks[i]->code_length; + if (fwrite(&mipsop, 1, 4, pfProfile) != 4 || + fwrite(&x86addr, 1, sizeof(char *), pfProfile) != sizeof(char *)) + DebugMessage(M64MSG_ERROR, "Error writing R4300 instruction address profiling data"); + } + fclose(pfProfile); + pfProfile = NULL; +#endif + free_blocks(); + } +#endif + else /* if (r4300emu == CORE_INTERPRETER) */ + { + DebugMessage(M64MSG_INFO, "Starting R4300 emulator: Cached Interpreter"); + r4300emu = CORE_INTERPRETER; + init_blocks(); + jump_to(0xa4000040); + + /* Prevent segfault on failed jump_to */ + if (!actual->block) + return; + + last_addr = PC->addr; + while (!stop) + { +#ifdef COMPARE_CORE + if (PC->ops == FIN_BLOCK && (PC->addr < 0x80000000 || PC->addr >= 0xc0000000)) + virtual_to_physical_address(PC->addr, 2); + CoreCompareCallback(); +#endif +#ifdef DBG + if (g_DebuggerActive) update_debugger(PC->addr); +#endif + PC->ops(); + } + + free_blocks(); + } + + debug_count+= Count; + DebugMessage(M64MSG_INFO, "R4300 emulator finished."); + + /* print instruction counts */ +#if defined(COUNT_INSTR) + if (r4300emu == CORE_DYNAREC) + { + unsigned int iTypeCount[11] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + unsigned int iTotal = 0; + char line[128], param[24]; + DebugMessage(M64MSG_INFO, "Instruction counters:"); + line[0] = 0; + for (i = 0; i < 131; i++) + { + sprintf(param, "%8s: %08i ", instr_name[i], instr_count[i]); + strcat(line, param); + if (i % 5 == 4) + { + DebugMessage(M64MSG_INFO, "%s", line); + line[0] = 0; + } + iTypeCount[instr_type[i]] += instr_count[i]; + iTotal += instr_count[i]; + } + DebugMessage(M64MSG_INFO, "Instruction type summary (total instructions = %i)", iTotal); + for (i = 0; i < 11; i++) + { + DebugMessage(M64MSG_INFO, "%20s: %04.1f%% (%i)", instr_typename[i], (float) iTypeCount[i] * 100.0 / iTotal, iTypeCount[i]); + } + } +#endif +}