From c288c60c688709eef69a91d672642ccbe54b8167 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Wed, 30 Sep 2020 20:56:50 -0400 Subject: [PATCH 01/10] Added initial window layout for trace logger. --- src/CMakeLists.txt | 1 + src/drivers/Qt/ConsoleWindow.cpp | 20 +++++ src/drivers/Qt/ConsoleWindow.h | 2 + src/drivers/Qt/TraceLogger.cpp | 131 +++++++++++++++++++++++++++++++ src/drivers/Qt/TraceLogger.h | 58 ++++++++++++++ 5 files changed, 212 insertions(+) create mode 100644 src/drivers/Qt/TraceLogger.cpp create mode 100644 src/drivers/Qt/TraceLogger.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 04c266e1..41036c60 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -438,6 +438,7 @@ set(SRC_DRIVERS_SDL ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleUtilities.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleVideoConf.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleSoundConf.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/TraceLogger.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/AboutWindow.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/fceuWrapper.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/config.cpp diff --git a/src/drivers/Qt/ConsoleWindow.cpp b/src/drivers/Qt/ConsoleWindow.cpp index 44e701e1..b3599e38 100644 --- a/src/drivers/Qt/ConsoleWindow.cpp +++ b/src/drivers/Qt/ConsoleWindow.cpp @@ -25,6 +25,7 @@ #include "Qt/LuaControl.h" #include "Qt/CheatsConf.h" #include "Qt/HexEditor.h" +#include "Qt/TraceLogger.h" #include "Qt/CodeDataLogger.h" #include "Qt/ConsoleDebugger.h" #include "Qt/ConsoleUtilities.h" @@ -508,6 +509,14 @@ void consoleWin_t::createMainMenu(void) debugMenu->addAction(codeDataLogAct); + // Debug -> Trace Logger + traceLogAct = new QAction(tr("Trace Logger..."), this); + //traceLogAct->setShortcut( QKeySequence(tr("Shift+F7"))); + traceLogAct->setStatusTip(tr("Open Trace Logger")); + connect(traceLogAct, SIGNAL(triggered()), this, SLOT(openTraceLogger(void)) ); + + debugMenu->addAction(traceLogAct); + //----------------------------------------------------------------------- // Movie movieMenu = menuBar()->addMenu(tr("Movie")); @@ -1023,6 +1032,17 @@ void consoleWin_t::openCodeDataLogger(void) cdlWin->show(); } +void consoleWin_t::openTraceLogger(void) +{ + TraceLoggerDialog_t *tlWin; + + //printf("Open Trace Logger Window\n"); + + tlWin = new TraceLoggerDialog_t(this); + + tlWin->show(); +} + void consoleWin_t::toggleAutoResume(void) { //printf("Auto Resume: %i\n", autoResume->isChecked() ); diff --git a/src/drivers/Qt/ConsoleWindow.h b/src/drivers/Qt/ConsoleWindow.h index 501c018a..a8d74264 100644 --- a/src/drivers/Qt/ConsoleWindow.h +++ b/src/drivers/Qt/ConsoleWindow.h @@ -91,6 +91,7 @@ class consoleWin_t : public QMainWindow QAction *cheatsAct; QAction *debuggerAct; QAction *codeDataLogAct; + QAction *traceLogAct; QAction *hexEditAct; QAction *openMovAct; QAction *stopMovAct; @@ -135,6 +136,7 @@ class consoleWin_t : public QMainWindow void openPaletteConfWin(void); void openGuiConfWin(void); void openCodeDataLogger(void); + void openTraceLogger(void); void toggleAutoResume(void); void toggleFullscreen(void); void updatePeriodic(void); diff --git a/src/drivers/Qt/TraceLogger.cpp b/src/drivers/Qt/TraceLogger.cpp new file mode 100644 index 00000000..4c921e3f --- /dev/null +++ b/src/drivers/Qt/TraceLogger.cpp @@ -0,0 +1,131 @@ +// CodeDataLogger.cpp +// +#include +#include +#include +#include + +#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/TraceLogger.h" +#include "Qt/main.h" +#include "Qt/dface.h" +#include "Qt/input.h" +#include "Qt/config.h" +#include "Qt/fceuWrapper.h" + +//---------------------------------------------------- +TraceLoggerDialog_t::TraceLoggerDialog_t(QWidget *parent) + : QDialog( parent ) +{ + QVBoxLayout *mainLayout; + QHBoxLayout *hbox; + QGridLayout *grid; + QGroupBox *frame; + QLabel *lbl; + + setWindowTitle( tr("Trace Logger") ); + + mainLayout = new QVBoxLayout(); + grid = new QGridLayout(); + + mainLayout->addLayout( grid ); + + lbl = new QLabel( tr("Lines") ); + logLastCbox = new QCheckBox( tr("Log Last") ); + logMaxLinesComboBox = new QComboBox(); + + logFileCbox = new QCheckBox( tr("Log to File") ); + selLogFileButton = new QPushButton( tr("Browse...") ); + startStopButton = new QPushButton( tr("Start Logging") ); + autoUpdateCbox = new QCheckBox( tr("Automatically update this window while logging") ); + + hbox = new QHBoxLayout(); + hbox->addWidget( logLastCbox ); + hbox->addWidget( logMaxLinesComboBox ); + hbox->addWidget( lbl ); + + grid->addLayout( hbox, 0, 0, Qt::AlignLeft ); + grid->addWidget( startStopButton, 0, 1, Qt::AlignCenter ); + + hbox = new QHBoxLayout(); + hbox->addWidget( logFileCbox ); + hbox->addWidget( selLogFileButton ); + + grid->addLayout( hbox, 1, 0, Qt::AlignLeft ); + grid->addWidget( autoUpdateCbox, 1, 1, Qt::AlignCenter ); + + grid = new QGridLayout(); + frame = new QGroupBox(tr("Log Options")); + frame->setLayout( grid ); + + logRegCbox = new QCheckBox( tr("Log State of Registers") ); + logFrameCbox = new QCheckBox( tr("Log Frames Count") ); + logEmuMsgCbox = new QCheckBox( tr("Log Emulator Messages") ); + symTraceEnaCbox = new QCheckBox( tr("Symbolic Trace") ); + logProcStatFlagCbox = new QCheckBox( tr("Log Processor Status Flags") ); + logCyclesCountCbox = new QCheckBox( tr("Log Cycles Count") ); + logBreakpointCbox = new QCheckBox( tr("Log Breakpoint Hits") ); + useStackPointerCbox = new QCheckBox( tr("Use Stack Pointer for Code Tabbing (Nesting Visualization)") ); + toLeftDisassemblyCbox = new QCheckBox( tr("To the Left from Disassembly") ); + logInstrCountCbox = new QCheckBox( tr("Log Instructions Count") ); + logBankNumCbox = new QCheckBox( tr("Log Bank Number") ); + + grid->addWidget( logRegCbox , 0, 0, Qt::AlignLeft ); + grid->addWidget( logFrameCbox , 1, 0, Qt::AlignLeft ); + grid->addWidget( logEmuMsgCbox , 2, 0, Qt::AlignLeft ); + grid->addWidget( symTraceEnaCbox, 3, 0, Qt::AlignLeft ); + grid->addWidget( logProcStatFlagCbox, 0, 1, Qt::AlignLeft ); + grid->addWidget( logCyclesCountCbox , 1, 1, Qt::AlignLeft ); + grid->addWidget( logBreakpointCbox , 2, 1, Qt::AlignLeft ); + grid->addWidget( useStackPointerCbox, 3, 1, 1, 2, Qt::AlignLeft ); + grid->addWidget( toLeftDisassemblyCbox, 0, 2, Qt::AlignLeft ); + grid->addWidget( logInstrCountCbox , 1, 2, Qt::AlignLeft ); + grid->addWidget( logBankNumCbox , 2, 2, Qt::AlignLeft ); + + mainLayout->addWidget( frame ); + + grid = new QGridLayout(); + frame = new QGroupBox(tr("Extra Log Options that work with the Code/Data Logger")); + frame->setLayout( grid ); + + logNewMapCodeCbox = new QCheckBox( tr("Only Log Newly Mapped Code") ); + logNewMapDataCbox = new QCheckBox( tr("Only Log that Accesses Newly Mapped Data") ); + + grid->addWidget( logNewMapCodeCbox, 0, 0, Qt::AlignLeft ); + grid->addWidget( logNewMapDataCbox, 0, 1, Qt::AlignLeft ); + + mainLayout->addWidget( frame ); + + setLayout( mainLayout ); + +} +//---------------------------------------------------- +TraceLoggerDialog_t::~TraceLoggerDialog_t(void) +{ + printf("Trace Logger Window Deleted\n"); +} +//---------------------------------------------------- +void TraceLoggerDialog_t::closeEvent(QCloseEvent *event) +{ + printf("Trace Logger Close Window Event\n"); + done(0); + deleteLater(); + event->accept(); +} +//---------------------------------------------------- +void TraceLoggerDialog_t::closeWindow(void) +{ + printf("Trace Logger Close Window\n"); + done(0); + deleteLater(); +} +//---------------------------------------------------- diff --git a/src/drivers/Qt/TraceLogger.h b/src/drivers/Qt/TraceLogger.h new file mode 100644 index 00000000..f27ea065 --- /dev/null +++ b/src/drivers/Qt/TraceLogger.h @@ -0,0 +1,58 @@ +// CodeDataLogger.h +// + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class TraceLoggerDialog_t : public QDialog +{ + Q_OBJECT + + public: + TraceLoggerDialog_t(QWidget *parent = 0); + ~TraceLoggerDialog_t(void); + + protected: + QCheckBox *logLastCbox; + QCheckBox *logFileCbox; + QComboBox *logMaxLinesComboBox; + + QCheckBox *autoUpdateCbox; + QCheckBox *logRegCbox; + QCheckBox *logFrameCbox; + QCheckBox *logEmuMsgCbox; + QCheckBox *logProcStatFlagCbox; + QCheckBox *logCyclesCountCbox; + QCheckBox *logBreakpointCbox; + QCheckBox *useStackPointerCbox; + QCheckBox *toLeftDisassemblyCbox; + QCheckBox *logInstrCountCbox; + QCheckBox *logBankNumCbox; + QCheckBox *symTraceEnaCbox; + QCheckBox *logNewMapCodeCbox; + QCheckBox *logNewMapDataCbox; + + QPushButton *selLogFileButton; + QPushButton *startStopButton; + + void closeEvent(QCloseEvent *bar); + + private: + + public slots: + void closeWindow(void); + private slots: +}; + From 9da84e16caf0955d71901731912555ee110cc3b8 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Wed, 30 Sep 2020 22:21:18 -0400 Subject: [PATCH 02/10] More setup of Qt Trace Logger window. --- src/drivers/Qt/TraceLogger.cpp | 327 +++++++++++++++++++++++++++++++++ src/drivers/Qt/TraceLogger.h | 16 ++ 2 files changed, 343 insertions(+) diff --git a/src/drivers/Qt/TraceLogger.cpp b/src/drivers/Qt/TraceLogger.cpp index 4c921e3f..fe2b75b5 100644 --- a/src/drivers/Qt/TraceLogger.cpp +++ b/src/drivers/Qt/TraceLogger.cpp @@ -10,9 +10,11 @@ #include "../../cart.h" #include "../../x6502.h" #include "../../debug.h" +#include "../../asm.h" #include "../../ppu.h" #include "../../ines.h" #include "../../nsf.h" +#include "../../movie.h" #include "Qt/ConsoleUtilities.h" #include "Qt/TraceLogger.h" @@ -22,6 +24,53 @@ #include "Qt/config.h" #include "Qt/fceuWrapper.h" +#define LOG_REGISTERS 0x00000001 +#define LOG_PROCESSOR_STATUS 0x00000002 +#define LOG_NEW_INSTRUCTIONS 0x00000004 +#define LOG_NEW_DATA 0x00000008 +#define LOG_TO_THE_LEFT 0x00000010 +#define LOG_FRAMES_COUNT 0x00000020 +#define LOG_MESSAGES 0x00000040 +#define LOG_BREAKPOINTS 0x00000080 +#define LOG_SYMBOLIC 0x00000100 +#define LOG_CODE_TABBING 0x00000200 +#define LOG_CYCLES_COUNT 0x00000400 +#define LOG_INSTRUCTIONS_COUNT 0x00000800 +#define LOG_BANK_NUMBER 0x00001000 + +#define LOG_LINE_MAX_LEN 160 +// Frames count - 1+6+1 symbols +// Cycles count - 1+11+1 symbols +// Instructions count - 1+11+1 symbols +// AXYS state - 20 +// Processor status - 11 +// Tabs - 31 +// Address - 6 +// Data - 10 +// Disassembly - 45 +// EOL (/0) - 1 +// ------------------------ +// 148 symbols total +#define LOG_AXYSTATE_MAX_LEN 21 +#define LOG_PROCSTATUS_MAX_LEN 12 +#define LOG_TABS_MASK 31 +#define LOG_ADDRESS_MAX_LEN 13 +#define LOG_DATA_MAX_LEN 11 +#define LOG_DISASSEMBLY_MAX_LEN 46 +#define NL_MAX_MULTILINE_COMMENT_LEN 1000 + +static int logging = 0; +static int logging_options = LOG_REGISTERS | LOG_PROCESSOR_STATUS | LOG_TO_THE_LEFT | LOG_MESSAGES | LOG_BREAKPOINTS | LOG_CODE_TABBING; +static char str_axystate[LOG_AXYSTATE_MAX_LEN] = {0}, str_procstatus[LOG_PROCSTATUS_MAX_LEN] = {0}; +static char str_tabs[LOG_TABS_MASK+1] = {0}, str_address[LOG_ADDRESS_MAX_LEN] = {0}, str_data[LOG_DATA_MAX_LEN] = {0}, str_disassembly[LOG_DISASSEMBLY_MAX_LEN] = {0}; +static char str_result[LOG_LINE_MAX_LEN] = {0}; +static char str_temp[LOG_LINE_MAX_LEN] = {0}; +static char str_decoration[NL_MAX_MULTILINE_COMMENT_LEN + 10] = {0}; +//static char str_decoration_comment[NL_MAX_MULTILINE_COMMENT_LEN + 10] = {0}; +//static char* tracer_decoration_comment = 0; +//static char* tracer_decoration_comment_end_pos = 0; +static int oldcodecount = 0, olddatacount = 0; + //---------------------------------------------------- TraceLoggerDialog_t::TraceLoggerDialog_t(QWidget *parent) : QDialog( parent ) @@ -36,7 +85,17 @@ TraceLoggerDialog_t::TraceLoggerDialog_t(QWidget *parent) mainLayout = new QVBoxLayout(); grid = new QGridLayout(); + mainLayout->addLayout( grid ); + traceView = new QTraceLogView(this); + vbar = new QScrollBar( Qt::Vertical, this ); + hbar = new QScrollBar( Qt::Horizontal, this ); + + grid->addWidget( traceView, 0, 0); + grid->addWidget( vbar , 0, 1 ); + grid->addWidget( hbar , 1, 0 ); + + grid = new QGridLayout(); mainLayout->addLayout( grid ); lbl = new QLabel( tr("Lines") ); @@ -127,5 +186,273 @@ void TraceLoggerDialog_t::closeWindow(void) printf("Trace Logger Close Window\n"); done(0); deleteLater(); +} +//todo: really speed this up +void FCEUD_TraceInstruction(uint8 *opcode, int size) +{ + if (!logging) + return; + + unsigned int addr = X.PC; + uint8 tmp; + static int unloggedlines = 0; + + // if instruction executed from the RAM, skip this, log all instead + // TODO: loops folding mame-lyke style + if (GetPRGAddress(addr) != -1) + { + if (((logging_options & LOG_NEW_INSTRUCTIONS) && (oldcodecount != codecount)) || + ((logging_options & LOG_NEW_DATA) && (olddatacount != datacount))) + { + //something new was logged + oldcodecount = codecount; + olddatacount = datacount; + if(unloggedlines > 0) + { + sprintf(str_result, "(%d lines skipped)", unloggedlines); + //OutputLogLine(str_result); + unloggedlines = 0; + } + } + else + { + if ((logging_options & LOG_NEW_INSTRUCTIONS) || + (logging_options & LOG_NEW_DATA)) + { + if (FCEUI_GetLoggingCD()) + { + unloggedlines++; + } + return; + } + } + } + + if ((addr + size) > 0xFFFF) + { + sprintf(str_data, "%02X ", opcode[0]); + sprintf(str_disassembly, "OVERFLOW"); + } + else + { + char* a = 0; + switch (size) + { + case 0: + sprintf(str_data, "%02X ", opcode[0]); + sprintf(str_disassembly,"UNDEFINED"); + break; + case 1: + { + sprintf(str_data, "%02X ", opcode[0]); + a = Disassemble(addr + 1, opcode); + // special case: an RTS opcode + if (opcode[0] == 0x60) + { + // add the beginning address of the subroutine that we exit from + unsigned int caller_addr = GetMem(((X.S) + 1)|0x0100) + (GetMem(((X.S) + 2)|0x0100) << 8) - 0x2; + if (GetMem(caller_addr) == 0x20) + { + // this was a JSR instruction - take the subroutine address from it + unsigned int call_addr = GetMem(caller_addr + 1) + (GetMem(caller_addr + 2) << 8); + sprintf(str_decoration, " (from $%04X)", call_addr); + strcat(a, str_decoration); + } + } + break; + } + case 2: + sprintf(str_data, "%02X %02X ", opcode[0],opcode[1]); + a = Disassemble(addr + 2, opcode); + break; + case 3: + sprintf(str_data, "%02X %02X %02X ", opcode[0],opcode[1],opcode[2]); + a = Disassemble(addr + 3, opcode); + break; + } + + if (a) + { + //if (logging_options & LOG_SYMBOLIC) + //{ + // loadNameFiles(); + // tempAddressesLog.resize(0); + // // Insert Name and Comment lines if needed + // Name* node = findNode(getNamesPointerForAddress(addr), addr); + // if (node) + // { + // if (node->name) + // { + // strcpy(str_decoration, node->name); + // strcat(str_decoration, ":"); + // tempAddressesLog.push_back(addr); + // //OutputLogLine(str_decoration, &tempAddressesLog); + // } + // if (node->comment) + // { + // // make a copy + // strcpy(str_decoration_comment, node->comment); + // strcat(str_decoration_comment, "\r\n"); + // tracer_decoration_comment = str_decoration_comment; + // // divide the str_decoration_comment into strings (Comment1, Comment2, ...) + // char* tracer_decoration_comment_end_pos = strstr(tracer_decoration_comment, "\r\n"); + // while (tracer_decoration_comment_end_pos) + // { + // tracer_decoration_comment_end_pos[0] = 0; // set \0 instead of \r + // strcpy(str_decoration, "; "); + // strcat(str_decoration, tracer_decoration_comment); + // //OutputLogLine(str_decoration, &tempAddressesLog); + // tracer_decoration_comment_end_pos += 2; + // tracer_decoration_comment = tracer_decoration_comment_end_pos; + // tracer_decoration_comment_end_pos = strstr(tracer_decoration_comment_end_pos, "\r\n"); + // } + // } + // } + // + // //replaceNames(ramBankNames, a, &tempAddressesLog); + // //for(int i=0;i>2, + 'V'|(tmp&0x40)>>1, + 'U'|(tmp&0x20), + 'B'|(tmp&0x10)<<1, + 'D'|(tmp&0x08)<<2, + 'I'|(tmp&0x04)<<3, + 'Z'|(tmp&0x02)<<4, + 'C'|(tmp&0x01)<<5 + ); + } + + if (logging_options & LOG_TO_THE_LEFT) + { + if (logging_options & LOG_REGISTERS) + { + strcat(str_result, str_axystate); + } + if (logging_options & LOG_PROCESSOR_STATUS) + { + strcat(str_result, str_procstatus); + } + } + + if (logging_options & LOG_CODE_TABBING) + { + // add spaces at the beginning of the line according to stack pointer + int spaces = (0xFF - X.S) & LOG_TABS_MASK; + for (int i = 0; i < spaces; i++) + { + str_tabs[i] = ' '; + } + str_tabs[spaces] = 0; + strcat(str_result, str_tabs); + } + else if (logging_options & LOG_TO_THE_LEFT) + { + strcat(str_result, " "); + } + + if (logging_options & LOG_BANK_NUMBER) + { + if (addr >= 0x8000) + { + sprintf(str_address, "$%02X:%04X: ", getBank(addr), addr); + } + else + { + sprintf(str_address, " $%04X: ", addr); + } + } + else + { + sprintf(str_address, "$%04X: ", addr); + } + + strcat(str_result, str_address); + strcat(str_result, str_data); + strcat(str_result, str_disassembly); + + if (!(logging_options & LOG_TO_THE_LEFT)) + { + if (logging_options & LOG_REGISTERS) + { + strcat(str_result, str_axystate); + } + if (logging_options & LOG_PROCESSOR_STATUS) + { + strcat(str_result, str_procstatus); + } + } + + //OutputLogLine(str_result, &tempAddressesLog); + + return; +} +//---------------------------------------------------- +QTraceLogView::QTraceLogView(QWidget *parent) + : QWidget(parent) +{ + +} +//---------------------------------------------------- +QTraceLogView::~QTraceLogView(void) +{ + } //---------------------------------------------------- diff --git a/src/drivers/Qt/TraceLogger.h b/src/drivers/Qt/TraceLogger.h index f27ea065..bda8c91f 100644 --- a/src/drivers/Qt/TraceLogger.h +++ b/src/drivers/Qt/TraceLogger.h @@ -14,8 +14,20 @@ #include #include #include +#include #include +class QTraceLogView : public QWidget +{ + Q_OBJECT + + public: + QTraceLogView(QWidget *parent = 0); + ~QTraceLogView(void); + + protected: +}; + class TraceLoggerDialog_t : public QDialog { Q_OBJECT @@ -47,6 +59,10 @@ class TraceLoggerDialog_t : public QDialog QPushButton *selLogFileButton; QPushButton *startStopButton; + QTraceLogView *traceView; + QScrollBar *hbar; + QScrollBar *vbar; + void closeEvent(QCloseEvent *bar); private: From 08da8fd76eaa744d5ffcc338f7109834edb11617 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Wed, 30 Sep 2020 22:44:56 -0400 Subject: [PATCH 03/10] Trace logger custom widget setup in work. --- src/drivers/Qt/TraceLogger.cpp | 79 +++++++++++++++++++++++++++++++--- src/drivers/Qt/TraceLogger.h | 23 +++++++++- 2 files changed, 96 insertions(+), 6 deletions(-) diff --git a/src/drivers/Qt/TraceLogger.cpp b/src/drivers/Qt/TraceLogger.cpp index fe2b75b5..29ca18c8 100644 --- a/src/drivers/Qt/TraceLogger.cpp +++ b/src/drivers/Qt/TraceLogger.cpp @@ -1,9 +1,10 @@ -// CodeDataLogger.cpp +// TraceLogger.cpp // #include #include #include #include +#include #include "../../types.h" #include "../../fceu.h" @@ -85,18 +86,24 @@ TraceLoggerDialog_t::TraceLoggerDialog_t(QWidget *parent) mainLayout = new QVBoxLayout(); grid = new QGridLayout(); - mainLayout->addLayout( grid ); + mainLayout->addLayout( grid, 100 ); traceView = new QTraceLogView(this); vbar = new QScrollBar( Qt::Vertical, this ); hbar = new QScrollBar( Qt::Horizontal, this ); + traceView->setScrollBars( hbar, vbar ); + hbar->setMinimum(0); + hbar->setMaximum(100); + vbar->setMinimum(0); + vbar->setMaximum(10000); + grid->addWidget( traceView, 0, 0); grid->addWidget( vbar , 0, 1 ); grid->addWidget( hbar , 1, 0 ); grid = new QGridLayout(); - mainLayout->addLayout( grid ); + mainLayout->addLayout( grid, 1 ); lbl = new QLabel( tr("Lines") ); logLastCbox = new QCheckBox( tr("Log Last") ); @@ -150,7 +157,7 @@ TraceLoggerDialog_t::TraceLoggerDialog_t(QWidget *parent) grid->addWidget( logInstrCountCbox , 1, 2, Qt::AlignLeft ); grid->addWidget( logBankNumCbox , 2, 2, Qt::AlignLeft ); - mainLayout->addWidget( frame ); + mainLayout->addWidget( frame, 1 ); grid = new QGridLayout(); frame = new QGroupBox(tr("Extra Log Options that work with the Code/Data Logger")); @@ -162,7 +169,7 @@ TraceLoggerDialog_t::TraceLoggerDialog_t(QWidget *parent) grid->addWidget( logNewMapCodeCbox, 0, 0, Qt::AlignLeft ); grid->addWidget( logNewMapDataCbox, 0, 1, Qt::AlignLeft ); - mainLayout->addWidget( frame ); + mainLayout->addWidget( frame, 1 ); setLayout( mainLayout ); @@ -448,7 +455,14 @@ void FCEUD_TraceInstruction(uint8 *opcode, int size) QTraceLogView::QTraceLogView(QWidget *parent) : QWidget(parent) { + font.setFamily("Courier New"); + font.setStyle( QFont::StyleNormal ); + font.setStyleHint( QFont::Monospace ); + calcFontData(); + + vbar = NULL; + hbar = NULL; } //---------------------------------------------------- QTraceLogView::~QTraceLogView(void) @@ -456,3 +470,58 @@ QTraceLogView::~QTraceLogView(void) } //---------------------------------------------------- +void QTraceLogView::calcFontData(void) +{ + this->setFont(font); + QFontMetrics metrics(font); +#if QT_VERSION > QT_VERSION_CHECK(5, 11, 0) + pxCharWidth = metrics.horizontalAdvance(QLatin1Char('2')); +#else + pxCharWidth = metrics.width(QLatin1Char('2')); +#endif + pxCharHeight = metrics.height(); + pxLineSpacing = metrics.lineSpacing() * 1.25; + pxLineLead = pxLineSpacing - pxCharHeight; + pxCursorHeight = pxCharHeight; + pxLineWidth = pxCharWidth * LOG_LINE_MAX_LEN; + + viewLines = (viewHeight / pxLineSpacing) + 1; +} +//---------------------------------------------------------------------------- +void QTraceLogView::setScrollBars( QScrollBar *h, QScrollBar *v ) +{ + hbar = h; vbar = v; +} +//---------------------------------------------------- +void QTraceLogView::resizeEvent(QResizeEvent *event) +{ + viewWidth = event->size().width(); + viewHeight = event->size().height(); + + //printf("QAsmView Resize: %ix%i\n", viewWidth, viewHeight ); + + viewLines = (viewHeight / pxLineSpacing) + 1; + + //maxLineOffset = 0; // mb.numLines() - viewLines + 1; + + if ( viewWidth >= pxLineWidth ) + { + pxLineXScroll = 0; + } + else + { + pxLineXScroll = (int)(0.010f * (float)hbar->value() * (float)(pxLineWidth - viewWidth) ); + } + +} +//---------------------------------------------------- +void QTraceLogView::paintEvent(QPaintEvent *event) +{ + QPainter painter(this); + + painter.setFont(font); + viewWidth = event->rect().width(); + viewHeight = event->rect().height(); + +} +//---------------------------------------------------- diff --git a/src/drivers/Qt/TraceLogger.h b/src/drivers/Qt/TraceLogger.h index bda8c91f..dde8d2f8 100644 --- a/src/drivers/Qt/TraceLogger.h +++ b/src/drivers/Qt/TraceLogger.h @@ -1,4 +1,4 @@ -// CodeDataLogger.h +// TraceLogger.h // #pragma once @@ -25,7 +25,28 @@ class QTraceLogView : public QWidget QTraceLogView(QWidget *parent = 0); ~QTraceLogView(void); + void setScrollBars( QScrollBar *h, QScrollBar *v ); protected: + void paintEvent(QPaintEvent *event); + void resizeEvent(QResizeEvent *event); + + void calcFontData(void); + + protected: + QFont font; + QScrollBar *vbar; + QScrollBar *hbar; + + int pxCharWidth; + int pxCharHeight; + int pxLineSpacing; + int pxLineLead; + int pxCursorHeight; + int pxLineXScroll; + int pxLineWidth; + int viewLines; + int viewWidth; + int viewHeight; }; class TraceLoggerDialog_t : public QDialog From 2524667d12627332ce4a0a758ce5f69793f5e59a Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Thu, 1 Oct 2020 06:14:35 -0400 Subject: [PATCH 04/10] Enabled trace instruction function. Still TODO, try to make it more efficient. --- src/debug.cpp | 5 ----- src/drivers/Qt/TraceLogger.cpp | 21 +++++++++++++++++++++ src/drivers/Qt/TraceLogger.h | 1 + src/drivers/sdl/debugger.cpp | 5 +++++ 4 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/debug.cpp b/src/debug.cpp index 89bcafa8..3c9e8703 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -865,10 +865,5 @@ void DebugCycle() if(debug_loggingCD) LogCDData(opcode, A, size); -#ifdef WIN32 - //This needs to be windows only or else the linux build system will fail since logging is declared in a - //windows source file FCEUD_TraceInstruction(opcode, size); -#endif - } diff --git a/src/drivers/Qt/TraceLogger.cpp b/src/drivers/Qt/TraceLogger.cpp index 29ca18c8..bb9c0865 100644 --- a/src/drivers/Qt/TraceLogger.cpp +++ b/src/drivers/Qt/TraceLogger.cpp @@ -114,6 +114,12 @@ TraceLoggerDialog_t::TraceLoggerDialog_t(QWidget *parent) startStopButton = new QPushButton( tr("Start Logging") ); autoUpdateCbox = new QCheckBox( tr("Automatically update this window while logging") ); + if ( logging ) + { + startStopButton->setText( tr("Stop Logging") ); + } + connect( startStopButton, SIGNAL(clicked(void)), this, SLOT(toggleLoggingOnOff(void)) ); + hbox = new QHBoxLayout(); hbox->addWidget( logLastCbox ); hbox->addWidget( logMaxLinesComboBox ); @@ -194,6 +200,21 @@ void TraceLoggerDialog_t::closeWindow(void) done(0); deleteLater(); } +//---------------------------------------------------- +void TraceLoggerDialog_t::toggleLoggingOnOff(void) +{ + logging = !logging; + + if ( logging ) + { + startStopButton->setText( tr("Stop Logging") ); + } + else + { + startStopButton->setText( tr("Start Logging") ); + } +} +//---------------------------------------------------- //todo: really speed this up void FCEUD_TraceInstruction(uint8 *opcode, int size) { diff --git a/src/drivers/Qt/TraceLogger.h b/src/drivers/Qt/TraceLogger.h index dde8d2f8..e1bd1dd3 100644 --- a/src/drivers/Qt/TraceLogger.h +++ b/src/drivers/Qt/TraceLogger.h @@ -91,5 +91,6 @@ class TraceLoggerDialog_t : public QDialog public slots: void closeWindow(void); private slots: + void toggleLoggingOnOff(void); }; diff --git a/src/drivers/sdl/debugger.cpp b/src/drivers/sdl/debugger.cpp index c5982e24..ea23deea 100644 --- a/src/drivers/sdl/debugger.cpp +++ b/src/drivers/sdl/debugger.cpp @@ -1709,6 +1709,11 @@ void FCEUD_DebugBreakpoint(int bp_num) } } +void FCEUD_TraceInstruction(uint8 *opcode, int size) +{ + // Place holder to allow for compiling. GTK GUI doesn't support this. Qt Does. +} + static void closeDebuggerWindow (GtkWidget * w, GdkEvent * e, debuggerWin_t * dw) { std::list < debuggerWin_t * >::iterator it; From 0b3d377e18ba93b146ca13491dc3eb5269651589 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Thu, 1 Oct 2020 07:04:52 -0400 Subject: [PATCH 05/10] Changed trace instruction logger to be more efficient. --- src/drivers/Qt/TraceLogger.cpp | 106 ++++++++++++++++++++++++++++----- src/drivers/Qt/TraceLogger.h | 31 ++++++++++ 2 files changed, 122 insertions(+), 15 deletions(-) diff --git a/src/drivers/Qt/TraceLogger.cpp b/src/drivers/Qt/TraceLogger.cpp index bb9c0865..3a1daa2b 100644 --- a/src/drivers/Qt/TraceLogger.cpp +++ b/src/drivers/Qt/TraceLogger.cpp @@ -66,7 +66,7 @@ static char str_axystate[LOG_AXYSTATE_MAX_LEN] = {0}, str_procstatus[LOG_PROCSTA static char str_tabs[LOG_TABS_MASK+1] = {0}, str_address[LOG_ADDRESS_MAX_LEN] = {0}, str_data[LOG_DATA_MAX_LEN] = {0}, str_disassembly[LOG_DISASSEMBLY_MAX_LEN] = {0}; static char str_result[LOG_LINE_MAX_LEN] = {0}; static char str_temp[LOG_LINE_MAX_LEN] = {0}; -static char str_decoration[NL_MAX_MULTILINE_COMMENT_LEN + 10] = {0}; +//static char str_decoration[NL_MAX_MULTILINE_COMMENT_LEN + 10] = {0}; //static char str_decoration_comment[NL_MAX_MULTILINE_COMMENT_LEN + 10] = {0}; //static char* tracer_decoration_comment = 0; //static char* tracer_decoration_comment_end_pos = 0; @@ -215,19 +215,86 @@ void TraceLoggerDialog_t::toggleLoggingOnOff(void) } } //---------------------------------------------------- +traceRecord_t::traceRecord_t(void) +{ + cpu.PC = 0; + cpu.A = 0; + cpu.X = 0; + cpu.Y = 0; + cpu.S = 0; + cpu.P = 0; + + opCode[0] = 0; + opCode[1] = 0; + opCode[2] = 0; + opSize = 0; + asmTxtSize = 0; + asmTxt[0] = 0; + + cycleCount = 0; + instrCount = 0; + flags = 0; + + callAddr = -1; + romAddr = -1; + bank = -1; + skippedLines = 0; +} +//---------------------------------------------------- +int traceRecord_t::appendAsmText( const char *txt ) +{ + int i=0; + + while ( txt[i] != 0 ) + { + asmTxt[ asmTxtSize ] = txt[i]; i++; asmTxtSize++; + } + asmTxt[ asmTxtSize ] = 0; + + return 0; +} +//---------------------------------------------------- //todo: really speed this up void FCEUD_TraceInstruction(uint8 *opcode, int size) { if (!logging) return; + traceRecord_t rec; + unsigned int addr = X.PC; uint8 tmp; static int unloggedlines = 0; + rec.cpu.PC = X.PC; + rec.cpu.A = X.A; + rec.cpu.X = X.X; + rec.cpu.Y = X.Y; + rec.cpu.S = X.S; + rec.cpu.P = X.P; + + for (int i=0; i 0) + if (unloggedlines > 0) { - sprintf(str_result, "(%d lines skipped)", unloggedlines); + //sprintf(str_result, "(%d lines skipped)", unloggedlines); //OutputLogLine(str_result); + rec.skippedLines = unloggedlines; unloggedlines = 0; } } @@ -258,8 +326,9 @@ void FCEUD_TraceInstruction(uint8 *opcode, int size) if ((addr + size) > 0xFFFF) { - sprintf(str_data, "%02X ", opcode[0]); - sprintf(str_disassembly, "OVERFLOW"); + //sprintf(str_data, "%02X ", opcode[0]); + //sprintf(str_disassembly, "OVERFLOW"); + rec.flags |= 0x01; } else { @@ -267,12 +336,13 @@ void FCEUD_TraceInstruction(uint8 *opcode, int size) switch (size) { case 0: - sprintf(str_data, "%02X ", opcode[0]); - sprintf(str_disassembly,"UNDEFINED"); + //sprintf(str_data, "%02X ", opcode[0]); + //sprintf(str_disassembly,"UNDEFINED"); + rec.flags |= 0x02; break; case 1: { - sprintf(str_data, "%02X ", opcode[0]); + //sprintf(str_data, "%02X ", opcode[0]); a = Disassemble(addr + 1, opcode); // special case: an RTS opcode if (opcode[0] == 0x60) @@ -283,18 +353,19 @@ void FCEUD_TraceInstruction(uint8 *opcode, int size) { // this was a JSR instruction - take the subroutine address from it unsigned int call_addr = GetMem(caller_addr + 1) + (GetMem(caller_addr + 2) << 8); - sprintf(str_decoration, " (from $%04X)", call_addr); - strcat(a, str_decoration); + //sprintf(str_decoration, " (from $%04X)", call_addr); + //strcat(a, str_decoration); + rec.callAddr = call_addr; } } break; } case 2: - sprintf(str_data, "%02X %02X ", opcode[0],opcode[1]); + //sprintf(str_data, "%02X %02X ", opcode[0],opcode[1]); a = Disassemble(addr + 2, opcode); break; case 3: - sprintf(str_data, "%02X %02X %02X ", opcode[0],opcode[1],opcode[2]); + //sprintf(str_data, "%02X %02X %02X ", opcode[0],opcode[1],opcode[2]); a = Disassemble(addr + 3, opcode); break; } @@ -343,10 +414,15 @@ void FCEUD_TraceInstruction(uint8 *opcode, int size) // // replaceNames(pageNames[i], a, &tempAddressesLog); // //} //} - strncpy(str_disassembly, a, LOG_DISASSEMBLY_MAX_LEN); - str_disassembly[LOG_DISASSEMBLY_MAX_LEN - 1] = 0; + //strncpy(str_disassembly, a, LOG_DISASSEMBLY_MAX_LEN); + //str_disassembly[LOG_DISASSEMBLY_MAX_LEN - 1] = 0; + + rec.appendAsmText(a); } } + return; // TEST + // All of the following log text creation is very cpu intensive, to keep emulation + // running realtime save data and have a separate thread do this translation. if (size == 1 && GetMem(addr) == 0x60) { diff --git a/src/drivers/Qt/TraceLogger.h b/src/drivers/Qt/TraceLogger.h index e1bd1dd3..12532544 100644 --- a/src/drivers/Qt/TraceLogger.h +++ b/src/drivers/Qt/TraceLogger.h @@ -17,6 +17,37 @@ #include #include +struct traceRecord_t +{ + struct { + uint16_t PC; + uint8_t A; + uint8_t X; + uint8_t Y; + uint8_t S; + uint8_t P; + } cpu; + + uint8_t opCode[3]; + uint8_t opSize; + uint8_t asmTxtSize; + char asmTxt[46]; + + uint64_t frameCount; + uint64_t cycleCount; + uint64_t instrCount; + uint64_t flags; + + int32_t callAddr; + int32_t romAddr; + int32_t bank; + int32_t skippedLines; + + traceRecord_t(void); + + int appendAsmText( const char *txt ); +}; + class QTraceLogView : public QWidget { Q_OBJECT From 5bf2b6537817fd0a77ceaceb0c725fd50d532d22 Mon Sep 17 00:00:00 2001 From: mjbudd77 Date: Fri, 2 Oct 2020 16:47:36 -0400 Subject: [PATCH 06/10] Added logic to display running trace log in Qt window viewport --- src/drivers/Qt/TraceLogger.cpp | 626 ++++++++++++++++++++++++++------- src/drivers/Qt/TraceLogger.h | 20 ++ 2 files changed, 519 insertions(+), 127 deletions(-) diff --git a/src/drivers/Qt/TraceLogger.cpp b/src/drivers/Qt/TraceLogger.cpp index 3a1daa2b..a195b6b0 100644 --- a/src/drivers/Qt/TraceLogger.cpp +++ b/src/drivers/Qt/TraceLogger.cpp @@ -62,16 +62,20 @@ static int logging = 0; static int logging_options = LOG_REGISTERS | LOG_PROCESSOR_STATUS | LOG_TO_THE_LEFT | LOG_MESSAGES | LOG_BREAKPOINTS | LOG_CODE_TABBING; -static char str_axystate[LOG_AXYSTATE_MAX_LEN] = {0}, str_procstatus[LOG_PROCSTATUS_MAX_LEN] = {0}; -static char str_tabs[LOG_TABS_MASK+1] = {0}, str_address[LOG_ADDRESS_MAX_LEN] = {0}, str_data[LOG_DATA_MAX_LEN] = {0}, str_disassembly[LOG_DISASSEMBLY_MAX_LEN] = {0}; -static char str_result[LOG_LINE_MAX_LEN] = {0}; -static char str_temp[LOG_LINE_MAX_LEN] = {0}; +//static char str_axystate[LOG_AXYSTATE_MAX_LEN] = {0}, str_procstatus[LOG_PROCSTATUS_MAX_LEN] = {0}; +//static char str_tabs[LOG_TABS_MASK+1] = {0}, str_address[LOG_ADDRESS_MAX_LEN] = {0}, str_data[LOG_DATA_MAX_LEN] = {0}, str_disassembly[LOG_DISASSEMBLY_MAX_LEN] = {0}; +//static char str_result[LOG_LINE_MAX_LEN] = {0}; +//static char str_temp[LOG_LINE_MAX_LEN] = {0}; //static char str_decoration[NL_MAX_MULTILINE_COMMENT_LEN + 10] = {0}; //static char str_decoration_comment[NL_MAX_MULTILINE_COMMENT_LEN + 10] = {0}; //static char* tracer_decoration_comment = 0; //static char* tracer_decoration_comment_end_pos = 0; static int oldcodecount = 0, olddatacount = 0; +static traceRecord_t *recBuf = NULL; +static int recBufMax = 0; +static int recBufHead = 0; +//static int recBufTail = 0; //---------------------------------------------------- TraceLoggerDialog_t::TraceLoggerDialog_t(QWidget *parent) : QDialog( parent ) @@ -82,6 +86,11 @@ TraceLoggerDialog_t::TraceLoggerDialog_t(QWidget *parent) QGroupBox *frame; QLabel *lbl; + if ( recBufMax == 0 ) + { + initTraceLogBuffer( 10000 ); + } + setWindowTitle( tr("Trace Logger") ); mainLayout = new QVBoxLayout(); @@ -92,11 +101,15 @@ TraceLoggerDialog_t::TraceLoggerDialog_t(QWidget *parent) vbar = new QScrollBar( Qt::Vertical, this ); hbar = new QScrollBar( Qt::Horizontal, this ); + connect( hbar, SIGNAL(valueChanged(int)), this, SLOT(hbarChanged(int)) ); + connect( vbar, SIGNAL(valueChanged(int)), this, SLOT(vbarChanged(int)) ); + traceView->setScrollBars( hbar, vbar ); hbar->setMinimum(0); hbar->setMaximum(100); vbar->setMinimum(0); - vbar->setMaximum(10000); + vbar->setMaximum(recBufMax); + vbar->setValue(recBufMax); grid->addWidget( traceView, 0, 0); grid->addWidget( vbar , 0, 1 ); @@ -151,6 +164,30 @@ TraceLoggerDialog_t::TraceLoggerDialog_t(QWidget *parent) logInstrCountCbox = new QCheckBox( tr("Log Instructions Count") ); logBankNumCbox = new QCheckBox( tr("Log Bank Number") ); + logRegCbox->setChecked( (logging_options & LOG_REGISTERS) ? true : false ); + logFrameCbox->setChecked( (logging_options & LOG_FRAMES_COUNT) ? true : false ); + logEmuMsgCbox->setChecked( (logging_options & LOG_MESSAGES) ? true : false ); + symTraceEnaCbox->setChecked( (logging_options & LOG_SYMBOLIC) ? true : false ); + logProcStatFlagCbox->setChecked( (logging_options & LOG_PROCESSOR_STATUS) ? true : false ); + logCyclesCountCbox->setChecked( (logging_options & LOG_CYCLES_COUNT) ? true : false ); + logBreakpointCbox->setChecked( (logging_options & LOG_BREAKPOINTS) ? true : false ); + useStackPointerCbox->setChecked( (logging_options & LOG_CODE_TABBING) ? true : false ); + toLeftDisassemblyCbox->setChecked( (logging_options & LOG_TO_THE_LEFT) ? true : false ); + logInstrCountCbox->setChecked( (logging_options & LOG_INSTRUCTIONS_COUNT) ? true : false ); + logBankNumCbox->setChecked( (logging_options & LOG_BANK_NUMBER) ? true : false ); + + connect( logRegCbox, SIGNAL(stateChanged(int)), this, SLOT(logRegStateChanged(int)) ); + connect( logFrameCbox, SIGNAL(stateChanged(int)), this, SLOT(logFrameStateChanged(int)) ); + connect( logEmuMsgCbox, SIGNAL(stateChanged(int)), this, SLOT(logEmuMsgStateChanged(int)) ); + connect( symTraceEnaCbox, SIGNAL(stateChanged(int)), this, SLOT(symTraceEnaStateChanged(int)) ); + connect( logProcStatFlagCbox, SIGNAL(stateChanged(int)), this, SLOT(logProcStatFlagStateChanged(int)) ); + connect( logCyclesCountCbox, SIGNAL(stateChanged(int)), this, SLOT(logCyclesCountStateChanged(int)) ); + connect( logBreakpointCbox, SIGNAL(stateChanged(int)), this, SLOT(logBreakpointStateChanged(int)) ); + connect( useStackPointerCbox, SIGNAL(stateChanged(int)), this, SLOT(useStackPointerStateChanged(int)) ); + connect( toLeftDisassemblyCbox, SIGNAL(stateChanged(int)), this, SLOT(toLeftDisassemblyStateChanged(int)) ); + connect( logInstrCountCbox, SIGNAL(stateChanged(int)), this, SLOT(logInstrCountStateChanged(int)) ); + connect( logBankNumCbox, SIGNAL(stateChanged(int)), this, SLOT(logBankNumStateChanged(int)) ); + grid->addWidget( logRegCbox , 0, 0, Qt::AlignLeft ); grid->addWidget( logFrameCbox , 1, 0, Qt::AlignLeft ); grid->addWidget( logEmuMsgCbox , 2, 0, Qt::AlignLeft ); @@ -172,6 +209,12 @@ TraceLoggerDialog_t::TraceLoggerDialog_t(QWidget *parent) logNewMapCodeCbox = new QCheckBox( tr("Only Log Newly Mapped Code") ); logNewMapDataCbox = new QCheckBox( tr("Only Log that Accesses Newly Mapped Data") ); + logNewMapCodeCbox->setChecked( (logging_options & LOG_NEW_INSTRUCTIONS) ? true : false ); + logNewMapDataCbox->setChecked( (logging_options & LOG_NEW_DATA) ? true : false ); + + connect( logNewMapCodeCbox, SIGNAL(stateChanged(int)), this, SLOT(logNewMapCodeChanged(int)) ); + connect( logNewMapDataCbox, SIGNAL(stateChanged(int)), this, SLOT(logNewMapDataChanged(int)) ); + grid->addWidget( logNewMapCodeCbox, 0, 0, Qt::AlignLeft ); grid->addWidget( logNewMapDataCbox, 0, 1, Qt::AlignLeft ); @@ -179,10 +222,17 @@ TraceLoggerDialog_t::TraceLoggerDialog_t(QWidget *parent) setLayout( mainLayout ); + updateTimer = new QTimer( this ); + + connect( updateTimer, &QTimer::timeout, this, &TraceLoggerDialog_t::updatePeriodic ); + + updateTimer->start( 200 ); // 5hz } //---------------------------------------------------- TraceLoggerDialog_t::~TraceLoggerDialog_t(void) { + updateTimer->stop(); + printf("Trace Logger Window Deleted\n"); } //---------------------------------------------------- @@ -201,6 +251,12 @@ void TraceLoggerDialog_t::closeWindow(void) deleteLater(); } //---------------------------------------------------- +void TraceLoggerDialog_t::updatePeriodic(void) +{ + + traceView->update(); +} +//---------------------------------------------------- void TraceLoggerDialog_t::toggleLoggingOnOff(void) { logging = !logging; @@ -215,6 +271,172 @@ void TraceLoggerDialog_t::toggleLoggingOnOff(void) } } //---------------------------------------------------- +void TraceLoggerDialog_t::hbarChanged(int val) +{ + traceView->update(); +} +//---------------------------------------------------- +void TraceLoggerDialog_t::vbarChanged(int val) +{ + traceView->update(); +} +//---------------------------------------------------- +void TraceLoggerDialog_t::logRegStateChanged(int state) +{ + if ( state == Qt::Unchecked ) + { + logging_options &= ~LOG_REGISTERS; + } + else + { + logging_options |= LOG_REGISTERS; + } +} +//---------------------------------------------------- +void TraceLoggerDialog_t::logFrameStateChanged(int state) +{ + if ( state == Qt::Unchecked ) + { + logging_options &= ~LOG_FRAMES_COUNT; + } + else + { + logging_options |= LOG_FRAMES_COUNT; + } +} +//---------------------------------------------------- +void TraceLoggerDialog_t::logEmuMsgStateChanged(int state) +{ + if ( state == Qt::Unchecked ) + { + logging_options &= ~LOG_MESSAGES; + } + else + { + logging_options |= LOG_MESSAGES; + } +} +//---------------------------------------------------- +void TraceLoggerDialog_t::symTraceEnaStateChanged(int state) +{ + if ( state == Qt::Unchecked ) + { + logging_options &= ~LOG_SYMBOLIC; + } + else + { + logging_options |= LOG_SYMBOLIC; + } +} +//---------------------------------------------------- +void TraceLoggerDialog_t::logProcStatFlagStateChanged(int state) +{ + if ( state == Qt::Unchecked ) + { + logging_options &= ~LOG_PROCESSOR_STATUS; + } + else + { + logging_options |= LOG_PROCESSOR_STATUS; + } +} +//---------------------------------------------------- +void TraceLoggerDialog_t::logCyclesCountStateChanged(int state) +{ + if ( state == Qt::Unchecked ) + { + logging_options &= ~LOG_CYCLES_COUNT; + } + else + { + logging_options |= LOG_CYCLES_COUNT; + } +} +//---------------------------------------------------- +void TraceLoggerDialog_t::logBreakpointStateChanged(int state) +{ + if ( state == Qt::Unchecked ) + { + logging_options &= ~LOG_BREAKPOINTS; + } + else + { + logging_options |= LOG_BREAKPOINTS; + } +} +//---------------------------------------------------- +void TraceLoggerDialog_t::useStackPointerStateChanged(int state) +{ + if ( state == Qt::Unchecked ) + { + logging_options &= ~LOG_CODE_TABBING; + } + else + { + logging_options |= LOG_CODE_TABBING; + } +} +//---------------------------------------------------- +void TraceLoggerDialog_t::toLeftDisassemblyStateChanged(int state) +{ + if ( state == Qt::Unchecked ) + { + logging_options &= ~LOG_TO_THE_LEFT; + } + else + { + logging_options |= LOG_TO_THE_LEFT; + } +} +//---------------------------------------------------- +void TraceLoggerDialog_t::logInstrCountStateChanged(int state) +{ + if ( state == Qt::Unchecked ) + { + logging_options &= ~LOG_INSTRUCTIONS_COUNT; + } + else + { + logging_options |= LOG_INSTRUCTIONS_COUNT; + } +} +//---------------------------------------------------- +void TraceLoggerDialog_t::logBankNumStateChanged(int state) +{ + if ( state == Qt::Unchecked ) + { + logging_options &= ~LOG_BANK_NUMBER; + } + else + { + logging_options |= LOG_BANK_NUMBER; + } +} +//---------------------------------------------------- +void TraceLoggerDialog_t::logNewMapCodeChanged(int state) +{ + if ( state == Qt::Unchecked ) + { + logging_options &= ~LOG_NEW_INSTRUCTIONS; + } + else + { + logging_options |= LOG_NEW_INSTRUCTIONS; + } +} +//---------------------------------------------------- +void TraceLoggerDialog_t::logNewMapDataChanged(int state) +{ + if ( state == Qt::Unchecked ) + { + logging_options &= ~LOG_NEW_DATA; + } + else + { + logging_options |= LOG_NEW_DATA; + } +} +//---------------------------------------------------- traceRecord_t::traceRecord_t(void) { cpu.PC = 0; @@ -254,6 +476,223 @@ int traceRecord_t::appendAsmText( const char *txt ) return 0; } //---------------------------------------------------- +static int convToXchar( int i ) +{ + int c = 0; + + if ( (i >= 0) && (i < 10) ) + { + c = i + '0'; + } + else if ( i < 16 ) + { + c = (i - 10) + 'A'; + } + return c; +} +//---------------------------------------------------- +int traceRecord_t::convToText( char *txt ) +{ + int i=0, j=0; + char stmp[128]; + char str_axystate[32], str_procstatus[32]; + + txt[0] = 0; + if ( opSize == 0 ) return -1; + + // Start filling the str_temp line: Frame count, Cycles count, Instructions count, AXYS state, Processor status, Tabs, Address, Data, Disassembly + if (logging_options & LOG_FRAMES_COUNT) + { + sprintf(stmp, "f%-6llu ", (long long unsigned int)frameCount); + + j=0; + while ( stmp[j] != 0 ) + { + txt[i] = stmp[j]; i++; j++; + } + } + + if (logging_options & LOG_CYCLES_COUNT) + { + sprintf(stmp, "c%-11llu ", (long long unsigned int)cycleCount); + + j=0; + while ( stmp[j] != 0 ) + { + txt[i] = stmp[j]; i++; j++; + } + } + + if (logging_options & LOG_INSTRUCTIONS_COUNT) + { + sprintf(stmp, "i%-11llu ", (long long unsigned int)instrCount); + + j=0; + while ( stmp[j] != 0 ) + { + txt[i] = stmp[j]; i++; j++; + } + } + + if (logging_options & LOG_REGISTERS) + { + sprintf(str_axystate,"A:%02X X:%02X Y:%02X S:%02X ",(cpu.A),(cpu.X),(cpu.Y),(cpu.S)); + } + + if (logging_options & LOG_PROCESSOR_STATUS) + { + int tmp = cpu.P^0xFF; + sprintf(str_procstatus,"P:%c%c%c%c%c%c%c%c ", + 'N'|(tmp&0x80)>>2, + 'V'|(tmp&0x40)>>1, + 'U'|(tmp&0x20), + 'B'|(tmp&0x10)<<1, + 'D'|(tmp&0x08)<<2, + 'I'|(tmp&0x04)<<3, + 'Z'|(tmp&0x02)<<4, + 'C'|(tmp&0x01)<<5 + ); + } + + if (logging_options & LOG_TO_THE_LEFT) + { + if (logging_options & LOG_REGISTERS) + { + j=0; + while ( str_axystate[j] != 0 ) + { + txt[i] = str_axystate[j]; i++; j++; + } + } + if (logging_options & LOG_PROCESSOR_STATUS) + { + j=0; + while ( str_procstatus[j] != 0 ) + { + txt[i] = str_procstatus[j]; i++; j++; + } + } + } + + if (logging_options & LOG_CODE_TABBING) + { + // add spaces at the beginning of the line according to stack pointer + int spaces = (0xFF - cpu.S) & LOG_TABS_MASK; + + while ( spaces > 0 ) + { + txt[i] = ' '; i++; spaces--; + } + } + else if (logging_options & LOG_TO_THE_LEFT) + { + txt[i] = ' '; i++; + } + + if (logging_options & LOG_BANK_NUMBER) + { + if (cpu.PC >= 0x8000) + { + sprintf(stmp, "$%02X:%04X: ", bank, cpu.PC); + } + else + { + sprintf(stmp, " $%04X: ", cpu.PC); + } + } + else + { + sprintf(stmp, "$%04X: ", cpu.PC); + } + j=0; + while ( stmp[j] != 0 ) + { + txt[i] = stmp[j]; i++; j++; + } + + for (j=0; j> 4) & 0x0F ); i++; + txt[i] = convToXchar( opCode[j] & 0x0F ); i++; + txt[i] = ' '; i++; + } + while ( j < 3 ) + { + txt[i] = ' '; i++; + txt[i] = ' '; i++; + txt[i] = ' '; i++; + j++; + } + j=0; + while ( asmTxt[j] != 0 ) + { + txt[i] = asmTxt[j]; i++; j++; + } + if ( callAddr >= 0 ) + { + sprintf(stmp, " (from $%04X)", callAddr); + + j=0; + while ( stmp[j] != 0 ) + { + txt[i] = stmp[j]; i++; j++; + } + } + + if (!(logging_options & LOG_TO_THE_LEFT)) + { + if (logging_options & LOG_REGISTERS) + { + j=0; + while ( str_axystate[j] != 0 ) + { + txt[i] = str_axystate[j]; i++; j++; + } + } + if (logging_options & LOG_PROCESSOR_STATUS) + { + j=0; + while ( str_procstatus[j] != 0 ) + { + txt[i] = str_procstatus[j]; i++; j++; + } + } + } + + txt[i] = 0; + + return 0; +} +//---------------------------------------------------- +int initTraceLogBuffer( int maxRecs ) +{ + if ( maxRecs != recBufMax ) + { + size_t size; + + size = maxRecs * sizeof(traceRecord_t); + + recBuf = (traceRecord_t*)malloc( size ); + + if ( recBuf ) + { + memset( (void*)recBuf, 0, size ); + recBufMax = maxRecs; + } + else + { + recBufMax = 0; + } + } + return recBuf == NULL; +} +//---------------------------------------------------- +static void pushToLogBuffer( traceRecord_t &rec ) +{ + recBuf[ recBufHead ] = rec; + recBufHead = (recBufHead + 1) % recBufMax; +} +//---------------------------------------------------- //todo: really speed this up void FCEUD_TraceInstruction(uint8 *opcode, int size) { @@ -263,7 +702,6 @@ void FCEUD_TraceInstruction(uint8 *opcode, int size) traceRecord_t rec; unsigned int addr = X.PC; - uint8 tmp; static int unloggedlines = 0; rec.cpu.PC = X.PC; @@ -420,131 +858,20 @@ void FCEUD_TraceInstruction(uint8 *opcode, int size) rec.appendAsmText(a); } } + + pushToLogBuffer( rec ); + return; // TEST // All of the following log text creation is very cpu intensive, to keep emulation // running realtime save data and have a separate thread do this translation. - if (size == 1 && GetMem(addr) == 0x60) - { - // special case: an RTS opcode - // add "----------" to emphasize the end of subroutine - static const char* emphasize = " -------------------------------------------------------------------------------------------------------------------------"; - strncat(str_disassembly, emphasize, LOG_DISASSEMBLY_MAX_LEN - strlen(str_disassembly) - 1); - } - // stretch the disassembly string out if we have to output other stuff. - if ((logging_options & (LOG_REGISTERS|LOG_PROCESSOR_STATUS)) && !(logging_options & LOG_TO_THE_LEFT)) - { - for (int i = strlen(str_disassembly); i < (LOG_DISASSEMBLY_MAX_LEN - 1); ++i) - str_disassembly[i] = ' '; - str_disassembly[LOG_DISASSEMBLY_MAX_LEN - 1] = 0; - } - - // Start filling the str_temp line: Frame count, Cycles count, Instructions count, AXYS state, Processor status, Tabs, Address, Data, Disassembly - if (logging_options & LOG_FRAMES_COUNT) - { - sprintf(str_result, "f%-6u ", currFrameCounter); - } else - { - str_result[0] = 0; - } - if (logging_options & LOG_CYCLES_COUNT) - { - int64 counter_value = timestampbase + (uint64)timestamp - total_cycles_base; - if (counter_value < 0) // sanity check - { - ResetDebugStatisticsCounters(); - counter_value = 0; - } - sprintf(str_temp, "c%-11llu ", counter_value); - strcat(str_result, str_temp); - } - if (logging_options & LOG_INSTRUCTIONS_COUNT) - { - sprintf(str_temp, "i%-11llu ", total_instructions); - strcat(str_result, str_temp); - } - - if (logging_options & LOG_REGISTERS) - { - sprintf(str_axystate,"A:%02X X:%02X Y:%02X S:%02X ",(X.A),(X.X),(X.Y),(X.S)); - } - - if (logging_options & LOG_PROCESSOR_STATUS) - { - tmp = X.P^0xFF; - sprintf(str_procstatus,"P:%c%c%c%c%c%c%c%c ", - 'N'|(tmp&0x80)>>2, - 'V'|(tmp&0x40)>>1, - 'U'|(tmp&0x20), - 'B'|(tmp&0x10)<<1, - 'D'|(tmp&0x08)<<2, - 'I'|(tmp&0x04)<<3, - 'Z'|(tmp&0x02)<<4, - 'C'|(tmp&0x01)<<5 - ); - } - - if (logging_options & LOG_TO_THE_LEFT) - { - if (logging_options & LOG_REGISTERS) - { - strcat(str_result, str_axystate); - } - if (logging_options & LOG_PROCESSOR_STATUS) - { - strcat(str_result, str_procstatus); - } - } - - if (logging_options & LOG_CODE_TABBING) - { - // add spaces at the beginning of the line according to stack pointer - int spaces = (0xFF - X.S) & LOG_TABS_MASK; - for (int i = 0; i < spaces; i++) - { - str_tabs[i] = ' '; - } - str_tabs[spaces] = 0; - strcat(str_result, str_tabs); - } - else if (logging_options & LOG_TO_THE_LEFT) - { - strcat(str_result, " "); - } - - if (logging_options & LOG_BANK_NUMBER) - { - if (addr >= 0x8000) - { - sprintf(str_address, "$%02X:%04X: ", getBank(addr), addr); - } - else - { - sprintf(str_address, " $%04X: ", addr); - } - } - else - { - sprintf(str_address, "$%04X: ", addr); - } - - strcat(str_result, str_address); - strcat(str_result, str_data); - strcat(str_result, str_disassembly); - - if (!(logging_options & LOG_TO_THE_LEFT)) - { - if (logging_options & LOG_REGISTERS) - { - strcat(str_result, str_axystate); - } - if (logging_options & LOG_PROCESSOR_STATUS) - { - strcat(str_result, str_procstatus); - } - } - - //OutputLogLine(str_result, &tempAddressesLog); + //if (size == 1 && GetMem(addr) == 0x60) + //{ + // // special case: an RTS opcode + // // add "----------" to emphasize the end of subroutine + // static const char* emphasize = " -------------------------------------------------------------------------------------------------------------------------"; + // strncat(str_disassembly, emphasize, LOG_DISASSEMBLY_MAX_LEN - strlen(str_disassembly) - 1); + //} return; } @@ -614,11 +941,56 @@ void QTraceLogView::resizeEvent(QResizeEvent *event) //---------------------------------------------------- void QTraceLogView::paintEvent(QPaintEvent *event) { + int x,y, ofs, row, start, end, nrow; QPainter painter(this); + char line[256]; + traceRecord_t rec[64]; painter.setFont(font); viewWidth = event->rect().width(); viewHeight = event->rect().height(); + nrow = (viewHeight - pxLineSpacing) / pxLineSpacing; + + if (nrow < 1 ) nrow = 1; + + viewLines = nrow; + + painter.fillRect( 0, 0, viewWidth, viewHeight, this->palette().color(QPalette::Background) ); + + painter.setPen( this->palette().color(QPalette::WindowText)); + + ofs = recBufMax - vbar->value(); + + end = recBufHead - ofs; + + if ( end < 0 ) end += recBufMax; + + start = (end - nrow - 1); + + if ( start < 0 ) start += recBufMax; + + row = 0; + while ( start != end ) + { + rec[row] = recBuf[ start ]; row++; + start = (start + 1) % recBufMax; + } + + y = pxLineSpacing; + + for (row=0; row Date: Fri, 2 Oct 2020 16:54:29 -0400 Subject: [PATCH 07/10] Added lines skipped logic for trace logger new code/data functionality. --- src/drivers/Qt/TraceLogger.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/drivers/Qt/TraceLogger.cpp b/src/drivers/Qt/TraceLogger.cpp index a195b6b0..25ded7da 100644 --- a/src/drivers/Qt/TraceLogger.cpp +++ b/src/drivers/Qt/TraceLogger.cpp @@ -500,6 +500,17 @@ int traceRecord_t::convToText( char *txt ) txt[0] = 0; if ( opSize == 0 ) return -1; + if ( skippedLines > 0 ) + { + sprintf(stmp, "(%d lines skipped) ", skippedLines); + + j=0; + while ( stmp[j] != 0 ) + { + txt[i] = stmp[j]; i++; j++; + } + } + // Start filling the str_temp line: Frame count, Cycles count, Instructions count, AXYS state, Processor status, Tabs, Address, Data, Disassembly if (logging_options & LOG_FRAMES_COUNT) { @@ -743,7 +754,6 @@ void FCEUD_TraceInstruction(uint8 *opcode, int size) if (unloggedlines > 0) { //sprintf(str_result, "(%d lines skipped)", unloggedlines); - //OutputLogLine(str_result); rec.skippedLines = unloggedlines; unloggedlines = 0; } @@ -774,13 +784,11 @@ void FCEUD_TraceInstruction(uint8 *opcode, int size) switch (size) { case 0: - //sprintf(str_data, "%02X ", opcode[0]); //sprintf(str_disassembly,"UNDEFINED"); rec.flags |= 0x02; break; case 1: { - //sprintf(str_data, "%02X ", opcode[0]); a = Disassemble(addr + 1, opcode); // special case: an RTS opcode if (opcode[0] == 0x60) @@ -791,19 +799,15 @@ void FCEUD_TraceInstruction(uint8 *opcode, int size) { // this was a JSR instruction - take the subroutine address from it unsigned int call_addr = GetMem(caller_addr + 1) + (GetMem(caller_addr + 2) << 8); - //sprintf(str_decoration, " (from $%04X)", call_addr); - //strcat(a, str_decoration); rec.callAddr = call_addr; } } break; } case 2: - //sprintf(str_data, "%02X %02X ", opcode[0],opcode[1]); a = Disassemble(addr + 2, opcode); break; case 3: - //sprintf(str_data, "%02X %02X %02X ", opcode[0],opcode[1],opcode[2]); a = Disassemble(addr + 3, opcode); break; } From af35f81f4fafa641c76ee3b78c87b2f2b4228c67 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Fri, 2 Oct 2020 21:44:47 -0400 Subject: [PATCH 08/10] More logic updates for Qt trace logger window. Added log to file feature. --- src/drivers/Qt/ConsoleWindow.cpp | 24 ++- src/drivers/Qt/TraceLogger.cpp | 245 ++++++++++++++++++++++++++++--- src/drivers/Qt/TraceLogger.h | 8 +- 3 files changed, 238 insertions(+), 39 deletions(-) diff --git a/src/drivers/Qt/ConsoleWindow.cpp b/src/drivers/Qt/ConsoleWindow.cpp index b3599e38..d4f7e723 100644 --- a/src/drivers/Qt/ConsoleWindow.cpp +++ b/src/drivers/Qt/ConsoleWindow.cpp @@ -501,14 +501,6 @@ 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); - // Debug -> Trace Logger traceLogAct = new QAction(tr("Trace Logger..."), this); //traceLogAct->setShortcut( QKeySequence(tr("Shift+F7"))); @@ -517,6 +509,14 @@ void consoleWin_t::createMainMenu(void) debugMenu->addAction(traceLogAct); + // 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")); @@ -1034,13 +1034,7 @@ void consoleWin_t::openCodeDataLogger(void) void consoleWin_t::openTraceLogger(void) { - TraceLoggerDialog_t *tlWin; - - //printf("Open Trace Logger Window\n"); - - tlWin = new TraceLoggerDialog_t(this); - - tlWin->show(); + openTraceLoggerWindow(this); } void consoleWin_t::toggleAutoResume(void) diff --git a/src/drivers/Qt/TraceLogger.cpp b/src/drivers/Qt/TraceLogger.cpp index 25ded7da..37bebb43 100644 --- a/src/drivers/Qt/TraceLogger.cpp +++ b/src/drivers/Qt/TraceLogger.cpp @@ -1,5 +1,7 @@ // TraceLogger.cpp // +#include + #include #include #include @@ -62,20 +64,15 @@ static int logging = 0; static int logging_options = LOG_REGISTERS | LOG_PROCESSOR_STATUS | LOG_TO_THE_LEFT | LOG_MESSAGES | LOG_BREAKPOINTS | LOG_CODE_TABBING; -//static char str_axystate[LOG_AXYSTATE_MAX_LEN] = {0}, str_procstatus[LOG_PROCSTATUS_MAX_LEN] = {0}; -//static char str_tabs[LOG_TABS_MASK+1] = {0}, str_address[LOG_ADDRESS_MAX_LEN] = {0}, str_data[LOG_DATA_MAX_LEN] = {0}, str_disassembly[LOG_DISASSEMBLY_MAX_LEN] = {0}; -//static char str_result[LOG_LINE_MAX_LEN] = {0}; -//static char str_temp[LOG_LINE_MAX_LEN] = {0}; -//static char str_decoration[NL_MAX_MULTILINE_COMMENT_LEN + 10] = {0}; -//static char str_decoration_comment[NL_MAX_MULTILINE_COMMENT_LEN + 10] = {0}; -//static char* tracer_decoration_comment = 0; -//static char* tracer_decoration_comment_end_pos = 0; static int oldcodecount = 0, olddatacount = 0; static traceRecord_t *recBuf = NULL; static int recBufMax = 0; static int recBufHead = 0; -//static int recBufTail = 0; +static int recBufTail = 0; +static FILE *logFile = NULL; +static TraceLoggerDialog_t *traceLogWindow = NULL; +static void pushMsgToLogBuffer( const char *msg ); //---------------------------------------------------- TraceLoggerDialog_t::TraceLoggerDialog_t(QWidget *parent) : QDialog( parent ) @@ -88,7 +85,7 @@ TraceLoggerDialog_t::TraceLoggerDialog_t(QWidget *parent) if ( recBufMax == 0 ) { - initTraceLogBuffer( 10000 ); + initTraceLogBuffer( 1000000 ); } setWindowTitle( tr("Trace Logger") ); @@ -122,16 +119,38 @@ TraceLoggerDialog_t::TraceLoggerDialog_t(QWidget *parent) logLastCbox = new QCheckBox( tr("Log Last") ); logMaxLinesComboBox = new QComboBox(); + logLastCbox->setChecked(true); + logMaxLinesComboBox->addItem( tr("3,000,000"), 3000000 ); + logMaxLinesComboBox->addItem( tr("1,000,000"), 1000000 ); + logMaxLinesComboBox->addItem( tr("300,000") , 300000 ); + logMaxLinesComboBox->addItem( tr("100,000") , 100000 ); + logMaxLinesComboBox->addItem( tr("30,000") , 30000 ); + logMaxLinesComboBox->addItem( tr("10,000") , 10000 ); + logMaxLinesComboBox->addItem( tr("3,000") , 3000 ); + logMaxLinesComboBox->addItem( tr("1,000") , 1000 ); + + for (int i=0; icount(); i++) + { + if ( logMaxLinesComboBox->itemData(i).toInt() == recBufMax ) + { + logMaxLinesComboBox->setCurrentIndex( i ); + } + } + connect( logMaxLinesComboBox, SIGNAL(activated(int)), this, SLOT(logMaxLinesChanged(int)) ); + logFileCbox = new QCheckBox( tr("Log to File") ); selLogFileButton = new QPushButton( tr("Browse...") ); startStopButton = new QPushButton( tr("Start Logging") ); autoUpdateCbox = new QCheckBox( tr("Automatically update this window while logging") ); + autoUpdateCbox->setChecked(true); + if ( logging ) { startStopButton->setText( tr("Stop Logging") ); } connect( startStopButton, SIGNAL(clicked(void)), this, SLOT(toggleLoggingOnOff(void)) ); + connect( selLogFileButton, SIGNAL(clicked(void)), this, SLOT(openLogFile(void)) ); hbox = new QHBoxLayout(); hbox->addWidget( logLastCbox ); @@ -222,17 +241,26 @@ TraceLoggerDialog_t::TraceLoggerDialog_t(QWidget *parent) setLayout( mainLayout ); + traceViewCounter = 0; + updateTimer = new QTimer( this ); connect( updateTimer, &QTimer::timeout, this, &TraceLoggerDialog_t::updatePeriodic ); - updateTimer->start( 200 ); // 5hz + updateTimer->start( 10 ); // 100hz } //---------------------------------------------------- TraceLoggerDialog_t::~TraceLoggerDialog_t(void) { updateTimer->stop(); + traceLogWindow = NULL; + logging = 0; + + if ( logFile ) + { + fclose( logFile ); logFile = NULL; + } printf("Trace Logger Window Deleted\n"); } //---------------------------------------------------- @@ -253,24 +281,149 @@ void TraceLoggerDialog_t::closeWindow(void) //---------------------------------------------------- void TraceLoggerDialog_t::updatePeriodic(void) { + char traceViewDrawEnable; - traceView->update(); + if ( logLastCbox->isChecked() ) + { + if ( FCEUI_EmulationPaused() ) + { + traceViewDrawEnable = 1; + } + else + { + traceViewDrawEnable = autoUpdateCbox->isChecked(); + } + } + else + { + traceViewDrawEnable = 0; + } + + if ( logFile && logFileCbox->isChecked() ) + { + char line[256]; + + while ( recBufHead != recBufTail ) + { + recBuf[ recBufTail ].convToText( line ); + + fprintf( logFile, "%s\n", line ); + + recBufTail = (recBufTail + 1) % recBufMax; + } + } + else + { + recBufTail = recBufHead; + } + + if ( traceViewCounter > 20 ) + { + if ( traceViewDrawEnable ) + { + traceView->update(); + } + traceViewCounter = 0; + } + traceViewCounter++; +} +//---------------------------------------------------- +void TraceLoggerDialog_t::logMaxLinesChanged(int index) +{ + int logPrev; + int maxLines = logMaxLinesComboBox->itemData(index).toInt(); + + logPrev = logging; + logging = 0; + + usleep(1000); + + initTraceLogBuffer( maxLines ); + + vbar->setMaximum(recBufMax); + vbar->setValue(recBufMax); + + logging = logPrev; } //---------------------------------------------------- void TraceLoggerDialog_t::toggleLoggingOnOff(void) { - logging = !logging; - if ( logging ) { - startStopButton->setText( tr("Stop Logging") ); + logging = 0; + usleep( 1000 ); + pushMsgToLogBuffer("Logging Finished"); + startStopButton->setText( tr("Start Logging") ); } else { - startStopButton->setText( tr("Start Logging") ); + pushMsgToLogBuffer("Log Start"); + startStopButton->setText( tr("Stop Logging") ); + logging = 1; } } //---------------------------------------------------- +void TraceLoggerDialog_t::openLogFile(void) +{ + const char *romFile; + int ret, useNativeFileDialogVal; + QString filename; + QFileDialog dialog(this, tr("Select Log File") ); + + printf("Log File Select\n"); + + dialog.setFileMode(QFileDialog::AnyFile); + + dialog.setNameFilter(tr("LOG files (*.log *.LOG) ;; All files (*)")); + + dialog.setViewMode(QFileDialog::List); + dialog.setFilter( QDir::AllEntries | QDir::Hidden ); + dialog.setLabelText( QFileDialog::Accept, tr("Open") ); + dialog.setDefaultSuffix( tr(".log") ); + + romFile = getRomFile(); + + if ( romFile != NULL ) + { + char dir[512]; + 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(); + + if ( logFile ) + { + fclose( logFile ); logFile = NULL; + } + logFile = fopen( filename.toStdString().c_str(), "w"); + + return; +} +//---------------------------------------------------- void TraceLoggerDialog_t::hbarChanged(int val) { traceView->update(); @@ -498,7 +651,17 @@ int traceRecord_t::convToText( char *txt ) char str_axystate[32], str_procstatus[32]; txt[0] = 0; - if ( opSize == 0 ) return -1; + if ( opSize == 0 ) + { + j=0; + while ( asmTxt[j] != 0 ) + { + txt[i] = asmTxt[j]; i++; j++; + } + txt[i] = 0; + + return -1; + } if ( skippedLines > 0 ) { @@ -698,10 +861,40 @@ int initTraceLogBuffer( int maxRecs ) return recBuf == NULL; } //---------------------------------------------------- +void openTraceLoggerWindow( QWidget *parent ) +{ + // Only allow one trace logger window to be open + if ( traceLogWindow != NULL ) + { + return; + } + //printf("Open Trace Logger Window\n"); + + traceLogWindow = new TraceLoggerDialog_t(parent); + + traceLogWindow->show(); +} +//---------------------------------------------------- static void pushToLogBuffer( traceRecord_t &rec ) { recBuf[ recBufHead ] = rec; recBufHead = (recBufHead + 1) % recBufMax; + + if ( recBufHead == recBufTail ) + { + printf("Trace Log Overrun!!!\n"); + } +} +//---------------------------------------------------- +static void pushMsgToLogBuffer( const char *msg ) +{ + traceRecord_t rec; + + strncpy( rec.asmTxt, msg, sizeof(rec.asmTxt) ); + + rec.asmTxt[ sizeof(rec.asmTxt)-1 ] = 0; + + pushToLogBuffer( rec ); } //---------------------------------------------------- //todo: really speed this up @@ -945,7 +1138,7 @@ void QTraceLogView::resizeEvent(QResizeEvent *event) //---------------------------------------------------- void QTraceLogView::paintEvent(QPaintEvent *event) { - int x,y, ofs, row, start, end, nrow; + int x,y, v, ofs, row, start, end, nrow; QPainter painter(this); char line[256]; traceRecord_t rec[64]; @@ -954,7 +1147,7 @@ void QTraceLogView::paintEvent(QPaintEvent *event) viewWidth = event->rect().width(); viewHeight = event->rect().height(); - nrow = (viewHeight - pxLineSpacing) / pxLineSpacing; + nrow = (viewHeight / pxLineSpacing); if (nrow < 1 ) nrow = 1; @@ -964,13 +1157,17 @@ void QTraceLogView::paintEvent(QPaintEvent *event) painter.setPen( this->palette().color(QPalette::WindowText)); - ofs = recBufMax - vbar->value(); + v = vbar->value(); + + if ( v < viewLines ) v = viewLines; + + ofs = recBufMax - v; end = recBufHead - ofs; if ( end < 0 ) end += recBufMax; - start = (end - nrow - 1); + start = (end - nrow); if ( start < 0 ) start += recBufMax; @@ -981,11 +1178,13 @@ void QTraceLogView::paintEvent(QPaintEvent *event) start = (start + 1) % recBufMax; } - y = pxLineSpacing; + pxLineXScroll = (int)(0.010f * (float)hbar->value() * (float)(pxLineWidth - viewWidth) ); + + x = -pxLineXScroll; + y = pxLineSpacing; for (row=0; row Date: Fri, 2 Oct 2020 21:58:34 -0400 Subject: [PATCH 09/10] Updated TODO-SDL file to show new Qt GUI features --- TODO-SDL | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/TODO-SDL b/TODO-SDL index e6000743..83f91b5c 100644 --- a/TODO-SDL +++ b/TODO-SDL @@ -46,8 +46,8 @@ TAS Editor | NO | NO PPU Viewer | NO | NO | Name Table Viewer | NO | NO | Memory Hex Editor | YES | YES | -Trace Logger | NO | NO | -Code/Data Logger | NO | NO | +Trace Logger | YES | NO | +Code/Data Logger | YES | NO | Game Genie Encoder/Decoder | NO | NO | iNES Header Editor | NO | NO | Built in help pages | NO | NO | From 896a97968989bc4e3729ff9305a8f0b274bdd339 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Fri, 2 Oct 2020 22:14:00 -0400 Subject: [PATCH 10/10] Added logic to auto open log file dialog window if file logging is checked and a start logging event occurs. --- src/drivers/Qt/TraceLogger.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/drivers/Qt/TraceLogger.cpp b/src/drivers/Qt/TraceLogger.cpp index 37bebb43..d8e098ff 100644 --- a/src/drivers/Qt/TraceLogger.cpp +++ b/src/drivers/Qt/TraceLogger.cpp @@ -354,9 +354,18 @@ void TraceLoggerDialog_t::toggleLoggingOnOff(void) usleep( 1000 ); pushMsgToLogBuffer("Logging Finished"); startStopButton->setText( tr("Start Logging") ); + + if ( logFile ) + { + fclose( logFile ); logFile = NULL; + } } else { + if ( logFileCbox->isChecked() ) + { + openLogFile(); + } pushMsgToLogBuffer("Log Start"); startStopButton->setText( tr("Stop Logging") ); logging = 1;