Cog/Frameworks/HighlyExperimental/HighlyExperimental/Core/r3000predict.txt
2013-09-30 03:36:30 -07:00

2004 lines
55 KiB
Text

// PSFWorkArea.cpp : implementation file
//
#include "stdafx.h"
#include "PSFLab.h"
#include "PSFWorkArea.h"
#include "../Emu/emu.h"
#include "CodeView.h"
#include "MemoryView.h"
#include "EventView.h"
#include "ImportBinaryDlg.h"
#include "BreakpointsDlg.h"
#include "ExeSettingsDlg.h"
#include "RunToSpecificLineDlg.h"
#include "StateSlotDlg.h"
#include "TagDlg.h"
#include "OptimizeDlg.h"
#include "WaveOutput.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define R3000CLASS(x) (R3000_REG_##x)
static const int anRegisterHWID[PSFWORKAREA_REG_N] = {
R3000CLASS(GEN)+ 0, R3000CLASS(GEN)+ 1, R3000CLASS(GEN)+ 2, R3000CLASS(GEN)+ 3,
R3000CLASS(GEN)+ 4, R3000CLASS(GEN)+ 5, R3000CLASS(GEN)+ 6, R3000CLASS(GEN)+ 7,
R3000CLASS(GEN)+ 8, R3000CLASS(GEN)+ 9, R3000CLASS(GEN)+10, R3000CLASS(GEN)+11,
R3000CLASS(GEN)+12, R3000CLASS(GEN)+13, R3000CLASS(GEN)+14, R3000CLASS(GEN)+15,
R3000CLASS(GEN)+16, R3000CLASS(GEN)+17, R3000CLASS(GEN)+18, R3000CLASS(GEN)+19,
R3000CLASS(GEN)+20, R3000CLASS(GEN)+21, R3000CLASS(GEN)+22, R3000CLASS(GEN)+23,
R3000CLASS(GEN)+24, R3000CLASS(GEN)+25, R3000CLASS(GEN)+26, R3000CLASS(GEN)+27,
R3000CLASS(GEN)+28, R3000CLASS(GEN)+29, R3000CLASS(GEN)+30, R3000CLASS(GEN)+31,
R3000CLASS(C0) + 0, R3000CLASS(C0) + 1, R3000CLASS(C0) + 2, R3000CLASS(C0) + 3,
R3000CLASS(C0) + 4, R3000CLASS(C0) + 5, R3000CLASS(C0) + 6, R3000CLASS(C0) + 7,
R3000CLASS(C0) + 8, R3000CLASS(C0) + 9, R3000CLASS(C0) +10, R3000CLASS(C0) +11,
R3000CLASS(C0) +12, R3000CLASS(C0) +13, R3000CLASS(C0) +14, R3000CLASS(C0) +15,
R3000CLASS(C0) +16, R3000CLASS(C0) +17, R3000CLASS(C0) +18, R3000CLASS(C0) +19,
R3000CLASS(C0) +20, R3000CLASS(C0) +21, R3000CLASS(C0) +22, R3000CLASS(C0) +23,
R3000CLASS(C0) +24, R3000CLASS(C0) +25, R3000CLASS(C0) +26, R3000CLASS(C0) +27,
R3000CLASS(C0) +28, R3000CLASS(C0) +29, R3000CLASS(C0) +30, R3000CLASS(C0) +31,
R3000CLASS(PC),
R3000CLASS(HI),
R3000CLASS(LO),
R3000CLASS(CI)
};
extern "C" void CPSFWorkArea__console_out(
void *context,
char c
) {
((CPSFWorkArea*)context)->console.AddChar(c);
// char asdf[2];
// asdf[0] = c;
// asdf[1] = 0;
// OutputDebugString(asdf);
}
extern "C" sint32 CPSFWorkArea__readfile_cb(
void *context,
const char *path,
sint32 offset,
char *buffer,
sint32 length
) {
int r;
char fool[1000];
//return -1;
//sprintf(fool,"[readfile: %s(%d) %d]",path,offset,length);OutputDebugString(fool);
if(length < 0) return -1;
if(offset < 0) return -1;
strncpy(fool,
(LPCTSTR)( ((CPSFLabApp*)(AfxGetApp()))->m_strPSF2Path ),
//"C:/Corlett",
//((CPSFWorkArea*)context)->m_sPSF2Path,
sizeof(fool)
);
fool[sizeof(fool)-1] = 0;
int l =strlen(fool);
while(l>0) {
char c=fool[l-1];
if(c=='/'||c=='\\'||c==':'){
fool[--l]=0;
continue;
}
break;
}
l = sizeof(fool)-strlen(fool);
strncpy(fool+strlen(fool),path,l);
fool[sizeof(fool)-1] = 0;
FILE *f = fopen(fool, "rb");
if(!f) return -1;
if(!length) { int l; fseek(f,0,SEEK_END);l=ftell(f);fclose(f); return l; }
fseek(f,offset,SEEK_SET);
r = fread(buffer, 1, length, f);
fclose(f);
//sprintf(fool,"(returned %d)",r);OutputDebugString(fool);OutputDebugString("\n");
return r;
}
/////////////////////////////////////////////////////////////////////////////
// CPSFWorkArea
IMPLEMENT_DYNCREATE(CPSFWorkArea, CDocument)
CPSFWorkArea::CPSFWorkArea()
{
/*
** Initialize state pointers
*/
m_pStateDebug = NULL;
m_pStatePlay = NULL;
m_nVersion = 1;
/*
** Initialize thread information
*/
m_pDebugThread = NULL;
m_pPlayThread = NULL;
m_bRunning = FALSE;
m_bPlaying = FALSE;
/*
** Initialize saved state system
*/
memset(m_apSavedStates, 0, sizeof(m_apSavedStates));
m_nCurrentStateSlot = 0;
/*
** Allocate debug state - this is always here
*/
m_pStateDebug = malloc(emu_get_state_size(m_nVersion));
ASSERT(m_pStateDebug);
/*
** Initialize the state just to ensure no problems
*/
emu_clear_state(m_pStateDebug, m_nVersion);
emu_set_readfile(m_pStateDebug, CPSFWorkArea__readfile_cb, this);
emu_set_console_out(m_pStateDebug, CPSFWorkArea__console_out, this);
// strcpy(m_sPSF2Path,
// (((CPSFLabApp*)(AfxGetApp()))->m_sPSF2Path)
// );
}
BOOL CPSFWorkArea::OnNewDocument()
{
TRACE("CPSFWorkArea::OnNewDocument()\n");
if(IsModified()) {
TRACE("Creating a new document over an existing modified one\n");
// MessageBox(NULL,"trying to do a file new on a modified thingy\n",NULL,MB_OK);
// return FALSE;
}
DeleteContents();
int nDesiredVersion = ((CPSFLabApp*)(::AfxGetApp()))->m_nNewPSFVersion;
if(m_nVersion != nDesiredVersion) {
m_nVersion = nDesiredVersion;
if(m_pStateDebug) {
free(m_pStateDebug);
m_pStateDebug = NULL;
}
m_pStateDebug = malloc(emu_get_state_size(m_nVersion));
emu_clear_state(m_pStateDebug, m_nVersion);
emu_set_readfile(m_pStateDebug, CPSFWorkArea__readfile_cb, this);
emu_set_console_out(m_pStateDebug, CPSFWorkArea__console_out, this);
// strcpy(m_sPSF2Path,
// (((CPSFLabApp*)(AfxGetApp()))->m_sPSF2Path)
// );
DeleteContents();
}
m_strPathName.Empty();
SetModifiedFlag(FALSE);
/*
** Restart debugger
*/
DebugRestart();
RegisterMonitor();
UpdateAllViews(NULL);
return TRUE;
}
CPSFWorkArea::~CPSFWorkArea()
{
KillDebugThreadAndBlock();
KillPlayThreadAndBlock();
ClearAllSavedStates();
if(m_pStateDebug) free(m_pStateDebug);
if(m_pStatePlay) free(m_pStatePlay);
}
BEGIN_MESSAGE_MAP(CPSFWorkArea, CDocument)
//{{AFX_MSG_MAP(CPSFWorkArea)
ON_UPDATE_COMMAND_UI(ID_DEBUG_GO, OnUpdateDebugGo)
ON_COMMAND(ID_DEBUG_GO, OnDebugGo)
ON_UPDATE_COMMAND_UI(ID_DEBUG_BREAK, OnUpdateDebugBreak)
ON_UPDATE_COMMAND_UI(ID_DEBUG_PLAY, OnUpdateDebugPlay)
ON_UPDATE_COMMAND_UI(ID_DEBUG_STOP, OnUpdateDebugStop)
ON_UPDATE_COMMAND_UI(ID_DEBUG_PAUSE, OnUpdateDebugPause)
ON_UPDATE_COMMAND_UI(ID_DEBUG_STEPINTO, OnUpdateDebugStepinto)
ON_UPDATE_COMMAND_UI(ID_DEBUG_STEPOUT, OnUpdateDebugStepout)
ON_UPDATE_COMMAND_UI(ID_DEBUG_STEPOVER, OnUpdateDebugStepover)
ON_COMMAND(ID_DEBUG_PLAY, OnDebugPlay)
ON_COMMAND(ID_DEBUG_PAUSE, OnDebugPause)
ON_COMMAND(ID_DEBUG_STOP, OnDebugStop)
ON_COMMAND(ID_DEBUG_BREAK, OnDebugBreak)
ON_UPDATE_COMMAND_UI(ID_DEBUG_RESTART, OnUpdateDebugRestart)
ON_COMMAND(ID_DEBUG_RESTART, OnDebugRestart)
ON_COMMAND(ID_DEBUG_STEPINTO, OnDebugStepinto)
ON_COMMAND(ID_DEBUG_STEPOUT, OnDebugStepout)
ON_COMMAND(ID_DEBUG_STEPOVER, OnDebugStepover)
ON_UPDATE_COMMAND_UI(ID_DEBUG_LOADSTATE, OnUpdateDebugLoadstate)
ON_COMMAND(ID_DEBUG_LOADSTATE, OnDebugLoadstate)
ON_UPDATE_COMMAND_UI(ID_DEBUG_SAVESTATE, OnUpdateDebugSavestate)
ON_COMMAND(ID_DEBUG_SAVESTATE, OnDebugSavestate)
ON_COMMAND(ID_FILE_IMPORTBINARY, OnFileImportbinary)
ON_UPDATE_COMMAND_UI(ID_FILE_IMPORTBINARY, OnUpdateFileImportbinary)
ON_UPDATE_COMMAND_UI(ID_DEBUG_RUNTOINT, OnUpdateDebugRuntoint)
ON_UPDATE_COMMAND_UI(ID_EDIT_BREAKPOINTS, OnUpdateEditBreakpoints)
ON_COMMAND(ID_EDIT_BREAKPOINTS, OnEditBreakpoints)
ON_UPDATE_COMMAND_UI(ID_EDIT_EXESETTINGS, OnUpdateEditExesettings)
ON_COMMAND(ID_EDIT_EXESETTINGS, OnEditExesettings)
ON_COMMAND(ID_DEBUG_EXECUTIONSTOPPED, OnDebugExecutionstopped)
ON_UPDATE_COMMAND_UI(ID_DEBUG_SPECIFICLINE, OnUpdateDebugSpecificline)
ON_COMMAND(ID_DEBUG_SPECIFICLINE, OnDebugSpecificline)
ON_COMMAND(ID_DEBUG_RUNTOINT, OnDebugRuntoint)
ON_COMMAND(ID_DEBUG_SELECTSLOT, OnDebugSelectslot)
ON_COMMAND(ID_EDIT_TAG, OnEditTag)
ON_COMMAND(ID_FILE_SAVEAS, OnFileSaveas)
ON_COMMAND(ID_FILE_IMPORTEXE, OnFileImportexe)
ON_UPDATE_COMMAND_UI(ID_FILE_IMPORTEXE, OnUpdateFileImportexe)
ON_COMMAND(ID_FILE_EXPORTEXE, OnFileExportexe)
ON_COMMAND(ID_FILE_FONDUE, OnFileFondue)
ON_UPDATE_COMMAND_UI(ID_EDIT_OPTIMIZE, OnUpdateEditOptimize)
ON_COMMAND(ID_EDIT_OPTIMIZE, OnEditOptimize)
ON_COMMAND(ID_FILE_EXPORTBIOSAREA, OnFileExportbiosarea)
ON_UPDATE_COMMAND_UI(ID_FILE_SAVE, OnUpdateFileSave)
ON_UPDATE_COMMAND_UI(ID_FILE_SAVEAS, OnUpdateFileSaveas)
ON_UPDATE_COMMAND_UI(ID_EDIT_TAG, OnUpdateEditTag)
ON_UPDATE_COMMAND_UI(ID_FILE_EXPORTEXE, OnUpdateFileExportexe)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CPSFWorkArea diagnostics
#ifdef _DEBUG
void CPSFWorkArea::AssertValid() const
{
CDocument::AssertValid();
}
void CPSFWorkArea::Dump(CDumpContext& dc) const
{
CDocument::Dump(dc);
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CPSFWorkArea serialization
void CPSFWorkArea::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
// TODO: add storing code here
}
else
{
// TODO: add loading code here
}
}
/////////////////////////////////////////////////////////////////////////////
// CPSFWorkArea commands
DWORD CPSFWorkArea::PeekWord(DWORD dwAddress) const
{
ASSERT(m_pStateDebug);
return iop_getword(emu_get_iop_state(m_pStateDebug), dwAddress);
}
BOOL CPSFWorkArea::IsWordPatched(DWORD dwAddress) const
{
int nEXEIndex = AddressToEXEIndex(dwAddress);
if(nEXEIndex < 0) return FALSE;
return ((m_adwPatchMap[nEXEIndex / 32] >> (nEXEIndex & 31)) & 1);
}
DWORD CPSFWorkArea::GetPatchWord(DWORD dwAddress) const
{
int nEXEIndex = AddressToEXEIndex(dwAddress);
if(nEXEIndex < 0) return 0;
return m_adwPatchData[nEXEIndex];
}
void CPSFWorkArea::SetPatchWord(DWORD dwAddress, DWORD dwValue)
{
if(m_nVersion == 1) SetModifiedFlag();
/*
** Copy the change to the current debug state too
*/
if(m_pStateDebug) {
iop_setword(emu_get_iop_state(m_pStateDebug), dwAddress, dwValue);
}
if(m_nVersion == 1) {
int nEXEIndex = AddressToEXEIndex(dwAddress);
if(nEXEIndex >= 0) {
m_adwPatchMap[nEXEIndex / 32] |= (1 << (nEXEIndex & 31));
m_adwPatchData[nEXEIndex] = dwValue;
}
}
}
int CPSFWorkArea::AddressToEXEIndex(DWORD dwAddress) const
{
dwAddress &= 0x1FFFFFFC;
if(dwAddress >= 0x1F000000) return -1;
dwAddress &= 0x1FFFFC;
if(dwAddress < 0x10000) return -1;
return (dwAddress - 0x10000) / 4;
}
DWORD CPSFWorkArea::GetPC() const
{
ASSERT(m_pStateDebug);
return r3000_getreg(iop_get_r3000_state(emu_get_iop_state(m_pStateDebug)), R3000CLASS(PC));
}
void CPSFWorkArea::DeletePatchWord(DWORD dwAddress)
{
int nWordIndex = AddressToEXEIndex(dwAddress);
if(nWordIndex < 0) return;
// If it wasn't patched to begin with, don't do anything
if(!(m_adwPatchMap[nWordIndex / 32] & (1 << (nWordIndex & 31)))) return;
m_adwPatchMap[nWordIndex / 32] &= ~(1 << (nWordIndex & 31));
/*
** Copy the change to the current debug state too
*/
ASSERT(m_pStateDebug);
iop_setword(emu_get_iop_state(m_pStateDebug), dwAddress, m_adwEXEData[nWordIndex]);
SetModifiedFlag();
}
int CPSFWorkArea::AddressToBreakpointIndex(DWORD dwAddress) const
{
dwAddress &= 0x1FFFFFFC;
if(dwAddress < 0x1F000000) return ((dwAddress & 0x1FFFFC) / 4);
if(dwAddress >= 0x1FC00000) return ((dwAddress & 0x7FFFC) / 4) + 0x80000;
return -1;
}
BOOL CPSFWorkArea::IsBreakpointOnExecute(DWORD dwAddress) const
{
int nWordIndex = AddressToBreakpointIndex(dwAddress);
if(nWordIndex < 0) return FALSE;
return (m_adwBreakpointMapExecute[nWordIndex / 32] >> (nWordIndex & 31)) & 1;
}
void CPSFWorkArea::SetBreakpointOnExecute(DWORD dwAddress, BOOL bBreak)
{
int nWordIndex = AddressToBreakpointIndex(dwAddress);
if(nWordIndex < 0) return;
if(bBreak) {
m_adwBreakpointMapExecute[nWordIndex / 32] |= (1 << (nWordIndex & 31));
} else {
m_adwBreakpointMapExecute[nWordIndex / 32] &= ~(1 << (nWordIndex & 31));
}
}
BOOL CPSFWorkArea::IsBreakpointOnRead(DWORD dwAddress) const
{
int nWordIndex = AddressToBreakpointIndex(dwAddress);
if(nWordIndex < 0) return FALSE;
return (m_adwBreakpointMapRead[nWordIndex / 32] >> (nWordIndex & 31)) & 1;
}
void CPSFWorkArea::SetBreakpointOnRead(DWORD dwAddress, BOOL bBreak)
{
int nWordIndex = AddressToBreakpointIndex(dwAddress);
if(nWordIndex < 0) return;
if(bBreak) {
m_adwBreakpointMapRead[nWordIndex / 32] |= (1 << (nWordIndex & 31));
} else {
m_adwBreakpointMapRead[nWordIndex / 32] &= ~(1 << (nWordIndex & 31));
}
}
BOOL CPSFWorkArea::IsBreakpointOnWrite(DWORD dwAddress) const
{
int nWordIndex = AddressToBreakpointIndex(dwAddress);
if(nWordIndex < 0) return FALSE;
return (m_adwBreakpointMapWrite[nWordIndex / 32] >> (nWordIndex & 31)) & 1;
}
void CPSFWorkArea::SetBreakpointOnWrite(DWORD dwAddress, BOOL bBreak)
{
int nWordIndex = AddressToBreakpointIndex(dwAddress);
if(nWordIndex < 0) return;
if(bBreak) {
m_adwBreakpointMapWrite[nWordIndex / 32] |= (1 << (nWordIndex & 31));
} else {
m_adwBreakpointMapWrite[nWordIndex / 32] &= ~(1 << (nWordIndex & 31));
}
}
CEventLog* CPSFWorkArea::GetEventLog()
{
return &m_eventlog;
}
void CPSFWorkArea::OnUpdateDebugGo (CCmdUI* pCmdUI) { pCmdUI->Enable(!IsRunning()); }
void CPSFWorkArea::OnUpdateDebugRestart(CCmdUI* pCmdUI) { pCmdUI->Enable(!IsRunning()); }
void CPSFWorkArea::OnUpdateDebugBreak (CCmdUI* pCmdUI) { pCmdUI->Enable( IsRunning()); }
void CPSFWorkArea::OnUpdateDebugStepinto (CCmdUI* pCmdUI) { pCmdUI->Enable(!IsRunning()); }
void CPSFWorkArea::OnUpdateDebugStepout (CCmdUI* pCmdUI) { pCmdUI->Enable(!IsRunning()); }
void CPSFWorkArea::OnUpdateDebugStepover (CCmdUI* pCmdUI) { pCmdUI->Enable(!IsRunning()); }
void CPSFWorkArea::OnUpdateDebugPlay (CCmdUI* pCmdUI) { pCmdUI->Enable(!IsPlaying()); }
void CPSFWorkArea::OnUpdateDebugPause(CCmdUI* pCmdUI) { pCmdUI->Enable( IsPlaying()); }
void CPSFWorkArea::OnUpdateDebugStop (CCmdUI* pCmdUI) { pCmdUI->Enable( IsPlaying()); }
void CPSFWorkArea::OnDebugGo()
{
KillDebugThreadAndBlock();
m_nDebugCommand = ID_DEBUG_GO;
StartDebugThreadAndBlock();
UpdateAllViews(NULL);
}
void CPSFWorkArea::OnDebugPlay() {
PlayStart();
}
void CPSFWorkArea::OnDebugPause() {
if(IsPlayPaused()) {
PlayUnpause();
} else {
PlayPause();
}
}
void CPSFWorkArea::OnDebugStop()
{
PlayStop();
}
void CPSFWorkArea::OnDebugBreak()
{
KillDebugThreadAndBlock();
OnDebugExecutionstopped();
//FILE*f=fopen("statedump","wb");
//if(f){
//fwrite(m_pStateDebug,1,emu_get_state_size(2),f);
//fclose(f);
//}
}
void CPSFWorkArea::OnDebugRestart()
{
KillDebugThreadAndBlock();
DebugRestart();
UpdateAllViews(NULL);
}
void CPSFWorkArea::OnDebugStepinto()
{
KillDebugThreadAndBlock();
m_nDebugCommand = ID_DEBUG_STEPINTO;
StartDebugThreadAndBlock();
UpdateAllViews(NULL);
}
void CPSFWorkArea::OnDebugStepout()
{
KillDebugThreadAndBlock();
m_nDebugCommand = ID_DEBUG_STEPOUT;
StartDebugThreadAndBlock();
UpdateAllViews(NULL);
}
void CPSFWorkArea::OnDebugStepover()
{
KillDebugThreadAndBlock();
m_nDebugCommand = ID_DEBUG_STEPOVER;
StartDebugThreadAndBlock();
UpdateAllViews(NULL);
}
void CPSFWorkArea::OnUpdateDebugLoadstate(CCmdUI* pCmdUI)
{
ASSERT(m_nCurrentStateSlot >= 0 && m_nCurrentStateSlot <= 9);
if(IsRunning()) { pCmdUI->Enable(FALSE); return; }
if(m_apSavedStates[m_nCurrentStateSlot]) {
pCmdUI->Enable(TRUE);
} else {
pCmdUI->Enable(FALSE);
}
}
void CPSFWorkArea::OnDebugLoadstate()
{
KillDebugThreadAndBlock();
ASSERT(m_nCurrentStateSlot >= 0 && m_nCurrentStateSlot <= 9);
LoadDebugState(m_nCurrentStateSlot);
CodeJumpTo(r3000_getreg(iop_get_r3000_state(emu_get_iop_state(m_pStateDebug)), R3000CLASS(PC)));
UpdateAllViews(FALSE);
}
void CPSFWorkArea::OnUpdateDebugSavestate(CCmdUI* pCmdUI) { pCmdUI->Enable(!IsRunning()); }
void CPSFWorkArea::OnDebugSavestate()
{
KillDebugThreadAndBlock();
ASSERT(m_nCurrentStateSlot >= 0 && m_nCurrentStateSlot <= 9);
SaveDebugState(m_nCurrentStateSlot);
}
void CPSFWorkArea::PlayStop()
{
KillPlayThreadAndBlock();
/*
** Free memory used by play state
*/
if(m_pStatePlay) {
free(m_pStatePlay);
m_pStatePlay = NULL;
}
}
void CPSFWorkArea::DebugRestart()
{
ASSERT(m_pStateDebug);
/*
** Initialize the state
*/
emu_clear_state(m_pStateDebug, m_nVersion);
emu_set_readfile(m_pStateDebug, CPSFWorkArea__readfile_cb, this);
emu_set_console_out(m_pStateDebug, CPSFWorkArea__console_out, this);
// strcpy(m_sPSF2Path,
// (((CPSFLabApp*)(AfxGetApp()))->m_sPSF2Path)
// );
if(m_nVersion == 1) {
/*
** Load EXE data and apply patches
*/
LoadEXEToState(m_pStateDebug);
ApplyPatchesToState(m_pStateDebug);
}
/*
** Update the code view with the place where we are
*/
// CodeJumpTo(m_dwEXEStartPC);
CodeJumpTo(GetPC());
/*
** Clear the event log and call stack
*/
m_eventlog.Clear();
m_callstack.Clear();
/*
** Reset the register change monitor
*/
RegisterMonitorReset();
}
CView* CPSFWorkArea::FindViewOfClass(CRuntimeClass *pClass)
{
POSITION p = GetFirstViewPosition();
CView *v;
for(;;) {
v = GetNextView(p);
if(!v) break;
if(v->IsKindOf(pClass)) break;
}
ASSERT(v);
return v;
}
DWORD CPSFWorkArea::GetRegister(int nRegisterIndex)
{
ASSERT(m_pStateDebug);
ASSERT(nRegisterIndex >= 0 && nRegisterIndex < PSFWORKAREA_REG_N);
return r3000_getreg(iop_get_r3000_state(emu_get_iop_state(m_pStateDebug)), anRegisterHWID[nRegisterIndex]);
}
void CPSFWorkArea::RegisterMonitor()
{
for(int i = 0; i < PSFWORKAREA_REG_N; i++) {
if(m_anRegisterChangeTimeout[i]) m_anRegisterChangeTimeout[i]--;
DWORD r = GetRegister(i);
if(r != m_adwRegisterPrevious[i]) {
m_adwRegisterPrevious[i] = r;
m_anRegisterChangeTimeout[i] = PSFWORKAREA_REGISTER_CHANGE_TIMEOUT;
}
}
}
void CPSFWorkArea::RegisterMonitorReset()
{
for(int i = 0; i < PSFWORKAREA_REG_N; i++) {
m_adwRegisterPrevious[i] = GetRegister(i);
m_anRegisterChangeTimeout[i] = 0;
}
}
BOOL CPSFWorkArea::RegisterChangedRecently(int nRegisterIndex) const
{
ASSERT(nRegisterIndex >= 0 && nRegisterIndex < PSFWORKAREA_REG_N);
return m_anRegisterChangeTimeout[nRegisterIndex] ? TRUE : FALSE;
}
CCallStack* CPSFWorkArea::GetCallStack()
{
return &m_callstack;
}
BOOL CPSFWorkArea::OnOpenDocument(LPCTSTR lpszPathName)
{
TRACE("CPSFWorkArea::OnOpenDocument(%s)\n", lpszPathName);
if(IsModified()) {
TRACE("Opening a new document over an existing modified one\n");
}
// can only open psf
SetVersion(1);
TRACE("set version to %d\n", m_nVersion);
// LPBYTE lpEXE = new BYTE[0x200000];
BOOL b;
CPSF psf;
CPSXEXE exe;
/*
** Load the EXE into an EXE buffer which we have temporarily allocated
** (if there's an error here, it's recoverable)
*/
b = psf.ReadFromFile(lpszPathName, CPSF::PSF_FILE_ALL, TRUE);
if(!b) {
CString s;
s.Format(_T("%s\n%s"), lpszPathName, (LPCTSTR)psf.GetLastError());
AfxGetMainWnd()->MessageBox(s, _T("Open"), MB_OK|MB_ICONHAND);
return FALSE;
}
b = exe.ReadFromPSF(psf, TRUE);
if(!b) {
CString s;
s.Format(_T("%s\n%s"), lpszPathName, (LPCTSTR)exe.GetLastError());
AfxGetMainWnd()->MessageBox(s, _T("Open"), MB_OK|MB_ICONHAND);
return FALSE;
}
/*
** Clear the document contents
*/
DeleteContents();
SetPathName(lpszPathName);
SetModifiedFlag(FALSE);
/*
** "Import" the EXE
*/
ImportEXEFromBuffer(
exe.GetEXEBuffer(),
exe.GetEXESize()
);
/*
** Silly reminder to myself that this hasn't been unicode-proofed yet
*/
ASSERT(sizeof(TCHAR)==1);
/*
** Attempt to load the tag
*/
m_tag.ReadFromPSF(psf, FALSE);
/*
** Restart debugger
*/
DebugRestart();
RegisterMonitor();
UpdateAllViews(NULL);
TRACE("got here, version is %d\n",m_nVersion);
return TRUE;
}
BOOL CPSFWorkArea::OnSaveDocument(LPCTSTR lpszPathName)
{
TRACE("CPSFWorkArea::OnSaveDocument(%s)\n", lpszPathName);
CWaitCursor cwc;
/*
** Silly reminder to myself that this hasn't been unicode-proofed yet
*/
ASSERT(sizeof(TCHAR)==1);
/*
** Create the EXE data
*/
CByteArray aEXE;
aEXE.SetSize(0x200000);
DWORD dwEXELength = ExportEXEToBuffer(aEXE.GetData());
aEXE.SetSize(dwEXELength);
/*
** Save the EXE data and tag to a PSF file
*/
CPSF psf;
psf.SetVersion(0x01);
psf.SetReservedSize(0);
UINT uMethod = ((CPSFLabApp*)(::AfxGetApp()))->GetCompressionMethodNumber();
BOOL b;
b = psf.SetProgramData(aEXE.GetData(), aEXE.GetSize(), uMethod);
if(!b) {
CString s;
s.Format(_T("%s\n%s"), lpszPathName, (LPCTSTR)psf.GetLastError());
AfxGetMainWnd()->MessageBox(s, _T("Save"), MB_OK|MB_ICONHAND);
return FALSE;
}
m_tag.WriteToPSF(psf, FALSE);
b = psf.WriteToFile(lpszPathName, CPSF::PSF_FILE_ALL, TRUE);
if(!b) {
CString s;
s.Format(_T("%s\n%s"), lpszPathName, (LPCTSTR)psf.GetLastError());
AfxGetMainWnd()->MessageBox(s, _T("Save"), MB_OK|MB_ICONHAND);
return FALSE;
}
/*
** Success
** Document is no longer modified
** (and may have a new pathname now)
*/
SetPathName(lpszPathName);
SetModifiedFlag(FALSE);
UpdateAllViews(NULL);
return TRUE;
}
void CPSFWorkArea::ClearWorkArea()
{
/*
** Clear original EXE data
*/
memset(m_adwEXEData, 0, sizeof(m_adwEXEData));
m_dwEXEStartAddress = 0x80010000;
m_dwEXEByteLength = 0;
m_dwEXEStartPC = 0x80010000;
m_dwEXEStartSP = 0x801FFFF0;
memset(m_EXEHeader, 0, 0x800);
memcpy(m_EXEHeader, "PS-X EXE", 8);
memcpy(m_EXEHeader+0x4C, "Sony Computer Entertainment Inc. for North America area", 0x37);
/*
** Clear patch/breakpoint info
*/
memset(m_adwPatchMap, 0, sizeof(m_adwPatchMap));
memset(m_adwBreakpointMapRead, 0, sizeof(m_adwBreakpointMapRead));
memset(m_adwBreakpointMapWrite, 0, sizeof(m_adwBreakpointMapWrite));
memset(m_adwBreakpointMapExecute, 0, sizeof(m_adwBreakpointMapExecute));
// clear register change monitoring
memset(m_adwRegisterPrevious, 0, sizeof(m_adwRegisterPrevious));
memset(m_anRegisterChangeTimeout, 0, sizeof(m_anRegisterChangeTimeout));
// clear console
console.Clear();
}
/***************************************************************************/
/*
** Debugging thread / debug core
*/
UINT AFX_CDECL CPSFWorkArea__DebugThread(LPVOID lpParam) {
CPSFWorkArea *me = (CPSFWorkArea*)lpParam;
ASSERT(me);
/*
** Signal thread start
*/
me->m_csDebug.Lock();
me->m_evDebug.SetEvent();
/*
** Initial preparations
*/
ASSERT(me->m_pStateDebug);
me->m_bDebugBreakpointReadFlag = FALSE;
me->m_bDebugBreakpointWriteFlag = FALSE;
me->m_bDebugBreakpointExecuteFlag = FALSE;
me->m_bDebugErrorFlag = FALSE;
me->m_bDebugBreakOnWeed = TRUE;
me->m_bDebugWeedFlag = FALSE;
/*
** Initial call stack caching (size, top PC/SP)
*/
int nInitialCallStackSize = me->m_callstack.GetSize();
int nCallStackSize = nInitialCallStackSize;
/*
** Clear the hardware event buffer
*/
iop_clear_events(emu_get_iop_state(me->m_pStateDebug));
/*
** Debug core loop
*/
while(!me->m_dwDebugKillFlag) {
DWORD dwIns;
#define INS_S ((DWORD)((dwIns>>21)&0x1F))
#define INS_T ((DWORD)((dwIns>>16)&0x1F))
#define INS_D ((DWORD)((dwIns>>11)&0x1F))
#define INS_H ((DWORD)((dwIns>>6 )&0x1F))
#define INS_I ((DWORD)((dwIns )&0xFFFF))
#define SIGNED16(x) ((INT32)(((SHORT)(x))))
#define UNSIGNED16(x) (((UINT32)(x))&0xFFFF)
#define REL_I(pc) ((pc)+4+((SIGNED16(INS_I))<<2))
#define ABS_I(pc) (((pc)&0xF0000000)|((dwIns<<2)&0x0FFFFFFC))
/*
** Prepare to execute the next instruction
*/
DWORD dwBeforePC = r3000_getreg(iop_get_r3000_state(emu_get_iop_state(me->m_pStateDebug)), R3000CLASS(PC));
/*
** Check for possible jump/call instructions and compute the target.
**
** This way we'll know whether there was a call to add to the call stack
** and be able to differentiate between jumps and exceptions.
**
** "The program counter changed - was this intentional?"
** We can know this ahead of time.
*/
BOOL bPossibleJump = FALSE;
BOOL bPossibleCall = FALSE;
DWORD dwPossibleJumpTarget = 0;
dwIns = iop_getword(emu_get_iop_state(me->m_pStateDebug), dwBeforePC);
if(dwIns < 0x04000000) {
/* MINOR */
switch(dwIns & 0x3F) {
case 0x09: /* jalr */
if(INS_D == 31) bPossibleCall = TRUE;
/* INTENTIONAL FALL THROUGH */
case 0x08: /* jr */
bPossibleJump = TRUE;
dwPossibleJumpTarget = r3000_getreg(iop_get_r3000_state(emu_get_iop_state(me->m_pStateDebug)), R3000CLASS(GEN)+INS_S);
break;
}
} else {
/* MAJOR */
switch(dwIns >> 26) {
case 0x01: /* various branch types */
switch(INS_T) {
case 0x10: case 0x11: bPossibleCall = TRUE;
}
/* INTENTIONAL FALL THROUGH */
case 0x04: /* beq */
case 0x05: /* bne */
case 0x06: /* blez */
case 0x07: /* bgtz */
bPossibleJump = TRUE;
dwPossibleJumpTarget = REL_I(dwBeforePC);
break;
case 0x03: /* jal */
bPossibleCall = TRUE;
/* INTENTIONAL FALL THROUGH */
case 0x02: /* j */
bPossibleJump = TRUE;
dwPossibleJumpTarget = ABS_I(dwBeforePC);
break;
}
}
/*
** Execute the next instruction
*/
signed short samplebuffer[2*100];
unsigned dwSoundSamples = 100;
int nExecuteError = emu_execute(me->m_pStateDebug, 1, samplebuffer, &dwSoundSamples, me->m_dwDebugEventMask);
/*
** Handle unrecoverable errors here
** Set the error flag and terminate directly
*/
if(nExecuteError < 0) {
me->m_bDebugErrorFlag = TRUE;
AfxGetMainWnd()->PostMessage(WM_COMMAND, ID_DEBUG_EXECUTIONSTOPPED, 0);
break;
}
/*
** Update the event log
*/
int c = iop_get_event_count(emu_get_iop_state(me->m_pStateDebug));
for(; c > 0; c--) {
TCHAR s[500];
UINT64 time;
char *fmt = "format not set(%08X,%08X,%08X,%08X)";
UINT32 type;
UINT32 arg[4];
iop_get_event(emu_get_iop_state(me->m_pStateDebug), &time, &type, &fmt, arg);
iop_dismiss_event(emu_get_iop_state(me->m_pStateDebug));
int i;
TCHAR *ps = s + 19;
for(i = 19; i >= 0; i--) {
int digit = (int)(time % 10);
time /= 10;
s[i] = _T("0123456789")[digit];
if(digit) ps = s + i;
}
s[20] = _T(':');
s[21] = _T(' ');
s[22] = 0;
wsprintf(s + lstrlen(s), _T("(pc=0x%08X) "), dwBeforePC);
wsprintf(s + lstrlen(s), fmt,
(UINT32)(arg[0]),
(UINT32)(arg[1]),
(UINT32)(arg[2]),
(UINT32)(arg[3])
);
me->m_eventlog.Add(ps);
}
/*
** Perform post-analysis on the instruction just executed
*/
DWORD dwPC = r3000_getreg(iop_get_r3000_state(emu_get_iop_state(me->m_pStateDebug)), R3000CLASS(PC));
DWORD dwSP = r3000_getreg(iop_get_r3000_state(emu_get_iop_state(me->m_pStateDebug)), R3000CLASS(GEN)+29);
BOOL bException = FALSE;
if(dwPC != (dwBeforePC + 4)) {
/*
** Check for return
*/
if(nCallStackSize) {
me->m_callstack.CheckForReturn(dwPC, dwSP);
nCallStackSize = me->m_callstack.GetSize();
}
/*
** Do some voodoo to see if an exception happened
*/
if(bPossibleJump && dwPC == dwPossibleJumpTarget) {
bException = FALSE;
} else {
bException = TRUE;
}
/*
** Handle calls or exceptions
*/
if(bPossibleCall || bException) {
SCallStackEntry e;
e.bException = bException;
e.dwArg[0] = r3000_getreg(iop_get_r3000_state(emu_get_iop_state(me->m_pStateDebug)), R3000CLASS(GEN)+4);
e.dwArg[1] = r3000_getreg(iop_get_r3000_state(emu_get_iop_state(me->m_pStateDebug)), R3000CLASS(GEN)+5);
e.dwArg[2] = r3000_getreg(iop_get_r3000_state(emu_get_iop_state(me->m_pStateDebug)), R3000CLASS(GEN)+6);
e.dwArg[3] = r3000_getreg(iop_get_r3000_state(emu_get_iop_state(me->m_pStateDebug)), R3000CLASS(GEN)+7);
e.dwCause = r3000_getreg(iop_get_r3000_state(emu_get_iop_state(me->m_pStateDebug)), R3000CLASS(C0)+13);
e.dwInvokedAddress = dwPC;
e.dwReturnPC = r3000_getreg(iop_get_r3000_state(emu_get_iop_state(me->m_pStateDebug)), bException ? (R3000CLASS(C0)+14) : (R3000CLASS(GEN)+31));
e.dwReturnSP = r3000_getreg(iop_get_r3000_state(emu_get_iop_state(me->m_pStateDebug)), R3000CLASS(GEN)+29);
me->m_callstack.Add(e);
nCallStackSize++;
}
}
/*
** Check for terminating conditions
*/
BOOL bTerminate = FALSE;
/*
** Code breakpoints
*/
if(me->IsBreakpointOnExecute(dwPC)) {
me->m_bDebugBreakpointExecuteFlag = TRUE;
me->m_dwDebugBreakpointExecuteAddress = dwPC;
bTerminate = TRUE;
}
/* Invalid PC */
if(me->m_bDebugBreakOnWeed) {
BOOL inv = FALSE;
switch((dwPC >> 29) & 7) {
case 1: case 2: case 3: case 6: case 7: inv = TRUE;
}
DWORD t = dwPC & 0x1FFFFFFF;
if(t >= 0x00800000 && t < 0x1F000000) inv = TRUE;
if(t >= 0x1F000000 && t < 0x1FC00000) inv = TRUE;
if(inv) {
me->m_bDebugWeedFlag = TRUE;
me->m_dwDebugWeedAddress = dwPC;
bTerminate = TRUE;
}
}
/*
** Memory breakpoints
** Terminate if there's a triggering load or store instruction
*/
dwIns = iop_getword(emu_get_iop_state(me->m_pStateDebug), dwPC);
DWORD dwOperandAddress;
switch(dwIns >> 26) {
case 0x20: /* lb */
case 0x21: /* lh */
case 0x23: /* lw */
case 0x24: /* lbu */
case 0x25: /* lhu */
dwOperandAddress = r3000_getreg(iop_get_r3000_state(emu_get_iop_state(me->m_pStateDebug)), R3000CLASS(GEN)+INS_S) + SIGNED16(INS_I);
dwOperandAddress &= 0xFFFFFFFC;
if(me->IsBreakpointOnRead(dwOperandAddress)) {
me->m_bDebugBreakpointReadFlag = TRUE;
me->m_dwDebugBreakpointReadAddress = dwOperandAddress;
bTerminate = TRUE;
}
break;
case 0x28: /* sb */
case 0x29: /* sh */
case 0x2B: /* sw */
dwOperandAddress = r3000_getreg(iop_get_r3000_state(emu_get_iop_state(me->m_pStateDebug)), R3000CLASS(GEN)+INS_S) + SIGNED16(INS_I);
dwOperandAddress &= 0xFFFFFFFC;
if(me->IsBreakpointOnWrite(dwOperandAddress)) {
me->m_bDebugBreakpointWriteFlag = TRUE;
me->m_dwDebugBreakpointWriteAddress = dwOperandAddress;
bTerminate = TRUE;
}
break;
}
/*
** Command-specific terminating conditions
*/
switch(me->m_nDebugCommand) {
/*
** Go: Never terminate
*/
case ID_DEBUG_GO:
break;
/*
** Step Into: Always terminate
*/
case ID_DEBUG_STEPINTO:
bTerminate = TRUE;
break;
/*
** Step Over: Terminate if the call stack level is the same as before
*/
case ID_DEBUG_STEPOVER:
if(nCallStackSize == nInitialCallStackSize) bTerminate = TRUE;
break;
/*
** Step Out: Terminate if the call stack level is less than before
*/
case ID_DEBUG_STEPOUT:
if(nCallStackSize < nInitialCallStackSize) bTerminate = TRUE;
break;
/*
** Run to Cursor / Run to Specific Address: Terminate when that address is reached
*/
case ID_DEBUG_RUNTOCURSOR:
case ID_DEBUG_SPECIFICLINE:
if((dwPC & 0x1FFFFFFC) == (me->m_dwDebugRunTarget & 0x1FFFFFFC)) bTerminate = TRUE;
break;
/*
** Run to Interrupt: Terminate if an interrupt just happened
*/
case ID_DEBUG_RUNTOINT:
if(bException) {
DWORD dwCause = r3000_getreg(iop_get_r3000_state(emu_get_iop_state(me->m_pStateDebug)), R3000CLASS(C0)+13);
/*
** Examine Cause bits
** 0 means hardware interrupt
*/
if(((dwCause >> 2) & 0xF) == 0x0) bTerminate = TRUE;
}
break;
/*
** Unknown command: Just terminate
*/
default:
bTerminate = TRUE;
break;
}
/*
** Handle terminating conditions, if they exist
*/
if(bTerminate) {
AfxGetMainWnd()->PostMessage(WM_COMMAND, ID_DEBUG_EXECUTIONSTOPPED, 0);
break;
}
}
/*
** Signal thread end; return
*/
me->m_pDebugThread = NULL;
me->m_csDebug.Unlock();
return 0;
}
/***************************************************************************/
/*
** Play thread must never die until specifically told to
** (via either m_dwPlayKillFlag or a WM_APP+1 message)
*/
UINT AFX_CDECL CPSFWorkArea__PlayThread(LPVOID lpParam) {
CPSFWorkArea *me = (CPSFWorkArea*)lpParam;
me->m_csPlay.Lock();
me->m_evPlay.SetEvent();
DWORD samplebuffer[8*4096];
CWaveOutput waveoutput;
waveoutput.Open(samplebuffer, 8, 4096,
(me->m_nVersion == 1) ? 44100 : 48000
);
// OutputDebugString("PlayThread started\n");
// void *pFilter = filter_open();
int q = 0;
while(!me->m_dwPlayKillFlag) {
MSG msg;
::GetMessage(&msg, NULL, WM_APP, WM_APP+2);
if(msg.message == WM_APP+2) {
//TRACE("pause %d\n",msg.wParam);
waveoutput.Pause(msg.wParam);
continue;
}
if(msg.message == WM_APP+1) break;
if(msg.message != WM_APP) continue;
short *pBuf = (short*)(msg.lParam);
int nSamples = 4096;
int r = 0;
while(nSamples > 0) {
int n = nSamples;
r = emu_execute(me->m_pStatePlay, 0x7FFFFFFF, pBuf, (unsigned*)(&n), 0);
/*
** On error, simply play silence
*/
if(r < 0) {
memset(pBuf, 0, sizeof(short)*2*nSamples);
n = nSamples;
} else {
/*
** Shove it through the filter
*/
// n = filter_process(pFilter, pBuf, n);
}
//for(r=0;r<2*n;r++)pBuf[r]=((q++)%168)*10;
pBuf += 2 * n;
nSamples -= n;
}
waveoutput.BufferReady(msg.wParam);
}
// filter_close(pFilter);
waveoutput.Close();
me->m_pPlayThread = NULL;
me->m_csPlay.Unlock();
return 0;
}
/***************************************************************************/
void CPSFWorkArea::DeleteContents()
{
KillDebugThreadAndBlock();
KillPlayThreadAndBlock();
ClearWorkArea();
ClearAllSavedStates();
m_tag.Empty();
}
void CPSFWorkArea::OnCloseDocument()
{
// TODO: Add your specialized code here and/or call the base class
CDocument::OnCloseDocument();
}
void CPSFWorkArea::OnFileImportbinary()
{
CImportBinaryDlg dlgImportBinary;
if(dlgImportBinary.DoModal() != IDOK) return;
CString strPathName = dlgImportBinary.m_strPathName;
DWORD dwOffset = dlgImportBinary.m_dwOffset;
DWORD dwLength = dlgImportBinary.m_dwLength;
DWORD dwDestinationAddress = dlgImportBinary.m_dwDestinationAddress;
// dwOffset &= 0xFFFFFFFC;
// dwLength &= 0xFFFFFFFC;
// dwDestinationAddress &= 0xFFFFFFFC;
if(!dwLength) return;
if(strPathName.IsEmpty()) return;
CString strCaption;
strCaption.LoadString(IDS_IMPORT_BINARY);
FILE *f = fopen((LPCSTR)strPathName, "rb");
if(!f) {
CString s;
s.Format(_T("Unable to open '%s'."), (LPCTSTR)strPathName);
AfxGetMainWnd()->MessageBox(s, (LPCTSTR)strCaption, MB_OK|MB_ICONHAND);
}
LPBYTE lpBuffer = new BYTE[dwLength];
memset(lpBuffer, 0, dwLength);
fseek(f, dwOffset, SEEK_SET);
fread(lpBuffer, 1, dwLength, f);
fclose(f);
ImportBinaryFromBuffer(lpBuffer, dwDestinationAddress, dwLength);
delete[] lpBuffer;
SetModifiedFlag();
UpdateAllViews(NULL);
}
void CPSFWorkArea::OnUpdateFileImportbinary(CCmdUI* pCmdUI) {
pCmdUI->Enable(
(GetVersion() == 1) && (!IsRunning())
);
}
void CPSFWorkArea::OnUpdateDebugRuntoint(CCmdUI* pCmdUI) { pCmdUI->Enable(!IsRunning()); }
void CPSFWorkArea::OnUpdateEditBreakpoints(CCmdUI* pCmdUI) { pCmdUI->Enable(!IsRunning()); }
void CPSFWorkArea::OnEditBreakpoints()
{
CBreakpointsDlg dlgBreakpoints;
dlgBreakpoints.m_pWorkArea = this;
/*
** Quick run through the breakpoint map to add all breakpoint addresses
** This makes the dialog's job a lot easier
*/
for(int i = 0; i < 0x5000; i++) {
DWORD dwMap =
m_adwBreakpointMapExecute[i] |
m_adwBreakpointMapRead[i] |
m_adwBreakpointMapWrite[i];
if(dwMap) {
DWORD dwBase = BreakpointIndexToAddress(32 * i);
for(int j = 0; j < 32; j++) {
if(dwMap & (1 << j)) dlgBreakpoints.m_adwBreakpoints.Add(dwBase + 4 * j);
}
}
}
/*
** Dialog will handle everything from here
*/
dlgBreakpoints.DoModal();
}
void CPSFWorkArea::OnUpdateEditExesettings(CCmdUI* pCmdUI) {
BOOL b = FALSE;
if((m_nVersion == 1) && (!IsRunning())) b = TRUE;
pCmdUI->Enable(b);
}
void CPSFWorkArea::OnEditExesettings()
{
CExeSettingsDlg dlgExeSettings;
dlgExeSettings.m_dwPC = m_dwEXEStartPC;
dlgExeSettings.m_dwSP = m_dwEXEStartSP;
dlgExeSettings.m_dwTextStart = m_dwEXEStartAddress;
dlgExeSettings.m_dwTextSize = m_dwEXEByteLength;
if(dlgExeSettings.DoModal() != IDOK) return;
m_dwEXEStartPC = dlgExeSettings.m_dwPC;
m_dwEXEStartSP = dlgExeSettings.m_dwSP;
m_dwEXEStartAddress = dlgExeSettings.m_dwTextStart;
m_dwEXEByteLength = dlgExeSettings.m_dwTextSize;
}
void CPSFWorkArea::PlayStart()
{
/*
** Kill old thread, if there was one
*/
KillPlayThreadAndBlock();
/*
** Allocate a play state if it doesn't already exist
*/
if(!m_pStatePlay) {
m_pStatePlay = malloc(emu_get_state_size(m_nVersion));
}
ASSERT(m_pStatePlay);
emu_clear_state(m_pStatePlay, m_nVersion);
emu_set_readfile(m_pStatePlay, CPSFWorkArea__readfile_cb, this);
// strcpy(m_sPSF2Path,
// (((CPSFLabApp*)(AfxGetApp()))->m_sPSF2Path)
// );
//emu_set_console_out(m_pStatePlay, CPSFWorkArea__console_out, this);
//spu_enable_reverb(iop_get_spu_state(emu_get_iop_state(m_pStatePlay)), 0);
/*
** Set emulation core settings
*/
SPSFEmuSettings es;
theApp.GetEmuSettings(PSF_EMUSETTINGS_PLAY, es);
iop_set_compat(emu_get_iop_state(m_pStatePlay), es.bFriendly ? IOP_COMPAT_FRIENDLY : IOP_COMPAT_HARSH);
/*
** Load the patched EXE into this play state
*/
if(m_nVersion == 1) {
LoadEXEToState(m_pStatePlay);
ApplyPatchesToState(m_pStatePlay);
}
/*
** Begin unpaused!
*/
m_bPlayPaused = FALSE;
/*
** Begin new thread
*/
StartPlayThreadAndBlock();
}
void CPSFWorkArea::PlayPause() {
if(m_bPlayPaused) return;
if(m_pPlayThread) m_pPlayThread->PostThreadMessage(WM_APP+2, TRUE, 0);
m_bPlayPaused = TRUE;
}
void CPSFWorkArea::PlayUnpause() {
if(!m_bPlayPaused) return;
if(m_pPlayThread) m_pPlayThread->PostThreadMessage(WM_APP+2, FALSE, 0);
m_bPlayPaused = FALSE;
}
void CPSFWorkArea::LoadEXEToState(void *pState)
{
ASSERT(pState);
/*
** Copy EXE data
*/
for(DWORD i = 0; i < 0x7C000; i++) {
iop_setword(emu_get_iop_state(pState), 0x80010000+4*i, m_adwEXEData[i]);
}
/*
** Set the initial PC/SP
*/
r3000_setreg(iop_get_r3000_state(emu_get_iop_state(pState)), R3000CLASS(PC) , m_dwEXEStartPC);
r3000_setreg(iop_get_r3000_state(emu_get_iop_state(pState)), R3000CLASS(GEN)+29, m_dwEXEStartSP);
}
void CPSFWorkArea::ApplyPatchesToState(void *pState)
{
ASSERT(pState);
DWORD dwAddress;
for(dwAddress = 0x80010000; dwAddress < 0x80200000; dwAddress += 4) {
if(IsWordPatched(dwAddress)) iop_setword(emu_get_iop_state(pState), dwAddress, GetPatchWord(dwAddress));
}
}
/***************************************************************************/
void CPSFWorkArea::KillDebugThreadAndBlock() {
m_dwDebugKillFlag = 1;
m_csDebug.Lock(); m_csDebug.Unlock();
m_bRunning = FALSE;
}
void CPSFWorkArea::KillPlayThreadAndBlock() {
if(m_pPlayThread) m_pPlayThread->PostThreadMessage(WM_APP+1,0,0);
m_dwPlayKillFlag = 1;
m_csPlay.Lock(); m_csPlay.Unlock();
m_bPlaying = FALSE;
}
void CPSFWorkArea::StartDebugThreadAndBlock() {
KillDebugThreadAndBlock();
m_evDebug.ResetEvent();
m_dwDebugKillFlag = 0;
m_bRunning = TRUE;
/*
** Must get app-global options here... can't really get them in the
** debug thread itself
*/
/*
** Event mask
*/
m_dwDebugEventMask = theApp.GetEventMask();
/*
** Emulation core settings
*/
SPSFEmuSettings es;
theApp.GetEmuSettings(PSF_EMUSETTINGS_DEBUG, es);
iop_set_compat(emu_get_iop_state(m_pStateDebug), es.bFriendly ? IOP_COMPAT_FRIENDLY : IOP_COMPAT_HARSH);
/*
** Now begin the thread
*/
m_pDebugThread = AfxBeginThread(CPSFWorkArea__DebugThread, (LPVOID)this);
m_evDebug.Lock();
}
void CPSFWorkArea::StartPlayThreadAndBlock() {
KillPlayThreadAndBlock();
m_evPlay.ResetEvent();
m_dwPlayKillFlag = 0;
m_bPlaying = TRUE;
m_pPlayThread = AfxBeginThread(CPSFWorkArea__PlayThread, (LPVOID)this);
m_evPlay.Lock();
}
/***************************************************************************/
/*
** This command is sent INTERNALLY when execution has stopped in the debug
** thread.
*/
void CPSFWorkArea::OnDebugExecutionstopped()
{
KillDebugThreadAndBlock();
/*
** Update views depending on what exactly happened
*/
DWORD dwPC = r3000_getreg(iop_get_r3000_state(emu_get_iop_state(m_pStateDebug)), R3000CLASS(PC));
CodeJumpTo(dwPC);
if(m_bDebugBreakpointReadFlag ) MemoryJumpTo(m_dwDebugBreakpointReadAddress );
if(m_bDebugBreakpointWriteFlag) MemoryJumpTo(m_dwDebugBreakpointWriteAddress);
CEventView *ev = (CEventView *)FindViewOfClass(RUNTIME_CLASS(CEventView ));
if(ev) { ev->JumpToBottom(); }
RegisterMonitor();
UpdateAllViews(NULL);
/*
** Message box depending on what happened
*/
CString str, strMessage;
CString strCaption;
strCaption.LoadString(IDS_BREAKPOINT);
UINT nType = MB_OK;
if(m_bDebugErrorFlag) {
str.Format(IDS_UNRECOVERABLE_ADDRESS, dwPC);
strMessage += str;
strCaption.LoadString(IDS_ERROR);
nType = MB_OK|MB_ICONHAND;
}
if(m_bDebugBreakpointExecuteFlag) {
str.Format(IDS_BREAKPOINT_EXECUTE_ADDRESS, dwPC);
strMessage += str;
}
if(m_bDebugBreakpointReadFlag) {
str.Format(IDS_BREAKPOINT_READ_ADDRESS, m_dwDebugBreakpointReadAddress);
strMessage += str;
}
if(m_bDebugBreakpointWriteFlag) {
str.Format(IDS_BREAKPOINT_WRITE_ADDRESS, m_dwDebugBreakpointWriteAddress);
strMessage += str;
}
if(m_bDebugWeedFlag) {
str.Format(IDS_WEED_ADDRESS, m_dwDebugWeedAddress);
strMessage += str;
}
if(!strMessage.IsEmpty()) {
AfxGetMainWnd()->MessageBox(strMessage, (LPCTSTR)strCaption, nType);
}
// commands will re-enable themselves automatically when this returns
}
void CPSFWorkArea::RunToAddress(DWORD dwAddress)
{
KillDebugThreadAndBlock();
m_nDebugCommand = ID_DEBUG_SPECIFICLINE;
m_dwDebugRunTarget = dwAddress;
StartDebugThreadAndBlock();
UpdateAllViews(NULL);
}
void CPSFWorkArea::OnUpdateDebugSpecificline(CCmdUI* pCmdUI) {
pCmdUI->Enable(!IsRunning());
}
void CPSFWorkArea::OnDebugSpecificline() {
CRunToSpecificLineDlg dlgRunToSpecificLine;
ASSERT(m_pStateDebug);
dlgRunToSpecificLine.m_dwAddress = r3000_getreg(iop_get_r3000_state(emu_get_iop_state(m_pStateDebug)), R3000CLASS(PC));
if(dlgRunToSpecificLine.DoModal() != IDOK) return;
RunToAddress(dlgRunToSpecificLine.m_dwAddress);
}
void CPSFWorkArea::OnDebugRuntoint()
{
KillDebugThreadAndBlock();
m_nDebugCommand = ID_DEBUG_RUNTOINT;
StartDebugThreadAndBlock();
UpdateAllViews(NULL);
}
void CPSFWorkArea::ClearAllSavedStates()
{
int i;
for(i = 0; i < 10; i++) {
if(m_apSavedStates[i]) {
free(m_apSavedStates[i]);
m_apSavedStates[i] = 0;
}
}
m_nCurrentStateSlot = 0;
}
void CPSFWorkArea::SaveDebugState(int nSlot)
{
ASSERT(m_pStateDebug);
ASSERT(nSlot >= 0 && nSlot <= 9);
int nStateSize = emu_get_state_size(m_nVersion);
if(!m_apSavedStates[nSlot]) {
m_apSavedStates[nSlot] = malloc(nStateSize);
}
memcpy(m_apSavedStates[nSlot], m_pStateDebug, nStateSize);
m_aSavedCallStacks[nSlot].CopyFrom(m_callstack);
m_aSavedEventLogs[nSlot].CopyFrom(m_eventlog);
}
void CPSFWorkArea::LoadDebugState(int nSlot)
{
ASSERT(m_pStateDebug);
ASSERT(nSlot >= 0 && nSlot <= 9);
if(!m_apSavedStates[nSlot]) return;
int nStateSize = emu_get_state_size(m_nVersion);
memcpy(m_pStateDebug, m_apSavedStates[nSlot], nStateSize);
m_callstack.CopyFrom(m_aSavedCallStacks[nSlot]);
m_eventlog.CopyFrom(m_aSavedEventLogs[nSlot]);
}
void CPSFWorkArea::OnDebugSelectslot()
{
CStateSlotDlg dlgStateSlot;
dlgStateSlot.m_nSlot = m_nCurrentStateSlot;
CString strInUse;
CString strNotInUse;
strInUse.LoadString(IDS_INUSE);
strNotInUse.LoadString(IDS_NOTINUSE);
dlgStateSlot.m_strInUse1 = m_apSavedStates[0] ? ((LPCTSTR)strInUse) : ((LPCTSTR)strNotInUse);
dlgStateSlot.m_strInUse2 = m_apSavedStates[1] ? ((LPCTSTR)strInUse) : ((LPCTSTR)strNotInUse);
dlgStateSlot.m_strInUse3 = m_apSavedStates[2] ? ((LPCTSTR)strInUse) : ((LPCTSTR)strNotInUse);
dlgStateSlot.m_strInUse4 = m_apSavedStates[3] ? ((LPCTSTR)strInUse) : ((LPCTSTR)strNotInUse);
dlgStateSlot.m_strInUse5 = m_apSavedStates[4] ? ((LPCTSTR)strInUse) : ((LPCTSTR)strNotInUse);
dlgStateSlot.m_strInUse6 = m_apSavedStates[5] ? ((LPCTSTR)strInUse) : ((LPCTSTR)strNotInUse);
dlgStateSlot.m_strInUse7 = m_apSavedStates[6] ? ((LPCTSTR)strInUse) : ((LPCTSTR)strNotInUse);
dlgStateSlot.m_strInUse8 = m_apSavedStates[7] ? ((LPCTSTR)strInUse) : ((LPCTSTR)strNotInUse);
dlgStateSlot.m_strInUse9 = m_apSavedStates[8] ? ((LPCTSTR)strInUse) : ((LPCTSTR)strNotInUse);
dlgStateSlot.m_strInUse0 = m_apSavedStates[9] ? ((LPCTSTR)strInUse) : ((LPCTSTR)strNotInUse);
if(dlgStateSlot.DoModal() != IDOK) return;
m_nCurrentStateSlot = dlgStateSlot.m_nSlot;
}
DWORD CPSFWorkArea::BreakpointIndexToAddress(int nIndex)
{
if(nIndex < 0) return 0;
if(nIndex >= 0xA0000) return 0;
if(nIndex < 0x80000) return 0x80000000 + 4 * nIndex;
return 0xBFC00000 + 4 * (nIndex - 0x80000);
}
void CPSFWorkArea::CodeJumpTo(DWORD dwAddress)
{
CCodeView *cv = (CCodeView*)FindViewOfClass(RUNTIME_CLASS(CCodeView));
if(cv) {
cv->JumpTo(dwAddress);
cv->SetFocus();
}
}
void CPSFWorkArea::MemoryJumpTo(DWORD dwAddress)
{
CMemoryView *mv = (CMemoryView*)FindViewOfClass(RUNTIME_CLASS(CMemoryView));
if(mv) {
mv->JumpTo(dwAddress);
mv->SetFocus();
}
}
void CPSFWorkArea::OnEditTag()
{
CTagDlg dlgTag;
CString strTag = m_tag.GetRaw();
dlgTag.m_strTag = strTag;
if(dlgTag.DoModal() != IDOK) return;
if(!lstrcmp((LPCTSTR)strTag, (LPCTSTR)dlgTag.m_strTag)) return;
m_tag.SetRaw(dlgTag.m_strTag);
SetModifiedFlag();
}
void CPSFWorkArea::ImportEXEFromBuffer(LPBYTE lpBuffer, DWORD dwLength)
{
if(dwLength < 0x800) return;
memcpy(m_EXEHeader, lpBuffer, 0x800);
m_dwEXEStartPC = *((DWORD*)(lpBuffer+0x10));
m_dwEXEStartSP = *((DWORD*)(lpBuffer+0x30));
m_dwEXEStartAddress = *((DWORD*)(lpBuffer+0x18));
m_dwEXEByteLength = *((DWORD*)(lpBuffer+0x1C));
if(m_dwEXEByteLength > (dwLength-0x800)) m_dwEXEByteLength = (dwLength-0x800);
ImportBinaryFromBuffer(lpBuffer+0x800, m_dwEXEStartAddress, m_dwEXEByteLength);
}
/*
** TODO
** Hi there!
** Fix me so I can load unaligned data!
*/
void CPSFWorkArea::ImportBinaryFromBuffer(LPBYTE lpBuffer, DWORD dwAddress, DWORD dwLength)
{
dwLength &= 0xFFFFFFFC;
for(DWORD i = 0; i < dwLength; i += 4) {
DWORD d = *((DWORD*)(lpBuffer+i));
DWORD a = (dwAddress + i) & 0xFFFFFFFC;
DeletePatchWord(a);
int nEXEIndex = AddressToEXEIndex(a);
if(nEXEIndex >= 0) m_adwEXEData[nEXEIndex] = d;
iop_setword(emu_get_iop_state(m_pStateDebug), a, d);
}
}
/*
** TODO
** Hi there!
** Fix me so I can export unaligned data!
*/
void CPSFWorkArea::ExportBinaryToBuffer(LPBYTE lpBuffer, DWORD dwAddress, DWORD dwLength)
{
dwLength &= 0xFFFFFFFC;
for(DWORD i = 0; i < dwLength; i += 4) {
DWORD a = (dwAddress & 0xFFFFFFFC) + i;
DWORD d = 0;
int nEXEIndex = AddressToEXEIndex(a);
if(nEXEIndex >= 0) d = m_adwEXEData[nEXEIndex];
if(IsWordPatched(a)) d = GetPatchWord(a);
*((DWORD*)(lpBuffer+i)) = d;
}
}
/*
** Buffer must have 0x200000 bytes available
*/
DWORD CPSFWorkArea::ExportEXEToBuffer(LPBYTE lpBuffer)
{
DWORD dwLen = m_dwEXEByteLength;
if(dwLen > 0x1F0000) dwLen = 0x1F0000;
/*
** Write header, hooray
*/
*((DWORD*)(m_EXEHeader+0x10)) = m_dwEXEStartPC;
*((DWORD*)(m_EXEHeader+0x30)) = m_dwEXEStartSP;
*((DWORD*)(m_EXEHeader+0x18)) = m_dwEXEStartAddress;
*((DWORD*)(m_EXEHeader+0x1C)) = m_dwEXEByteLength;
memcpy(lpBuffer, m_EXEHeader, 0x800);
/*
** Export the text section
*/
ExportBinaryToBuffer(lpBuffer + 0x800, m_dwEXEStartAddress, m_dwEXEByteLength);
/*
** Return the total length
*/
return (0x800 + m_dwEXEByteLength);
}
void CPSFWorkArea::OnFileSaveas()
{
CString strFilterName;
CString strFilterExt;
CDocTemplate *pDocTemplate = GetDocTemplate();
ASSERT(pDocTemplate);
pDocTemplate->GetDocString(strFilterName, CDocTemplate::filterName);
pDocTemplate->GetDocString(strFilterExt , CDocTemplate::filterExt );
CString strFilterString = strFilterName + _T("|*") + strFilterExt + _T("||");
CFileDialog dlgFile(
FALSE,
(LPCTSTR)strFilterExt,
(LPCTSTR)m_strPathName,
OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
(LPCTSTR)strFilterString
);
if(dlgFile.DoModal() != IDOK) return;
CString strSaveAsPathName = dlgFile.GetPathName();
OnSaveDocument((LPCTSTR)strSaveAsPathName);
}
void CPSFWorkArea::OnFileImportexe()
{
CString strEXEFilter;
CString strAllFilter;
strEXEFilter.LoadString(IDS_FILTER_EXE);
strAllFilter.LoadString(IDS_FILTER_ALL);
CString strFilterString = strEXEFilter + _T("|") + strAllFilter + _T("||");
CFileDialog dlgFile(
TRUE,
_T(""),
_T(""),
OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
(LPCTSTR)strFilterString
);
CString strTitle;
strTitle.LoadString(IDS_IMPORT_EXE);
dlgFile.m_ofn.lpstrTitle = (LPCTSTR)strTitle;
if(dlgFile.DoModal() != IDOK) return;
CString strPathName = dlgFile.GetPathName();
FILE *f;
f = fopen((LPCSTR)strPathName, "rb");
if(!f) {
CString s;
s.Format(_T("Unable to open '%s'."), (LPCTSTR)strPathName);
AfxGetMainWnd()->MessageBox(s, (LPCTSTR)strTitle, MB_OK|MB_ICONHAND);
}
fseek(f, 0, SEEK_END);
int nLength = ftell(f);
fseek(f, 0, SEEK_SET);
if(nLength < 0) nLength = 0;
LPBYTE lpEXE = new BYTE[nLength];
ASSERT(lpEXE);
memset(lpEXE, 0, nLength);
fread(lpEXE, 1, nLength, f);
fclose(f);
ImportEXEFromBuffer(lpEXE, nLength);
delete[] lpEXE;
/*
** Might as well restart the debugger
*/
DebugRestart();
RegisterMonitor();
SetModifiedFlag();
UpdateAllViews(NULL);
}
void CPSFWorkArea::OnUpdateFileImportexe(CCmdUI* pCmdUI) {
pCmdUI->Enable(
(GetVersion() == 1) && (!IsRunning())
);
}
void CPSFWorkArea::OnFileExportexe()
{
CString strEXEFilter;
CString strAllFilter;
strEXEFilter.LoadString(IDS_FILTER_EXE);
strAllFilter.LoadString(IDS_FILTER_ALL);
CString strFilterString = strEXEFilter + _T("|") + strAllFilter + _T("||");
CFileDialog dlgFile(
FALSE,
_T(""),
_T(""),
OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
(LPCTSTR)strFilterString
);
CString strTitle;
strTitle.LoadString(IDS_EXPORT_EXE);
dlgFile.m_ofn.lpstrTitle = (LPCTSTR)strTitle;
if(dlgFile.DoModal() != IDOK) return;
CString strPathName = dlgFile.GetPathName();
LPBYTE lpEXE = new BYTE[0x200000];
ASSERT(lpEXE);
DWORD dwEXELength = ExportEXEToBuffer(lpEXE);
FILE *f;
f = fopen((LPCSTR)strPathName, "wb");
if(!f) {
delete[] lpEXE;
CString s;
s.Format(_T("Unable to open '%s'."), (LPCTSTR)strPathName);
AfxGetMainWnd()->MessageBox(s, (LPCTSTR)strTitle, MB_OK|MB_ICONHAND);
}
fwrite(lpEXE, 1, dwEXELength, f);
fclose(f);
delete[] lpEXE;
}
void CPSFWorkArea::OnFileFondue()
{
while(AfxGetMainWnd()->MessageBox(
_T("Please insert Disk 22 to continue"),
_T("Disk Change"),
MB_OKCANCEL|MB_ICONINFORMATION
) != IDCANCEL);
AfxGetMainWnd()->MessageBox(
_T("Unable to load overlay for CPSFWorkArea::OnFondue()\nFile not found"),
_T("Critical Error"),
MB_OK|MB_ICONHAND
);
}
void CPSFWorkArea::OnUpdateEditOptimize(CCmdUI* pCmdUI) {
BOOL b = FALSE;
if((m_nVersion == 1) && (!IsRunning())) b = TRUE;
pCmdUI->Enable(b);
}
void CPSFWorkArea::OnEditOptimize()
{
COptimizeDlg dlg;
dlg.m_pWorkArea = this;
if(dlg.DoModal() != IDOK) return;
}
void CPSFWorkArea::AuditCommit(CPSFAudit &audit) {
DWORD i;
DWORD last_i_read = 0;
for(i = 0x80010000; i < 0x80200000; i += 4) {
if(audit.IsWordUsed(i)) {
last_i_read = i;
} else {
SetPatchWord(i, 0);
}
}
last_i_read += 4;
last_i_read &= 0x1FFFFC;
if(last_i_read < (m_dwEXEStartAddress & 0x1FFFFC)) {
last_i_read = (m_dwEXEStartAddress & 0x1FFFFC);
}
m_dwEXEByteLength = last_i_read - (m_dwEXEStartAddress & 0x1FFFFC);
if(m_dwEXEByteLength > 0x1F0000) { m_dwEXEByteLength = 0x1F0000; }
UpdateAllViews(NULL);
}
void CPSFWorkArea::AuditUpload(CPSFAudit &audit) {
/*
** Copy the executable there
*/
audit.Upload(0x80010000, m_adwEXEData, 0x1F0000);
/*
** Set the initial PC/SP
*/
audit.SetPC(m_dwEXEStartPC);
audit.SetSP(m_dwEXEStartSP);
/*
** Apply all patches
*/
DWORD dwAddress;
for(dwAddress = 0x80010000; dwAddress < 0x80200000; dwAddress += 4) {
if(IsWordPatched(dwAddress)) {
DWORD dwData = GetPatchWord(dwAddress);
audit.Upload(dwAddress, &dwData, 4);
}
}
}
void CPSFWorkArea::OnFileExportbiosarea()
{
// TODO: Add your command handler code here
if(!m_pStateDebug) return;
FILE *f = fopen("test-ram", "wb");
if(!f) return;
DWORD tmp;
DWORD i;
for(i = 0; i < 0x200000; i += 4) {
tmp = iop_getword(emu_get_iop_state(m_pStateDebug), 0x80000000 + i);
fwrite(&tmp, 1, 4, f);
}
fclose(f);
}
void CPSFWorkArea::SetVersion(int n)
{
if(m_nVersion == n) return;
((CPSFLabApp*)(AfxGetApp()))->m_nNewPSFVersion = n;
((CPSFLabApp*)(AfxGetApp()))->m_nWorkAreaVersion = n;
DeleteContents();
m_nVersion = n;
if(m_pStateDebug) {
free(m_pStateDebug);
m_pStateDebug = NULL;
}
m_pStateDebug = malloc(emu_get_state_size(m_nVersion));
emu_clear_state(m_pStateDebug, m_nVersion);
emu_set_readfile(m_pStateDebug, CPSFWorkArea__readfile_cb, this);
emu_set_console_out(m_pStateDebug, CPSFWorkArea__console_out, this);
// strcpy(m_sPSF2Path,
// (((CPSFLabApp*)(AfxGetApp()))->m_sPSF2Path)
// );
OnNewDocument();
}
int CPSFWorkArea::GetVersion()
{
return m_nVersion;
}
void CPSFWorkArea::OnUpdateFileSave(CCmdUI* pCmdUI)
{
pCmdUI->Enable(GetVersion() == 1);
}
void CPSFWorkArea::OnUpdateFileSaveas(CCmdUI* pCmdUI)
{
pCmdUI->Enable(GetVersion() == 1);
}
void CPSFWorkArea::OnUpdateEditTag(CCmdUI* pCmdUI)
{
pCmdUI->Enable(GetVersion() == 1);
}
void CPSFWorkArea::OnUpdateFileExportexe(CCmdUI* pCmdUI)
{
pCmdUI->Enable(GetVersion() == 1);
}