diff --git a/src/debug.cpp b/src/debug.cpp index 47e873ed..89bcafa8 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -421,12 +421,12 @@ int condition(watchpointinfo* wp) //--------------------- -volatile int codecount, datacount, undefinedcount; -unsigned char *cdloggerdata; +volatile int codecount = 0, datacount = 0, undefinedcount = 0; +unsigned char *cdloggerdata = NULL; unsigned int cdloggerdataSize = 0; -static int indirectnext; +static int indirectnext = 0; -int debug_loggingCD; +int debug_loggingCD = 0; //called by the cpu to perform logging if CDLogging is enabled void LogCDVectors(int which){ diff --git a/src/drivers/Qt/CodeDataLogger.cpp b/src/drivers/Qt/CodeDataLogger.cpp index 4ec7a510..55e6a584 100644 --- a/src/drivers/Qt/CodeDataLogger.cpp +++ b/src/drivers/Qt/CodeDataLogger.cpp @@ -4,6 +4,14 @@ #include #include +#include "../../types.h" +#include "../../fceu.h" +#include "../../cart.h" +#include "../../x6502.h" +#include "../../debug.h" +#include "../../ppu.h" + +#include "Qt/ConsoleUtilities.h" #include "Qt/CodeDataLogger.h" #include "Qt/main.h" #include "Qt/dface.h" @@ -11,6 +19,12 @@ #include "Qt/config.h" #include "Qt/fceuWrapper.h" +static int autoSaveCDL = true; +static int autoLoadCDL = true; +static int autoResumeCDL = false; +static char loadedcdfile[512] = {0}; + +static int getDefaultCDLFile( char *filepath ); //---------------------------------------------------- CodeDataLoggerDialog_t::CodeDataLoggerDialog_t(QWidget *parent) : QDialog( parent ) @@ -20,7 +34,6 @@ CodeDataLoggerDialog_t::CodeDataLoggerDialog_t(QWidget *parent) QGridLayout *grid; QGroupBox *frame, *subframe; QPushButton *btn; - QLabel *lbl; updateTimer = new QTimer( this ); @@ -30,27 +43,42 @@ CodeDataLoggerDialog_t::CodeDataLoggerDialog_t(QWidget *parent) mainLayout = new QVBoxLayout(); vbox1 = new QVBoxLayout(); + hbox = new QHBoxLayout(); grid = new QGridLayout(); - lbl = new QLabel( tr("Press Start to Run Logger") ); + statLabel = new QLabel( tr(" Logger is Paused: Press Start to Run ") ); cdlFileLabel = new QLabel( tr("CDL File:") ); vbox1->addLayout( grid ); - vbox1->addWidget( lbl ); + vbox1->addLayout( hbox ); vbox1->addWidget( cdlFileLabel ); + hbox->addWidget( statLabel, 0, Qt::AlignHCenter ); + frame = new QGroupBox(tr("Code/Data Log Status")); frame->setLayout( vbox1 ); - prgLoggedCodeLabel = new QLabel( tr("0x00000 0.00%") ); - prgLoggedDataLabel = new QLabel( tr("0x00000 0.00%") ); - prgUnloggedLabel = new QLabel( tr("0x00000 0.00%") ); - chrLoggedCodeLabel = new QLabel( tr("0x00000 0.00%") ); - chrLoggedDataLabel = new QLabel( tr("0x00000 0.00%") ); - chrUnloggedLabel = new QLabel( tr("0x00000 0.00%") ); + prgLoggedCodeLabel = new QLabel( tr("0x000000 0.00%") ); + prgLoggedDataLabel = new QLabel( tr("0x000000 0.00%") ); + prgUnloggedLabel = new QLabel( tr("0x000000 0.00%") ); + chrLoggedCodeLabel = new QLabel( tr("0x000000 0.00%") ); + chrLoggedDataLabel = new QLabel( tr("0x000000 0.00%") ); + chrUnloggedLabel = new QLabel( tr("0x000000 0.00%") ); autoSaveCdlCbox = new QCheckBox( tr("Auto-save .CDL when closing ROMs") ); autoLoadCdlCbox = new QCheckBox( tr("Auto-load .CDL when opening this window") ); autoResumeLogCbox = new QCheckBox( tr("Auto-resume logging when loading ROMs") ); + g_config->getOption("SDL.AutoSaveCDL", &autoSaveCDL); + g_config->getOption("SDL.AutoLoadCDL", &autoLoadCDL); + g_config->getOption("SDL.AutoResumeCDL", &autoResumeCDL); + + autoSaveCdlCbox->setChecked( autoSaveCDL ); + autoLoadCdlCbox->setChecked( autoLoadCDL ); + autoResumeLogCbox->setChecked( autoResumeCDL ); + + connect(autoSaveCdlCbox , SIGNAL(stateChanged(int)), this, SLOT(autoSaveCdlStateChange(int)) ); + connect(autoLoadCdlCbox , SIGNAL(stateChanged(int)), this, SLOT(autoLoadCdlStateChange(int)) ); + connect(autoResumeLogCbox, SIGNAL(stateChanged(int)), this, SLOT(autoResumeCdlStateChange(int)) ); + subframe = new QGroupBox(tr("PRG Logged as Code")); vbox = new QVBoxLayout(); vbox->addWidget( prgLoggedCodeLabel ); @@ -97,9 +125,11 @@ CodeDataLoggerDialog_t::CodeDataLoggerDialog_t(QWidget *parent) vbox1->addLayout( grid ); btn = new QPushButton( tr("Reset Log") ); grid->addWidget( btn, 0, 0, Qt::AlignCenter ); + connect( btn, SIGNAL(clicked(void)), this, SLOT(ResetCDLogClicked(void))); - btn = new QPushButton( tr("Start") ); - grid->addWidget( btn, 0, 1, Qt::AlignCenter ); + startPauseButton = new QPushButton( tr("Start") ); + grid->addWidget( startPauseButton, 0, 1, Qt::AlignCenter ); + connect( startPauseButton, SIGNAL(clicked(void)), this, SLOT(StartPauseCDLogClicked(void))); btn = new QPushButton( tr("Save") ); grid->addWidget( btn, 0, 2, Qt::AlignCenter ); @@ -137,6 +167,12 @@ CodeDataLoggerDialog_t::CodeDataLoggerDialog_t(QWidget *parent) updateTimer->start( 100 ); // 10hz + if (autoLoadCDL) + { + char nameo[2048]; + getDefaultCDLFile( nameo ); + LoadCDLog(nameo); + } } //---------------------------------------------------- CodeDataLoggerDialog_t::~CodeDataLoggerDialog_t(void) @@ -161,8 +197,334 @@ void CodeDataLoggerDialog_t::closeWindow(void) deleteLater(); } //---------------------------------------------------- -void CodeDataLoggerDialog_t::updatePeriodic(void) +void CodeDataLoggerDialog_t::autoSaveCdlStateChange(int state) { + autoSaveCDL = state != Qt::Unchecked; + g_config->setOption("SDL.AutoSaveCDL", autoSaveCDL); +} +//---------------------------------------------------- +void CodeDataLoggerDialog_t::autoLoadCdlStateChange(int state) +{ + autoLoadCDL = state != Qt::Unchecked; + + g_config->setOption("SDL.AutoLoadCDL", autoLoadCDL); +} +//---------------------------------------------------- +void CodeDataLoggerDialog_t::autoResumeCdlStateChange(int state) +{ + autoResumeCDL = state != Qt::Unchecked; + + g_config->setOption("SDL.AutoResumeCDL", autoResumeCDL); +} +//---------------------------------------------------- +void CodeDataLoggerDialog_t::updatePeriodic(void) +{ + char str[768]; + float fcodecount = codecount; + float fdatacount = datacount; + float frendercount = rendercount; + float fvromreadcount = vromreadcount; + float fundefinedcount = undefinedcount; + float fundefinedvromcount = undefinedvromcount; + float fromsize = cdloggerdataSize; + float fvromsize = (cdloggerVideoDataSize != 0) ? cdloggerVideoDataSize : 1; + + if ( FCEUI_GetLoggingCD() ) + { + startPauseButton->setText( tr("Pause") ); + statLabel->setText( tr(" Logger is Running: Press Pause to Stop ") ); + statLabel->setStyleSheet("background-color: green; color: white;"); + } + else + { + startPauseButton->setText( tr("Start") ); + statLabel->setText( tr(" Logger is Paused: Press Start to Run ") ); + statLabel->setStyleSheet("background-color: red; color: white;"); + } + + if ( cdloggerdataSize > 0 ) + { + sprintf(str,"0x%06x %.2f%%", codecount, (fcodecount / fromsize) * 100); + prgLoggedCodeLabel->setText( tr(str) ); + + sprintf(str,"0x%06x %.2f%%", datacount,(fdatacount / fromsize) * 100); + prgLoggedDataLabel->setText( tr(str) ); + + sprintf(str,"0x%06x %.2f%%", undefinedcount, (fundefinedcount / fromsize) * 100); + prgUnloggedLabel->setText( tr(str) ); + + sprintf(str,"0x%06x %.2f%%", rendercount, (frendercount / fvromsize) * 100); + chrLoggedCodeLabel->setText( tr(str) ); + + sprintf(str,"0x%06x %.2f%%", vromreadcount, (fvromreadcount / fvromsize) * 100); + chrLoggedDataLabel->setText( tr(str) ); + + sprintf(str,"0x%06x %.2f%%", undefinedvromcount, (fundefinedvromcount / fvromsize) * 100); + chrUnloggedLabel->setText( tr(str) ); + } + else + { + prgLoggedCodeLabel->setText( tr("------") ); + prgLoggedDataLabel->setText( tr("------") ); + prgUnloggedLabel->setText( tr("------") ); + chrLoggedCodeLabel->setText( tr("------") ); + chrLoggedDataLabel->setText( tr("------") ); + chrUnloggedLabel->setText( tr("------") ); + } + + sprintf( str, "CDL File: %s", loadedcdfile ); + + cdlFileLabel->setText( tr(str) ); +} +//---------------------------------------------------- +void CodeDataLoggerDialog_t::ResetCDLogClicked(void) +{ + ::ResetCDLog(); +} +//---------------------------------------------------- +void CodeDataLoggerDialog_t::StartPauseCDLogClicked(void) +{ + if ( FCEUI_GetLoggingCD() ) + { + printf("CD Logging Paused\n"); + PauseCDLogging(); + startPauseButton->setText( tr("Start") ); + } + else + { + printf("CD Logging Started\n"); + StartCDLogging(); + startPauseButton->setText( tr("Pause") ); + } +} +//---------------------------------------------------- +static int getDefaultCDLFile( char *filepath ) +{ + const char *romFile; + char dir[512], baseFile[256]; + + filepath[0] = 0; + + romFile = getRomFile(); + + if ( romFile == NULL ) + { + return -1; + } + + parseFilepath( romFile, dir, baseFile ); + + sprintf( filepath, "%s/%s.cdl", dir, baseFile ); + + //printf("%s\n", filepath ); + + return 0; +} +//---------------------------------------------------- +void FreeCDLog(void) +{ + fceuWrapperLock(); + if (cdloggerdata) + { + free(cdloggerdata); + cdloggerdata = NULL; + cdloggerdataSize = 0; + } + if (cdloggervdata) + { + free(cdloggervdata); + cdloggervdata = NULL; + cdloggerVideoDataSize = 0; + } + fceuWrapperUnLock(); +} +//---------------------------------------------------- +void InitCDLog(void) +{ + fceuWrapperLock(); + cdloggerdataSize = PRGsize[0]; + cdloggerdata = (unsigned char*)malloc(cdloggerdataSize); + if (!CHRram[0] || (CHRptr[0] == PRGptr[0])) { // Some kind of workaround for my OneBus VRAM hack, will remove it if I find another solution for that + cdloggerVideoDataSize = CHRsize[0]; + cdloggervdata = (unsigned char*)malloc(cdloggerVideoDataSize); + } else { + if (GameInfo->type != GIT_NSF) { + cdloggerVideoDataSize = 0; + cdloggervdata = (unsigned char*)malloc(8192); + } + } + fceuWrapperUnLock(); +} +//---------------------------------------------------- +void ResetCDLog(void) +{ + if ( GameInfo == NULL ) + { + return; + } + fceuWrapperLock(); + + codecount = datacount = rendercount = vromreadcount = 0; + undefinedcount = cdloggerdataSize; + + if ( cdloggerdata != NULL ) + { + memset(cdloggerdata, 0, cdloggerdataSize); + } + if (cdloggerVideoDataSize != 0) + { + undefinedvromcount = cdloggerVideoDataSize; + + if ( cdloggervdata != NULL ) + { + memset(cdloggervdata, 0, cdloggerVideoDataSize); + } + } + else + { + if (GameInfo->type != GIT_NSF) + { + undefinedvromcount = 8192; + memset(cdloggervdata, 0, 8192); + } + } + fceuWrapperUnLock(); +} +//---------------------------------------------------- +bool LoadCDLog(const char* nameo) +{ + FILE *FP; + int i,j; + + FP = fopen(nameo, "rb"); + if (FP == NULL) + return false; + + for(i = 0;i < (int)cdloggerdataSize;i++) + { + j = fgetc(FP); + if (j == EOF) + break; + if ((j & 1) && !(cdloggerdata[i] & 1)) + codecount++; //if the new byte has something logged and + if ((j & 2) && !(cdloggerdata[i] & 2)) + datacount++; //and the old one doesn't. Then increment + if ((j & 3) && !(cdloggerdata[i] & 3)) + undefinedcount--; //the appropriate counter. + cdloggerdata[i] |= j; + } + + if(cdloggerVideoDataSize != 0) + { + for(i = 0;i < (int)cdloggerVideoDataSize;i++) + { + j = fgetc(FP); + if(j == EOF)break; + if((j & 1) && !(cdloggervdata[i] & 1))rendercount++; //if the new byte has something logged and + if((j & 2) && !(cdloggervdata[i] & 2))vromreadcount++; //if the new byte has something logged and + if((j & 3) && !(cdloggervdata[i] & 3))undefinedvromcount--; //the appropriate counter. + cdloggervdata[i] |= j; + } + } + + fclose(FP); + RenameCDLog(nameo); + + return true; +} +//---------------------------------------------------- +void StartCDLogging(void) +{ + fceuWrapperLock(); + FCEUI_SetLoggingCD(1); + //EnableTracerMenuItems(); + //SetDlgItemText(hCDLogger, BTN_CDLOGGER_START_PAUSE, "Pause"); + fceuWrapperUnLock(); +} +//---------------------------------------------------- +bool PauseCDLogging(void) +{ + // can't pause while Trace Logger is using + //if ((logging) && (logging_options & LOG_NEW_INSTRUCTIONS)) + //{ + // MessageBox(hCDLogger, "The Trace Logger is currently using this for some of its features.\nPlease turn the Trace Logger off and try again.","Unable to Pause Code/Data Logger", MB_OK); + // return false; + //} + fceuWrapperLock(); + FCEUI_SetLoggingCD(0); + //EnableTracerMenuItems(); + //SetDlgItemText(hCDLogger, BTN_CDLOGGER_START_PAUSE, "Start"); + fceuWrapperUnLock(); + return true; +} +//---------------------------------------------------- +void CDLoggerROMClosed(void) +{ + PauseCDLogging(); + if (autoSaveCDL) + { + SaveCDLogFile(); + } +} +//---------------------------------------------------- +void CDLoggerROMChanged(void) +{ + FreeCDLog(); + InitCDLog(); + ResetCDLog(); + RenameCDLog(""); + + if (!autoResumeCDL) + return; + + // try to load respective CDL file + char nameo[1024]; + getDefaultCDLFile( nameo ); + + FILE *FP; + FP = fopen(nameo, "rb"); + if (FP != NULL) + { + // .cdl file with this ROM name exists + fclose(FP); + //if (!hCDLogger) + //{ + // DoCDLogger(); + //} + if (LoadCDLog(nameo)) + { + StartCDLogging(); + } + } +} +//---------------------------------------------------- +void RenameCDLog(const char* newName) +{ + strcpy(loadedcdfile, newName); +} +//---------------------------------------------------- +void SaveCDLogFile(void) +{ + if (loadedcdfile[0] == 0) + { + char nameo[1024]; + getDefaultCDLFile( nameo ); + RenameCDLog(nameo); + } + + FILE *FP; + FP = fopen(loadedcdfile, "wb"); + if (FP == NULL) + { + FCEUD_PrintError("Error Saving File"); + return; + } + fwrite(cdloggerdata, cdloggerdataSize, 1, FP); + if (cdloggerVideoDataSize != 0) + { + fwrite(cdloggervdata, cdloggerVideoDataSize, 1, FP); + } + fclose(FP); } //---------------------------------------------------- diff --git a/src/drivers/Qt/CodeDataLogger.h b/src/drivers/Qt/CodeDataLogger.h index 301e710e..c1782041 100644 --- a/src/drivers/Qt/CodeDataLogger.h +++ b/src/drivers/Qt/CodeDataLogger.h @@ -25,24 +25,43 @@ class CodeDataLoggerDialog_t : public QDialog ~CodeDataLoggerDialog_t(void); protected: - QTimer *updateTimer; - QLabel *prgLoggedCodeLabel; - QLabel *prgLoggedDataLabel; - QLabel *prgUnloggedLabel; - QLabel *chrLoggedCodeLabel; - QLabel *chrLoggedDataLabel; - QLabel *chrUnloggedLabel; - QLabel *cdlFileLabel; - QCheckBox *autoSaveCdlCbox; - QCheckBox *autoLoadCdlCbox; - QCheckBox *autoResumeLogCbox; + QTimer *updateTimer; + QLabel *prgLoggedCodeLabel; + QLabel *prgLoggedDataLabel; + QLabel *prgUnloggedLabel; + QLabel *chrLoggedCodeLabel; + QLabel *chrLoggedDataLabel; + QLabel *chrUnloggedLabel; + QLabel *cdlFileLabel; + QLabel *statLabel; + QCheckBox *autoSaveCdlCbox; + QCheckBox *autoLoadCdlCbox; + QCheckBox *autoResumeLogCbox; + QPushButton *startPauseButton; void closeEvent(QCloseEvent *bar); + private: public slots: void closeWindow(void); private slots: void updatePeriodic(void); + void ResetCDLogClicked(void); + void StartPauseCDLogClicked(void); + void autoSaveCdlStateChange(int state); + void autoLoadCdlStateChange(int state); + void autoResumeCdlStateChange(int state); }; +void InitCDLog(void); +void ResetCDLog(void); +void FreeCDLog(void); +void StartCDLogging(void); +bool PauseCDLogging(void); +bool LoadCDLog(const char* nameo); +void RenameCDLog(const char* newName); +void CDLoggerROMClosed(void); +void CDLoggerROMChanged(void); +void SaveCDLogFile(void); + diff --git a/src/drivers/Qt/ConsoleUtilities.cpp b/src/drivers/Qt/ConsoleUtilities.cpp index d118dd7d..c9fa3a48 100644 --- a/src/drivers/Qt/ConsoleUtilities.cpp +++ b/src/drivers/Qt/ConsoleUtilities.cpp @@ -83,3 +83,63 @@ int getFileBaseName( const char *filepath, char *base ) return end; } //--------------------------------------------------------------------------- +int parseFilepath( const char *filepath, char *dir, char *base, char *suffix ) +{ + int i=0,j=0,end=0; + if ( filepath == NULL ) + { + base[0] = 0; + return 0; + } + i=0; j=0; + while ( filepath[i] != 0 ) + { + if ( (filepath[i] == '/') || (filepath[i] == '\\') ) + { + j = i+1; + } + if ( dir ) + { + dir[i] = filepath[i]; + } + i++; + } + if ( dir ) + { + dir[j] = 0; + } + i = j; + + if ( base == NULL ) + { + return end; + } + + j=0; + while ( filepath[i] != 0 ) + { + base[j] = filepath[i]; i++; j++; + } + base[j] = 0; end=j; + + if ( suffix ) + { + suffix[0] = 0; + } + + while ( j > 1 ) + { + j--; + if ( base[j] == '.' ) + { + if ( suffix ) + { + strcpy( suffix, &base[j] ); + } + end=j; base[j] = 0; + break; + } + } + return end; +} +//--------------------------------------------------------------------------- diff --git a/src/drivers/Qt/ConsoleUtilities.h b/src/drivers/Qt/ConsoleUtilities.h index e55e0361..12838ddc 100644 --- a/src/drivers/Qt/ConsoleUtilities.h +++ b/src/drivers/Qt/ConsoleUtilities.h @@ -5,3 +5,5 @@ int getDirFromFile( const char *path, char *dir ); const char *getRomFile( void ); int getFileBaseName( const char *filepath, char *base ); + +int parseFilepath( const char *filepath, char *dir, char *base, char *suffix = NULL ); diff --git a/src/drivers/Qt/config.cpp b/src/drivers/Qt/config.cpp index 3fec6409..35d6b0f2 100644 --- a/src/drivers/Qt/config.cpp +++ b/src/drivers/Qt/config.cpp @@ -263,6 +263,11 @@ InitConfig() config->addOption("autoLoadDebugFiles", "SDL.AutoLoadDebugFiles", 1); config->addOption("autoOpenDebugger" , "SDL.AutoOpenDebugger" , 0); + // Code Data Logger Options + config->addOption("autoSaveCDL" , "SDL.AutoSaveCDL", 1); + config->addOption("autoLoadCDL" , "SDL.AutoLoadCDL", 1); + config->addOption("autoResumeCDL", "SDL.AutoResumeCDL", 0); + // overwrite the config file? config->addOption("no-config", "SDL.NoConfig", 0); diff --git a/src/drivers/Qt/fceuWrapper.cpp b/src/drivers/Qt/fceuWrapper.cpp index f618991f..0f204e16 100644 --- a/src/drivers/Qt/fceuWrapper.cpp +++ b/src/drivers/Qt/fceuWrapper.cpp @@ -16,6 +16,7 @@ #include "Qt/unix-netplay.h" #include "Qt/HexEditor.h" #include "Qt/SymbolicDebug.h" +#include "Qt/CodeDataLogger.h" #include "Qt/ConsoleDebugger.h" #include "Qt/ConsoleWindow.h" #include "Qt/fceux_git_info.h" @@ -247,6 +248,8 @@ int LoadGame(const char *path) debugSymbolTable.loadGameSymbols(); + CDLoggerROMChanged(); + int state_to_load; g_config->getOption("SDL.AutoLoadState", &state_to_load); if (state_to_load >= 0 && state_to_load < 10){ @@ -299,6 +302,7 @@ CloseGame(void) debugSymbolTable.save(); debugSymbolTable.clear(); + CDLoggerROMClosed(); int state_to_save; g_config->getOption("SDL.AutoSaveState", &state_to_save); @@ -946,17 +950,23 @@ static void DoFun(int frameskip, int periodic_saves) void fceuWrapperLock(void) { mutexPending++; - consoleWindow->mutex->lock(); + if ( consoleWindow != NULL ) + { + consoleWindow->mutex->lock(); + } mutexPending--; mutexLocks++; } bool fceuWrapperTryLock(int timeout) { - bool lockAcq; + bool lockAcq = false; mutexPending++; - lockAcq = consoleWindow->mutex->tryLock( timeout ); + if ( consoleWindow != NULL ) + { + lockAcq = consoleWindow->mutex->tryLock( timeout ); + } mutexPending--; if ( lockAcq ) @@ -970,7 +980,10 @@ void fceuWrapperUnLock(void) { if ( mutexLocks > 0 ) { - consoleWindow->mutex->unlock(); + if ( consoleWindow != NULL ) + { + consoleWindow->mutex->unlock(); + } mutexLocks--; } else diff --git a/src/ppu.h b/src/ppu.h index a3d2ded5..4555264d 100644 --- a/src/ppu.h +++ b/src/ppu.h @@ -48,3 +48,7 @@ enum PPUPHASE { }; extern PPUPHASE ppuphase; + +extern unsigned char *cdloggervdata; +extern unsigned int cdloggerVideoDataSize; +extern volatile int rendercount, vromreadcount, undefinedvromcount;