Merge pull request #176 from mjbudd77/master

Added Code/Data Logger Feature to Qt/SDL Port
This commit is contained in:
mjbudd77 2020-09-29 00:18:13 -04:00 committed by GitHub
commit 0da191bd7f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 1152 additions and 10 deletions

View File

@ -432,6 +432,7 @@ set(SRC_DRIVERS_SDL
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/LuaControl.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/CheatsConf.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/HexEditor.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/CodeDataLogger.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/SymbolicDebug.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleDebugger.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleUtilities.cpp

View File

@ -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){

View File

@ -0,0 +1,840 @@
// CodeDataLogger.cpp
//
#include <QDir>
#include <QFileDialog>
#include <QInputDialog>
#include <QMessageBox>
#include "../../types.h"
#include "../../fceu.h"
#include "../../cart.h"
#include "../../x6502.h"
#include "../../debug.h"
#include "../../ppu.h"
#include "../../ines.h"
#include "../../nsf.h"
#include "Qt/ConsoleUtilities.h"
#include "Qt/CodeDataLogger.h"
#include "Qt/main.h"
#include "Qt/dface.h"
#include "Qt/input.h"
#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 )
{
QVBoxLayout *mainLayout, *vbox1, *vbox;
QHBoxLayout *hbox;
QGridLayout *grid;
QGroupBox *frame, *subframe;
QPushButton *btn;
updateTimer = new QTimer( this );
connect( updateTimer, &QTimer::timeout, this, &CodeDataLoggerDialog_t::updatePeriodic );
setWindowTitle( tr("Code Data Logger") );
mainLayout = new QVBoxLayout();
vbox1 = new QVBoxLayout();
hbox = new QHBoxLayout();
grid = new QGridLayout();
statLabel = new QLabel( tr(" Logger is Paused: Press Start to Run ") );
cdlFileLabel = new QLabel( tr("CDL File:") );
vbox1->addLayout( grid );
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("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 );
subframe->setLayout( vbox );
grid->addWidget( subframe, 0, 0, Qt::AlignCenter );
subframe = new QGroupBox(tr("PRG Logged as Data"));
vbox = new QVBoxLayout();
vbox->addWidget( prgLoggedDataLabel );
subframe->setLayout( vbox );
grid->addWidget( subframe, 0, 1, Qt::AlignCenter );
subframe = new QGroupBox(tr("PRG not Logged"));
vbox = new QVBoxLayout();
vbox->addWidget( prgUnloggedLabel );
subframe->setLayout( vbox );
grid->addWidget( subframe, 0, 2, Qt::AlignCenter );
subframe = new QGroupBox(tr("CHR Logged as Code"));
vbox = new QVBoxLayout();
vbox->addWidget( chrLoggedCodeLabel );
subframe->setLayout( vbox );
grid->addWidget( subframe, 1, 0, Qt::AlignCenter );
subframe = new QGroupBox(tr("CHR Logged as Data"));
vbox = new QVBoxLayout();
vbox->addWidget( chrLoggedDataLabel );
subframe->setLayout( vbox );
grid->addWidget( subframe, 1, 1, Qt::AlignCenter );
subframe = new QGroupBox(tr("CHR not Logged"));
vbox = new QVBoxLayout();
vbox->addWidget( chrUnloggedLabel );
subframe->setLayout( vbox );
grid->addWidget( subframe, 1, 2, Qt::AlignCenter );
grid = new QGridLayout();
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)));
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 );
connect( btn, SIGNAL(clicked(void)), this, SLOT(saveCdlFile(void)));
btn = new QPushButton( tr("Load") );
grid->addWidget( btn, 1, 0, Qt::AlignCenter );
connect( btn, SIGNAL(clicked(void)), this, SLOT(loadCdlFile(void)));
btn = new QPushButton( tr("Save As") );
grid->addWidget( btn, 1, 2, Qt::AlignCenter );
connect( btn, SIGNAL(clicked(void)), this, SLOT(saveCdlFileAs(void)));
hbox = new QHBoxLayout();
vbox1->addLayout( hbox );
subframe = new QGroupBox(tr("Logging Workflow Options"));
vbox = new QVBoxLayout();
vbox->addWidget( autoSaveCdlCbox );
vbox->addWidget( autoLoadCdlCbox );
vbox->addWidget( autoResumeLogCbox );
subframe->setLayout( vbox );
hbox->addWidget( subframe );
subframe = new QGroupBox(tr("Generate ROM"));
vbox = new QVBoxLayout();
btn = new QPushButton( tr("Save Stripped Data") );
vbox->addWidget( btn );
connect( btn, SIGNAL(clicked(void)), this, SLOT(SaveStrippedROMClicked(void)));
btn = new QPushButton( tr("Save Unused Data") );
vbox->addWidget( btn );
connect( btn, SIGNAL(clicked(void)), this, SLOT(SaveUnusedROMClicked(void)));
subframe->setLayout( vbox );
hbox->addWidget( subframe );
mainLayout->addWidget( frame );
setLayout( mainLayout );
updateTimer->start( 200 ); // 5hz
if (autoLoadCDL)
{
char nameo[2048];
getDefaultCDLFile( nameo );
LoadCDLog(nameo);
}
}
//----------------------------------------------------
CodeDataLoggerDialog_t::~CodeDataLoggerDialog_t(void)
{
updateTimer->stop();
printf("Code Data Logger Window Deleted\n");
}
//----------------------------------------------------
void CodeDataLoggerDialog_t::closeEvent(QCloseEvent *event)
{
printf("Code Data Logger Close Window Event\n");
done(0);
deleteLater();
event->accept();
}
//----------------------------------------------------
void CodeDataLoggerDialog_t::closeWindow(void)
{
printf("Code Data Logger Close Window\n");
done(0);
deleteLater();
}
//----------------------------------------------------
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") );
}
}
//----------------------------------------------------
void CodeDataLoggerDialog_t::saveCdlFile(void)
{
SaveCDLogFile();
}
//----------------------------------------------------
void CodeDataLoggerDialog_t::saveCdlFileAs(void)
{
int ret, useNativeFileDialogVal;
QString filename;
const char *romFile;
QFileDialog dialog(this, tr("Save CDL To File") );
dialog.setFileMode(QFileDialog::AnyFile);
dialog.setNameFilter(tr("CDL Files (*.cdl *.CDL) ;; All files (*)"));
dialog.setViewMode(QFileDialog::List);
dialog.setFilter( QDir::AllEntries | QDir::Hidden );
dialog.setLabelText( QFileDialog::Accept, tr("Save") );
dialog.setDefaultSuffix( tr(".cdl") );
romFile = getRomFile();
if ( romFile != NULL )
{
char dir[512], base[256];
parseFilepath( romFile, dir, base );
strcat( base, ".cdl");
dialog.setDirectory( tr(dir) );
dialog.selectFile( tr(base) );
}
// Check config option to use native file dialog or not
g_config->getOption ("SDL.UseNativeFileDialog", &useNativeFileDialogVal);
dialog.setOption(QFileDialog::DontUseNativeDialog, !useNativeFileDialogVal);
dialog.show();
ret = dialog.exec();
if ( ret )
{
QStringList fileList;
fileList = dialog.selectedFiles();
if ( fileList.size() > 0 )
{
filename = fileList[0];
}
}
if ( filename.isNull() )
{
return;
}
//qDebug() << "selected file path : " << filename.toUtf8();
fceuWrapperLock();
strcpy( loadedcdfile, filename.toStdString().c_str() );
SaveCDLogFile();
fceuWrapperUnLock();
}
//----------------------------------------------------
void CodeDataLoggerDialog_t::loadCdlFile(void)
{
int ret, useNativeFileDialogVal;
QString filename;
char dir[512];
const char *romFile;
QFileDialog dialog(this, tr("Load CDL File") );
dialog.setFileMode(QFileDialog::ExistingFile);
dialog.setNameFilter(tr("CDL files (*.cdl *.CDL) ;; All files (*)"));
dialog.setViewMode(QFileDialog::List);
dialog.setFilter( QDir::AllEntries | QDir::Hidden );
dialog.setLabelText( QFileDialog::Accept, tr("Load") );
romFile = getRomFile();
if ( romFile )
{
getDirFromFile( romFile, dir );
dialog.setDirectory( tr(dir) );
}
// Check config option to use native file dialog or not
g_config->getOption ("SDL.UseNativeFileDialog", &useNativeFileDialogVal);
dialog.setOption(QFileDialog::DontUseNativeDialog, !useNativeFileDialogVal);
dialog.show();
ret = dialog.exec();
if ( ret )
{
QStringList fileList;
fileList = dialog.selectedFiles();
if ( fileList.size() > 0 )
{
filename = fileList[0];
}
}
if ( filename.isNull() )
{
return;
}
//qDebug() << "selected file path : " << filename.toUtf8();
fceuWrapperLock();
LoadCDLog ( filename.toStdString().c_str() );
fceuWrapperUnLock();
return;
}
//----------------------------------------------------
void CodeDataLoggerDialog_t::SaveStrippedROM(int invert)
{
//this is based off of iNesSave()
//todo: make this support NSF
//
if (!GameInfo)
return;
if (GameInfo->type==GIT_NSF)
{
printf("Sorry, you're not allowed to save optimized NSFs yet. Please don't optimize individual banks, as there are still some issues with several NSFs to be fixed, and it is easier to fix those issues with as much of the bank data intact as possible.");
return;
}
if (codecount == 0)
{
printf("Unable to Generate Stripped ROM. Get Something Logged and try again.");
return;
}
int i, ret, useNativeFileDialogVal;
QString filename;
const char *romFile;
QFileDialog dialog(this, tr("Save Stripped File As...") );
dialog.setFileMode(QFileDialog::AnyFile);
if (GameInfo->type==GIT_NSF)
{
dialog.setNameFilter(tr("NSF Files (*.nsf *.NSF) ;; All files (*)"));
dialog.setDefaultSuffix( tr(".nsf") );
}
else
{
dialog.setNameFilter(tr("NES Files (*.nes *.NES) ;; All files (*)"));
dialog.setDefaultSuffix( tr(".nes") );
}
dialog.setViewMode(QFileDialog::List);
dialog.setFilter( QDir::AllEntries | QDir::Hidden );
dialog.setLabelText( QFileDialog::Accept, tr("Save") );
romFile = getRomFile();
if ( romFile != NULL )
{
char dir[512], base[256];
parseFilepath( romFile, dir, base );
dialog.setDirectory( tr(dir) );
}
// Check config option to use native file dialog or not
g_config->getOption ("SDL.UseNativeFileDialog", &useNativeFileDialogVal);
dialog.setOption(QFileDialog::DontUseNativeDialog, !useNativeFileDialogVal);
dialog.show();
ret = dialog.exec();
if ( ret )
{
QStringList fileList;
fileList = dialog.selectedFiles();
if ( fileList.size() > 0 )
{
filename = fileList[0];
}
}
if ( filename.isNull() )
{
return;
}
//qDebug() << "selected file path : " << filename.toUtf8();
FILE *fp = fopen( filename.toStdString().c_str(),"wb");
if (!fp)
{
FCEUD_PrintError("Error opening target stripped rom file!");
return;
}
if (GameInfo->type==GIT_NSF)
{
uint8 NSFLoadLow;
uint8 NSFLoadHigh;
//Not used because if bankswitching, the addresses involved
//could still end up being used through writes
//static uint16 LoadAddr;
//LoadAddr=NSFHeader.LoadAddressLow;
//LoadAddr|=(NSFHeader.LoadAddressHigh&0x7F)<<8;
//Simple store/restore for writing a working NSF header
NSFLoadLow = NSFHeader.LoadAddressLow;
NSFLoadHigh = NSFHeader.LoadAddressHigh;
NSFHeader.LoadAddressLow=0;
NSFHeader.LoadAddressHigh&=0xF0;
fwrite(&NSFHeader,1,0x8,fp);
NSFHeader.LoadAddressLow = NSFLoadLow;
NSFHeader.LoadAddressHigh = NSFLoadHigh;
fseek(fp,0x8,SEEK_SET);
for (i = 0;i < ((NSFMaxBank+1)*4096);i++){
unsigned char pchar;
if (cdloggerdata[i] & 3)
{
pchar = invert?0:NSFDATA[i];
}
else
{
pchar = invert?NSFDATA[i]:0;
}
fputc(pchar, fp);
}
}
else
{
iNES_HEADER cdlhead;
cdlhead.ID[0] = 'N';
cdlhead.ID[1] = 'E';
cdlhead.ID[2] = 'S';
cdlhead.ID[3] = 0x1A;
cdlhead.ROM_size = cdloggerdataSize >> 14;
cdlhead.VROM_size = cdloggerVideoDataSize >> 13;
fwrite(&cdlhead,1,16,fp);
for (i = 0; i < (int)cdloggerdataSize; i++){
unsigned char pchar;
if (cdloggerdata[i] & 3)
{
pchar = invert?0:PRGptr[0][i];
}
else
{
pchar = invert?PRGptr[0][i]:0;
}
fputc(pchar, fp);
}
if (cdloggerVideoDataSize != 0)
{
// since the OldPPU at least logs the $2007 read accesses, we should save the data anyway
for (i = 0; i < (int)cdloggerVideoDataSize; i++) {
unsigned char vchar;
if (cdloggervdata[i] & 3)
{
vchar = invert?0:CHRptr[0][i];
}
else
{
vchar = invert?CHRptr[0][i]:0;
}
fputc(vchar, fp);
}
}
}
fclose(fp);
}
//----------------------------------------------------
void CodeDataLoggerDialog_t::SaveStrippedROMClicked(void)
{
SaveStrippedROM(0);
}
//----------------------------------------------------
void CodeDataLoggerDialog_t::SaveUnusedROMClicked(void)
{
SaveStrippedROM(1);
}
//----------------------------------------------------
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);
}
//----------------------------------------------------

