Changes for new built-in console-based debugger (only compiled in if SUPERMODEL_DEBUGGER defined):

- added code to create debugger object and attach it to system,
 - added new command lines options -enter-debugger and -disable-debugger,
 - added new UI input to halt execution and enter debugger (default Alt+B),
 - added new CLogger class to route all output via debugger if required.
This commit is contained in:
Nik Henson 2011-06-27 23:44:51 +00:00
parent 036c371592
commit 8a9924b884

View file

@ -57,6 +57,9 @@
#include "OSD/Windows/DirectInputSystem.h" #include "OSD/Windows/DirectInputSystem.h"
#endif #endif
CLogger *GetLogger();
void SetLogger(CLogger *logger);
/****************************************************************************** /******************************************************************************
Display Management Display Management
******************************************************************************/ ******************************************************************************/
@ -75,7 +78,8 @@ unsigned xRes, yRes; // renderer output resolution (can be smaller than GL vi
* because the actual drawing area may need to be adjusted to preserve the * because the actual drawing area may need to be adjusted to preserve the
* Model 3 aspect ratio. The new resolution will be passed back as well. * Model 3 aspect ratio. The new resolution will be passed back as well.
*/ */
static BOOL CreateGLScreen(const char *caption, unsigned *xOffsetPtr, unsigned *yOffsetPtr, unsigned *xResPtr, unsigned *yResPtr, BOOL fullScreen) static BOOL CreateGLScreen(const char *caption, unsigned *xOffsetPtr, unsigned *yOffsetPtr, unsigned *xResPtr, unsigned *yResPtr,
BOOL keepAspectRatio, BOOL fullScreen)
{ {
const SDL_VideoInfo *VideoInfo; const SDL_VideoInfo *VideoInfo;
GLenum err; GLenum err;
@ -102,15 +106,18 @@ static BOOL CreateGLScreen(const char *caption, unsigned *xOffsetPtr, unsigned *
VideoInfo = SDL_GetVideoInfo(); // what resolution did we actually get? VideoInfo = SDL_GetVideoInfo(); // what resolution did we actually get?
// Fix the aspect ratio of the resolution that the user passed to match Model 3 ratio // If required, fix the aspect ratio of the resolution that the user passed to match Model 3 ratio
xRes = (float) *xResPtr; xRes = (float) *xResPtr;
yRes = (float) *yResPtr; yRes = (float) *yResPtr;
if (keepAspectRatio)
{
model3Ratio = 496.0f/384.0f; model3Ratio = 496.0f/384.0f;
ratio = xRes/yRes; ratio = xRes/yRes;
if (yRes < (xRes/model3Ratio)) if (yRes < (xRes/model3Ratio))
xRes = yRes*model3Ratio; xRes = yRes*model3Ratio;
if (xRes < (yRes*model3Ratio)) if (xRes < (yRes*model3Ratio))
yRes = xRes/model3Ratio; yRes = xRes/model3Ratio;
}
// Center the visible area // Center the visible area
*xOffsetPtr = (*xResPtr - (unsigned) xRes)/2; *xOffsetPtr = (*xResPtr - (unsigned) xRes)/2;
@ -187,7 +194,7 @@ static CInputs *CreateInputs(CInputSystem *InputSystem, BOOL configure)
{ {
// Open an SDL window // Open an SDL window
unsigned xOffset, yOffset, xRes=496, yRes=384; unsigned xOffset, yOffset, xRes=496, yRes=384;
if (OKAY != CreateGLScreen("Supermodel - Configuring Inputs...",&xOffset,&yOffset,&xRes,&yRes,FALSE)) if (OKAY != CreateGLScreen("Supermodel - Configuring Inputs...",&xOffset,&yOffset,&xRes,&yRes,FALSE,FALSE))
{ {
ErrorLog("Unable to start SDL to configure inputs.\n"); ErrorLog("Unable to start SDL to configure inputs.\n");
return NULL; return NULL;
@ -353,10 +360,18 @@ static void LoadNVRAM(CModel3 *Model3)
All configuration management is done prior to calling Supermodel(). All configuration management is done prior to calling Supermodel().
******************************************************************************/ ******************************************************************************/
static int Supermodel(const char *zipFile, CInputs *Inputs, unsigned ppcFrequency, unsigned xResParam, unsigned yResParam, BOOL fullScreen, BOOL noThrottle, BOOL showFPS, const char *vsFile, const char *fsFile) #ifdef SUPERMODEL_DEBUGGER
int Supermodel(const char *zipFile, CModel3 *Model3, CInputs *Inputs, Debugger::CDebugger *Debugger, unsigned ppcFrequency,
unsigned xResParam, unsigned yResParam, BOOL keepAspectRatio, BOOL fullScreen, BOOL noThrottle, BOOL showFPS,
const char *vsFile, const char *fsFile)
{
#else
int Supermodel(const char *zipFile, CInputs *Inputs, unsigned ppcFrequency, unsigned xResParam, unsigned yResParam,
BOOL keepAspectRatio, BOOL fullScreen, BOOL noThrottle, BOOL showFPS, const char *vsFile, const char *fsFile)
{ {
char titleStr[128], titleFPSStr[128];
CModel3 *Model3 = new CModel3(); CModel3 *Model3 = new CModel3();
#endif // SUPERMODEL_DEBUGGER
char titleStr[128], titleFPSStr[128];
CRender2D *Render2D = new CRender2D(); CRender2D *Render2D = new CRender2D();
CRender3D *Render3D = new CRender3D(); CRender3D *Render3D = new CRender3D();
unsigned prevFPSTicks, currentFPSTicks, currentTicks, targetTicks, startTicks; unsigned prevFPSTicks, currentFPSTicks, currentTicks, targetTicks, startTicks;
@ -382,7 +397,7 @@ static int Supermodel(const char *zipFile, CInputs *Inputs, unsigned ppcFrequenc
xRes = xResParam; xRes = xResParam;
yRes = yResParam; yRes = yResParam;
sprintf(titleStr, "Supermodel - %s", Model3->GetGameInfo()->title); sprintf(titleStr, "Supermodel - %s", Model3->GetGameInfo()->title);
if (OKAY != CreateGLScreen(titleStr,&xOffset,&yOffset,&xRes,&yRes,fullScreen)) if (OKAY != CreateGLScreen(titleStr,&xOffset,&yOffset,&xRes,&yRes,keepAspectRatio,fullScreen))
return 1; return 1;
// Hide mouse if fullscreen // Hide mouse if fullscreen
@ -398,15 +413,27 @@ static int Supermodel(const char *zipFile, CInputs *Inputs, unsigned ppcFrequenc
goto QuitError; goto QuitError;
Model3->AttachRenderers(Render2D,Render3D); Model3->AttachRenderers(Render2D,Render3D);
// Emulate! // Reset emulator
Model3->Reset(); Model3->Reset();
#ifdef SUPERMODEL_DEBUGGER
// If debugger was supplied, set it as logger and attach it to system
CLogger *oldLogger = GetLogger();
if (Debugger != NULL)
{
SetLogger(Debugger);
Debugger->Attach();
}
#endif // SUPERMODEL_DEBUGGER
// Emulate!
fpsFramesElapsed = 0; fpsFramesElapsed = 0;
framesElapsed = 0; framesElapsed = 0;
prevFPSTicks = SDL_GetTicks(); prevFPSTicks = SDL_GetTicks();
startTicks = prevFPSTicks; startTicks = prevFPSTicks;
while (!quit) while (!quit)
{ {
// If not paused, run one frame // Check if paused
if (!paused) if (!paused)
{ {
// If not, run one frame // If not, run one frame
@ -420,6 +447,20 @@ static int Supermodel(const char *zipFile, CInputs *Inputs, unsigned ppcFrequenc
if (!Inputs->Poll(Model3->GetGameInfo(), xOffset, yOffset, xRes, yRes)) if (!Inputs->Poll(Model3->GetGameInfo(), xOffset, yOffset, xRes, yRes))
quit = 1; quit = 1;
#ifdef SUPERMODEL_DEBUGGER
if (Debugger != NULL)
{
Debugger->Poll();
// Check if debugger requests exit or pause
if (Debugger->CheckExit())
quit = 1;
else if (Debugger->CheckPause())
paused = 1;
else
{
#endif // SUPERMODEL_DEBUGGER
// Check UI controls // Check UI controls
if (Inputs->uiExit->Pressed()) if (Inputs->uiExit->Pressed())
{ {
@ -430,6 +471,13 @@ static int Supermodel(const char *zipFile, CInputs *Inputs, unsigned ppcFrequenc
{ {
// Reset emulator // Reset emulator
Model3->Reset(); Model3->Reset();
#ifdef SUPERMODEL_DEBUGGER
// If debugger was supplied, reset it too
if (Debugger != NULL)
Debugger->Reset();
#endif // SUPERMODEL_DEBUGGER
printf("Model 3 reset.\n"); printf("Model 3 reset.\n");
} }
else if (Inputs->uiPause->Pressed()) else if (Inputs->uiPause->Pressed())
@ -453,6 +501,12 @@ static int Supermodel(const char *zipFile, CInputs *Inputs, unsigned ppcFrequenc
{ {
// Load game state // Load game state
LoadState(Model3); LoadState(Model3);
#ifdef SUPERMODEL_DEBUGGER
// If debugger was supplied, reset it after loading state
if (Debugger != NULL)
Debugger->Reset();
#endif // SUPERMODEL_DEBUGGER
} }
else if (Inputs->uiDumpInpState->Pressed()) else if (Inputs->uiDumpInpState->Pressed())
{ {
@ -495,6 +549,15 @@ static int Supermodel(const char *zipFile, CInputs *Inputs, unsigned ppcFrequenc
// A0 11 xx (0F=time extend, 11=jumbo left right) // A0 11 xx (0F=time extend, 11=jumbo left right)
// AF 10 xx (music -- 01 seems to work) // AF 10 xx (music -- 01 seems to work)
} }
#ifdef SUPERMODEL_DEBUGGER
else if (Inputs->uiEnterDebugger->Pressed())
{
// Break execution and enter debugger
Debugger->ForceBreak(true);
}
}
}
#endif // SUPERMODEL_DEBUGGER
// FPS and frame rate // FPS and frame rate
currentFPSTicks = SDL_GetTicks(); currentFPSTicks = SDL_GetTicks();
@ -528,11 +591,22 @@ static int Supermodel(const char *zipFile, CInputs *Inputs, unsigned ppcFrequenc
} }
} }
#ifdef SUPERMODEL_DEBUGGER
// If debugger was supplied, detach it from system and restore old logger
if (Debugger != NULL)
{
Debugger->Detach();
SetLogger(oldLogger);
}
#endif // SUPERMODEL_DEBUGGER
// Save NVRAM // Save NVRAM
SaveNVRAM(Model3); SaveNVRAM(Model3);
// Shut down // Shut down
#ifndef SUPERMODEL_DEBUGGER
delete Model3; delete Model3;
#endif // SUPERMODEL_DEBUGGER
delete Render2D; delete Render2D;
delete Render3D; delete Render3D;
@ -561,14 +635,18 @@ static int Supermodel(const char *zipFile, CInputs *Inputs, unsigned ppcFrequenc
printf("SR%d=%08X\n", i, ppc_read_sr(i)); printf("SR%d=%08X\n", i, ppc_read_sr(i));
printf("SDR1=%08X\n", ppc_read_spr(SPR603E_SDR1)); printf("SDR1=%08X\n", ppc_read_spr(SPR603E_SDR1));
*/ */
#ifdef SUPERMODEL_SOUND
printf("68K PC =%08X\n", Turbo68KReadPC()); printf("68K PC =%08X\n", Turbo68KReadPC());
#endif
#endif #endif
return 0; return 0;
// Quit with an error // Quit with an error
QuitError: QuitError:
#ifndef SUPERMODEL_DEBUGGER
delete Model3; delete Model3;
#endif // SUPERMODEL_DEBUGGER
delete Render2D; delete Render2D;
delete Render3D; delete Render3D;
return 1; return 1;
@ -579,14 +657,28 @@ QuitError:
Error and Debug Logging Error and Debug Logging
******************************************************************************/ ******************************************************************************/
#define DEBUG_LOG_FILE "debug.log" static CLogger *s_logger = NULL;
#define ERROR_LOG_FILE "error.log"
/*
* Returns the current logger.
*/
CLogger *GetLogger()
{
return s_logger;
}
/*
* Sets the current logger.
*/
void SetLogger(CLogger *logger)
{
s_logger = logger;
}
/* /*
* DebugLog(fmt, ...): * DebugLog(fmt, ...):
* *
* Prints to debug log. The file is opened and closed each time so that its * Logs a debug message with the logger.
* contents are preserved even if the program crashes.
* *
* Parameters: * Parameters:
* fmt Format string (same as printf()). * fmt Format string (same as printf()).
@ -594,28 +686,18 @@ QuitError:
*/ */
void DebugLog(const char *fmt, ...) void DebugLog(const char *fmt, ...)
{ {
#ifdef DEBUG if (s_logger == NULL)
char string[1024]; return;
va_list vl; va_list vl;
FILE *fp;
fp = fopen(DEBUG_LOG_FILE, "ab");
if (NULL != fp)
{
va_start(vl, fmt); va_start(vl, fmt);
vsprintf(string, fmt, vl); s_logger->DebugLog(fmt, vl);
va_end(vl); va_end(vl);
fprintf(fp, string);
fclose(fp);
}
#endif
} }
/* /*
* InfoLog(fmt, ...); * InfoLog(fmt, ...);
* *
* Prints information to the error log file but does not print to stderr. This * Logs an info message with the logger.
* is useful for logging non-error information.
* *
* Parameters: * Parameters:
* fmt Format string (same as printf()). * fmt Format string (same as printf()).
@ -623,30 +705,18 @@ void DebugLog(const char *fmt, ...)
*/ */
void InfoLog(const char *fmt, ...) void InfoLog(const char *fmt, ...)
{ {
char string[4096]; if (s_logger == NULL)
return;
va_list vl; va_list vl;
FILE *fp;
va_start(vl, fmt); va_start(vl, fmt);
vsprintf(string, fmt, vl); s_logger->InfoLog(fmt, vl);
va_end(vl); va_end(vl);
fp = fopen(ERROR_LOG_FILE, "ab");
if (NULL != fp)
{
fprintf(fp, "%s\n", string);
fclose(fp);
}
DebugLog("Info: ");
DebugLog(string);
DebugLog("\n");
} }
/* /*
* ErrorLog(fmt, ...): * ErrorLog(fmt, ...):
* *
* Prints an error to stderr and the error log file. * Logs an error message with the logger.
* *
* Parameters: * Parameters:
* fmt Format string (same as printf()). * fmt Format string (same as printf()).
@ -657,31 +727,116 @@ void InfoLog(const char *fmt, ...)
*/ */
BOOL ErrorLog(const char *fmt, ...) BOOL ErrorLog(const char *fmt, ...)
{ {
char string[4096]; if (s_logger == NULL)
return FAIL;
va_list vl; va_list vl;
va_start(vl, fmt);
s_logger->ErrorLog(fmt, vl);
va_end(vl);
return FAIL;
}
#define DEBUG_LOG_FILE "debug.log"
#define ERROR_LOG_FILE "error.log"
/*
* Default logger that logs to debug and error log files.
*/
class CFileLogger : public CLogger
{
private:
const char *m_debugLogFile;
const char *m_errorLogFile;
public:
CFileLogger(const char *debugLogFile, const char *errorLogFile) :
m_debugLogFile(debugLogFile), m_errorLogFile(errorLogFile)
{
//
}
/*
* DebugLog(fmt, ...):
*
* Prints to debug log. The file is opened and closed each time so that its
* contents are preserved even if the program crashes.
*/
void DebugLog(const char *fmt, va_list vl)
{
#ifdef DEBUG
char string[1024];
FILE *fp; FILE *fp;
va_start(vl, fmt); fp = fopen(m_debugLogFile, "ab");
if (NULL != fp)
{
vsprintf(string, fmt, vl); vsprintf(string, fmt, vl);
va_end(vl); fprintf(fp, string);
fprintf(stderr, "Error: %s\n", string); fclose(fp);
}
#endif // DEBUG
}
fp = fopen(ERROR_LOG_FILE, "ab"); /*
* InfoLog(fmt, ...);
*
* Prints information to the error log file but does not print to stderr. This
* is useful for logging non-error information.
*/
void InfoLog(const char *fmt, va_list vl)
{
char string[4096];
FILE *fp;
vsprintf(string, fmt, vl);
fp = fopen(m_errorLogFile, "ab");
if (NULL != fp) if (NULL != fp)
{ {
fprintf(fp, "%s\n", string); fprintf(fp, "%s\n", string);
fclose(fp); fclose(fp);
} }
DebugLog("Error: "); CLogger::DebugLog("Info: ");
DebugLog(string); CLogger::DebugLog(string);
DebugLog("\n"); CLogger::DebugLog("\n");
}
return FAIL; /*
* ErrorLog(fmt, ...):
*
* Prints an error to stderr and the error log file.
*/
void ErrorLog(const char *fmt, va_list vl)
{
char string[4096];
FILE *fp;
vsprintf(string, fmt, vl);
fprintf(stderr, "Error: %s\n", string);
fp = fopen(m_errorLogFile, "ab");
if (NULL != fp)
{
fprintf(fp, "%s\n", string);
fclose(fp);
}
CLogger::DebugLog("Error: ");
CLogger::DebugLog(string);
CLogger::DebugLog("\n");
}
void ClearLogs()
{
#ifdef DEBUG
ClearLog(DEBUG_LOG_FILE, "Supermodel v"SUPERMODEL_VERSION" Debug Log");
#endif // DEBUG
ClearLog(ERROR_LOG_FILE, "Supermodel v"SUPERMODEL_VERSION" Error Log");
} }
// Clear log file // Clear log file
static void ClearLog(const char *file, const char *title) void ClearLog(const char *file, const char *title)
{ {
FILE *fp = fopen(file, "w"); FILE *fp = fopen(file, "w");
if (NULL != fp) if (NULL != fp)
@ -694,7 +849,7 @@ static void ClearLog(const char *file, const char *title)
fclose(fp); fclose(fp);
} }
} }
};
/****************************************************************************** /******************************************************************************
Diagnostic Commands Diagnostic Commands
@ -772,7 +927,7 @@ static void PrintGLInfo(BOOL printExtensions)
GLint value; GLint value;
unsigned xOffset, yOffset, xRes=496, yRes=384; unsigned xOffset, yOffset, xRes=496, yRes=384;
if (OKAY != CreateGLScreen("Supermodel - Querying OpenGL Information...",&xOffset,&yOffset,&xRes,&yRes,FALSE)) if (OKAY != CreateGLScreen("Supermodel - Querying OpenGL Information...",&xOffset,&yOffset,&xRes,&yRes,FALSE,FALSE))
{ {
ErrorLog("Unable to query OpenGL.\n"); ErrorLog("Unable to query OpenGL.\n");
return; return;
@ -847,6 +1002,10 @@ static void Help(void)
puts(""); puts("");
puts("Emulation Options:"); puts("Emulation Options:");
puts(" -ppc-frequency=<f> Set PowerPC frequency in MHz [Default: 25]"); puts(" -ppc-frequency=<f> Set PowerPC frequency in MHz [Default: 25]");
#ifdef SUPERMODEL_DEBUGGER
puts(" -disable-debugger Completely disable debugger functionality");
puts(" -enter-debugger Enter debugger at start of emulation");
#endif // SUPERMODEL_DEBUGGER
puts(""); puts("");
puts("Video Options:"); puts("Video Options:");
puts(" -res=<x>,<y> Resolution"); puts(" -res=<x>,<y> Resolution");
@ -897,6 +1056,9 @@ int main(int argc, char **argv)
{ {
int i, ret; int i, ret;
int cmd=0, fileIdx=0, cmdFullScreen=0, cmdNoThrottle=0, cmdShowFPS=0, cmdPrintInputs=0, cmdConfigInputs=0, cmdPrintGames=0, cmdDis=0, cmdPrintGLInfo=0; int cmd=0, fileIdx=0, cmdFullScreen=0, cmdNoThrottle=0, cmdShowFPS=0, cmdPrintInputs=0, cmdConfigInputs=0, cmdPrintGames=0, cmdDis=0, cmdPrintGLInfo=0;
#ifdef SUPERMODEL_DEBUGGER
int cmdDisableDebugger = 0, cmdEnterDebugger=0;
#endif // SUPERMODEL_DEBUGGER
unsigned n, xRes=496, yRes=384, ppcFrequency=25000000; unsigned n, xRes=496, yRes=384, ppcFrequency=25000000;
char *vsFile = NULL, *fsFile = NULL, *inpSysName = NULL; char *vsFile = NULL, *fsFile = NULL, *inpSysName = NULL;
UINT32 addr; UINT32 addr;
@ -908,10 +1070,10 @@ int main(int argc, char **argv)
return 0; return 0;
} }
#ifdef DEBUG // Create default logger
ClearLog(DEBUG_LOG_FILE, "Supermodel v"SUPERMODEL_VERSION" Debug Log"); CFileLogger Logger(DEBUG_LOG_FILE, ERROR_LOG_FILE);
#endif Logger.ClearLogs();
ClearLog(ERROR_LOG_FILE, "Supermodel v"SUPERMODEL_VERSION" Error Log"); SetLogger(&Logger);
// Parse command line // Parse command line
for (i = 1; i < argc; i++) for (i = 1; i < argc; i++)
@ -937,6 +1099,12 @@ int main(int argc, char **argv)
ppcFrequency = f*1000000; ppcFrequency = f*1000000;
} }
} }
#ifdef SUPERMODEL_DEBUGGER
else if (!strncmp(argv[i],"-disable-debugger",17))
cmd = cmdDisableDebugger = 1;
else if (!strncmp(argv[i],"-enter-debugger",15))
cmd = cmdEnterDebugger = 1;
#endif // SUPERMODEL_DEBUGGER
else if (!strncmp(argv[i],"-res",4)) else if (!strncmp(argv[i],"-res",4))
{ {
unsigned x, y; unsigned x, y;
@ -1017,6 +1185,10 @@ int main(int argc, char **argv)
CInputSystem *InputSystem = NULL; CInputSystem *InputSystem = NULL;
CInputs *Inputs = NULL; CInputs *Inputs = NULL;
int exitCode = 0; int exitCode = 0;
#ifdef SUPERMODEL_DEBUGGER
CModel3 *Model3 = NULL;
Debugger::CSupermodelDebugger *Debugger = NULL;
#endif // SUPERMODEL_DEBUGGER
// Create input system (default is SDL) // Create input system (default is SDL)
if (inpSysName == NULL || stricmp(inpSysName, "sdl") == 0) if (inpSysName == NULL || stricmp(inpSysName, "sdl") == 0)
@ -1028,7 +1200,7 @@ int main(int argc, char **argv)
InputSystem = new CDirectInputSystem(false, true, false); InputSystem = new CDirectInputSystem(false, true, false);
else if (stricmp(inpSysName, "rawinput") == 0) else if (stricmp(inpSysName, "rawinput") == 0)
InputSystem = new CDirectInputSystem(true, false, false); InputSystem = new CDirectInputSystem(true, false, false);
#endif #endif // SUPERMODEL_WIN32
else else
{ {
ErrorLog("Unknown input system: '%s'.\n", inpSysName); ErrorLog("Unknown input system: '%s'.\n", inpSysName);
@ -1084,8 +1256,26 @@ int main(int argc, char **argv)
} }
} }
#ifdef SUPERMODEL_DEBUGGER
// Create Model3
Model3 = new CModel3();
// Create Supermodel debugger unless debugging is disabled
if (!cmdDisableDebugger)
{
Debugger = new Debugger::CSupermodelDebugger(Model3, Inputs, &Logger);
// If -enter-debugger option was set force debugger to break straightaway
if (cmdEnterDebugger)
Debugger->ForceBreak(true);
}
// Fire up Supermodel with debugger
exitCode = Supermodel(argv[fileIdx],Model3,Inputs,Debugger,ppcFrequency,xRes,yRes,TRUE,cmdFullScreen,cmdNoThrottle,cmdShowFPS,vsFile,fsFile);
if (Debugger != NULL)
delete Debugger;
delete Model3;
#else
// Fire up Supermodel // Fire up Supermodel
exitCode = Supermodel(argv[fileIdx],Inputs,ppcFrequency,xRes,yRes,cmdFullScreen,cmdNoThrottle,cmdShowFPS,vsFile,fsFile); exitCode = Supermodel(argv[fileIdx],Inputs,ppcFrequency,xRes,yRes,TRUE,cmdFullScreen,cmdNoThrottle,cmdShowFPS,vsFile,fsFile);
#endif // SUPERMODEL_DEBUGGER
Exit: Exit:
if (Inputs != NULL) if (Inputs != NULL)