Files
Project64-Legacy/Cpu.c
rgarciaz80 3dfc995d02 Expose r4300i debugger stuff, controlled through two new apps settings "Have Debugger=True" and "Show More Messages=True"
This makes it so the Release External build can now be used to debug the roms without having to also provide a Release build.
Next commit will add these options via the graphical interface and clean up some options that have become deprecated
2021-04-22 06:52:47 -05:00

1310 lines
39 KiB
C

/*
* Project 64 - A Nintendo 64 emulator.
*
* (c) Copyright 2001 zilmar (zilmar@emulation64.com) and
* Jabo (jabo@emulation64.com).
*
* pj64 homepage: www.pj64.net
*
* Permission to use, copy, modify and distribute Project64 in both binary and
* source form, for non-commercial purposes, is hereby granted without fee,
* providing that this license information and copyright notice appear with
* all copies and any derived work.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event shall the authors be held liable for any damages
* arising from the use of this software.
*
* Project64 is freeware for PERSONAL USE only. Commercial users should
* seek permission of the copyright holders first. Commercial use includes
* charging money for Project64 or software derived from Project64.
*
* The copyright holders request that bug fixes and improvements to the code
* should be forwarded to them so if they want them.
*
*/
#include <windows.h>
#include <commctrl.h>
#include <stdio.h>
#include "main.h"
#include "Compression/unzip.h"
#include "Compression/zip.h"
#include "cpu.h"
#include "cheats.h"
#include "debugger.h"
#include "plugin.h"
#include "EmulateAI.h"
#include "resource.h"
#include "CheatSearch.h"
int NextInstruction, JumpToLocation, ManualPaused, CPU_Paused, CountPerOp;
char SaveAsFileName[255], LoadFileName[255];
int DlistCount, AlistCount, CurrentSaveSlot;
enum SaveType SaveUsing;
CPU_ACTION CPU_Action;
SYSTEM_TIMERS Timers;
HANDLE hPauseMutex;
OPCODE Opcode;
HANDLE hCPU;
BOOL inFullScreen, CPURunning, SPHack;
DWORD MemoryStack;
#ifdef CFB_READ
DWORD CFBStart = 0, CFBEnd = 0;
#endif
#ifdef Interpreter_StackTest
DWORD StackValue;
#endif
#ifdef CFB_READ
void __cdecl SetFrameBuffer (DWORD Address, DWORD Length) {
DWORD NewStart, NewLength, OldProtect;
NewStart = Address;
NewLength = Length;
if (CFBStart != 0) {
VirtualProtect(N64MEM + CFBStart,CFBEnd - CFBStart,PAGE_READWRITE,&OldProtect);
}
if (Length == 0) {
CFBStart = 0;
CFBEnd = 0;
return;
}
CFBStart = Address & ~0xFFF;
CFBEnd = ((CFBStart + Length + 0xFFC) & ~0xFFF) - 1;
VirtualProtect(N64MEM + CFBStart,CFBEnd - CFBStart,PAGE_READONLY,&OldProtect);
}
#endif
char *TimeName[MaxTimers] = { "CompareTimer","SiTimer","PiTimer","ViTimer" };
void InitiliazeCPUFlags (void) {
inFullScreen = FALSE;
CPURunning = FALSE;
CurrentSaveSlot = ID_CURRENTSAVE_DEFAULT;
SPHack = FALSE;
}
void ChangeCompareTimer(void) {
DWORD NextCompare = COMPARE_REGISTER - COUNT_REGISTER;
if ((NextCompare & 0x80000000) != 0) { NextCompare = 0x7FFFFFFF; }
if (NextCompare == 0) { NextCompare = 0x1; }
ChangeTimer(CompareTimer,NextCompare);
}
void ChangeTimer(int Type, int Value) {
if (Value == 0) {
Timers.NextTimer[Type] = 0;
Timers.Active[Type] = FALSE;
return;
}
Timers.NextTimer[Type] = Value - Timers.Timer;
Timers.Active[Type] = TRUE;
CheckTimer();
}
void CheckTimer (void) {
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 CloseCpu (void) {
DWORD ExitCode, OldProtect, count;
if (!CPURunning || hCPU == NULL) { return; }
CPU_Action.CloseCPU = TRUE;
CPU_Action.Stepping = FALSE;
CPU_Action.DoSomething = TRUE;
PulseEvent(CPU_Action.hStepping);
ManualPaused = FALSE;
if (CPU_Paused) { PauseCpu(); }
{
BOOL Temp = AlwaysOnTop;
AlwaysOnTop = FALSE;
AlwaysOnTopWindow(hMainWindow);
AlwaysOnTop = Temp;
}
for (count = 0; count < 20; count ++ ) {
GetExitCodeThread(hCPU, &ExitCode);
if (ExitCode != STILL_ACTIVE) {
hCPU = NULL;
break;
}
Sleep(50);
//if (CPU_Action.CloseCPU == TRUE)
// PulseEvent(CPU_Action.hStepping);
}
if (hCPU != NULL) {
//DisplayError("Emulation thread failed to terminate plugins\nReport this if you can reproduce reliably");
TerminateThread(hCPU, 0);
hCPU = NULL;
SetupPlugins(hMainWindow);
}
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 (ContRomClosed != NULL) { ContRomClosed(); }*/
if (AiRomClosed != NULL) { AiRomClosed(); }
if (RSPRomClosed) { RSPRomClosed(); }
if (Profiling) { GenerateTimerResults(); }
CloseHandle(CPU_Action.hStepping);
SendMessage( hStatusWnd, SB_SETTEXT, 0, (LPARAM)GS(MSG_EMULATION_ENDED) );
}
int DelaySlotEffectsCompare (DWORD PC, DWORD Reg1, DWORD Reg2) {
OPCODE Command;
if (!r4300i_LW_VAddr(PC + 4, &Command.Hex)) {
DisplayError("Failed to load word 2");
ExitThread(0);
// return TRUE;
}
if (SelfModCheck == ModCode_ChangeMemory) {
if ( (Command.Hex >> 16) == 0x7C7C) {
Command.Hex = OrigMem[(Command.Hex & 0xFFFF)].OriginalValue;
}
}
switch (Command.BRANCH.op) {
case R4300i_SPECIAL:
switch (Command.REG.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.REG.rd == 0) { return FALSE; }
if (Command.REG.rd == Reg1) { return TRUE; }
if (Command.REG.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:
if (ShowDebugMessages)
DisplayError("Does %s effect Delay slot at %X?",R4300iOpcodeName(Command.Hex,PC+4), PC);
return TRUE;
}
break;
case R4300i_CP0:
switch (Command.BRANCH.rs) {
case R4300i_COP0_MT: break;
case R4300i_COP0_MF:
if (Command.BRANCH.rt == 0) { return FALSE; }
if (Command.BRANCH.rt == Reg1) { return TRUE; }
if (Command.BRANCH.rt == Reg2) { return TRUE; }
break;
default:
if ( (Command.BRANCH.rs & 0x10 ) != 0 ) {
switch( Opcode.REG.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:
if (ShowDebugMessages)
DisplayError("Does %s effect Delay slot at %X?\n6",R4300iOpcodeName(Command.Hex,PC+4), PC);
return TRUE;
}
} else {
if (ShowDebugMessages)
DisplayError("Does %s effect Delay slot at %X?\n7",R4300iOpcodeName(Command.Hex,PC+4), PC);
return TRUE;
}
}
break;
case R4300i_CP1:
switch (Command.FP.fmt) {
case R4300i_COP1_MF:
if (Command.BRANCH.rt == 0) { return FALSE; }
if (Command.BRANCH.rt == Reg1) { return TRUE; }
if (Command.BRANCH.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;
default:
if (ShowDebugMessages)
DisplayError("Does %s effect Delay slot at %X?",R4300iOpcodeName(Command.Hex,PC+4), PC);
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.BRANCH.rt == 0) { return FALSE; }
if (Command.BRANCH.rt == Reg1) { return TRUE; }
if (Command.BRANCH.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:
if (ShowDebugMessages)
DisplayError("Does %s effect Delay slot at %X?",R4300iOpcodeName(Command.Hex,PC+4), PC);
return TRUE;
}
return FALSE;
}
int DelaySlotEffectsJump (DWORD JumpPC) {
OPCODE Command;
if (!r4300i_LW_VAddr(JumpPC, &Command.Hex)) { return TRUE; }
if (SelfModCheck == ModCode_ChangeMemory) {
if ( (Command.Hex >> 16) == 0x7C7C) {
Command.Hex = OrigMem[(Command.Hex & 0xFFFF)].OriginalValue;
}
}
switch (Command.BRANCH.op) {
case R4300i_SPECIAL:
switch (Command.REG.funct) {
case R4300i_SPECIAL_JR: return DelaySlotEffectsCompare(JumpPC,Command.BRANCH.rs,0);
case R4300i_SPECIAL_JALR: return DelaySlotEffectsCompare(JumpPC,Command.BRANCH.rs,31);
}
break;
case R4300i_REGIMM:
switch (Command.BRANCH.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.BRANCH.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.BRANCH.rs,Command.BRANCH.rt);
case R4300i_CP1:
switch (Command.FP.fmt) {
case R4300i_COP1_BC:
switch (Command.FP.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 (!r4300i_LW_VAddr(JumpPC + 4, &NewCommand.Hex)) { return TRUE; }
EffectDelaySlot = FALSE;
if (NewCommand.BRANCH.op == R4300i_CP1) {
if (NewCommand.FP.fmt == R4300i_COP1_S && (NewCommand.REG.funct & 0x30) == 0x30 ) {
EffectDelaySlot = TRUE;
}
if (NewCommand.FP.fmt == R4300i_COP1_D && (NewCommand.REG.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.BRANCH.rs,Command.BRANCH.rt);
}
return TRUE;
}
void ProcessMessages (void) {
HANDLE hEvent;
MSG msg;
hEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
MsgWaitForMultipleObjects(1,&hEvent,FALSE,1000,QS_ALLINPUT);
CloseHandle(hEvent);
while (PeekMessage(&msg,NULL,0,0,PM_REMOVE) != 0) {
TranslateMessage(&msg);
DispatchMessage(&msg);
if (msg.message == WM_QUIT) {
PostMessage(msg.hwnd,msg.message,msg.wParam,msg.lParam);
return;
}
}
}
void DoSomething ( void ) {
if (CPU_Action.CloseCPU) {
if (GfxRomClosed != NULL)
GfxRomClosed();
if (ContRomClosed != NULL)
ContRomClosed();
CoUninitialize();
ExitThread(0);
}
if (CPU_Action.CheckInterrupts) {
CPU_Action.CheckInterrupts = FALSE;
CheckInterrupts();
}
if (CPU_Action.DoInterrupt) {
CPU_Action.DoInterrupt = FALSE;
DoIntrException(FALSE);
if (CPU_Type == CPU_SyncCores) {
SyncRegisters.MI[2] = Registers.MI[2];
SwitchSyncRegisters();
DoIntrException(FALSE);
SwitchSyncRegisters();
}
}
if (CPU_Action.ChangeWindow) {
CPU_Action.ChangeWindow = FALSE;
CPU_Paused = TRUE;
SendMessage(hMainWindow,WM_COMMAND,ID_OPTIONS_FULLSCREEN,0);
CPU_Paused = FALSE;
}
if (CPU_Action.Pause) {
WaitForSingleObject(hPauseMutex, INFINITE);
if (CPU_Action.Pause) {
HMENU hMenu = GetMenu(hMainWindow);
HMENU hSubMenu = GetSubMenu(hMenu,1);
MenuSetText(hSubMenu, 1, GS(MENU_RESUME),"F2");
CurrentFrame = 0;
CurrentPercent = 0;
CPU_Paused = TRUE;
CPU_Action.Pause = FALSE;
ReleaseMutex(hPauseMutex);
SendMessage( hStatusWnd, SB_SETTEXT, 0, (LPARAM)GS(MSG_CPU_PAUSED));
DisplayFPS ();
if (DrawScreen != NULL) { DrawScreen(); }
WaitForSingleObject(hPauseMutex, INFINITE);
if (CPU_Paused) {
ReleaseMutex(hPauseMutex);
SuspendThread(hCPU);
} else {
ReleaseMutex(hPauseMutex);
}
} else {
ReleaseMutex(hPauseMutex);
}
}
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) { return; }
//Timers.Timer -= 5;
//COUNT_REGISTER +=5;
//if (CPU_Type == CPU_SyncCores) { SyncRegisters.CP0[9] +=5; }
/* Interrupts enabled */
if (( STATUS_REGISTER & STATUS_IE ) == 0 ) { goto InterruptsDisabled; }
if (( STATUS_REGISTER & STATUS_EXL ) != 0 ) { goto InterruptsDisabled; }
if (( STATUS_REGISTER & STATUS_ERL ) != 0 ) { goto InterruptsDisabled; }
if (( STATUS_REGISTER & 0xFF00) == 0) { goto InterruptsDisabled; }
/* check sound playing */
//if (AiReadLength() != 0) { return; }
/* check RSP running */
/* check RDP running */
if (Timers.Timer > 0) {
COUNT_REGISTER += Timers.Timer + 1;
if (CPU_Type == CPU_SyncCores) { SyncRegisters.CP0[9] += Timers.Timer + 1; }
Timers.Timer = -1;
}
return;
InterruptsDisabled:
if (UpdateScreen != NULL) { UpdateScreen(); }
CurrentFrame = 0;
CurrentPercent = 0;
DisplayFPS();
DisplayError(GS(MSG_PERM_LOOP));
ExitThread(0);
}
BOOL Machine_LoadState(void) {
char Directory[255], FileName[255], ZipFile[255], LoadHeader[64], String[100];
char drive[_MAX_DRIVE] ,dir[_MAX_DIR], ext[_MAX_EXT];
DWORD dwRead, Value, count, SaveRDRAMSize;
BOOL LoadedZipFile = FALSE;
HANDLE hSaveFile;
unzFile file;
if (strlen(LoadFileName) == 0) {
Settings_GetDirectory(InstantSaveDir, Directory, sizeof(Directory));
sprintf(FileName,"%s%s",Directory,CurrentSave);
sprintf(ZipFile,"%s.zip",FileName);
} else {
strcpy(FileName,LoadFileName);
strcpy(ZipFile,LoadFileName);
}
file = unzOpen(ZipFile);
if (file != NULL) {
unz_file_info info;
char zname[132];
int port = 0;
port = unzGoToFirstFile(file);
while (port == UNZ_OK && LoadedZipFile == FALSE) {
unzGetCurrentFileInfo(file, &info, zname, 128, NULL,0, NULL,0);
if (unzLocateFile(file, zname, 1) != UNZ_OK ) {
unzClose(file);
port = -1;
continue;
}
if( unzOpenCurrentFile(file) != UNZ_OK ) {
unzClose(file);
port = -1;
continue;
}
unzReadCurrentFile(file,&Value,4);
if (Value != 0x23D8A6C8) {
unzCloseCurrentFile(file);
continue;
}
unzReadCurrentFile(file,&SaveRDRAMSize,sizeof(SaveRDRAMSize));
unzReadCurrentFile(file,LoadHeader,0x40);
//Check header
if (memcmp(LoadHeader,RomHeader,0x40) != 0) {
int result;
if (inFullScreen) { return FALSE; }
result = MessageBox(hMainWindow,GS(MSG_SAVE_STATE_HEADER),GS(MSG_MSGBOX_TITLE),
MB_YESNO|MB_ICONQUESTION|MB_DEFBUTTON2);
if (result == IDNO) { return FALSE; }
}
if (CPU_Type == CPU_SyncCores) {
DWORD OldProtect;
VirtualProtect(N64MEM,RdramSize,PAGE_READWRITE,&OldProtect);
VirtualProtect(N64MEM + 0x04000000,0x2000,PAGE_READWRITE,&OldProtect);
VirtualProtect(SyncMemory,RdramSize,PAGE_READWRITE,&OldProtect);
VirtualProtect(SyncMemory + 0x04000000,0x2000,PAGE_READWRITE,&OldProtect);
}
if (CPU_Type != CPU_Interpreter) {
ResetRecompCode();
}
Timers.CurrentTimerType = -1;
Timers.Timer = 0;
for (count = 0; count < MaxTimers; count ++) { Timers.Active[count] = FALSE; }
//fix rdram size
if (SaveRDRAMSize != RdramSize) {
if (RdramSize == 0x400000) {
if (VirtualAlloc(N64MEM + 0x400000, 0x400000, MEM_COMMIT, PAGE_READWRITE)==NULL) {
if (HaveDebugger)
DisplayError("Failed to Extend memory to 8mb");
else
DisplayError(GS(MSG_MEM_ALLOC_ERROR));
ExitThread(0);
}
if (VirtualAlloc((BYTE *)JumpTable + 0x400000, 0x400000, MEM_COMMIT, PAGE_READWRITE)==NULL) {
if (HaveDebugger)
DisplayError("Failed to Extend Jump Table to 8mb");
else
DisplayError(GS(MSG_MEM_ALLOC_ERROR));
ExitThread(0);
}
if (VirtualAlloc((BYTE *)DelaySlotTable + (0x400000 >> 0xA), (0x400000 >> 0xA), MEM_COMMIT, PAGE_READWRITE)==NULL) {
if (HaveDebugger)
DisplayError("Failed to Extend Delay Slot Table to 8mb");
else
DisplayError(GS(MSG_MEM_ALLOC_ERROR));
ExitThread(0);
}
} else {
VirtualFree(N64MEM + 0x400000, 0x400000,MEM_DECOMMIT);
VirtualFree((BYTE *)JumpTable + 0x400000, 0x400000,MEM_DECOMMIT);
VirtualFree((BYTE *)DelaySlotTable + (0x400000 >> 0xA), (0x400000 >> 0xA),MEM_DECOMMIT);
}
}
RdramSize = SaveRDRAMSize;
unzReadCurrentFile(file,&Value,sizeof(Value));
ChangeTimer(ViTimer,Value);
unzReadCurrentFile(file,&PROGRAM_COUNTER,sizeof(PROGRAM_COUNTER));
unzReadCurrentFile(file,GPR,sizeof(_int64)*32);
unzReadCurrentFile(file,FPR,sizeof(_int64)*32);
unzReadCurrentFile(file,CP0,sizeof(DWORD)*32);
unzReadCurrentFile(file,FPCR,sizeof(DWORD)*32);
unzReadCurrentFile(file,&HI,sizeof(_int64));
unzReadCurrentFile(file,&LO,sizeof(_int64));
unzReadCurrentFile(file,RegRDRAM,sizeof(DWORD)*10);
unzReadCurrentFile(file,RegSP,sizeof(DWORD)*10);
unzReadCurrentFile(file,RegDPC,sizeof(DWORD)*10);
unzReadCurrentFile(file,RegMI,sizeof(DWORD)*4);
unzReadCurrentFile(file,RegVI,sizeof(DWORD)*14);
unzReadCurrentFile(file,RegAI,sizeof(DWORD)*6);
unzReadCurrentFile(file,RegPI,sizeof(DWORD)*13);
unzReadCurrentFile(file,RegRI,sizeof(DWORD)*8);
unzReadCurrentFile(file,RegSI,sizeof(DWORD)*4);
unzReadCurrentFile(file,tlb,sizeof(TLB)*32);
unzReadCurrentFile(file,PIF_Ram,0x40);
unzReadCurrentFile(file,RDRAM,RdramSize);
unzReadCurrentFile(file,DMEM,0x1000);
unzReadCurrentFile(file,IMEM,0x1000);
unzCloseCurrentFile(file);
unzClose(file);
LoadedZipFile = TRUE;
_splitpath( ZipFile, drive, dir, ZipFile, ext );
sprintf(FileName,"%s%s",ZipFile,ext);
}
}
if (!LoadedZipFile) {
hSaveFile = CreateFile(FileName,GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ,NULL,OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL);
if (hSaveFile == INVALID_HANDLE_VALUE) {
_splitpath( FileName, drive, dir, ZipFile, ext );
sprintf(String,"%s %s%s",GS(MSG_UNABLED_LOAD_STATE),ZipFile,ext);
SendMessage( hStatusWnd, SB_SETTEXT, 0, (LPARAM)String );
return FALSE;
}
SetFilePointer(hSaveFile,0,NULL,FILE_BEGIN);
ReadFile( hSaveFile,&Value,sizeof(Value),&dwRead,NULL);
if (Value != 0x23D8A6C8) { return FALSE; }
ReadFile( hSaveFile,&SaveRDRAMSize,sizeof(SaveRDRAMSize),&dwRead,NULL);
ReadFile( hSaveFile,LoadHeader,0x40,&dwRead,NULL);
//Check header
if (memcmp(LoadHeader,ROM,0x40) != 0) {
int result;
if (inFullScreen) { return FALSE; }
result = MessageBox(hMainWindow,GS(MSG_SAVE_STATE_HEADER),GS(MSG_MSGBOX_TITLE),
MB_YESNO|MB_ICONQUESTION|MB_DEFBUTTON2);
if (result == IDNO) { return FALSE; }
}
if (CPU_Type == CPU_SyncCores) {
DWORD OldProtect;
VirtualProtect(N64MEM,RdramSize,PAGE_READWRITE,&OldProtect);
VirtualProtect(N64MEM + 0x04000000,0x2000,PAGE_READWRITE,&OldProtect);
VirtualProtect(SyncMemory,RdramSize,PAGE_READWRITE,&OldProtect);
VirtualProtect(SyncMemory + 0x04000000,0x2000,PAGE_READWRITE,&OldProtect);
}
if (CPU_Type != CPU_Interpreter) {
ResetRecompCode();
}
Timers.CurrentTimerType = -1;
Timers.Timer = 0;
for (count = 0; count < MaxTimers; count ++) { Timers.Active[count] = FALSE; }
//fix rdram size
if (SaveRDRAMSize != RdramSize) {
if (RdramSize == 0x400000) {
if (VirtualAlloc(N64MEM + 0x400000, 0x400000, MEM_COMMIT, PAGE_READWRITE)==NULL) {
if (HaveDebugger)
DisplayError("Failed to Extend memory to 8mb");
else
DisplayError(GS(MSG_MEM_ALLOC_ERROR));
ExitThread(0);
}
if (VirtualAlloc((BYTE *)JumpTable + 0x400000, 0x400000, MEM_COMMIT, PAGE_READWRITE)==NULL) {
if (HaveDebugger)
DisplayError("Failed to Extend Jump Table to 8mb");
else
DisplayError(GS(MSG_MEM_ALLOC_ERROR));
ExitThread(0);
}
if (VirtualAlloc((BYTE *)DelaySlotTable + (0x400000 >> 0xA), (0x400000 >> 0xA), MEM_COMMIT, PAGE_READWRITE)==NULL) {
if (HaveDebugger)
DisplayError("Failed to Extend Delay Slot Table to 8mb");
else
DisplayError(GS(MSG_MEM_ALLOC_ERROR));
ExitThread(0);
}
} else {
VirtualFree(N64MEM + 0x400000, 0x400000,MEM_DECOMMIT);
VirtualFree((BYTE *)JumpTable + 0x400000, 0x400000,MEM_DECOMMIT);
VirtualFree((BYTE *)DelaySlotTable + (0x400000 >> 0xA), (0x400000 >> 0xA),MEM_DECOMMIT);
}
}
RdramSize = SaveRDRAMSize;
ReadFile( hSaveFile,&Value,sizeof(Value),&dwRead,NULL);
ChangeTimer(ViTimer,Value);
ReadFile( hSaveFile,&PROGRAM_COUNTER,sizeof(PROGRAM_COUNTER),&dwRead,NULL);
ReadFile( hSaveFile,GPR,sizeof(_int64)*32,&dwRead,NULL);
ReadFile( hSaveFile,FPR,sizeof(_int64)*32,&dwRead,NULL);
ReadFile( hSaveFile,CP0,sizeof(DWORD)*32,&dwRead,NULL);
ReadFile( hSaveFile,FPCR,sizeof(DWORD)*32,&dwRead,NULL);
ReadFile( hSaveFile,&HI,sizeof(_int64),&dwRead,NULL);
ReadFile( hSaveFile,&LO,sizeof(_int64),&dwRead,NULL);
ReadFile( hSaveFile,RegRDRAM,sizeof(DWORD)*10,&dwRead,NULL);
ReadFile( hSaveFile,RegSP,sizeof(DWORD)*10,&dwRead,NULL);
ReadFile( hSaveFile,RegDPC,sizeof(DWORD)*10,&dwRead,NULL);
ReadFile( hSaveFile,RegMI,sizeof(DWORD)*4,&dwRead,NULL);
ReadFile( hSaveFile,RegVI,sizeof(DWORD)*14,&dwRead,NULL);
ReadFile( hSaveFile,RegAI,sizeof(DWORD)*6,&dwRead,NULL);
ReadFile( hSaveFile,RegPI,sizeof(DWORD)*13,&dwRead,NULL);
ReadFile( hSaveFile,RegRI,sizeof(DWORD)*8,&dwRead,NULL);
ReadFile( hSaveFile,RegSI,sizeof(DWORD)*4,&dwRead,NULL);
ReadFile( hSaveFile,tlb,sizeof(TLB)*32,&dwRead,NULL);
ReadFile( hSaveFile,PIF_Ram,0x40,&dwRead,NULL);
ReadFile( hSaveFile,RDRAM,RdramSize,&dwRead,NULL);
ReadFile( hSaveFile,DMEM,0x1000,&dwRead,NULL);
ReadFile( hSaveFile,IMEM,0x1000,&dwRead,NULL);
CloseHandle(hSaveFile);
_splitpath( FileName, drive, dir, ZipFile, ext );
sprintf(FileName,"%s%s",ZipFile,ext);
}
//memcpy(RomHeader,ROM,sizeof(RomHeader));
ChangeCompareTimer();
if (GfxRomClosed != NULL) { GfxRomClosed(); }
if (AiRomClosed != NULL) { AiRomClosed(); }
if (ContRomClosed != NULL) { ContRomClosed(); }
if (RSPRomClosed) { RSPRomClosed(); }
if (GfxRomOpen != NULL) { GfxRomOpen(); }
if (ContRomOpen != NULL) { ContRomOpen(); }
DlistCount = 0;
AlistCount = 0;
AI_STATUS_REG = 0;
EmuAI_ClearAudio();
AiDacrateChanged(SYSTEM_NTSC);
ViStatusChanged();
ViWidthChanged();
SetupTLB();
//Fix up Memory stack location
MemoryStack = GPR[29].W[0];
TranslateVaddr(&MemoryStack);
MemoryStack += (DWORD)N64MEM;
CheckInterrupts();
DMAUsed = TRUE;
strcpy(SaveAsFileName,"");
strcpy(LoadFileName,"");
if (CPU_Type == CPU_SyncCores) {
Registers.PROGRAM_COUNTER = PROGRAM_COUNTER;
Registers.HI.DW = HI.DW;
Registers.LO.DW = LO.DW;
Registers.DMAUsed = DMAUsed;
memcpy(&SyncRegisters,&Registers,sizeof(Registers));
memcpy(SyncFastTlb,FastTlb,sizeof(FastTlb));
memcpy(SyncTlb,tlb,sizeof(tlb));
memcpy(SyncMemory,N64MEM,RdramSize);
memcpy(SyncMemory + 0x04000000,N64MEM + 0x04000000,0x2000);
SwitchSyncRegisters();
SetupTLB();
SwitchSyncRegisters();
SyncNextInstruction = NORMAL;
SyncJumpToLocation = -1;
NextInstruction = NORMAL;
JumpToLocation = -1;
MemAddrUsedCount[0] = 0;
MemAddrUsedCount[1] = 0;
SyncToPC ();
DisplayError("Loaded");
}
#ifdef Log_x86Code
Stop_x86_Log();
Start_x86_Log();
#endif
if (HaveDebugger) {
StopLog();
StartLog();
}
sprintf(String,"%s %s",GS(MSG_LOADED_STATE),FileName);
SendMessage( hStatusWnd, SB_SETTEXT, 0, (LPARAM)String );
return TRUE;
}
BOOL Machine_SaveState(void) {
char Directory[255], FileName[255], ZipFile[255], String[100];
char drive[_MAX_DRIVE] ,dir[_MAX_DIR], ext[_MAX_EXT];
DWORD dwWritten, Value;
HANDLE hSaveFile;
//LogMessage("SaveState");
if (Timers.CurrentTimerType != CompareTimer && Timers.CurrentTimerType != ViTimer) {
return FALSE;
}
if (strlen(SaveAsFileName) == 0) {
Settings_GetDirectory(InstantSaveDir, Directory, sizeof(Directory));
sprintf(FileName,"%s%s",Directory,CurrentSave);
sprintf(ZipFile,"%s.zip",FileName);
} else {
sprintf(FileName,"%s.pj",SaveAsFileName);
sprintf(ZipFile,"%s.zip",SaveAsFileName);
}
if (SelfModCheck == ModCode_ChangeMemory) { ResetRecompCode(); }
if (AutoZip) {
zip_fileinfo ZipInfo;
zipFile file;
CreateDirectory(Directory,NULL);
file = zipOpen(ZipFile,FALSE);
zipOpenNewFileInZip(file,CurrentSave,&ZipInfo,NULL,0,NULL,0,NULL,Z_DEFLATED,Z_DEFAULT_COMPRESSION);
Value = 0x23D8A6C8;
zipWriteInFileInZip( file,&Value,sizeof(Value));
zipWriteInFileInZip( file,&RdramSize,sizeof(RdramSize));
zipWriteInFileInZip( file,RomHeader,0x40);
Value = Timers.NextTimer[ViTimer] + Timers.Timer;
zipWriteInFileInZip( file,&Value,sizeof(Value));
zipWriteInFileInZip( file,&PROGRAM_COUNTER,sizeof(PROGRAM_COUNTER));
zipWriteInFileInZip( file,GPR,sizeof(_int64)*32);
zipWriteInFileInZip( file,FPR,sizeof(_int64)*32);
zipWriteInFileInZip( file,CP0,sizeof(DWORD)*32);
zipWriteInFileInZip( file,FPCR,sizeof(DWORD)*32);
zipWriteInFileInZip( file,&HI,sizeof(_int64));
zipWriteInFileInZip( file,&LO,sizeof(_int64));
zipWriteInFileInZip( file,RegRDRAM,sizeof(DWORD)*10);
zipWriteInFileInZip( file,RegSP,sizeof(DWORD)*10);
zipWriteInFileInZip( file,RegDPC,sizeof(DWORD)*10);
Value = MI_INTR_REG;
if (AiReadLength() != 0) { MI_INTR_REG |= MI_INTR_AI; }
zipWriteInFileInZip( file,RegMI,sizeof(DWORD)*4);
MI_INTR_REG = Value;
zipWriteInFileInZip( file,RegVI,sizeof(DWORD)*14);
zipWriteInFileInZip( file,RegAI,sizeof(DWORD)*6);
zipWriteInFileInZip( file,RegPI,sizeof(DWORD)*13);
zipWriteInFileInZip( file,RegRI,sizeof(DWORD)*8);
zipWriteInFileInZip( file,RegSI,sizeof(DWORD)*4);
zipWriteInFileInZip( file,tlb,sizeof(TLB)*32);
zipWriteInFileInZip( file,PIF_Ram,0x40);
zipWriteInFileInZip( file,RDRAM,RdramSize);
zipWriteInFileInZip( file,DMEM,0x1000);
zipWriteInFileInZip( file,IMEM,0x1000);
zipCloseFileInZip(file);
zipClose(file,"");
DeleteFile(FileName);
_splitpath( ZipFile, drive, dir, FileName, ext );
sprintf(FileName,"%s%s",FileName,ext);
} else {
hSaveFile = CreateFile(FileName,GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ,NULL,OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL);
if (hSaveFile == INVALID_HANDLE_VALUE) {
switch (GetLastError()) {
case ERROR_PATH_NOT_FOUND:
CreateDirectory(Directory,NULL);
hSaveFile = CreateFile(FileName,GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ,
NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL);
if (hSaveFile == INVALID_HANDLE_VALUE) {
DisplayError(GS(MSG_FAIL_OPEN_SAVE));
return TRUE;
}
break;
default:
DisplayError(GS(MSG_FAIL_OPEN_SAVE));
return TRUE;
}
}
while ((int)Registers.CP0[1] < (int)Registers.CP0[6]) {
Registers.CP0[1] += 32 - Registers.CP0[6];
}
//if fake cause set then do not save ????
SetFilePointer(hSaveFile,0,NULL,FILE_BEGIN);
Value = 0x23D8A6C8;
WriteFile( hSaveFile,&Value,sizeof(Value),&dwWritten,NULL);
WriteFile( hSaveFile,&RdramSize,sizeof(RdramSize),&dwWritten,NULL);
WriteFile( hSaveFile,RomHeader,0x40,&dwWritten,NULL);
Value = Timers.NextTimer[ViTimer] + Timers.Timer;
WriteFile( hSaveFile,&Value,sizeof(Value),&dwWritten,NULL);
WriteFile( hSaveFile,&PROGRAM_COUNTER,sizeof(PROGRAM_COUNTER),&dwWritten,NULL);
WriteFile( hSaveFile,GPR,sizeof(_int64)*32,&dwWritten,NULL);
WriteFile( hSaveFile,FPR,sizeof(_int64)*32,&dwWritten,NULL);
WriteFile( hSaveFile,CP0,sizeof(DWORD)*32,&dwWritten,NULL);
WriteFile( hSaveFile,FPCR,sizeof(DWORD)*32,&dwWritten,NULL);
WriteFile( hSaveFile,&HI,sizeof(_int64),&dwWritten,NULL);
WriteFile( hSaveFile,&LO,sizeof(_int64),&dwWritten,NULL);
WriteFile( hSaveFile,RegRDRAM,sizeof(DWORD)*10,&dwWritten,NULL);
WriteFile( hSaveFile,RegSP,sizeof(DWORD)*10,&dwWritten,NULL);
WriteFile( hSaveFile,RegDPC,sizeof(DWORD)*10,&dwWritten,NULL);
Value = MI_INTR_REG;
if (AiReadLength() != 0) { MI_INTR_REG |= MI_INTR_AI; }
WriteFile( hSaveFile,RegMI,sizeof(DWORD)*4,&dwWritten,NULL);
MI_INTR_REG = Value;
WriteFile( hSaveFile,RegVI,sizeof(DWORD)*14,&dwWritten,NULL);
WriteFile( hSaveFile,RegAI,sizeof(DWORD)*6,&dwWritten,NULL);
WriteFile( hSaveFile,RegPI,sizeof(DWORD)*13,&dwWritten,NULL);
WriteFile( hSaveFile,RegRI,sizeof(DWORD)*8,&dwWritten,NULL);
WriteFile( hSaveFile,RegSI,sizeof(DWORD)*4,&dwWritten,NULL);
WriteFile( hSaveFile,tlb,sizeof(TLB)*32,&dwWritten,NULL);
WriteFile( hSaveFile,PIF_Ram,0x40,&dwWritten,NULL);
WriteFile( hSaveFile,RDRAM,RdramSize,&dwWritten,NULL);
WriteFile( hSaveFile,DMEM,0x1000,&dwWritten,NULL);
WriteFile( hSaveFile,IMEM,0x1000,&dwWritten,NULL);
CloseHandle(hSaveFile);
DeleteFile(ZipFile);
_splitpath( FileName, drive, dir, ZipFile, ext );
sprintf(FileName,"%s%s",ZipFile,ext);
}
strcpy(SaveAsFileName,"");
strcpy(LoadFileName,"");
sprintf(String,"%s %s",GS(MSG_SAVED_STATE),FileName);
SendMessage( hStatusWnd, SB_SETTEXT, 0, (LPARAM)String );
return TRUE;
}
void PauseCpu (void) {
DWORD Result;
if (!CPURunning) { return; }
do {
Result = MsgWaitForMultipleObjects(1,&hPauseMutex,FALSE,INFINITE,QS_ALLINPUT);
if (Result != WAIT_OBJECT_0) {
MSG msg;
while (PeekMessage(&msg,NULL,0,0,PM_REMOVE) != 0) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
} while (Result != WAIT_OBJECT_0);
if (CPU_Paused || CPU_Action.Pause) {
HMENU hMenu = GetMenu(hMainWindow);
HMENU hSubMenu = GetSubMenu(hMenu,1);
if (CPU_Action.Pause) {
CPU_Action.Pause = FALSE;
CPU_Paused = FALSE;
ManualPaused = FALSE;
SendMessage( hStatusWnd, SB_SETTEXT, 0, (LPARAM)GS(MSG_CPU_RESUMED) );
ReleaseMutex(hPauseMutex);
return;
}
ResumeThread(hCPU);
SendMessage( hStatusWnd, SB_SETTEXT, 0, (LPARAM)GS(MSG_CPU_RESUMED));
MenuSetText(hSubMenu, 1, GS(MENU_PAUSE),"F2");
ManualPaused = FALSE;
CPU_Paused = FALSE;
} else {
CPU_Action.Pause = TRUE;
CPU_Action.DoSomething = TRUE;
}
ReleaseMutex(hPauseMutex);
}
void RefreshScreen (void ){
static DWORD VI_INTR_TIME = 500000;
static DWORD DlistWaitFor = -2, VIWaitMult = 0;
LARGE_INTEGER Time;
char Label[100];
// A hack to allow the iQue games to boot faster, seems the VI call may be incomplete?
// This allows them to wait for longer and for now this will use the DlistCount
if (DlistWaitFor == -2) {
char Identifier[100];
RomID(Identifier, RomHeader);
DlistWaitFor = Settings_ReadInt(RDS_NAME, Identifier, "DlistWait", -1);
VIWaitMult = Settings_ReadInt(RDS_NAME, Identifier, "WaitMult", -1);
if (DlistWaitFor <= 0)
DlistWaitFor = -1;
}
if (Profiling || ShowCPUPer) { memcpy(Label,ProfilingLabel,sizeof(Label)); }
if (Profiling) { StartTimer("RefreshScreen"); }
if (VI_V_SYNC_REG == 0) {
VI_INTR_TIME = 500000;
}
else {
VI_INTR_TIME = (VI_V_SYNC_REG + 1) * ModVI;
if (DlistWaitFor != -1 && DlistCount <= DlistWaitFor) // The hack that allows a much longer wait time than normal
VI_INTR_TIME *= VIWaitMult;
if ((VI_V_SYNC_REG % 1) != 0) {
VI_INTR_TIME -= 38;
}
}
ChangeTimer(ViTimer,Timers.Timer + Timers.NextTimer[ViTimer] + VI_INTR_TIME);
EmuAI_SetVICountPerFrame(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 Idle"); }
if (LimitFPS) { 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].QuadPart = Time.QuadPart - LastFrame.QuadPart;
LastFrame.QuadPart = 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(); Apply_CheatSearchDev(); }
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 0: {
// TWINTRIS Support, the RSP Task is 0 yet it is meant to be a 1 (Graphics call)
unsigned int ucode = *( DWORD *)(DMEM + 0xFFC);
unsigned int size = *( DWORD *)(DMEM + 0x100B) & 0xF80;
unsigned int i, sum;
for (i = 0, sum = 0; i < (size / 2); i++)
sum += *(BYTE *)(RDRAM + ucode + i);
if (sum == 0x7efd)
*( DWORD *)(DMEM + 0xFC0) = 1;
}
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) {
char StatusString[256];
sprintf(StatusString,"Dlist: %d Alist: %d",DlistCount,AlistCount);
SendMessage( hStatusWnd, SB_SETTEXT, 0, (LPARAM)StatusString );
}
if (Profiling || ShowCPUPer) {
char Label[100];
strncpy(Label,ProfilingLabel,sizeof(Label));
if (IndividualBlock && !ShowCPUPer) {
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 SetCoreToRunning ( void ) {
CPU_Action.Stepping = FALSE;
PulseEvent( CPU_Action.hStepping );
}
void SetCoreToStepping ( void ) {
CPU_Action.Stepping = TRUE;
}
void StartEmulation ( void ) {
DWORD ThreadID, count;
CloseCpu();
memset(&CPU_Action,0,sizeof(CPU_Action));
//memcpy(RomHeader,ROM,sizeof(RomHeader));
CPU_Action.hStepping = CreateEvent( NULL, FALSE, FALSE, NULL);
WrittenToRom = FALSE;
// Previous versions of PJ64 did not clear memory upon start of emulation
// This resulted in junk being left in memory and potentially affecting future games being loaded or checked
if (Settings_ReadBool(APPS_NAME, STR_SETTINGS, STR_CLEAR_MEMORY, TRUE))
memset(N64MEM, 0, RdramSize);
InitilizeTLB();
InitalizeR4300iRegisters(LoadPifRom(*(ROM + 0x3D)),*(ROM + 0x3D),GetCicChipID(ROM));
BuildInterpreter();
RecompPos = RecompCode;
if (HaveDebugger)
Enable_R4300i_Commands_Window();
if (InR4300iCommandsWindow) {
SetCoreToStepping();
}
DlistCount = 0;
AlistCount = 0;
Timers.CurrentTimerType = -1;
Timers.Timer = 0;
CurrentFrame = 0;
CurrentPercent = 0;
for (count = 0; count < MaxTimers; count ++) { Timers.Active[count] = FALSE; }
ChangeTimer(ViTimer,5000);
ChangeCompareTimer();
ViFieldNumber = 0;
DMAUsed = FALSE;
CPU_Paused = FALSE;
ManualPaused = FALSE;
Timer_Start();
LoadRomOptions();
LoadCheats();
if (Profiling) { ResetTimerList(); }
strcpy(ProfilingLabel,"");
strcpy(LoadFileName,"");
strcpy(SaveAsFileName,"");
CPURunning = TRUE;
SetupMenu(hMainWindow);
// TEST CASE!!!
// TO DO! (Commenting out to see if this resolves Ice's plugin related crashes)
//if (!inFullScreen) // Only reset plugins if not in fullscreen
SetupPlugins(hMainWindow);
//else
// ResetAudio(hMainWindow);
switch (CPU_Type) {
case CPU_Interpreter: hCPU = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)StartInterpreterCPU,NULL,0, &ThreadID); break;
case CPU_Recompiler: hCPU = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)StartRecompilerCPU,NULL,0, &ThreadID); break;
case CPU_SyncCores: hCPU = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)StartSyncCPU,NULL,0, &ThreadID); break;
default:
DisplayError("Unhandled CPU %d",CPU_Type);
}
SendMessage( hStatusWnd, SB_SETTEXT, 0, (LPARAM)GS(MSG_EMULATION_STARTED) );
AlwaysOnTopWindow(hMainWindow);
}
void StepOpcode ( void ) {
PulseEvent( CPU_Action.hStepping );
}
void TimerDone (void) {
char Label[100];
if (Profiling) {
strncpy(Label, ProfilingLabel, sizeof(Label));
StartTimer("TimerDone");
}
switch (Timers.CurrentTimerType) {
case CompareTimer:
FAKE_CAUSE_REGISTER |= CAUSE_IP7;
CheckInterrupts();
ChangeCompareTimer();
break;
case SiTimer:
ChangeTimer(SiTimer,0);
MI_INTR_REG |= MI_INTR_SI;
SI_STATUS_REG |= SI_STATUS_INTERRUPT;
CheckInterrupts();
break;
case PiTimer:
ChangeTimer(PiTimer,0);
PI_STATUS_REG &= ~PI_STATUS_DMA_BUSY;
MI_INTR_REG |= MI_INTR_PI;
CheckInterrupts();
break;
case ViTimer:
RefreshScreen();
MI_INTR_REG |= MI_INTR_VI;
CheckInterrupts();
break;
case RspTimer:
ChangeTimer(RspTimer,0);
RunRsp();
CheckInterrupts(); // Test to see if this helps netplay out any.
// Jabo believes if it does help netplay then there could be a possible issue inside the rsp.
break;
case AiTimer:
EmuAI_SetNextTimer();
AudioIntrReg |= MI_INTR_AI;
AiCheckInterrupts();
break;
}
CheckTimer();
if (Profiling) {
StartTimer(Label);
}
}