View File

@ -0,0 +1,73 @@
// CodeDataLogger.h
//
#pragma once
#include <QWidget>
#include <QDialog>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QComboBox>
#include <QCheckBox>
#include <QPushButton>
#include <QLabel>
#include <QFrame>
#include <QTimer>
#include <QGroupBox>
#include <QCloseEvent>
class CodeDataLoggerDialog_t : public QDialog
{
Q_OBJECT
public:
CodeDataLoggerDialog_t(QWidget *parent = 0);
~CodeDataLoggerDialog_t(void);
protected:
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);
void SaveStrippedROM(int invert);
private:
public slots:
void closeWindow(void);
private slots:
void loadCdlFile(void);
void saveCdlFile(void);
void saveCdlFileAs(void);
void updatePeriodic(void);
void ResetCDLogClicked(void);
void StartPauseCDLogClicked(void);
void autoSaveCdlStateChange(int state);
void autoLoadCdlStateChange(int state);
void autoResumeCdlStateChange(int state);
void SaveStrippedROMClicked(void);
void SaveUnusedROMClicked(void);
};
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);

View File

@ -83,3 +83,65 @@ 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 )
{
if ( dir ) dir[0] = 0;
if ( base ) base[0] = 0;
if ( suffix) suffix[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;
}
//---------------------------------------------------------------------------

View File

@ -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 );

