mirror of
https://github.com/mupen64plus/mupen64plus-oldsvn.git
synced 2025-04-02 10:52:35 -04:00
1981 lines
44 KiB
C
1981 lines
44 KiB
C
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
* 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 <stdlib.h>
|
|
|
|
#include "r4300.h"
|
|
#include "ops.h"
|
|
#include "exception.h"
|
|
#include "interupt.h"
|
|
#include "macros.h"
|
|
#include "recomp.h"
|
|
#include "recomph.h"
|
|
|
|
#include "../memory/memory.h"
|
|
|
|
#ifdef DBG
|
|
#include "../debugger/debugger.h"
|
|
#endif
|
|
|
|
unsigned int dynacore = 0, interpcore = 0;
|
|
int no_compiled_jump = 0;
|
|
int stop, llbit, rompause;
|
|
long long int reg[32], hi, lo;
|
|
long long int local_rs, local_rt;
|
|
unsigned int reg_cop0[32];
|
|
int local_rs32, local_rt32;
|
|
unsigned int jump_target;
|
|
float *reg_cop1_simple[32];
|
|
double *reg_cop1_double[32];
|
|
long long int reg_cop1_fgr_64[32];
|
|
int FCR0, FCR31;
|
|
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 next_interupt, CIC_Chip;
|
|
precomp_instr *PC;
|
|
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;
|
|
void (*code)();
|
|
|
|
/*#define check_memory() \
|
|
if (!invalid_code[address>>12]) \
|
|
invalid_code[address>>12] = 1;*/
|
|
|
|
#define check_memory() \
|
|
if (!invalid_code[address>>12]) \
|
|
if (blocks[address>>12]->block[(address&0xFFF)/4].ops != NOTCOMPILED) \
|
|
invalid_code[address>>12] = 1;
|
|
|
|
void NI()
|
|
{
|
|
printf("NI() @ %x\n", (int)PC->addr);
|
|
printf("opcode not implemented : ");
|
|
if (PC->addr >= 0xa4000000 && PC->addr < 0xa4001000)
|
|
printf("%x:%x\n", (int)PC->addr, (int)SP_DMEM[(PC->addr-0xa4000000)/4]);
|
|
else
|
|
printf("%x:%x\n", (int)PC->addr, (int)rdram[(PC->addr-0x80000000)/4]);
|
|
stop=1;
|
|
}
|
|
|
|
void RESERVED()
|
|
{
|
|
printf("reserved opcode : ");
|
|
if (PC->addr >= 0xa4000000 && PC->addr < 0xa4001000)
|
|
printf("%x:%x\n", (int)PC->addr, (int)SP_DMEM[(PC->addr-0xa4000000)/4]);
|
|
else
|
|
printf("%x:%x\n", (int)PC->addr, (int)rdram[(PC->addr-0x80000000)/4]);
|
|
stop=1;
|
|
}
|
|
|
|
void FIN_BLOCK()
|
|
{
|
|
if (!delay_slot)
|
|
{
|
|
jump_to((PC-1)->addr+4);
|
|
/*#ifdef DBG
|
|
if (debugger_mode) update_debugger(PC->addr);
|
|
#endif
|
|
Used by dynarec only, check should be unnecessary
|
|
*/
|
|
PC->ops();
|
|
if (dynacore) dyna_jump();
|
|
}
|
|
else
|
|
{
|
|
precomp_block *blk = actual;
|
|
precomp_instr *inst = PC;
|
|
jump_to((PC-1)->addr+4);
|
|
|
|
/*#ifdef DBG
|
|
if (debugger_mode) 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 (dynacore) dyna_jump();
|
|
}
|
|
}
|
|
|
|
void J()
|
|
{
|
|
PC++;
|
|
delay_slot=1;
|
|
#ifdef DBG
|
|
if (debugger_mode) update_debugger(PC->addr);
|
|
#endif
|
|
PC->ops();
|
|
update_count();
|
|
delay_slot=0;
|
|
if (!skip_jump)
|
|
PC=actual->block+
|
|
(((((PC-2)->f.j.inst_index<<2) | ((PC-1)->addr & 0xF0000000))-actual->start)>>2);
|
|
last_addr = PC->addr;
|
|
if (next_interupt <= Count) gen_interupt();
|
|
}
|
|
|
|
void J_OUT()
|
|
{
|
|
jump_target = (PC->addr & 0xF0000000) | (PC->f.j.inst_index<<2);
|
|
PC++;
|
|
delay_slot=1;
|
|
#ifdef DBG
|
|
if (debugger_mode) update_debugger(PC->addr);
|
|
#endif
|
|
PC->ops();
|
|
update_count();
|
|
delay_slot=0;
|
|
if (!skip_jump)
|
|
jump_to(jump_target);
|
|
last_addr = PC->addr;
|
|
if (next_interupt <= Count) gen_interupt();
|
|
}
|
|
|
|
void J_IDLE()
|
|
{
|
|
int skip;
|
|
update_count();
|
|
skip = next_interupt - Count;
|
|
if (skip > 3) Count += (skip & 0xFFFFFFFC);
|
|
else J();
|
|
}
|
|
|
|
void JAL()
|
|
{
|
|
PC++;
|
|
delay_slot=1;
|
|
#ifdef DBG
|
|
if (debugger_mode) update_debugger(PC->addr);
|
|
#endif
|
|
PC->ops();
|
|
update_count();
|
|
delay_slot=0;
|
|
if (!skip_jump)
|
|
{
|
|
reg[31]=PC->addr;
|
|
sign_extended(reg[31]);
|
|
|
|
PC=actual->block+
|
|
(((((PC-2)->f.j.inst_index<<2) | ((PC-1)->addr & 0xF0000000))-actual->start)>>2);
|
|
}
|
|
last_addr = PC->addr;
|
|
if (next_interupt <= Count) gen_interupt();
|
|
}
|
|
|
|
void JAL_OUT()
|
|
{
|
|
jump_target = (PC->addr & 0xF0000000) | (PC->f.j.inst_index<<2);
|
|
PC++;
|
|
delay_slot=1;
|
|
#ifdef DBG
|
|
if (debugger_mode) update_debugger(PC->addr);
|
|
#endif
|
|
PC->ops();
|
|
update_count();
|
|
delay_slot=0;
|
|
if (!skip_jump)
|
|
{
|
|
reg[31]=PC->addr;
|
|
sign_extended(reg[31]);
|
|
|
|
jump_to(jump_target);
|
|
}
|
|
last_addr = PC->addr;
|
|
if (next_interupt <= Count) gen_interupt();
|
|
}
|
|
|
|
void JAL_IDLE()
|
|
{
|
|
int skip;
|
|
update_count();
|
|
skip = next_interupt - Count;
|
|
if (skip > 3) Count += (skip & 0xFFFFFFFC);
|
|
else JAL();
|
|
}
|
|
|
|
void BEQ()
|
|
{
|
|
local_rs = irs;
|
|
local_rt = irt;
|
|
PC++;
|
|
delay_slot=1;
|
|
#ifdef DBG
|
|
if (debugger_mode) update_debugger(PC->addr);
|
|
#endif
|
|
PC->ops();
|
|
update_count();
|
|
delay_slot=0;
|
|
if (local_rs == local_rt && !skip_jump)
|
|
PC += (PC-2)->f.i.immediate-1;
|
|
last_addr = PC->addr;
|
|
if (next_interupt <= Count) gen_interupt();
|
|
}
|
|
|
|
void BEQ_OUT()
|
|
{
|
|
local_rs = irs;
|
|
local_rt = irt;
|
|
jump_target = (int)PC->f.i.immediate;
|
|
PC++;
|
|
delay_slot=1;
|
|
#ifdef DBG
|
|
if (debugger_mode) update_debugger(PC->addr);
|
|
#endif
|
|
PC->ops();
|
|
update_count();
|
|
delay_slot=0;
|
|
if (!skip_jump && local_rs == local_rt)
|
|
jump_to(PC->addr + ((jump_target-1)<<2));
|
|
last_addr = PC->addr;
|
|
if (next_interupt <= Count) gen_interupt();
|
|
}
|
|
|
|
void BEQ_IDLE()
|
|
{
|
|
int skip;
|
|
if (irs == irt)
|
|
{
|
|
update_count();
|
|
skip = next_interupt - Count;
|
|
if (skip > 3) Count += (skip & 0xFFFFFFFC);
|
|
else BEQ();
|
|
}
|
|
else BEQ();
|
|
}
|
|
|
|
void BNE()
|
|
{
|
|
local_rs = irs;
|
|
local_rt = irt;
|
|
PC++;
|
|
delay_slot=1;
|
|
#ifdef DBG
|
|
if (debugger_mode) update_debugger(PC->addr);
|
|
#endif
|
|
PC->ops();
|
|
update_count();
|
|
delay_slot=0;
|
|
if (local_rs != local_rt && !skip_jump)
|
|
PC += (PC-2)->f.i.immediate-1;
|
|
last_addr = PC->addr;
|
|
if (next_interupt <= Count) gen_interupt();
|
|
}
|
|
|
|
void BNE_OUT()
|
|
{
|
|
local_rs = irs;
|
|
local_rt = irt;
|
|
jump_target = (int)PC->f.i.immediate;
|
|
PC++;
|
|
delay_slot=1;
|
|
#ifdef DBG
|
|
if (debugger_mode) update_debugger(PC->addr);
|
|
#endif
|
|
PC->ops();
|
|
update_count();
|
|
delay_slot=0;
|
|
if (!skip_jump && local_rs != local_rt)
|
|
jump_to(PC->addr + ((jump_target-1)<<2));
|
|
last_addr = PC->addr;
|
|
if (next_interupt <= Count) gen_interupt();
|
|
}
|
|
|
|
void BNE_IDLE()
|
|
{
|
|
int skip;
|
|
if (irs != irt)
|
|
{
|
|
update_count();
|
|
skip = next_interupt - Count;
|
|
if (skip > 3) Count += (skip & 0xFFFFFFFC);
|
|
else BNE();
|
|
}
|
|
else BNE();
|
|
}
|
|
|
|
void BLEZ()
|
|
{
|
|
local_rs = irs;
|
|
PC++;
|
|
delay_slot=1;
|
|
#ifdef DBG
|
|
if (debugger_mode) update_debugger(PC->addr);
|
|
#endif
|
|
PC->ops();
|
|
update_count();
|
|
delay_slot=0;
|
|
if (local_rs <= 0 && !skip_jump)
|
|
PC += (PC-2)->f.i.immediate-1;
|
|
last_addr = PC->addr;
|
|
if (next_interupt <= Count) gen_interupt();
|
|
}
|
|
|
|
void BLEZ_OUT()
|
|
{
|
|
local_rs = irs;
|
|
jump_target = (int)PC->f.i.immediate;
|
|
PC++;
|
|
delay_slot=1;
|
|
#ifdef DBG
|
|
if (debugger_mode) update_debugger(PC->addr);
|
|
#endif
|
|
PC->ops();
|
|
update_count();
|
|
delay_slot=0;
|
|
if (!skip_jump && local_rs <= 0)
|
|
jump_to(PC->addr + ((jump_target-1)<<2));
|
|
last_addr = PC->addr;
|
|
if (next_interupt <= Count) gen_interupt();
|
|
}
|
|
|
|
void BLEZ_IDLE()
|
|
{
|
|
int skip;
|
|
if (irs <= irt)
|
|
{
|
|
update_count();
|
|
skip = next_interupt - Count;
|
|
if (skip > 3) Count += (skip & 0xFFFFFFFC);
|
|
else BLEZ();
|
|
}
|
|
else BLEZ();
|
|
}
|
|
|
|
void BGTZ()
|
|
{
|
|
local_rs = irs;
|
|
PC++;
|
|
delay_slot=1;
|
|
#ifdef DBG
|
|
if (debugger_mode) update_debugger(PC->addr);
|
|
#endif
|
|
PC->ops();
|
|
update_count();
|
|
delay_slot=0;
|
|
if (local_rs > 0 && !skip_jump)
|
|
PC += (PC-2)->f.i.immediate-1;
|
|
last_addr = PC->addr;
|
|
if (next_interupt <= Count) gen_interupt();
|
|
}
|
|
|
|
void BGTZ_OUT()
|
|
{
|
|
local_rs = irs;
|
|
jump_target = (int)PC->f.i.immediate;
|
|
PC++;
|
|
delay_slot=1;
|
|
#ifdef DBG
|
|
if (debugger_mode) update_debugger(PC->addr);
|
|
#endif
|
|
PC->ops();
|
|
update_count();
|
|
delay_slot=0;
|
|
if (!skip_jump && local_rs > 0)
|
|
jump_to(PC->addr + ((jump_target-1)<<2));
|
|
last_addr = PC->addr;
|
|
if (next_interupt <= Count) gen_interupt();
|
|
}
|
|
|
|
void BGTZ_IDLE()
|
|
{
|
|
int skip;
|
|
if (irs > irt)
|
|
{
|
|
update_count();
|
|
skip = next_interupt - Count;
|
|
if (skip > 3) Count += (skip & 0xFFFFFFFC);
|
|
else BGTZ();
|
|
}
|
|
else BGTZ();
|
|
}
|
|
|
|
void ADDI()
|
|
{
|
|
irt32 = irs32 + iimmediate;
|
|
sign_extended(irt);
|
|
PC++;
|
|
}
|
|
|
|
void ADDIU()
|
|
{
|
|
irt32 = irs32 + iimmediate;
|
|
sign_extended(irt);
|
|
PC++;
|
|
}
|
|
|
|
void SLTI()
|
|
{
|
|
if (irs < iimmediate) irt = 1;
|
|
else irt = 0;
|
|
PC++;
|
|
}
|
|
|
|
void SLTIU()
|
|
{
|
|
if ((unsigned long long)irs < (unsigned long long)((long long)iimmediate))
|
|
irt = 1;
|
|
else irt = 0;
|
|
PC++;
|
|
}
|
|
|
|
void ANDI()
|
|
{
|
|
irt = irs & (unsigned short)iimmediate;
|
|
PC++;
|
|
}
|
|
|
|
void ORI()
|
|
{
|
|
irt = irs | (unsigned short)iimmediate;
|
|
PC++;
|
|
}
|
|
|
|
void XORI()
|
|
{
|
|
irt = irs ^ (unsigned short)iimmediate;
|
|
PC++;
|
|
}
|
|
|
|
void LUI()
|
|
{
|
|
irt32 = iimmediate << 16;
|
|
sign_extended(irt);
|
|
PC++;
|
|
}
|
|
|
|
void BEQL()
|
|
{
|
|
if (irs == irt)
|
|
{
|
|
PC++;
|
|
delay_slot=1;
|
|
#ifdef DBG
|
|
if (debugger_mode) update_debugger(PC->addr);
|
|
#endif
|
|
PC->ops();
|
|
update_count();
|
|
delay_slot=0;
|
|
if(!skip_jump)
|
|
PC += (PC-2)->f.i.immediate-1;
|
|
}
|
|
else
|
|
{
|
|
PC+=2;
|
|
update_count();
|
|
}
|
|
last_addr = PC->addr;
|
|
if (next_interupt <= Count) gen_interupt();
|
|
}
|
|
|
|
void BEQL_OUT()
|
|
{
|
|
if (irs == irt)
|
|
{
|
|
jump_target = (int)PC->f.i.immediate;
|
|
PC++;
|
|
delay_slot=1;
|
|
#ifdef DBG
|
|
if (debugger_mode) update_debugger(PC->addr);
|
|
#endif
|
|
PC->ops();
|
|
update_count();
|
|
delay_slot=0;
|
|
if (!skip_jump)
|
|
jump_to(PC->addr + ((jump_target-1)<<2));
|
|
}
|
|
else
|
|
{
|
|
PC+=2;
|
|
update_count();
|
|
}
|
|
last_addr = PC->addr;
|
|
if (next_interupt <= Count) gen_interupt();
|
|
}
|
|
|
|
void BEQL_IDLE()
|
|
{
|
|
int skip;
|
|
if (irs == irt)
|
|
{
|
|
update_count();
|
|
skip = next_interupt - Count;
|
|
if (skip > 3) Count += (skip & 0xFFFFFFFC);
|
|
else BEQL();
|
|
}
|
|
else BEQL();
|
|
}
|
|
|
|
void BNEL()
|
|
{
|
|
if (irs != irt)
|
|
{
|
|
PC++;
|
|
delay_slot=1;
|
|
#ifdef DBG
|
|
if (debugger_mode) update_debugger(PC->addr);
|
|
#endif
|
|
PC->ops();
|
|
update_count();
|
|
delay_slot=0;
|
|
if(!skip_jump)
|
|
PC += (PC-2)->f.i.immediate-1;
|
|
}
|
|
else
|
|
{
|
|
PC+=2;
|
|
update_count();
|
|
}
|
|
last_addr = PC->addr;
|
|
if (next_interupt <= Count) gen_interupt();
|
|
}
|
|
|
|
void BNEL_OUT()
|
|
{
|
|
if (irs != irt)
|
|
{
|
|
jump_target = (int)PC->f.i.immediate;
|
|
PC++;
|
|
delay_slot=1;
|
|
#ifdef DBG
|
|
if (debugger_mode) update_debugger(PC->addr);
|
|
#endif
|
|
PC->ops();
|
|
update_count();
|
|
delay_slot=0;
|
|
if (!skip_jump)
|
|
jump_to(PC->addr + ((jump_target-1)<<2));
|
|
}
|
|
else
|
|
{
|
|
PC+=2;
|
|
update_count();
|
|
}
|
|
last_addr = PC->addr;
|
|
if (next_interupt <= Count) gen_interupt();
|
|
}
|
|
|
|
void BNEL_IDLE()
|
|
{
|
|
int skip;
|
|
if (irs != irt)
|
|
{
|
|
update_count();
|
|
skip = next_interupt - Count;
|
|
if (skip > 3) Count += (skip & 0xFFFFFFFC);
|
|
else BNEL();
|
|
}
|
|
else BNEL();
|
|
}
|
|
|
|
void BLEZL()
|
|
{
|
|
if (irs <= 0)
|
|
{
|
|
PC++;
|
|
delay_slot=1;
|
|
#ifdef DBG
|
|
if (debugger_mode) update_debugger(PC->addr);
|
|
#endif
|
|
PC->ops();
|
|
update_count();
|
|
delay_slot=0;
|
|
if(!skip_jump)
|
|
PC += (PC-2)->f.i.immediate-1;
|
|
}
|
|
else
|
|
{
|
|
PC+=2;
|
|
update_count();
|
|
}
|
|
last_addr = PC->addr;
|
|
if (next_interupt <= Count) gen_interupt();
|
|
}
|
|
|
|
void BLEZL_OUT()
|
|
{
|
|
if (irs <= 0)
|
|
{
|
|
jump_target = (int)PC->f.i.immediate;
|
|
PC++;
|
|
delay_slot=1;
|
|
#ifdef DBG
|
|
if (debugger_mode) update_debugger(PC->addr);
|
|
#endif
|
|
PC->ops();
|
|
update_count();
|
|
delay_slot=0;
|
|
if (!skip_jump)
|
|
jump_to(PC->addr + ((jump_target-1)<<2));
|
|
}
|
|
else
|
|
{
|
|
PC+=2;
|
|
update_count();
|
|
}
|
|
last_addr = PC->addr;
|
|
if (next_interupt <= Count) gen_interupt();
|
|
}
|
|
|
|
void BLEZL_IDLE()
|
|
{
|
|
int skip;
|
|
if (irs <= irt)
|
|
{
|
|
update_count();
|
|
skip = next_interupt - Count;
|
|
if (skip > 3) Count += (skip & 0xFFFFFFFC);
|
|
else BLEZL();
|
|
}
|
|
else BLEZL();
|
|
}
|
|
|
|
void BGTZL()
|
|
{
|
|
if (irs > 0)
|
|
{
|
|
PC++;
|
|
delay_slot=1;
|
|
#ifdef DBG
|
|
if (debugger_mode) update_debugger(PC->addr);
|
|
#endif
|
|
PC->ops();
|
|
update_count();
|
|
delay_slot=0;
|
|
if(!skip_jump)
|
|
PC += (PC-2)->f.i.immediate-1;
|
|
}
|
|
else
|
|
{
|
|
PC+=2;
|
|
update_count();
|
|
}
|
|
last_addr = PC->addr;
|
|
if (next_interupt <= Count) gen_interupt();
|
|
}
|
|
|
|
void BGTZL_OUT()
|
|
{
|
|
if (irs > 0)
|
|
{
|
|
jump_target = (int)PC->f.i.immediate;
|
|
PC++;
|
|
delay_slot=1;
|
|
#ifdef DBG
|
|
if (debugger_mode) update_debugger(PC->addr);
|
|
#endif
|
|
PC->ops();
|
|
update_count();
|
|
delay_slot=0;
|
|
if (!skip_jump)
|
|
jump_to(PC->addr + ((jump_target-1)<<2));
|
|
}
|
|
else
|
|
{
|
|
PC+=2;
|
|
update_count();
|
|
}
|
|
last_addr = PC->addr;
|
|
if (next_interupt <= Count) gen_interupt();
|
|
}
|
|
|
|
void BGTZL_IDLE()
|
|
{
|
|
int skip;
|
|
if (irs > irt)
|
|
{
|
|
update_count();
|
|
skip = next_interupt - Count;
|
|
if (skip > 3) Count += (skip & 0xFFFFFFFC);
|
|
else BGTZL();
|
|
}
|
|
else BGTZL();
|
|
}
|
|
|
|
void DADDI()
|
|
{
|
|
irt = irs + iimmediate;
|
|
PC++;
|
|
}
|
|
|
|
void DADDIU()
|
|
{
|
|
irt = irs + iimmediate;
|
|
PC++;
|
|
}
|
|
|
|
void LDL()
|
|
{
|
|
unsigned long long int word = 0;
|
|
PC++;
|
|
switch ((lsaddr) & 7)
|
|
{
|
|
case 0:
|
|
address = lsaddr;
|
|
rdword = (unsigned long long *) &lsrt;
|
|
read_dword_in_memory();
|
|
break;
|
|
case 1:
|
|
address = (lsaddr) & 0xFFFFFFF8;
|
|
rdword = &word;
|
|
read_dword_in_memory();
|
|
if(address)
|
|
lsrt = (lsrt & 0xFF) | (word << 8);
|
|
break;
|
|
case 2:
|
|
address = (lsaddr) & 0xFFFFFFF8;
|
|
rdword = &word;
|
|
read_dword_in_memory();
|
|
if(address)
|
|
lsrt = (lsrt & 0xFFFF) | (word << 16);
|
|
break;
|
|
case 3:
|
|
address = (lsaddr) & 0xFFFFFFF8;
|
|
rdword = &word;
|
|
read_dword_in_memory();
|
|
if(address)
|
|
lsrt = (lsrt & 0xFFFFFF) | (word << 24);
|
|
break;
|
|
case 4:
|
|
address = (lsaddr) & 0xFFFFFFF8;
|
|
rdword = &word;
|
|
read_dword_in_memory();
|
|
if(address)
|
|
lsrt = (lsrt & 0xFFFFFFFF) | (word << 32);
|
|
break;
|
|
case 5:
|
|
address = (lsaddr) & 0xFFFFFFF8;
|
|
rdword = &word;
|
|
read_dword_in_memory();
|
|
if(address)
|
|
lsrt = (lsrt & 0xFFFFFFFFFFLL) | (word << 40);
|
|
break;
|
|
case 6:
|
|
address = (lsaddr) & 0xFFFFFFF8;
|
|
rdword = &word;
|
|
read_dword_in_memory();
|
|
if(address)
|
|
lsrt = (lsrt & 0xFFFFFFFFFFFFLL) | (word << 48);
|
|
break;
|
|
case 7:
|
|
address = (lsaddr) & 0xFFFFFFF8;
|
|
rdword = &word;
|
|
read_dword_in_memory();
|
|
if(address)
|
|
lsrt = (lsrt & 0xFFFFFFFFFFFFFFLL) | (word << 56);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void LDR()
|
|
{
|
|
unsigned long long int word = 0;
|
|
PC++;
|
|
switch ((lsaddr) & 7)
|
|
{
|
|
case 0:
|
|
address = (lsaddr) & 0xFFFFFFF8;
|
|
rdword = &word;
|
|
read_dword_in_memory();
|
|
if(address)
|
|
lsrt = (lsrt & 0xFFFFFFFFFFFFFF00LL) | (word >> 56);
|
|
break;
|
|
case 1:
|
|
address = (lsaddr) & 0xFFFFFFF8;
|
|
rdword = &word;
|
|
read_dword_in_memory();
|
|
if(address)
|
|
lsrt = (lsrt & 0xFFFFFFFFFFFF0000LL) | (word >> 48);
|
|
break;
|
|
case 2:
|
|
address = (lsaddr) & 0xFFFFFFF8;
|
|
rdword = &word;
|
|
read_dword_in_memory();
|
|
if(address)
|
|
lsrt = (lsrt & 0xFFFFFFFFFF000000LL) | (word >> 40);
|
|
break;
|
|
case 3:
|
|
address = (lsaddr) & 0xFFFFFFF8;
|
|
rdword = &word;
|
|
read_dword_in_memory();
|
|
if(address)
|
|
lsrt = (lsrt & 0xFFFFFFFF00000000LL) | (word >> 32);
|
|
break;
|
|
case 4:
|
|
address = (lsaddr) & 0xFFFFFFF8;
|
|
rdword = &word;
|
|
read_dword_in_memory();
|
|
if(address)
|
|
lsrt = (lsrt & 0xFFFFFF0000000000LL) | (word >> 24);
|
|
break;
|
|
case 5:
|
|
address = (lsaddr) & 0xFFFFFFF8;
|
|
rdword = &word;
|
|
read_dword_in_memory();
|
|
if(address)
|
|
lsrt = (lsrt & 0xFFFF000000000000LL) | (word >> 16);
|
|
break;
|
|
case 6:
|
|
address = (lsaddr) & 0xFFFFFFF8;
|
|
rdword = &word;
|
|
read_dword_in_memory();
|
|
if(address)
|
|
lsrt = (lsrt & 0xFF00000000000000LL) | (word >> 8);
|
|
break;
|
|
case 7:
|
|
address = (lsaddr) & 0xFFFFFFF8;
|
|
rdword = (unsigned long long *) &lsrt;
|
|
read_dword_in_memory();
|
|
break;
|
|
}
|
|
}
|
|
|
|
void LB()
|
|
{
|
|
PC++;
|
|
address = lsaddr;
|
|
rdword = (unsigned long long *) &lsrt;
|
|
read_byte_in_memory();
|
|
if (address)
|
|
sign_extendedb(lsrt);
|
|
}
|
|
|
|
void LH()
|
|
{
|
|
PC++;
|
|
address = lsaddr;
|
|
rdword = (unsigned long long *) &lsrt;
|
|
read_hword_in_memory();
|
|
if (address)
|
|
sign_extendedh(lsrt);
|
|
}
|
|
|
|
void LWL()
|
|
{
|
|
unsigned long long int word = 0;
|
|
PC++;
|
|
switch ((lsaddr) & 3)
|
|
{
|
|
case 0:
|
|
address = lsaddr;
|
|
rdword = (unsigned long long *) &lsrt;
|
|
read_word_in_memory();
|
|
break;
|
|
case 1:
|
|
address = (lsaddr) & 0xFFFFFFFC;
|
|
rdword = &word;
|
|
read_word_in_memory();
|
|
if(address)
|
|
lsrt = (lsrt & 0xFF) | (word << 8);
|
|
break;
|
|
case 2:
|
|
address = (lsaddr) & 0xFFFFFFFC;
|
|
rdword = &word;
|
|
read_word_in_memory();
|
|
if(address)
|
|
lsrt = (lsrt & 0xFFFF) | (word << 16);
|
|
break;
|
|
case 3:
|
|
address = (lsaddr) & 0xFFFFFFFC;
|
|
rdword = &word;
|
|
read_word_in_memory();
|
|
if(address)
|
|
lsrt = (lsrt & 0xFFFFFF) | (word << 24);
|
|
break;
|
|
}
|
|
if(address)
|
|
sign_extended(lsrt);
|
|
}
|
|
|
|
void LW()
|
|
{
|
|
PC++;
|
|
address = lsaddr;
|
|
rdword = (unsigned long long *) &lsrt;
|
|
read_word_in_memory();
|
|
if (address)
|
|
sign_extended(lsrt);
|
|
}
|
|
|
|
void LBU()
|
|
{
|
|
PC++;
|
|
address = lsaddr;
|
|
rdword = (unsigned long long *) &lsrt;
|
|
read_byte_in_memory();
|
|
}
|
|
|
|
void LHU()
|
|
{
|
|
PC++;
|
|
address = lsaddr;
|
|
rdword = (unsigned long long *) &lsrt;
|
|
read_hword_in_memory();
|
|
}
|
|
|
|
void LWR()
|
|
{
|
|
unsigned long long int word = 0;
|
|
PC++;
|
|
switch ((lsaddr) & 3)
|
|
{
|
|
case 0:
|
|
address = (lsaddr) & 0xFFFFFFFC;
|
|
rdword = &word;
|
|
read_word_in_memory();
|
|
if(address)
|
|
lsrt = (lsrt & 0xFFFFFFFFFFFFFF00LL) | ((word >> 24) & 0xFF);
|
|
break;
|
|
case 1:
|
|
address = (lsaddr) & 0xFFFFFFFC;
|
|
rdword = &word;
|
|
read_word_in_memory();
|
|
if(address)
|
|
lsrt = (lsrt & 0xFFFFFFFFFFFF0000LL) | ((word >> 16) & 0xFFFF);
|
|
break;
|
|
case 2:
|
|
address = (lsaddr) & 0xFFFFFFFC;
|
|
rdword = &word;
|
|
read_word_in_memory();
|
|
if(address)
|
|
lsrt = (lsrt & 0xFFFFFFFFFF000000LL) | ((word >> 8) & 0XFFFFFF);
|
|
break;
|
|
case 3:
|
|
address = (lsaddr) & 0xFFFFFFFC;
|
|
rdword = (unsigned long long *) &lsrt;
|
|
read_word_in_memory();
|
|
if(address)
|
|
sign_extended(lsrt);
|
|
}
|
|
}
|
|
|
|
void LWU()
|
|
{
|
|
PC++;
|
|
address = lsaddr;
|
|
rdword = (unsigned long long *) &lsrt;
|
|
read_word_in_memory();
|
|
}
|
|
|
|
void SB()
|
|
{
|
|
PC++;
|
|
address = lsaddr;
|
|
byte = (unsigned char)(lsrt & 0xFF);
|
|
write_byte_in_memory();
|
|
check_memory();
|
|
}
|
|
|
|
void SH()
|
|
{
|
|
PC++;
|
|
address = lsaddr;
|
|
hword = (unsigned short)(lsrt & 0xFFFF);
|
|
write_hword_in_memory();
|
|
check_memory();
|
|
}
|
|
|
|
void SWL()
|
|
{
|
|
unsigned long long int old_word = 0;
|
|
PC++;
|
|
switch ((lsaddr) & 3)
|
|
{
|
|
case 0:
|
|
address = (lsaddr) & 0xFFFFFFFC;
|
|
word = (unsigned int)lsrt;
|
|
write_word_in_memory();
|
|
check_memory();
|
|
break;
|
|
case 1:
|
|
address = (lsaddr) & 0xFFFFFFFC;
|
|
rdword = &old_word;
|
|
read_word_in_memory();
|
|
if(address)
|
|
{
|
|
word = ((unsigned int)lsrt >> 8) | (old_word & 0xFF000000);
|
|
write_word_in_memory();
|
|
check_memory();
|
|
}
|
|
break;
|
|
case 2:
|
|
address = (lsaddr) & 0xFFFFFFFC;
|
|
rdword = &old_word;
|
|
read_word_in_memory();
|
|
if(address)
|
|
{
|
|
word = ((unsigned int)lsrt >> 16) | (old_word & 0xFFFF0000);
|
|
write_word_in_memory();
|
|
check_memory();
|
|
}
|
|
break;
|
|
case 3:
|
|
address = lsaddr;
|
|
byte = (unsigned char)(lsrt >> 24);
|
|
write_byte_in_memory();
|
|
check_memory();
|
|
break;
|
|
}
|
|
}
|
|
|
|
void SW()
|
|
{
|
|
PC++;
|
|
address = lsaddr;
|
|
word = (unsigned int)(lsrt & 0xFFFFFFFF);
|
|
write_word_in_memory();
|
|
check_memory();
|
|
}
|
|
|
|
void SDL()
|
|
{
|
|
unsigned long long int old_word = 0;
|
|
PC++;
|
|
switch ((lsaddr) & 7)
|
|
{
|
|
case 0:
|
|
address = (lsaddr) & 0xFFFFFFF8;
|
|
dword = lsrt;
|
|
write_dword_in_memory();
|
|
check_memory();
|
|
break;
|
|
case 1:
|
|
address = (lsaddr) & 0xFFFFFFF8;
|
|
rdword = &old_word;
|
|
read_dword_in_memory();
|
|
if(address)
|
|
{
|
|
dword = ((unsigned long long)lsrt >> 8)|(old_word & 0xFF00000000000000LL);
|
|
write_dword_in_memory();
|
|
check_memory();
|
|
}
|
|
break;
|
|
case 2:
|
|
address = (lsaddr) & 0xFFFFFFF8;
|
|
rdword = &old_word;
|
|
read_dword_in_memory();
|
|
if(address)
|
|
{
|
|
dword = ((unsigned long long)lsrt >> 16)|(old_word & 0xFFFF000000000000LL);
|
|
write_dword_in_memory();
|
|
check_memory();
|
|
}
|
|
break;
|
|
case 3:
|
|
address = (lsaddr) & 0xFFFFFFF8;
|
|
rdword = &old_word;
|
|
read_dword_in_memory();
|
|
if(address)
|
|
{
|
|
dword = ((unsigned long long)lsrt >> 24)|(old_word & 0xFFFFFF0000000000LL);
|
|
write_dword_in_memory();
|
|
check_memory();
|
|
}
|
|
break;
|
|
case 4:
|
|
address = (lsaddr) & 0xFFFFFFF8;
|
|
rdword = &old_word;
|
|
read_dword_in_memory();
|
|
if(address)
|
|
{
|
|
dword = ((unsigned long long)lsrt >> 32)|(old_word & 0xFFFFFFFF00000000LL);
|
|
write_dword_in_memory();
|
|
check_memory();
|
|
}
|
|
break;
|
|
case 5:
|
|
address = (lsaddr) & 0xFFFFFFF8;
|
|
rdword = &old_word;
|
|
read_dword_in_memory();
|
|
if(address)
|
|
{
|
|
dword = ((unsigned long long)lsrt >> 40)|(old_word & 0xFFFFFFFFFF000000LL);
|
|
write_dword_in_memory();
|
|
check_memory();
|
|
}
|
|
break;
|
|
case 6:
|
|
address = (lsaddr) & 0xFFFFFFF8;
|
|
rdword = &old_word;
|
|
read_dword_in_memory();
|
|
if(address)
|
|
{
|
|
dword = ((unsigned long long)lsrt >> 48)|(old_word & 0xFFFFFFFFFFFF0000LL);
|
|
write_dword_in_memory();
|
|
check_memory();
|
|
}
|
|
break;
|
|
case 7:
|
|
address = (lsaddr) & 0xFFFFFFF8;
|
|
rdword = &old_word;
|
|
read_dword_in_memory();
|
|
if(address)
|
|
{
|
|
dword = ((unsigned long long)lsrt >> 56)|(old_word & 0xFFFFFFFFFFFFFF00LL);
|
|
write_dword_in_memory();
|
|
check_memory();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void SDR()
|
|
{
|
|
unsigned long long int old_word = 0;
|
|
PC++;
|
|
switch ((lsaddr) & 7)
|
|
{
|
|
case 0:
|
|
address = lsaddr;
|
|
rdword = &old_word;
|
|
read_dword_in_memory();
|
|
if(address)
|
|
{
|
|
dword = (lsrt << 56) | (old_word & 0x00FFFFFFFFFFFFFFLL);
|
|
write_dword_in_memory();
|
|
check_memory();
|
|
}
|
|
break;
|
|
case 1:
|
|
address = (lsaddr) & 0xFFFFFFF8;
|
|
rdword = &old_word;
|
|
read_dword_in_memory();
|
|
if(address)
|
|
{
|
|
dword = (lsrt << 48) | (old_word & 0x0000FFFFFFFFFFFFLL);
|
|
write_dword_in_memory();
|
|
check_memory();
|
|
}
|
|
break;
|
|
case 2:
|
|
address = (lsaddr) & 0xFFFFFFF8;
|
|
rdword = &old_word;
|
|
read_dword_in_memory();
|
|
if(address)
|
|
{
|
|
dword = (lsrt << 40) | (old_word & 0x000000FFFFFFFFFFLL);
|
|
write_dword_in_memory();
|
|
check_memory();
|
|
}
|
|
break;
|
|
case 3:
|
|
address = (lsaddr) & 0xFFFFFFF8;
|
|
rdword = &old_word;
|
|
read_dword_in_memory();
|
|
if(address)
|
|
{
|
|
dword = (lsrt << 32) | (old_word & 0x00000000FFFFFFFFLL);
|
|
write_dword_in_memory();
|
|
check_memory();
|
|
}
|
|
break;
|
|
case 4:
|
|
address = (lsaddr) & 0xFFFFFFF8;
|
|
rdword = &old_word;
|
|
read_dword_in_memory();
|
|
if(address)
|
|
{
|
|
dword = (lsrt << 24) | (old_word & 0x0000000000FFFFFFLL);
|
|
write_dword_in_memory();
|
|
check_memory();
|
|
}
|
|
break;
|
|
case 5:
|
|
address = (lsaddr) & 0xFFFFFFF8;
|
|
rdword = &old_word;
|
|
read_dword_in_memory();
|
|
if(address)
|
|
{
|
|
dword = (lsrt << 16) | (old_word & 0x000000000000FFFFLL);
|
|
write_dword_in_memory();
|
|
check_memory();
|
|
}
|
|
break;
|
|
case 6:
|
|
address = (lsaddr) & 0xFFFFFFF8;
|
|
rdword = &old_word;
|
|
read_dword_in_memory();
|
|
if(address)
|
|
{
|
|
dword = (lsrt << 8) | (old_word & 0x00000000000000FFLL);
|
|
write_dword_in_memory();
|
|
check_memory();
|
|
}
|
|
break;
|
|
case 7:
|
|
address = (lsaddr) & 0xFFFFFFF8;
|
|
dword = lsrt;
|
|
write_dword_in_memory();
|
|
check_memory();
|
|
break;
|
|
}
|
|
}
|
|
|
|
void SWR()
|
|
{
|
|
unsigned long long int old_word = 0;
|
|
PC++;
|
|
switch ((lsaddr) & 3)
|
|
{
|
|
case 0:
|
|
address = lsaddr;
|
|
rdword = &old_word;
|
|
read_word_in_memory();
|
|
if(address)
|
|
{
|
|
word = ((unsigned int)lsrt << 24) | (old_word & 0x00FFFFFF);
|
|
write_word_in_memory();
|
|
check_memory();
|
|
}
|
|
break;
|
|
case 1:
|
|
address = (lsaddr) & 0xFFFFFFFC;
|
|
rdword = &old_word;
|
|
read_word_in_memory();
|
|
if(address)
|
|
{
|
|
word = ((unsigned int)lsrt << 16) | (old_word & 0x0000FFFF);
|
|
write_word_in_memory();
|
|
check_memory();
|
|
}
|
|
break;
|
|
case 2:
|
|
address = (lsaddr) & 0xFFFFFFFC;
|
|
rdword = &old_word;
|
|
read_word_in_memory();
|
|
if(address)
|
|
{
|
|
word = ((unsigned int)lsrt << 8) | (old_word & 0x000000FF);
|
|
write_word_in_memory();
|
|
check_memory();
|
|
}
|
|
break;
|
|
case 3:
|
|
address = (lsaddr) & 0xFFFFFFFC;
|
|
word = (unsigned int)lsrt;
|
|
write_word_in_memory();
|
|
check_memory();
|
|
break;
|
|
}
|
|
}
|
|
|
|
void CACHE()
|
|
{
|
|
PC++;
|
|
}
|
|
|
|
void LL()
|
|
{
|
|
PC++;
|
|
address = lsaddr;
|
|
rdword = (unsigned long long *) &lsrt;
|
|
read_word_in_memory();
|
|
if (address)
|
|
{
|
|
sign_extended(lsrt);
|
|
llbit = 1;
|
|
}
|
|
}
|
|
|
|
void LWC1()
|
|
{
|
|
unsigned long long int temp;
|
|
if (check_cop1_unusable()) return;
|
|
PC++;
|
|
address = lslfaddr;
|
|
rdword = &temp;
|
|
read_word_in_memory();
|
|
if (address)
|
|
*((int*)reg_cop1_simple[lslfft]) = *rdword;
|
|
}
|
|
|
|
void LDC1()
|
|
{
|
|
if (check_cop1_unusable()) return;
|
|
PC++;
|
|
address = lslfaddr;
|
|
rdword = (unsigned long long *)reg_cop1_double[lslfft];
|
|
read_dword_in_memory();
|
|
}
|
|
|
|
void LD()
|
|
{
|
|
PC++;
|
|
address = lsaddr;
|
|
rdword = (unsigned long long *) &lsrt;
|
|
read_dword_in_memory();
|
|
}
|
|
|
|
void SC()
|
|
{
|
|
/*PC++;
|
|
printf("SC\n");
|
|
if (llbit) {
|
|
address = lsaddr;
|
|
word = (unsigned int)(lsrt & 0xFFFFFFFF);
|
|
write_word_in_memory();
|
|
}
|
|
lsrt = llbit;*/
|
|
|
|
PC++;
|
|
if(llbit)
|
|
{
|
|
address = lsaddr;
|
|
word = (unsigned int)(lsrt & 0xFFFFFFFF);
|
|
write_word_in_memory();
|
|
check_memory();
|
|
llbit = 0;
|
|
lsrt = 1;
|
|
}
|
|
else
|
|
{
|
|
lsrt = 0;
|
|
}
|
|
}
|
|
|
|
void SWC1()
|
|
{
|
|
if (check_cop1_unusable()) return;
|
|
PC++;
|
|
address = lslfaddr;
|
|
word = *((int*)reg_cop1_simple[lslfft]);
|
|
write_word_in_memory();
|
|
check_memory();
|
|
}
|
|
|
|
void SDC1()
|
|
{
|
|
if (check_cop1_unusable()) return;
|
|
PC++;
|
|
address = lslfaddr;
|
|
dword = *((unsigned long long*)reg_cop1_double[lslfft]);
|
|
write_dword_in_memory();
|
|
check_memory();
|
|
}
|
|
|
|
void SD()
|
|
{
|
|
PC++;
|
|
address = lsaddr;
|
|
dword = lsrt;
|
|
write_dword_in_memory();
|
|
check_memory();
|
|
}
|
|
|
|
void NOTCOMPILED()
|
|
{
|
|
#ifdef CORE_DBG
|
|
printf("NOTCOMPILED: addr = %x ops = %lx\n", PC->addr, (long) PC->ops);
|
|
#endif
|
|
|
|
if ((PC->addr>>16) == 0xa400)
|
|
recompile_block((int *) SP_DMEM, blocks[0xa4000000>>12], PC->addr);
|
|
else
|
|
{
|
|
unsigned int paddr = 0;
|
|
if (PC->addr >= 0x80000000 && PC->addr < 0xc0000000)
|
|
paddr = PC->addr;
|
|
else
|
|
paddr = virtual_to_physical_address(PC->addr, 2);
|
|
if (paddr)
|
|
{
|
|
if ((paddr & 0x1FFFFFFF) >= 0x10000000)
|
|
{
|
|
recompile_block((int *) rom+((((paddr-(PC->addr-blocks[PC->addr>>12]->start)) & 0x1FFFFFFF) - 0x10000000)>>2),
|
|
blocks[PC->addr>>12], PC->addr);
|
|
}
|
|
else
|
|
recompile_block((int *) rdram+(((paddr-(PC->addr-blocks[PC->addr>>12]->start)) & 0x1FFFFFFF)>>2),
|
|
blocks[PC->addr>>12], PC->addr);
|
|
}
|
|
else printf("not compiled exception\n");
|
|
}
|
|
/*#ifdef DBG
|
|
if (debugger_mode) 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 (dynacore)
|
|
dyna_jump();
|
|
}
|
|
|
|
void NOTCOMPILED2()
|
|
{
|
|
NOTCOMPILED();
|
|
}
|
|
|
|
static inline 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()
|
|
{
|
|
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] = 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((int *) rdram+(((paddr-(addr-blocks[addr>>12]->start)) & 0x1FFFFFFF)>>2),
|
|
blocks[addr>>12]);
|
|
}
|
|
PC=actual->block+((addr-actual->start)>>2);
|
|
|
|
if (dynacore) dyna_jump();
|
|
}
|
|
#undef addr
|
|
|
|
/* 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(_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++)
|
|
{
|
|
int least32 = *((int *) ®_cop1_fgr_64[i*2] + isBigEndian);
|
|
int most32 = *((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(_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()
|
|
{
|
|
if (!(Status & 0x20000000))
|
|
{
|
|
Cause = (11 << 2) | 0x10000000;
|
|
exception_general();
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void update_count()
|
|
{
|
|
if (interpcore)
|
|
{
|
|
Count = Count + (interp_addr - last_addr)/2;
|
|
last_addr = interp_addr;
|
|
}
|
|
else
|
|
{
|
|
if (PC->addr < last_addr)
|
|
{
|
|
printf("PC->addr < last_addr\n");
|
|
}
|
|
Count = Count + (PC->addr - last_addr)/2;
|
|
last_addr = PC->addr;
|
|
}
|
|
#ifdef COMPARE_CORE
|
|
if (delay_slot)
|
|
compare_core();
|
|
#endif
|
|
/*#ifdef DBG
|
|
if (debugger_mode && !delay_slot) update_debugger(PC->addr);
|
|
#endif
|
|
*/
|
|
}
|
|
|
|
void init_blocks()
|
|
{
|
|
int i;
|
|
for (i=0; i<0x100000; i++)
|
|
{
|
|
invalid_code[i] = 1;
|
|
blocks[i] = NULL;
|
|
}
|
|
blocks[0xa4000000>>12] = malloc(sizeof(precomp_block));
|
|
invalid_code[0xa4000000>>12] = 1;
|
|
blocks[0xa4000000>>12]->code = NULL;
|
|
blocks[0xa4000000>>12]->block = NULL;
|
|
blocks[0xa4000000>>12]->jumps_table = NULL;
|
|
blocks[0xa4000000>>12]->riprel_table = NULL;
|
|
blocks[0xa4000000>>12]->start = 0xa4000000;
|
|
blocks[0xa4000000>>12]->end = 0xa4001000;
|
|
actual=blocks[0xa4000000>>12];
|
|
init_block((int *) SP_DMEM, blocks[0xa4000000>>12]);
|
|
PC=actual->block+(0x40/4);
|
|
/*#ifdef DBG //should only be needed by dynamic recompiler
|
|
if (debugger_mode) // debugger shows initial state (before 1st instruction).
|
|
update_debugger(PC->addr);
|
|
#endif*/
|
|
}
|
|
|
|
/* this hard reset function simulates the boot-up state of the R4300 CPU */
|
|
void r4300_reset_hard()
|
|
{
|
|
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 */
|
|
void r4300_reset_soft()
|
|
{
|
|
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_HEADER->Country_code&0xFF)
|
|
{
|
|
case 0x44:
|
|
case 0x46:
|
|
case 0x49:
|
|
case 0x50:
|
|
case 0x53:
|
|
case 0x55:
|
|
case 0x58:
|
|
case 0x59:
|
|
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 0x37:
|
|
case 0x41:
|
|
case 0x45:
|
|
case 0x4A:
|
|
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;
|
|
}
|
|
|
|
}
|
|
|
|
void r4300_execute()
|
|
{
|
|
unsigned int i;
|
|
|
|
debug_count = 0;
|
|
printf("Starting r4300 emulator\n");
|
|
|
|
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();
|
|
interpcore = 0;
|
|
|
|
if (dynacore == 0)
|
|
{
|
|
printf ("R4300 Core mode: Interpreter\n");
|
|
init_blocks();
|
|
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);
|
|
compare_core();
|
|
#endif
|
|
#ifdef DBG
|
|
if (debugger_mode) update_debugger(PC->addr);
|
|
#endif
|
|
PC->ops();
|
|
}
|
|
}
|
|
#if !defined(NO_ASM) && (defined(__i386__) || defined(__x86_64__))
|
|
else if (dynacore == 1)
|
|
{
|
|
dynacore = 1;
|
|
printf ("R4300 Core mode: Dynamic Recompiler\n");
|
|
init_blocks();
|
|
code = (void *)(actual->code+(actual->block[0x40/4].local_addr));
|
|
dyna_start(code);
|
|
PC++;
|
|
#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;
|
|
fwrite(&mipsop, 1, 4, pfProfile);
|
|
fwrite(&x86addr, 1, sizeof(char *), pfProfile);
|
|
}
|
|
fclose(pfProfile);
|
|
pfProfile = NULL;
|
|
#endif
|
|
}
|
|
#endif
|
|
else
|
|
{
|
|
printf ("R4300 Core mode: Pure Interpreter\n");
|
|
dynacore = 0;
|
|
interpcore = 1;
|
|
pure_interpreter();
|
|
}
|
|
debug_count+= Count;
|
|
printf("R4300 core finished.\n");
|
|
for (i=0; i<0x100000; i++)
|
|
{
|
|
if (blocks[i])
|
|
{
|
|
if (blocks[i]->block) { free(blocks[i]->block); blocks[i]->block = NULL; }
|
|
if (blocks[i]->code) { free(blocks[i]->code); blocks[i]->code = NULL; }
|
|
if (blocks[i]->jumps_table) { free(blocks[i]->jumps_table); blocks[i]->jumps_table = NULL; }
|
|
if (blocks[i]->riprel_table) { free(blocks[i]->riprel_table); blocks[i]->riprel_table = NULL; }
|
|
free(blocks[i]);
|
|
blocks[i] = NULL;
|
|
}
|
|
}
|
|
if (!dynacore && interpcore) free(PC);
|
|
|
|
/* print instruction counts */
|
|
#if defined(COUNT_INSTR)
|
|
if (dynacore)
|
|
{
|
|
unsigned int iTypeCount[11] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
|
unsigned int iTotal = 0;
|
|
printf("Instruction counters:\n");
|
|
for (i = 0; i < 131; i++)
|
|
{
|
|
printf("%8s: %08i ", instr_name[i], instr_count[i]);
|
|
if (i % 5 == 4) printf("\n");
|
|
iTypeCount[instr_type[i]] += instr_count[i];
|
|
iTotal += instr_count[i];
|
|
}
|
|
printf("\nInstruction type summary (total instructions = %i)\n", iTotal);
|
|
for (i = 0; i < 11; i++)
|
|
{
|
|
printf("%20s: %04.1f%% (%i)\n", instr_typename[i], (float) iTypeCount[i] * 100.0 / iTotal, iTypeCount[i]);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|