project64/Source/Project64/N64 System/C Core/CPU.cpp

640 lines
17 KiB
C++

#include "main.h"
#include "CPU.h"
#include "debugger.h"
//int NextInstruction, ManualPaused;
//int DlistCount, AlistCount;
//SYSTEM_TIMERS Timers;
//DWORD MemoryStack;
DWORD JumpToLocation;
R4300iOp_FUNC * R4300i_Opcode;
void InitializeCPUCore ( void )
{
LARGE_INTEGER PerformanceFrequency;
//R4300i_Opcode = R4300iOp::BuildInterpreter();
R4300i_Opcode = R4300iOp32::BuildInterpreter();
CurrentFrame = 0;
QueryPerformanceFrequency(&PerformanceFrequency);
Frequency = PerformanceFrequency.QuadPart;
{
switch (_Rom->GetCountry())
{
case Germany: case french: case Italian:
case Europe: case Spanish: case Australia:
case X_PAL: case Y_PAL:
Timer_Initialize(50);
g_SystemType = SYSTEM_PAL;
break;
default:
Timer_Initialize(60);
g_SystemType = SYSTEM_NTSC;
break;
}
}
#ifndef EXTERNAL_RELEASE
LogOptions.GenerateLog = g_GenerateLog;
LoadLogOptions(&LogOptions, FALSE);
StartLog();
#endif
// switch (CPU_Type) {
// case CPU_Interpreter: StartInterpreterCPU(); break;
// case CPU_Recompiler: StartRecompilerCPU(); break;
// case CPU_SyncCores: StartRecompilerCPU(); break;
// default:
// DisplayError("Unhandled CPU %d",CPU_Type);
// }
// if (TargetInfo)
// {
// VirtualFree(TargetInfo,0,MEM_RELEASE);
// TargetInfo = NULL;
// }
}
int DelaySlotEffectsJump (DWORD JumpPC) {
OPCODE Command;
if (!_MMU->LW_VAddr(JumpPC, Command.Hex)) { return TRUE; }
switch (Command.op) {
case R4300i_SPECIAL:
switch (Command.funct) {
case R4300i_SPECIAL_JR: return DelaySlotEffectsCompare(JumpPC,Command.rs,0);
case R4300i_SPECIAL_JALR: return DelaySlotEffectsCompare(JumpPC,Command.rs,31);
}
break;
case R4300i_REGIMM:
switch (Command.rt) {
case R4300i_REGIMM_BLTZ:
case R4300i_REGIMM_BGEZ:
case R4300i_REGIMM_BLTZL:
case R4300i_REGIMM_BGEZL:
case R4300i_REGIMM_BLTZAL:
case R4300i_REGIMM_BGEZAL:
return DelaySlotEffectsCompare(JumpPC,Command.rs,0);
}
break;
case R4300i_JAL:
case R4300i_SPECIAL_JALR: return DelaySlotEffectsCompare(JumpPC,31,0); break;
case R4300i_J: return FALSE;
case R4300i_BEQ:
case R4300i_BNE:
case R4300i_BLEZ:
case R4300i_BGTZ:
return DelaySlotEffectsCompare(JumpPC,Command.rs,Command.rt);
case R4300i_CP1:
switch (Command.fmt) {
case R4300i_COP1_BC:
switch (Command.ft) {
case R4300i_COP1_BC_BCF:
case R4300i_COP1_BC_BCT:
case R4300i_COP1_BC_BCFL:
case R4300i_COP1_BC_BCTL:
{
int EffectDelaySlot;
OPCODE NewCommand;
if (!_MMU->LW_VAddr(JumpPC + 4, NewCommand.Hex)) { return TRUE; }
EffectDelaySlot = FALSE;
if (NewCommand.op == R4300i_CP1) {
if (NewCommand.fmt == R4300i_COP1_S && (NewCommand.funct & 0x30) == 0x30 ) {
EffectDelaySlot = TRUE;
}
if (NewCommand.fmt == R4300i_COP1_D && (NewCommand.funct & 0x30) == 0x30 ) {
EffectDelaySlot = TRUE;
}
}
return EffectDelaySlot;
}
break;
}
break;
}
break;
case R4300i_BEQL:
case R4300i_BNEL:
case R4300i_BLEZL:
case R4300i_BGTZL:
return DelaySlotEffectsCompare(JumpPC,Command.rs,Command.rt);
}
return TRUE;
}
void DoSomething ( void ) {
if (CPU_Action.CloseCPU) {
return;
}
if (CPU_Action.SoftReset)
{
CPU_Action.SoftReset = false;
_SystemTimer->SetTimer(CSystemTimer::SoftResetTimer,0x3000000,false);
ShowCFB();
_Reg->FAKE_CAUSE_REGISTER |= CAUSE_IP4;
CheckInterrupts();
_Plugins->Gfx()->SoftReset();
}
if (CPU_Action.GenerateInterrupt)
{
CPU_Action.GenerateInterrupt = FALSE;
_Reg->MI_INTR_REG |= CPU_Action.InterruptFlag;
CPU_Action.InterruptFlag = 0;
CheckInterrupts();
}
if (CPU_Action.CheckInterrupts) {
CPU_Action.CheckInterrupts = FALSE;
CheckInterrupts();
}
if (CPU_Action.ProfileStartStop) {
CPU_Action.ProfileStartStop = FALSE;
ResetTimer();
}
if (CPU_Action.ProfileResetStats) {
CPU_Action.ProfileResetStats = FALSE;
ResetTimer();
}
if (CPU_Action.ProfileGenerateLogs) {
CPU_Action.ProfileGenerateLogs = FALSE;
GenerateProfileLog();
}
if (CPU_Action.DoInterrupt) {
CPU_Action.DoInterrupt = FALSE;
if (DoIntrException(FALSE) && !CPU_Action.InterruptExecuted)
{
CPU_Action.InterruptExecuted = TRUE;
ClearRecompCodeInitialCode();
}
}
if (CPU_Action.ChangeWindow) {
CPU_Action.ChangeWindow = FALSE;
ChangeFullScreenFunc();
}
if (CPU_Action.Pause) {
PauseExecution();
CPU_Action.Pause = FALSE;
}
if (CPU_Action.ChangePlugin) {
ChangePluginFunc();
CPU_Action.ChangePlugin = FALSE;
}
if (CPU_Action.GSButton) {
ApplyGSButtonCheats();
CPU_Action.GSButton = FALSE;
}
CPU_Action.DoSomething = FALSE;
if (CPU_Action.SaveState) {
//test if allowed
CPU_Action.SaveState = FALSE;
if (!Machine_SaveState()) {
CPU_Action.SaveState = TRUE;
CPU_Action.DoSomething = TRUE;
}
}
if (CPU_Action.RestoreState) {
CPU_Action.RestoreState = FALSE;
Machine_LoadState();
}
if (CPU_Action.DoInterrupt == TRUE) { CPU_Action.DoSomething = TRUE; }
}
void InPermLoop (void) {
// *** Changed ***/
if (CPU_Action.DoInterrupt)
{
CPU_Action.DoSomething = TRUE;
return;
}
//if (CPU_Type == CPU_SyncCores) { SyncRegisters.CP0[9] +=5; }
/* Interrupts enabled */
if (( _Reg->STATUS_REGISTER & STATUS_IE ) == 0 ) { goto InterruptsDisabled; }
if (( _Reg->STATUS_REGISTER & STATUS_EXL ) != 0 ) { goto InterruptsDisabled; }
if (( _Reg->STATUS_REGISTER & STATUS_ERL ) != 0 ) { goto InterruptsDisabled; }
if (( _Reg->STATUS_REGISTER & 0xFF00) == 0) { goto InterruptsDisabled; }
/* check sound playing */
_N64System->SyncToAudio();
/* check RSP running */
/* check RDP running */
if (*_NextTimer > 0) {
//_Reg->COUNT_REGISTER += *_Timer + 1;
//if (CPU_Type == CPU_SyncCores) { SyncRegisters.CP0[9] += Timers.Timer + 1; }
*_NextTimer = -1;
}
return;
InterruptsDisabled:
if (UpdateScreen != NULL) { UpdateScreen(); }
//CurrentFrame = 0;
//CurrentPercent = 0;
//DisplayFPS();
DisplayError(GS(MSG_PERM_LOOP));
StopEmulation();
}
int DelaySlotEffectsCompare (DWORD PC, DWORD Reg1, DWORD Reg2) {
OPCODE Command;
if (!_MMU->LW_VAddr(PC + 4, Command.Hex)) {
//DisplayError("Failed to load word 2");
//ExitThread(0);
return TRUE;
}
switch (Command.op) {
case R4300i_SPECIAL:
switch (Command.funct) {
case R4300i_SPECIAL_SLL:
case R4300i_SPECIAL_SRL:
case R4300i_SPECIAL_SRA:
case R4300i_SPECIAL_SLLV:
case R4300i_SPECIAL_SRLV:
case R4300i_SPECIAL_SRAV:
case R4300i_SPECIAL_MFHI:
case R4300i_SPECIAL_MTHI:
case R4300i_SPECIAL_MFLO:
case R4300i_SPECIAL_MTLO:
case R4300i_SPECIAL_DSLLV:
case R4300i_SPECIAL_DSRLV:
case R4300i_SPECIAL_DSRAV:
case R4300i_SPECIAL_ADD:
case R4300i_SPECIAL_ADDU:
case R4300i_SPECIAL_SUB:
case R4300i_SPECIAL_SUBU:
case R4300i_SPECIAL_AND:
case R4300i_SPECIAL_OR:
case R4300i_SPECIAL_XOR:
case R4300i_SPECIAL_NOR:
case R4300i_SPECIAL_SLT:
case R4300i_SPECIAL_SLTU:
case R4300i_SPECIAL_DADD:
case R4300i_SPECIAL_DADDU:
case R4300i_SPECIAL_DSUB:
case R4300i_SPECIAL_DSUBU:
case R4300i_SPECIAL_DSLL:
case R4300i_SPECIAL_DSRL:
case R4300i_SPECIAL_DSRA:
case R4300i_SPECIAL_DSLL32:
case R4300i_SPECIAL_DSRL32:
case R4300i_SPECIAL_DSRA32:
if (Command.rd == 0) { return FALSE; }
if (Command.rd == Reg1) { return TRUE; }
if (Command.rd == Reg2) { return TRUE; }
break;
case R4300i_SPECIAL_MULT:
case R4300i_SPECIAL_MULTU:
case R4300i_SPECIAL_DIV:
case R4300i_SPECIAL_DIVU:
case R4300i_SPECIAL_DMULT:
case R4300i_SPECIAL_DMULTU:
case R4300i_SPECIAL_DDIV:
case R4300i_SPECIAL_DDIVU:
break;
default:
#ifndef EXTERNAL_RELEASE
DisplayError("Does %s effect Delay slot at %X?",R4300iOpcodeName(Command.Hex,PC+4), PC);
#endif
return TRUE;
}
break;
case R4300i_CP0:
switch (Command.rs) {
case R4300i_COP0_MT: break;
case R4300i_COP0_MF:
if (Command.rt == 0) { return FALSE; }
if (Command.rt == Reg1) { return TRUE; }
if (Command.rt == Reg2) { return TRUE; }
break;
default:
if ( (Command.rs & 0x10 ) != 0 ) {
switch( Command.funct ) {
case R4300i_COP0_CO_TLBR: break;
case R4300i_COP0_CO_TLBWI: break;
case R4300i_COP0_CO_TLBWR: break;
case R4300i_COP0_CO_TLBP: break;
default:
#ifndef EXTERNAL_RELEASE
DisplayError("Does %s effect Delay slot at %X?\n6",R4300iOpcodeName(Command.Hex,PC+4), PC);
#endif
return TRUE;
}
} else {
#ifndef EXTERNAL_RELEASE
DisplayError("Does %s effect Delay slot at %X?\n7",R4300iOpcodeName(Command.Hex,PC+4), PC);
#endif
return TRUE;
}
}
break;
case R4300i_CP1:
switch (Command.fmt) {
case R4300i_COP1_MF:
if (Command.rt == 0) { return FALSE; }
if (Command.rt == Reg1) { return TRUE; }
if (Command.rt == Reg2) { return TRUE; }
break;
case R4300i_COP1_CF: break;
case R4300i_COP1_MT: break;
case R4300i_COP1_CT: break;
case R4300i_COP1_S: break;
case R4300i_COP1_D: break;
case R4300i_COP1_W: break;
case R4300i_COP1_L: break;
#ifndef EXTERNAL_RELEASE
default:
DisplayError("Does %s effect Delay slot at %X?",R4300iOpcodeName(Command.Hex,PC+4), PC);
#endif
return TRUE;
}
break;
case R4300i_ANDI:
case R4300i_ORI:
case R4300i_XORI:
case R4300i_LUI:
case R4300i_ADDI:
case R4300i_ADDIU:
case R4300i_SLTI:
case R4300i_SLTIU:
case R4300i_DADDI:
case R4300i_DADDIU:
case R4300i_LB:
case R4300i_LH:
case R4300i_LW:
case R4300i_LWL:
case R4300i_LWR:
case R4300i_LDL:
case R4300i_LDR:
case R4300i_LBU:
case R4300i_LHU:
case R4300i_LD:
case R4300i_LWC1:
case R4300i_LDC1:
if (Command.rt == 0) { return FALSE; }
if (Command.rt == Reg1) { return TRUE; }
if (Command.rt == Reg2) { return TRUE; }
break;
case R4300i_CACHE: break;
case R4300i_SB: break;
case R4300i_SH: break;
case R4300i_SW: break;
case R4300i_SWR: break;
case R4300i_SWL: break;
case R4300i_SWC1: break;
case R4300i_SDC1: break;
case R4300i_SD: break;
default:
#ifndef EXTERNAL_RELEASE
DisplayError("Does %s effect Delay slot at %X?",R4300iOpcodeName(Command.Hex,PC+4), PC);
#endif
return TRUE;
}
return FALSE;
}
#ifdef toremove
void ChangeCompareTimer(void) {
DWORD NextCompare = _Reg->COMPARE_REGISTER - _Reg->COUNT_REGISTER;
if ((NextCompare & 0x80000000) != 0) { NextCompare = 0x7FFFFFFF; }
if (NextCompare == 0) { NextCompare = 0x1; }
_SystemTimer->SetTimer(CSystemTimer::CompareTimer,NextCompare,false);
}
#endif
void CheckTimer (void) {
BreakPoint(__FILE__,__LINE__);
/* int count;
for (count = 0; count < MaxTimers; count++) {
if (!Timers.Active[count]) { continue; }
if (!(count == CompareTimer && Timers.NextTimer[count] == 0x7FFFFFFF)) {
Timers.NextTimer[count] += Timers.Timer;
}
}
Timers.CurrentTimerType = -1;
Timers.Timer = 0x7FFFFFFF;
for (count = 0; count < MaxTimers; count++) {
if (!Timers.Active[count]) { continue; }
if (Timers.NextTimer[count] >= Timers.Timer) { continue; }
Timers.Timer = Timers.NextTimer[count];
Timers.CurrentTimerType = count;
}
if (Timers.CurrentTimerType == -1) {
DisplayError("No active timers ???\nEmulation Stoped");
ExitThread(0);
}
for (count = 0; count < MaxTimers; count++) {
if (!Timers.Active[count]) { continue; }
if (!(count == CompareTimer && Timers.NextTimer[count] == 0x7FFFFFFF)) {
Timers.NextTimer[count] -= Timers.Timer;
}
}
if (Timers.NextTimer[CompareTimer] == 0x7FFFFFFF) {
DWORD NextCompare = COMPARE_REGISTER - COUNT_REGISTER;
if ((NextCompare & 0x80000000) == 0 && NextCompare != 0x7FFFFFFF) {
ChangeCompareTimer();
}
}*/
}
/*void RefreshScreen (void ){
static DWORD OLD_VI_V_SYNC_REG = 0, VI_INTR_TIME = 500000;
LARGE_INTEGER Time;
char Label[100];
if (Profiling || ShowCPUPer) { memcpy(Label,ProfilingLabel,sizeof(Label)); }
if (Profiling) { StartTimer("RefreshScreen"); }
if (OLD_VI_V_SYNC_REG != VI_V_SYNC_REG) {
if (VI_V_SYNC_REG == 0) {
VI_INTR_TIME = 500000;
} else {
VI_INTR_TIME = (VI_V_SYNC_REG + 1) * 1500;
if ((VI_V_SYNC_REG % 1) != 0) {
VI_INTR_TIME -= 38;
}
}
}
ChangeTimerRelative(ViTimer,VI_INTR_TIME);
if (g_FixedAudio)
{
UpdateAudioTimer (VI_INTR_TIME);
}
if ((VI_STATUS_REG & 0x10) != 0) {
if (ViFieldNumber == 0) {
ViFieldNumber = 1;
} else {
ViFieldNumber = 0;
}
} else {
ViFieldNumber = 0;
}
if (ShowCPUPer || Profiling) { StartTimer("CPU Idel"); }
if (Limit_FPS()) { Timer_Process(NULL); }
if (ShowCPUPer || Profiling) { StopTimer(); }
if (Profiling) { StartTimer("RefreshScreen: Update FPS"); }
if ((CurrentFrame & 7) == 0) {
//Disables Screen saver
//mouse_event(MOUSEEVENTF_MOVE,1,1,0,GetMessageExtraInfo());
//mouse_event(MOUSEEVENTF_MOVE,-1,-1,0,GetMessageExtraInfo());
QueryPerformanceCounter(&Time);
Frames[(CurrentFrame >> 3) % NoOfFrames] = Time.QuadPart - LastFrame;
LastFrame = Time.QuadPart;
DisplayFPS();
}
if (Profiling) { StopTimer(); }
if (ShowCPUPer) { DisplayCPUPer(); }
CurrentFrame += 1;
if (Profiling) { StartTimer("RefreshScreen: Update Screen"); }
__try {
if (UpdateScreen != NULL)
{
UpdateScreen();
}
} __except( r4300i_CPU_MemoryFilter( GetExceptionCode(), GetExceptionInformation()) ) {
DisplayError("Unknown memory action in trying to update the screen\n\nEmulation stop");
ExitThread(0);
}
if (Profiling) { StartTimer("RefreshScreen: Cheats"); }
if ((STATUS_REGISTER & STATUS_IE) != 0 ) { ApplyCheats(); }
if (Profiling || ShowCPUPer) { StartTimer(Label); }
}
void RunRsp (void) {
if ( ( SP_STATUS_REG & SP_STATUS_HALT ) == 0) {
if ( ( SP_STATUS_REG & SP_STATUS_BROKE ) == 0 ) {
DWORD Task = *( DWORD *)(DMEM + 0xFC0);
if (Task == 1 && (DPC_STATUS_REG & DPC_STATUS_FREEZE) != 0)
{
return;
}
switch (Task) {
case 1:
DlistCount += 1;
/*if ((DlistCount % 2) == 0) {
SP_STATUS_REG |= (0x0203 );
MI_INTR_REG |= MI_INTR_SP | MI_INTR_DP;
CheckInterrupts();
return;
}*/
/* break;
case 2:
AlistCount += 1;
break;
}
if (ShowDListAListCount) {
DisplayMessage("Dlist: %d Alist: %d",DlistCount,AlistCount);
}
if (Profiling || DisplayCPUPer) {
char Label[100];
strncpy(Label,ProfilingLabel,sizeof(Label));
if (IndvidualBlock && !DisplayCPUPer) {
StartTimer("RSP");
} else {
switch (*( DWORD *)(DMEM + 0xFC0)) {
case 1: StartTimer("RSP: Dlist"); break;
case 2: StartTimer("RSP: Alist"); break;
default: StartTimer("RSP: Unknown"); break;
}
}
DoRspCycles(100);
StartTimer(Label);
} else {
DoRspCycles(100);
}
#ifdef CFB_READ
if (VI_ORIGIN_REG > 0x280) {
SetFrameBuffer(VI_ORIGIN_REG, (DWORD)(VI_WIDTH_REG * (VI_WIDTH_REG *.75)));
}
#endif
}
}
}
*/
void DisplayFPS (void) {
if (CurrentFrame > (NoOfFrames << 3)) {
__int64 Total = 0;
int count;
for (count = 0; count < NoOfFrames; count ++) {
Total += Frames[count];
}
DisplayMessage2("FPS: %.2f", (__int64)Frequency/ ((double)Total / (NoOfFrames << 3)));
} else {
DisplayMessage2("FPS: -.--" );
}
}
void CloseCpu (void) {
// DWORD ExitCode, count, OldProtect;
//
// if (!CPURunning) { return; }
// ManualPaused = FALSE;
// if (CPU_Paused) { PauseCpu (); Sleep(1000); }
//
// {
// BOOL Temp = AlwaysOnTop;
// AlwaysOnTop = FALSE;
// AlwaysOnTopWindow(hMainWindow);
// AlwaysOnTop = Temp;
// }
//
// for (count = 0; count < 20; count ++ ) {
// CPU_Action.CloseCPU = TRUE;
// CPU_Action.Stepping = FALSE;
// CPU_Action.DoSomething = TRUE;
// PulseEvent( CPU_Action.hStepping );
// Sleep(100);
// GetExitCodeThread(hCPU,&ExitCode);
// if (ExitCode != STILL_ACTIVE) {
// hCPU = NULL;
// count = 100;
// }
// }
// if (hCPU != NULL) { TerminateThread(hCPU,0); hCPU = NULL; }
// CPURunning = FALSE;
// VirtualProtect(N64MEM,RdramSize,PAGE_READWRITE,&OldProtect);
// VirtualProtect(N64MEM + 0x04000000,0x2000,PAGE_READWRITE,&OldProtect);
// Timer_Stop();
// SetCurrentSaveState(hMainWindow,ID_CURRENTSAVE_DEFAULT);
// CloseEeprom();
// CloseMempak();
// CloseSram();
// FreeSyncMemory();
// if (GfxRomClosed != NULL) { GfxRomClosed(); }
// if (AiRomClosed != NULL) { AiRomClosed(); }
// if (ContRomClosed != NULL) { ContRomClosed(); }
// if (RSPRomClosed) { RSPRomClosed(); }
// if (Profiling) { GenerateTimerResults(); }
// CloseHandle(CPU_Action.hStepping);
// SendMessage( hStatusWnd, SB_SETTEXT, 0, (LPARAM)GS(MSG_EMULATION_ENDED) );
}