View File

@ -25,6 +25,7 @@
#include "Qt/LuaControl.h"
#include "Qt/CheatsConf.h"
#include "Qt/HexEditor.h"
#include "Qt/CodeDataLogger.h"
#include "Qt/ConsoleDebugger.h"
#include "Qt/ConsoleUtilities.h"
#include "Qt/ConsoleSoundConf.h"
@ -483,7 +484,7 @@ void consoleWin_t::createMainMenu(void)
// Debug
debugMenu = menuBar()->addMenu(tr("Debug"));
// Debug -> Hex Editor
// Debug -> Debugger
debuggerAct = new QAction(tr("Debugger..."), this);
//debuggerAct->setShortcut( QKeySequence(tr("Shift+F7")));
debuggerAct->setStatusTip(tr("Open 6502 Debugger"));
@ -499,6 +500,14 @@ void consoleWin_t::createMainMenu(void)
debugMenu->addAction(hexEditAct);
// Debug -> Code/Data Logger
codeDataLogAct = new QAction(tr("Code/Data Logger..."), this);
//codeDataLogAct->setShortcut( QKeySequence(tr("Shift+F7")));
codeDataLogAct->setStatusTip(tr("Open Code Data Logger"));
connect(codeDataLogAct, SIGNAL(triggered()), this, SLOT(openCodeDataLogger(void)) );
debugMenu->addAction(codeDataLogAct);
//-----------------------------------------------------------------------
// Movie
movieMenu = menuBar()->addMenu(tr("Movie"));
@ -1003,6 +1012,17 @@ void consoleWin_t::openHexEditor(void)
hexEditWin->show();
}
void consoleWin_t::openCodeDataLogger(void)
{
CodeDataLoggerDialog_t *cdlWin;
//printf("Open Code Data Logger Window\n");
cdlWin = new CodeDataLoggerDialog_t(this);
cdlWin->show();
}
void consoleWin_t::toggleAutoResume(void)
{
//printf("Auto Resume: %i\n", autoResume->isChecked() );

View File

@ -90,6 +90,7 @@ class consoleWin_t : public QMainWindow
QAction *fdsLoadBiosAct;
QAction *cheatsAct;
QAction *debuggerAct;
QAction *codeDataLogAct;
QAction *hexEditAct;
QAction *openMovAct;
QAction *stopMovAct;
@ -133,6 +134,7 @@ class consoleWin_t : public QMainWindow
void openHotkeyConfWin(void);
void openPaletteConfWin(void);
void openGuiConfWin(void);
void openCodeDataLogger(void);
void toggleAutoResume(void);
void toggleFullscreen(void);
void updatePeriodic(void);

View File

@ -24,6 +24,7 @@
#include "../../movie.h"
#include "../../palette.h"
#include "../../fds.h"
#include "../../ppu.h"
#include "../../cart.h"
#include "../../ines.h"
#include "../common/configSys.h"
@ -1999,6 +2000,106 @@ int QHexEdit::checkMemActivity(void)
return 0;
}
//----------------------------------------------------------------------------
int QHexEdit::getRomAddrColor( int addr, QColor &fg, QColor &bg )
{
int temp_offset;
QColor color, oppColor;
fg = this->palette().color(QPalette::WindowText);
bg = this->palette().color(QPalette::Background);
if ( reverseVideo )
{
color = this->palette().color(QPalette::Background);
oppColor = this->palette().color(QPalette::WindowText);
}
else
{
color = this->palette().color(QPalette::WindowText);
oppColor = this->palette().color(QPalette::Background);
}
if ( viewMode != MODE_NES_ROM )
{
return -1;
}
if (cdloggerdataSize == 0)
{
return -1;
}
temp_offset = addr - 16;
if (temp_offset >= 0)
{
if ((unsigned int)temp_offset < cdloggerdataSize)
{
// PRG
if ((cdloggerdata[temp_offset] & 3) == 3)
{
// the byte is both Code and Data - green
color.setRgb(0, 190, 0);
}
else if ((cdloggerdata[temp_offset] & 3) == 1)
{
// the byte is Code - dark-yellow
color.setRgb(160, 140, 0);
oppColor.setRgb( 0, 0, 0 );
}
else if ((cdloggerdata[temp_offset] & 3) == 2)
{
// the byte is Data - blue/cyan
if (cdloggerdata[temp_offset] & 0x40)
{
// PCM data - cyan
color.setRgb(0, 130, 160);
}
else
{
// non-PCM data - blue
color.setRgb(0, 0, 210);
}
}
}
else
{
temp_offset -= cdloggerdataSize;
if (((unsigned int)temp_offset < cdloggerVideoDataSize))
{
// CHR
if ((cdloggervdata[temp_offset] & 3) == 3)
{
// the byte was both rendered and read programmatically - light-green
color.setRgb(5, 255, 5);
}
else if ((cdloggervdata[temp_offset] & 3) == 1)
{
// the byte was rendered - yellow
color.setRgb(210, 190, 0);
oppColor.setRgb( 0, 0, 0 );
}
else if ((cdloggervdata[temp_offset] & 3) == 2)
{
// the byte was read programmatically - light-blue
color.setRgb(15, 15, 255);
}
}
}
}
if ( reverseVideo )
{
bg = color;
fg = oppColor;
}
else
{
fg = color;
bg = oppColor;
}
return 0;
}
//----------------------------------------------------------------------------
void QHexEdit::memModeUpdate(void)
{
int memSize;
@ -2178,7 +2279,24 @@ void QHexEdit::paintEvent(QPaintEvent *event)
}
else
{
if ( actvHighlightEnable && (mb.buf[addr].actv > 0) )
if ( viewMode == MODE_NES_ROM )
{
QColor romBgColor, romFgColor;
getRomAddrColor( addr, romFgColor, romBgColor );
if ( reverseVideo )
{
painter.setPen( romFgColor );
painter.fillRect( x - (0.5*pxCharWidth) , y-pxLineSpacing+pxLineLead, 3*pxCharWidth, pxLineSpacing, romBgColor );
painter.fillRect( pxHexAscii + (col*pxCharWidth) - pxLineXScroll, y-pxLineSpacing+pxLineLead, pxCharWidth, pxLineSpacing, romBgColor );
}
else
{
painter.setPen( romFgColor );
}
}
else if ( actvHighlightEnable && (mb.buf[addr].actv > 0) )
{
if ( reverseVideo )
{

View File

@ -138,6 +138,8 @@ class QHexEdit : public QWidget
QFont font;
int getRomAddrColor( int addr, QColor &fg, QColor &bg );
memBlock_t mb;
int (*memAccessFunc)( unsigned int offset);

View File

@ -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);

View File

@ -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

View File

@ -48,3 +48,7 @@ enum PPUPHASE {
};
extern PPUPHASE ppuphase;
extern unsigned char *cdloggervdata;
extern unsigned int cdloggerVideoDataSize;
extern volatile int rendercount, vromreadcount, undefinedvromcount;