From 7001b555694ee3aff7f515d1a81188c09e2c161f Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Tue, 1 Sep 2020 22:04:59 -0400 Subject: [PATCH 01/57] Added initial framework for console breakpoint debugger window. --- src/CMakeLists.txt | 1 + src/drivers/Qt/CheatsConf.cpp | 1 + src/drivers/Qt/ConsoleDebugger.cpp | 268 +++++++++++++++++++++++++++++ src/drivers/Qt/ConsoleDebugger.h | 77 +++++++++ src/drivers/Qt/ConsoleWindow.cpp | 20 +++ src/drivers/Qt/ConsoleWindow.h | 2 + src/drivers/Qt/HotKeyConf.h | 2 +- 7 files changed, 370 insertions(+), 1 deletion(-) create mode 100644 src/drivers/Qt/ConsoleDebugger.cpp create mode 100644 src/drivers/Qt/ConsoleDebugger.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4ef224bb..211f2dca 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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/ConsoleDebugger.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleUtilities.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleVideoConf.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleSoundConf.cpp diff --git a/src/drivers/Qt/CheatsConf.cpp b/src/drivers/Qt/CheatsConf.cpp index 1f53e556..18af6258 100644 --- a/src/drivers/Qt/CheatsConf.cpp +++ b/src/drivers/Qt/CheatsConf.cpp @@ -45,6 +45,7 @@ GuiCheatsDialog_t::GuiCheatsDialog_t(QWidget *parent) //printf("Pix Ratio: %f \n", devPixRatio ); } + font.setFamily("Courier New"); font.setStyle( QFont::StyleNormal ); font.setStyleHint( QFont::Monospace ); diff --git a/src/drivers/Qt/ConsoleDebugger.cpp b/src/drivers/Qt/ConsoleDebugger.cpp new file mode 100644 index 00000000..abd69e87 --- /dev/null +++ b/src/drivers/Qt/ConsoleDebugger.cpp @@ -0,0 +1,268 @@ +// ConsoleDebugger.cpp +// +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "Qt/main.h" +#include "Qt/dface.h" +#include "Qt/config.h" +#include "Qt/fceuWrapper.h" +#include "Qt/ConsoleDebugger.h" + +//---------------------------------------------------------------------------- +ConsoleDebugger::ConsoleDebugger(QWidget *parent) + : QDialog( parent ) +{ + QHBoxLayout *mainLayout; + QVBoxLayout *vbox, *vbox1, *vbox2, *vbox3; + QHBoxLayout *hbox, *hbox1, *hbox2; + QGridLayout *grid; + QPushButton *button; + QFrame *frame; + QLabel *lbl; + float fontCharWidth; + + font.setFamily("Courier New"); + font.setStyle( QFont::StyleNormal ); + font.setStyleHint( QFont::Monospace ); + QFontMetrics fm(font); + + fontCharWidth = 1.00 * fm.averageCharWidth(); + + setWindowTitle("6502 Debugger"); + + //resize( 512, 512 ); + + mainLayout = new QHBoxLayout(); + + asmText = new QTextEdit(this); + vbox1 = new QVBoxLayout(); + vbox2 = new QVBoxLayout(); + hbox1 = new QHBoxLayout(); + grid = new QGridLayout(); + + asmText->setFont(font); + asmText->setMinimumWidth( 20 * fontCharWidth ); + + vbox1->addLayout( hbox1 ); + hbox1->addLayout( vbox2 ); + vbox2->addLayout( grid ); + + mainLayout->addWidget( asmText ); + mainLayout->addLayout( vbox1 ); + + button = new QPushButton( tr("Run") ); + grid->addWidget( button, 0, 0, Qt::AlignLeft ); + + button = new QPushButton( tr("Step Into") ); + grid->addWidget( button, 0, 1, Qt::AlignLeft ); + + button = new QPushButton( tr("Step Out") ); + grid->addWidget( button, 1, 0, Qt::AlignLeft ); + + button = new QPushButton( tr("Step Over") ); + grid->addWidget( button, 1, 1, Qt::AlignLeft ); + + button = new QPushButton( tr("Run Line") ); + grid->addWidget( button, 2, 0, Qt::AlignLeft ); + + button = new QPushButton( tr("128 Lines") ); + grid->addWidget( button, 2, 1, Qt::AlignLeft ); + + button = new QPushButton( tr("Seek To:") ); + grid->addWidget( button, 3, 0, Qt::AlignLeft ); + + seekEntry = new QLineEdit(); + seekEntry->setFont( font ); + seekEntry->setMaxLength( 4 ); + seekEntry->setInputMask( ">HHHH;0" ); + seekEntry->setAlignment(Qt::AlignCenter); + seekEntry->setMaximumWidth( 6 * fontCharWidth ); + grid->addWidget( seekEntry, 3, 1, Qt::AlignLeft ); + + hbox = new QHBoxLayout(); + lbl = new QLabel( tr("PC:") ); + pcEntry = new QLineEdit(); + pcEntry->setFont( font ); + pcEntry->setMaxLength( 4 ); + pcEntry->setInputMask( ">HHHH;0" ); + pcEntry->setAlignment(Qt::AlignCenter); + pcEntry->setMaximumWidth( 6 * fontCharWidth ); + hbox->addWidget( lbl ); + hbox->addWidget( pcEntry, 1, Qt::AlignLeft ); + grid->addLayout( hbox, 4, 0, Qt::AlignLeft ); + + button = new QPushButton( tr("Seek PC") ); + grid->addWidget( button, 4, 1, Qt::AlignLeft ); + + hbox = new QHBoxLayout(); + lbl = new QLabel( tr("A:") ); + regAEntry = new QLineEdit(); + regAEntry->setFont( font ); + regAEntry->setMaxLength( 2 ); + regAEntry->setInputMask( ">HH;0" ); + regAEntry->setAlignment(Qt::AlignCenter); + regAEntry->setMaximumWidth( 4 * fontCharWidth ); + hbox->addWidget( lbl ); + hbox->addWidget( regAEntry, 1, Qt::AlignLeft ); + lbl = new QLabel( tr("X:") ); + regXEntry = new QLineEdit(); + regXEntry->setFont( font ); + regXEntry->setMaxLength( 2 ); + regXEntry->setInputMask( ">HH;0" ); + regXEntry->setAlignment(Qt::AlignCenter); + regXEntry->setMaximumWidth( 4 * fontCharWidth ); + hbox->addWidget( lbl ); + hbox->addWidget( regXEntry, 1, Qt::AlignLeft ); + lbl = new QLabel( tr("Y:") ); + regYEntry = new QLineEdit(); + regYEntry->setFont( font ); + regYEntry->setMaxLength( 2 ); + regYEntry->setInputMask( ">HH;0" ); + regYEntry->setAlignment(Qt::AlignCenter); + regYEntry->setMaximumWidth( 4 * fontCharWidth ); + hbox->addWidget( lbl ); + hbox->addWidget( regYEntry, 1, Qt::AlignLeft ); + vbox2->addLayout( hbox ); + + stackFrame = new QGroupBox(tr("Stack $0100")); + stackText = new QTextEdit(this); + hbox = new QHBoxLayout(); + hbox->addWidget( stackText ); + vbox2->addWidget( stackFrame ); + stackFrame->setLayout( hbox ); + stackText->setFont(font); + stackText->setReadOnly(true); + stackText->setMaximumWidth( 16 * fontCharWidth ); + + bpFrame = new QGroupBox(tr("Breakpoints")); + vbox3 = new QVBoxLayout(); + vbox = new QVBoxLayout(); + hbox = new QHBoxLayout(); + bpTree = new QTreeWidget(); + + bpTree->setColumnCount(1); + + hbox->addWidget( bpTree ); + + hbox = new QHBoxLayout(); + button = new QPushButton( tr("Add") ); + hbox->addWidget( button ); + + button = new QPushButton( tr("Delete") ); + hbox->addWidget( button ); + + button = new QPushButton( tr("Edit") ); + hbox->addWidget( button ); + + brkBadOpsCbox = new QCheckBox( tr("Break on Bad Opcodes") ); + + vbox->addWidget( bpTree ); + vbox->addLayout( hbox ); + vbox->addWidget( brkBadOpsCbox ); + bpFrame->setLayout( vbox ); + + sfFrame = new QGroupBox(tr("Status Flags")); + grid = new QGridLayout(); + sfFrame->setLayout( grid ); + + N_chkbox = new QCheckBox( tr("N") ); + V_chkbox = new QCheckBox( tr("V") ); + U_chkbox = new QCheckBox( tr("U") ); + B_chkbox = new QCheckBox( tr("B") ); + D_chkbox = new QCheckBox( tr("D") ); + I_chkbox = new QCheckBox( tr("I") ); + Z_chkbox = new QCheckBox( tr("Z") ); + C_chkbox = new QCheckBox( tr("C") ); + + grid->addWidget( N_chkbox, 0, 0, Qt::AlignCenter ); + grid->addWidget( V_chkbox, 0, 1, Qt::AlignCenter ); + grid->addWidget( U_chkbox, 0, 2, Qt::AlignCenter ); + grid->addWidget( B_chkbox, 0, 3, Qt::AlignCenter ); + grid->addWidget( D_chkbox, 1, 0, Qt::AlignCenter ); + grid->addWidget( I_chkbox, 1, 1, Qt::AlignCenter ); + grid->addWidget( Z_chkbox, 1, 2, Qt::AlignCenter ); + grid->addWidget( C_chkbox, 1, 3, Qt::AlignCenter ); + + vbox3->addWidget( bpFrame); + vbox3->addWidget( sfFrame); + hbox1->addLayout( vbox3 ); + + hbox2 = new QHBoxLayout(); + vbox = new QVBoxLayout(); + frame = new QFrame(); + ppuLbl = new QLabel( tr("PPU:") ); + spriteLbl = new QLabel( tr("Sprite:") ); + scanLineLbl = new QLabel( tr("Scanline:") ); + pixLbl = new QLabel( tr("Pixel:") ); + vbox->addWidget( ppuLbl ); + vbox->addWidget( spriteLbl ); + vbox->addWidget( scanLineLbl ); + vbox->addWidget( pixLbl ); + vbox1->addLayout( hbox2 ); + hbox2->addWidget( frame ); + frame->setLayout( vbox ); + frame->setFrameShape( QFrame::Box ); + + vbox = new QVBoxLayout(); + hbox = new QHBoxLayout(); + cpuCyclesLbl = new QLabel( tr("CPU Cycles:") ); + cpuInstrsLbl = new QLabel( tr("Instructions:") ); + brkCpuCycExd = new QCheckBox( tr("Break when Exceed") ); + brkInstrsExd = new QCheckBox( tr("Break when Exceed") ); + cpuCycExdVal = new QLineEdit( tr("0") ); + instrExdVal = new QLineEdit( tr("0") ); + vbox->addWidget( cpuCyclesLbl ); + vbox->addLayout( hbox ); + hbox->addWidget( brkCpuCycExd ); + hbox->addWidget( cpuCycExdVal, 1, Qt::AlignLeft ); + + hbox = new QHBoxLayout(); + vbox->addWidget( cpuInstrsLbl ); + vbox->addLayout( hbox ); + hbox->addWidget( brkInstrsExd ); + hbox->addWidget( instrExdVal, 1, Qt::AlignLeft ); + hbox2->addLayout( vbox ); + + cpuCycExdVal->setFont( font ); + cpuCycExdVal->setMaxLength( 10 ); + cpuCycExdVal->setInputMask( ">DDDD;0" ); + cpuCycExdVal->setAlignment(Qt::AlignCenter); + cpuCycExdVal->setMaximumWidth( 12 * fontCharWidth ); + + instrExdVal->setFont( font ); + instrExdVal->setMaxLength( 10 ); + instrExdVal->setInputMask( ">DDDD;0" ); + instrExdVal->setAlignment(Qt::AlignCenter); + instrExdVal->setMaximumWidth( 12 * fontCharWidth ); + + setLayout( mainLayout ); +} +//---------------------------------------------------------------------------- +ConsoleDebugger::~ConsoleDebugger(void) +{ + printf("Destroy Debugger Window\n"); +} +//---------------------------------------------------------------------------- +void ConsoleDebugger::closeEvent(QCloseEvent *event) +{ + printf("Debugger Close Window Event\n"); + done(0); + deleteLater(); + event->accept(); +} +//---------------------------------------------------------------------------- +void ConsoleDebugger::closeWindow(void) +{ + //printf("Close Window\n"); + done(0); + deleteLater(); +} +//---------------------------------------------------------------------------- diff --git a/src/drivers/Qt/ConsoleDebugger.h b/src/drivers/Qt/ConsoleDebugger.h new file mode 100644 index 00000000..009ee9ad --- /dev/null +++ b/src/drivers/Qt/ConsoleDebugger.h @@ -0,0 +1,77 @@ +// ConsoleDebugger.h +// + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Qt/main.h" + +class ConsoleDebugger : public QDialog +{ + Q_OBJECT + + public: + ConsoleDebugger(QWidget *parent = 0); + ~ConsoleDebugger(void); + + protected: + void closeEvent(QCloseEvent *event); + //void keyPressEvent(QKeyEvent *event); + //void keyReleaseEvent(QKeyEvent *event); + + //QTreeWidget *tree; + QTextEdit *asmText; + QTextEdit *stackText; + QLineEdit *seekEntry; + QLineEdit *pcEntry; + QLineEdit *regAEntry; + QLineEdit *regXEntry; + QLineEdit *regYEntry; + QLineEdit *cpuCycExdVal; + QLineEdit *instrExdVal; + QGroupBox *stackFrame; + QGroupBox *bpFrame; + QGroupBox *sfFrame; + QTreeWidget * bpTree; + QCheckBox *brkBadOpsCbox; + QCheckBox *N_chkbox; + QCheckBox *V_chkbox; + QCheckBox *U_chkbox; + QCheckBox *B_chkbox; + QCheckBox *D_chkbox; + QCheckBox *I_chkbox; + QCheckBox *Z_chkbox; + QCheckBox *C_chkbox; + QCheckBox *brkCpuCycExd; + QCheckBox *brkInstrsExd; + QLabel *ppuLbl; + QLabel *spriteLbl; + QLabel *scanLineLbl; + QLabel *pixLbl; + QLabel *cpuCyclesLbl; + QLabel *cpuInstrsLbl; + QFont font; + + private: + + public slots: + void closeWindow(void); + private slots: + +}; diff --git a/src/drivers/Qt/ConsoleWindow.cpp b/src/drivers/Qt/ConsoleWindow.cpp index 57102e8e..a220ce88 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/ConsoleDebugger.h" #include "Qt/ConsoleUtilities.h" #include "Qt/ConsoleSoundConf.h" #include "Qt/ConsoleVideoConf.h" @@ -482,6 +483,14 @@ void consoleWin_t::createMainMenu(void) // Debug debugMenu = menuBar()->addMenu(tr("Debug")); + // Debug -> Hex Editor + debuggerAct = new QAction(tr("Debugger..."), this); + //debuggerAct->setShortcut( QKeySequence(tr("Shift+F7"))); + debuggerAct->setStatusTip(tr("Open 6502 Debugger")); + connect(debuggerAct, SIGNAL(triggered()), this, SLOT(openDebugWindow(void)) ); + + debugMenu->addAction(debuggerAct); + // Debug -> Hex Editor hexEditAct = new QAction(tr("Hex Editor..."), this); //hexEditAct->setShortcut( QKeySequence(tr("Shift+F7"))); @@ -970,6 +979,17 @@ void consoleWin_t::openCheats(void) cheatWin->show(); } +void consoleWin_t::openDebugWindow(void) +{ + ConsoleDebugger *debugWin; + + //printf("Open GUI 6502 Debugger Window\n"); + + debugWin = new ConsoleDebugger(this); + + debugWin->show(); +} + void consoleWin_t::openHexEditor(void) { HexEditorDialog_t *hexEditWin; diff --git a/src/drivers/Qt/ConsoleWindow.h b/src/drivers/Qt/ConsoleWindow.h index eb5fdddb..375aea1f 100644 --- a/src/drivers/Qt/ConsoleWindow.h +++ b/src/drivers/Qt/ConsoleWindow.h @@ -89,6 +89,7 @@ class consoleWin_t : public QMainWindow QAction *fdsEjectAct; QAction *fdsLoadBiosAct; QAction *cheatsAct; + QAction *debuggerAct; QAction *hexEditAct; QAction *openMovAct; QAction *stopMovAct; @@ -155,6 +156,7 @@ class consoleWin_t : public QMainWindow void fdsEjectDisk(void); void fdsLoadBiosFile(void); void openCheats(void); + void openDebugWindow(void); void openHexEditor(void); void openMovie(void); void stopMovie(void); diff --git a/src/drivers/Qt/HotKeyConf.h b/src/drivers/Qt/HotKeyConf.h index bf9c8a8f..b8db1909 100644 --- a/src/drivers/Qt/HotKeyConf.h +++ b/src/drivers/Qt/HotKeyConf.h @@ -1,4 +1,4 @@ -// GamePadConf.h +// HotKeyConf.h // #pragma once From ccbcab5e77fff9083da5b8cb3b44c031ce8fe825 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Wed, 2 Sep 2020 21:31:54 -0400 Subject: [PATCH 02/57] Initial port of ASM window code. --- src/drivers/Qt/ConsoleDebugger.cpp | 361 ++++++++++++++++++++++++++++- src/drivers/Qt/ConsoleDebugger.h | 33 +++ src/drivers/Qt/fceuWrapper.cpp | 5 - 3 files changed, 383 insertions(+), 16 deletions(-) diff --git a/src/drivers/Qt/ConsoleDebugger.cpp b/src/drivers/Qt/ConsoleDebugger.cpp index abd69e87..94cadf01 100644 --- a/src/drivers/Qt/ConsoleDebugger.cpp +++ b/src/drivers/Qt/ConsoleDebugger.cpp @@ -4,18 +4,37 @@ #include #include #include +#include #include #include #include #include +#include "../../types.h" +#include "../../fceu.h" +#include "../../cheat.h" +#include "../../debug.h" +#include "../../driver.h" +#include "../../version.h" +#include "../../video.h" +#include "../../movie.h" +#include "../../palette.h" +#include "../../fds.h" +#include "../../cart.h" +#include "../../ines.h" +#include "../../asm.h" +#include "../../ppu.h" +#include "../../x6502.h" +#include "common/configSys.h" + #include "Qt/main.h" #include "Qt/dface.h" #include "Qt/config.h" #include "Qt/fceuWrapper.h" #include "Qt/ConsoleDebugger.h" +static std::list dbgWinList; //---------------------------------------------------------------------------- ConsoleDebugger::ConsoleDebugger(QWidget *parent) : QDialog( parent ) @@ -55,8 +74,8 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent) hbox1->addLayout( vbox2 ); vbox2->addLayout( grid ); - mainLayout->addWidget( asmText ); - mainLayout->addLayout( vbox1 ); + mainLayout->addWidget( asmText, 10 ); + mainLayout->addLayout( vbox1, 1 ); button = new QPushButton( tr("Run") ); grid->addWidget( button, 0, 0, Qt::AlignLeft ); @@ -140,7 +159,7 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent) stackFrame->setLayout( hbox ); stackText->setFont(font); stackText->setReadOnly(true); - stackText->setMaximumWidth( 16 * fontCharWidth ); + //stackText->setMaximumWidth( 16 * fontCharWidth ); bpFrame = new QGroupBox(tr("Breakpoints")); vbox3 = new QVBoxLayout(); @@ -232,23 +251,31 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent) hbox2->addLayout( vbox ); cpuCycExdVal->setFont( font ); - cpuCycExdVal->setMaxLength( 10 ); - cpuCycExdVal->setInputMask( ">DDDD;0" ); - cpuCycExdVal->setAlignment(Qt::AlignCenter); - cpuCycExdVal->setMaximumWidth( 12 * fontCharWidth ); + cpuCycExdVal->setMaxLength( 16 ); + cpuCycExdVal->setInputMask( ">9000000000000000;" ); + cpuCycExdVal->setAlignment(Qt::AlignLeft); + cpuCycExdVal->setMaximumWidth( 18 * fontCharWidth ); instrExdVal->setFont( font ); - instrExdVal->setMaxLength( 10 ); - instrExdVal->setInputMask( ">DDDD;0" ); - instrExdVal->setAlignment(Qt::AlignCenter); - instrExdVal->setMaximumWidth( 12 * fontCharWidth ); + instrExdVal->setMaxLength( 16 ); + instrExdVal->setInputMask( ">9000000000000000;" ); + instrExdVal->setAlignment(Qt::AlignLeft); + instrExdVal->setMaximumWidth( 18 * fontCharWidth ); setLayout( mainLayout ); + + displayROMoffsets = 0; + asmPC = NULL; + + dbgWinList.push_back( this ); + + updateWindowData(); } //---------------------------------------------------------------------------- ConsoleDebugger::~ConsoleDebugger(void) { printf("Destroy Debugger Window\n"); + asmClear(); } //---------------------------------------------------------------------------- void ConsoleDebugger::closeEvent(QCloseEvent *event) @@ -266,3 +293,315 @@ void ConsoleDebugger::closeWindow(void) deleteLater(); } //---------------------------------------------------------------------------- +void ConsoleDebugger::asmClear(void) +{ + for (size_t i=0; iaddr ) + { + return 0; + } + else if ( addr > asmEntry[ asmEntry.size() - 1 ]->addr ) + { + return asmEntry.size() - 1; + } + + if ( incr < 1 ) incr = 1; + + nextLine = line = incr; + + // algorithm to efficiently find line from address. Starts in middle of list and + // keeps dividing the list in 2 until it arrives at an answer. + while ( run ) + { + //printf("incr:%i line:%i addr:%04X delta:%i\n", incr, line, asmEntry[line]->addr, addr - asmEntry[line]->addr); + + if ( incr == 1 ) + { + if ( asmEntry[line]->addr < addr ) + { + nextLine = line + 1; + if ( asmEntry[line]->addr > nextLine ) + { + break; + } + line = nextLine; + } + else if ( asmEntry[line]->addr > addr ) + { + nextLine = line - 1; + if ( asmEntry[line]->addr < nextLine ) + { + break; + } + line = nextLine; + } + else + { + run = 0; break; + } + } + else + { + incr = incr / 2; + if ( incr < 1 ) incr = 1; + + if ( asmEntry[line]->addr < addr ) + { + nextLine = line + incr; + } + else if ( asmEntry[line]->addr > addr ) + { + nextLine = line - incr; + } + else + { + run = 0; break; + } + line = nextLine; + } + } + + //for (size_t i=0; iaddr >= addr ) + // { + // line = i; break; + // } + //} + + return line; +} +//---------------------------------------------------------------------------- +// This function is for "smart" scrolling... +// it attempts to scroll up one line by a whole instruction +static int InstructionUp(int from) +{ + int i = std::min(16, from), j; + + while (i > 0) + { + j = i; + while (j > 0) + { + if (GetMem(from - j) == 0x00) + break; // BRK usually signifies data + if (opsize[GetMem(from - j)] == 0) + break; // invalid instruction! + if (opsize[GetMem(from - j)] > j) + break; // instruction is too long! + if (opsize[GetMem(from - j)] == j) + return (from - j); // instruction is just right! :D + j -= opsize[GetMem(from - j)]; + } + i--; + } + + // if we get here, no suitable instruction was found + if ((from >= 2) && (GetMem(from - 2) == 0x00)) + return (from - 2); // if a BRK instruction is possible, use that + if (from) + return (from - 1); // else, scroll up one byte + return 0; // of course, if we can't scroll up, just return 0! +} +//static int InstructionDown(int from) +//{ +// int tmp = opsize[GetMem(from)]; +// if ((tmp)) +// return from + tmp; +// else +// return from + 1; // this is data or undefined instruction +//} +//---------------------------------------------------------------------------- +void ConsoleDebugger::updateAssemblyView(void) +{ + int starting_address, start_address_lp, addr, size; + int instruction_addr; + std::string line; + char chr[64]; + uint8 opcode[3]; + const char *disassemblyText = NULL; + dbg_asm_entry_t *a; + //GtkTextIter iter, next_iter; + char pc_found = 0; + + start_address_lp = starting_address = X.PC; + + for (int i=0; i < 0xFFFF; i++) + { + //printf("%i: Start Address: 0x%04X \n", i, start_address_lp ); + + starting_address = InstructionUp( start_address_lp ); + + if ( starting_address == start_address_lp ) + { + break; + } + if ( starting_address < 0 ) + { + starting_address = start_address_lp; + break; + } + start_address_lp = starting_address; + } + + asmClear(); + + addr = starting_address; + asmPC = NULL; + + //gtk_text_buffer_get_start_iter( textbuf, &iter ); + + //textview_lines_allocated = gtk_text_buffer_get_line_count( textbuf ) - 1; + + //printf("Num Lines: %i\n", textview_lines_allocated ); + + for (int i=0; i < 0xFFFF; i++) + { + line.clear(); + + // PC pointer + if (addr > 0xFFFF) break; + + a = new dbg_asm_entry_t; + + instruction_addr = addr; + + if ( !pc_found ) + { + if (addr > X.PC) + { + asmPC = a; + line.assign(">"); + pc_found = 1; + } + else if (addr == X.PC) + { + asmPC = a; + line.assign(">"); + pc_found = 1; + } + else + { + line.assign(" "); + } + } + else + { + line.assign(" "); + } + a->addr = addr; + + if (addr >= 0x8000) + { + a->bank = getBank(addr); + a->rom = GetNesFileAddress(addr); + + if (displayROMoffsets && (a->rom != -1) ) + { + sprintf(chr, " %06X: ", a->rom); + } + else + { + sprintf(chr, "%02X:%04X: ", a->bank, addr); + } + } + else + { + sprintf(chr, " :%04X: ", addr); + } + line.append(chr); + + size = opsize[GetMem(addr)]; + if (size == 0) + { + sprintf(chr, "%02X UNDEFINED", GetMem(addr++)); + line.append(chr); + } else + { + if ((addr + size) > 0xFFFF) + { + while (addr < 0xFFFF) + { + sprintf(chr, "%02X OVERFLOW\n", GetMem(addr++)); + line.append(chr); + } + break; + } + for (int j = 0; j < size; j++) + { + sprintf(chr, "%02X ", opcode[j] = GetMem(addr++)); + line.append(chr); + } + while (size < 3) + { + line.append(" "); //pad output to align ASM + size++; + } + + disassemblyText = Disassemble(addr, opcode); + + if ( disassemblyText ) + { + line.append( disassemblyText ); + } + } + for (int j=0; jopcode[j] = opcode[j]; + } + a->size = size; + + // special case: an RTS opcode + if (GetMem(instruction_addr) == 0x60) + { + line.append("-------------------------"); + } + + a->text.assign( line ); + + a->line = asmEntry.size(); + + line.append("\n"); + + asmText->insertPlainText( tr(line.c_str()) ); + + asmEntry.push_back(a); + } + +} +//---------------------------------------------------------------------------- +void ConsoleDebugger::updateWindowData(void) +{ + updateAssemblyView(); + +} +//---------------------------------------------------------------------------- +void FCEUD_DebugBreakpoint( int addr ) +{ + std::list ::iterator it; + printf("Breakpoint Hit: 0x%04X \n", addr ); + + for (it=dbgWinList.begin(); it!=dbgWinList.end(); it++) + { + (*it)->updateWindowData(); + } +} +//---------------------------------------------------------------------------- diff --git a/src/drivers/Qt/ConsoleDebugger.h b/src/drivers/Qt/ConsoleDebugger.h index 009ee9ad..a808d0a0 100644 --- a/src/drivers/Qt/ConsoleDebugger.h +++ b/src/drivers/Qt/ConsoleDebugger.h @@ -22,6 +22,29 @@ #include "Qt/main.h" +struct dbg_asm_entry_t +{ + int addr; + int bank; + int rom; + int size; + int line; + uint8 opcode[3]; + std::string text; + + + dbg_asm_entry_t(void) + { + addr = 0; bank = 0; rom = -1; + size = 0; line = 0; + + for (int i=0; i<3; i++) + { + opcode[i] = 0; + } + } +}; + class ConsoleDebugger : public QDialog { Q_OBJECT @@ -30,6 +53,11 @@ class ConsoleDebugger : public QDialog ConsoleDebugger(QWidget *parent = 0); ~ConsoleDebugger(void); + void updateWindowData(void); + void updateAssemblyView(void); + void asmClear(void); + int getAsmLineFromAddr(int addr); + protected: void closeEvent(QCloseEvent *event); //void keyPressEvent(QKeyEvent *event); @@ -68,6 +96,11 @@ class ConsoleDebugger : public QDialog QLabel *cpuInstrsLbl; QFont font; + dbg_asm_entry_t *asmPC; + std::vector asmEntry; + + char displayROMoffsets; + private: public slots: diff --git a/src/drivers/Qt/fceuWrapper.cpp b/src/drivers/Qt/fceuWrapper.cpp index 9fe90965..84eb5ae8 100644 --- a/src/drivers/Qt/fceuWrapper.cpp +++ b/src/drivers/Qt/fceuWrapper.cpp @@ -159,11 +159,6 @@ FCEUD_GetTimeFreq(void) return 1000; } -void FCEUD_DebugBreakpoint( int addr ) -{ - // TODO -} - /** * Initialize all of the subsystem drivers: video, audio, and joystick. */ From 254a1a1d3750f5797df1a5ef5dcf4d2a1945ad1a Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Wed, 2 Sep 2020 22:16:41 -0400 Subject: [PATCH 03/57] ASM display window changed to use QPlainTextEdit instead of QTextEdit. --- src/drivers/Qt/ConsoleDebugger.cpp | 48 ++++++++++++++++++++++++++---- src/drivers/Qt/ConsoleDebugger.h | 12 ++++++-- 2 files changed, 52 insertions(+), 8 deletions(-) diff --git a/src/drivers/Qt/ConsoleDebugger.cpp b/src/drivers/Qt/ConsoleDebugger.cpp index 94cadf01..b21c1c14 100644 --- a/src/drivers/Qt/ConsoleDebugger.cpp +++ b/src/drivers/Qt/ConsoleDebugger.cpp @@ -61,14 +61,17 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent) mainLayout = new QHBoxLayout(); - asmText = new QTextEdit(this); + asmText = new QPlainTextEdit(this); vbox1 = new QVBoxLayout(); vbox2 = new QVBoxLayout(); hbox1 = new QHBoxLayout(); grid = new QGridLayout(); asmText->setFont(font); + asmText->setReadOnly(true); + asmText->setOverwriteMode(true); asmText->setMinimumWidth( 20 * fontCharWidth ); + asmText->setLineWrapMode( QPlainTextEdit::NoWrap ); vbox1->addLayout( hbox1 ); hbox1->addLayout( vbox2 ); @@ -152,7 +155,7 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent) vbox2->addLayout( hbox ); stackFrame = new QGroupBox(tr("Stack $0100")); - stackText = new QTextEdit(this); + stackText = new QPlainTextEdit(this); hbox = new QHBoxLayout(); hbox->addWidget( stackText ); vbox2->addWidget( stackFrame ); @@ -264,17 +267,23 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent) setLayout( mainLayout ); - displayROMoffsets = 0; + displayROMoffsets = false; + windowUpdateReq = true; asmPC = NULL; dbgWinList.push_back( this ); - updateWindowData(); + periodicTimer = new QTimer( this ); + + connect( periodicTimer, &QTimer::timeout, this, &ConsoleDebugger::updatePeriodic ); + + periodicTimer->start( 100 ); // 10hz } //---------------------------------------------------------------------------- ConsoleDebugger::~ConsoleDebugger(void) { printf("Destroy Debugger Window\n"); + periodicTimer->stop(); asmClear(); } //---------------------------------------------------------------------------- @@ -467,6 +476,8 @@ void ConsoleDebugger::updateAssemblyView(void) addr = starting_address; asmPC = NULL; + asmText->clear(); + //gtk_text_buffer_get_start_iter( textbuf, &iter ); //textview_lines_allocated = gtk_text_buffer_get_line_count( textbuf ) - 1; @@ -592,16 +603,43 @@ void ConsoleDebugger::updateWindowData(void) { updateAssemblyView(); + windowUpdateReq = false; +} +//---------------------------------------------------------------------------- +void ConsoleDebugger::updatePeriodic(void) +{ + //printf("Update Periodic\n"); + + if ( windowUpdateReq ) + { + fceuWrapperLock(); + updateWindowData(); + fceuWrapperUnLock(); + } +} +//---------------------------------------------------------------------------- +void ConsoleDebugger::breakPointNotify( int addr ) +{ + windowUpdateReq = true; } //---------------------------------------------------------------------------- void FCEUD_DebugBreakpoint( int addr ) { std::list ::iterator it; + printf("Breakpoint Hit: 0x%04X \n", addr ); + + fceuWrapperUnLock(); for (it=dbgWinList.begin(); it!=dbgWinList.end(); it++) { - (*it)->updateWindowData(); + (*it)->breakPointNotify( addr ); } + + while (FCEUI_EmulationPaused() && !FCEUI_EmulationFrameStepped()) + { + usleep(100000); + } + fceuWrapperLock(); } //---------------------------------------------------------------------------- diff --git a/src/drivers/Qt/ConsoleDebugger.h b/src/drivers/Qt/ConsoleDebugger.h index a808d0a0..5d52a924 100644 --- a/src/drivers/Qt/ConsoleDebugger.h +++ b/src/drivers/Qt/ConsoleDebugger.h @@ -13,12 +13,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include "Qt/main.h" @@ -57,6 +59,7 @@ class ConsoleDebugger : public QDialog void updateAssemblyView(void); void asmClear(void); int getAsmLineFromAddr(int addr); + void breakPointNotify(int addr); protected: void closeEvent(QCloseEvent *event); @@ -64,8 +67,8 @@ class ConsoleDebugger : public QDialog //void keyReleaseEvent(QKeyEvent *event); //QTreeWidget *tree; - QTextEdit *asmText; - QTextEdit *stackText; + QPlainTextEdit *asmText; + QPlainTextEdit *stackText; QLineEdit *seekEntry; QLineEdit *pcEntry; QLineEdit *regAEntry; @@ -94,17 +97,20 @@ class ConsoleDebugger : public QDialog QLabel *pixLbl; QLabel *cpuCyclesLbl; QLabel *cpuInstrsLbl; + QTimer *periodicTimer; QFont font; dbg_asm_entry_t *asmPC; std::vector asmEntry; - char displayROMoffsets; + bool displayROMoffsets; + bool windowUpdateReq; private: public slots: void closeWindow(void); private slots: + void updatePeriodic(void); }; From fc201b5ff735f562edeba2bf938eacd5624265ac Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Thu, 3 Sep 2020 22:21:53 -0400 Subject: [PATCH 04/57] Created custom widget for ASM viewport. --- src/drivers/Qt/ConsoleDebugger.cpp | 206 +++++++++++++++++++++++++---- src/drivers/Qt/ConsoleDebugger.h | 59 +++++++-- 2 files changed, 230 insertions(+), 35 deletions(-) diff --git a/src/drivers/Qt/ConsoleDebugger.cpp b/src/drivers/Qt/ConsoleDebugger.cpp index b21c1c14..4cdfa903 100644 --- a/src/drivers/Qt/ConsoleDebugger.cpp +++ b/src/drivers/Qt/ConsoleDebugger.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -61,25 +62,41 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent) mainLayout = new QHBoxLayout(); - asmText = new QPlainTextEdit(this); + grid = new QGridLayout(); + asmView = new QAsmView(this); + vbar = new QScrollBar( Qt::Vertical, this ); + hbar = new QScrollBar( Qt::Horizontal, this ); + + asmView->setScrollBars( hbar, vbar ); + + grid->addWidget( asmView, 0, 0 ); + grid->addWidget( vbar , 0, 1 ); + grid->addWidget( hbar , 1, 0 ); + vbox1 = new QVBoxLayout(); vbox2 = new QVBoxLayout(); hbox1 = new QHBoxLayout(); - grid = new QGridLayout(); - asmText->setFont(font); - asmText->setReadOnly(true); - asmText->setOverwriteMode(true); - asmText->setMinimumWidth( 20 * fontCharWidth ); - asmText->setLineWrapMode( QPlainTextEdit::NoWrap ); + hbar->setMinimum(0); + hbar->setMaximum(100); + vbar->setMinimum(0); + vbar->setMaximum( 0x10000 ); + + //asmText->setFont(font); + //asmText->setReadOnly(true); + //asmText->setOverwriteMode(true); + //asmText->setMinimumWidth( 20 * fontCharWidth ); + //asmText->setLineWrapMode( QPlainTextEdit::NoWrap ); + + mainLayout->addLayout( grid, 10 ); + mainLayout->addLayout( vbox1, 1 ); + + grid = new QGridLayout(); vbox1->addLayout( hbox1 ); hbox1->addLayout( vbox2 ); vbox2->addLayout( grid ); - mainLayout->addWidget( asmText, 10 ); - mainLayout->addLayout( vbox1, 1 ); - button = new QPushButton( tr("Run") ); grid->addWidget( button, 0, 0, Qt::AlignLeft ); @@ -267,9 +284,7 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent) setLayout( mainLayout ); - displayROMoffsets = false; windowUpdateReq = true; - asmPC = NULL; dbgWinList.push_back( this ); @@ -284,7 +299,6 @@ ConsoleDebugger::~ConsoleDebugger(void) { printf("Destroy Debugger Window\n"); periodicTimer->stop(); - asmClear(); } //---------------------------------------------------------------------------- void ConsoleDebugger::closeEvent(QCloseEvent *event) @@ -302,16 +316,7 @@ void ConsoleDebugger::closeWindow(void) deleteLater(); } //---------------------------------------------------------------------------- -void ConsoleDebugger::asmClear(void) -{ - for (size_t i=0; iclear(); + //asmText->clear(); //gtk_text_buffer_get_start_iter( textbuf, &iter ); @@ -592,7 +597,7 @@ void ConsoleDebugger::updateAssemblyView(void) line.append("\n"); - asmText->insertPlainText( tr(line.c_str()) ); + //asmText->insertPlainText( tr(line.c_str()) ); asmEntry.push_back(a); } @@ -601,7 +606,7 @@ void ConsoleDebugger::updateAssemblyView(void) //---------------------------------------------------------------------------- void ConsoleDebugger::updateWindowData(void) { - updateAssemblyView(); + asmView->updateAssemblyView(); windowUpdateReq = false; } @@ -616,6 +621,7 @@ void ConsoleDebugger::updatePeriodic(void) updateWindowData(); fceuWrapperUnLock(); } + asmView->update(); } //---------------------------------------------------------------------------- void ConsoleDebugger::breakPointNotify( int addr ) @@ -643,3 +649,149 @@ void FCEUD_DebugBreakpoint( int addr ) fceuWrapperLock(); } //---------------------------------------------------------------------------- +QAsmView::QAsmView(QWidget *parent) + : QWidget( parent ) +{ + QPalette pal; + QColor fg("black"), bg("white"); + + font.setFamily("Courier New"); + font.setStyle( QFont::StyleNormal ); + font.setStyleHint( QFont::Monospace ); + + pal = this->palette(); + pal.setColor(QPalette::Base , bg ); + pal.setColor(QPalette::Background, bg ); + pal.setColor(QPalette::WindowText, fg ); + + this->setPalette(pal); + + calcFontData(); + + vbar = NULL; + hbar = NULL; + asmPC = NULL; + displayROMoffsets = false; + lineOffset = 0; + maxLineOffset = 0; +} +//---------------------------------------------------------------------------- +QAsmView::~QAsmView(void) +{ + asmClear(); +} +//---------------------------------------------------------------------------- +void QAsmView::asmClear(void) +{ + for (size_t i=0; isetFont(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; + + viewLines = (viewHeight / pxLineSpacing) + 1; +} +//---------------------------------------------------------------------------- +void QAsmView::setScrollBars( QScrollBar *h, QScrollBar *v ) +{ + hbar = h; vbar = v; +} +//---------------------------------------------------------------------------- +void QAsmView::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 QAsmView::keyPressEvent(QKeyEvent *event) +{ + printf("Debug ASM Window Key Press: 0x%x \n", event->key() ); + +} +//---------------------------------------------------------------------------- +void QAsmView::keyReleaseEvent(QKeyEvent *event) +{ + printf("Debug ASM Window Key Release: 0x%x \n", event->key() ); + //assignHotkey( event ); +} +//---------------------------------------------------------------------------- +void QAsmView::mousePressEvent(QMouseEvent * event) +{ + // TODO QPoint c = convPixToCursor( event->pos() ); + +} +//---------------------------------------------------------------------------- +void QAsmView::contextMenuEvent(QContextMenuEvent *event) +{ + // TODO +} +//---------------------------------------------------------------------------- +void QAsmView::paintEvent(QPaintEvent *event) +{ + int x,y,l, row, nrow; + QPainter painter(this); + + painter.setFont(font); + viewWidth = event->rect().width(); + viewHeight = event->rect().height(); + + nrow = (viewHeight / pxLineSpacing) + 1; + + if ( nrow < 1 ) nrow = 1; + + viewLines = nrow; + + if ( cursorPosY >= viewLines ) + { + cursorPosY = viewLines-1; + } + + painter.fillRect( 0, 0, viewWidth, viewHeight, this->palette().color(QPalette::Background) ); + + y = pxLineSpacing; + + for (row=0; row < nrow; row++) + { + x=0; + l = lineOffset + row; + painter.setPen( this->palette().color(QPalette::WindowText)); + + if ( l < asmEntry.size() ) + { + painter.drawText( x, y, tr(asmEntry[l]->text.c_str()) ); + } + y += pxLineSpacing; + } +} +//---------------------------------------------------------------------------- diff --git a/src/drivers/Qt/ConsoleDebugger.h b/src/drivers/Qt/ConsoleDebugger.h index 5d52a924..230c6f55 100644 --- a/src/drivers/Qt/ConsoleDebugger.h +++ b/src/drivers/Qt/ConsoleDebugger.h @@ -21,6 +21,7 @@ #include #include #include +#include #include "Qt/main.h" @@ -47,6 +48,53 @@ struct dbg_asm_entry_t } }; +class QAsmView : public QWidget +{ + Q_OBJECT + + public: + QAsmView(QWidget *parent = 0); + ~QAsmView(void); + + void setScrollBars( QScrollBar *h, QScrollBar *v ); + void updateAssemblyView(void); + void asmClear(void); + int getAsmLineFromAddr(int addr); + protected: + void paintEvent(QPaintEvent *event); + void keyPressEvent(QKeyEvent *event); + void keyReleaseEvent(QKeyEvent *event); + void mousePressEvent(QMouseEvent * event); + void resizeEvent(QResizeEvent *event); + void contextMenuEvent(QContextMenuEvent *event); + + void calcFontData(void); + + private: + QFont font; + QScrollBar *vbar; + QScrollBar *hbar; + + int pxCharWidth; + int pxCharHeight; + int pxCursorHeight; + int pxLineSpacing; + int pxLineLead; + int viewLines; + int viewWidth; + int viewHeight; + int lineOffset; + int maxLineOffset; + int pxLineXScroll; + int cursorPosX; + int cursorPosY; + + dbg_asm_entry_t *asmPC; + std::vector asmEntry; + + bool displayROMoffsets; +}; + class ConsoleDebugger : public QDialog { Q_OBJECT @@ -56,9 +104,6 @@ class ConsoleDebugger : public QDialog ~ConsoleDebugger(void); void updateWindowData(void); - void updateAssemblyView(void); - void asmClear(void); - int getAsmLineFromAddr(int addr); void breakPointNotify(int addr); protected: @@ -67,7 +112,9 @@ class ConsoleDebugger : public QDialog //void keyReleaseEvent(QKeyEvent *event); //QTreeWidget *tree; - QPlainTextEdit *asmText; + QScrollBar *vbar; + QScrollBar *hbar; + QAsmView *asmView; QPlainTextEdit *stackText; QLineEdit *seekEntry; QLineEdit *pcEntry; @@ -100,10 +147,6 @@ class ConsoleDebugger : public QDialog QTimer *periodicTimer; QFont font; - dbg_asm_entry_t *asmPC; - std::vector asmEntry; - - bool displayROMoffsets; bool windowUpdateReq; private: From e688ebe23b12b1bca89f470219b61894904f1ff9 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Thu, 3 Sep 2020 22:39:01 -0400 Subject: [PATCH 05/57] ASM view port in work. --- src/drivers/Qt/ConsoleDebugger.cpp | 25 +++++++++++++++++++++++++ src/drivers/Qt/ConsoleDebugger.h | 2 ++ src/drivers/Qt/HexEditor.cpp | 5 +++++ 3 files changed, 32 insertions(+) diff --git a/src/drivers/Qt/ConsoleDebugger.cpp b/src/drivers/Qt/ConsoleDebugger.cpp index 4cdfa903..cc9a9474 100644 --- a/src/drivers/Qt/ConsoleDebugger.cpp +++ b/src/drivers/Qt/ConsoleDebugger.cpp @@ -291,6 +291,8 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent) periodicTimer = new QTimer( this ); connect( periodicTimer, &QTimer::timeout, this, &ConsoleDebugger::updatePeriodic ); + //connect( hbar, SIGNAL(valueChanged(int)), this, SLOT(hbarChanged(int)) ); + connect( vbar, SIGNAL(valueChanged(int)), this, SLOT(vbarChanged(int)) ); periodicTimer->start( 100 ); // 10hz } @@ -602,6 +604,7 @@ void QAsmView::updateAssemblyView(void) asmEntry.push_back(a); } + vbar->setMaximum( asmEntry.size() ); } //---------------------------------------------------------------------------- void ConsoleDebugger::updateWindowData(void) @@ -629,6 +632,12 @@ void ConsoleDebugger::breakPointNotify( int addr ) windowUpdateReq = true; } //---------------------------------------------------------------------------- +void ConsoleDebugger::vbarChanged(int value) +{ + //printf("VBar Changed: %i\n", value); + asmView->setLine( value ); +} +//---------------------------------------------------------------------------- void FCEUD_DebugBreakpoint( int addr ) { std::list ::iterator it; @@ -690,6 +699,11 @@ void QAsmView::asmClear(void) asmEntry.clear(); } //---------------------------------------------------------------------------- +void QAsmView::setLine(int lineNum) +{ + lineOffset = lineNum; +} +//---------------------------------------------------------------------------- void QAsmView::calcFontData(void) { this->setFont(font); @@ -776,6 +790,17 @@ void QAsmView::paintEvent(QPaintEvent *event) { cursorPosY = viewLines-1; } + maxLineOffset = asmEntry.size() - nrow + 1; + + if ( maxLineOffset < 0 ) + { + maxLineOffset = 0; + } + + if ( lineOffset > maxLineOffset ) + { + lineOffset = maxLineOffset; + } painter.fillRect( 0, 0, viewWidth, viewHeight, this->palette().color(QPalette::Background) ); diff --git a/src/drivers/Qt/ConsoleDebugger.h b/src/drivers/Qt/ConsoleDebugger.h index 230c6f55..f4d59822 100644 --- a/src/drivers/Qt/ConsoleDebugger.h +++ b/src/drivers/Qt/ConsoleDebugger.h @@ -60,6 +60,7 @@ class QAsmView : public QWidget void updateAssemblyView(void); void asmClear(void); int getAsmLineFromAddr(int addr); + void setLine(int lineNum); protected: void paintEvent(QPaintEvent *event); void keyPressEvent(QKeyEvent *event); @@ -155,5 +156,6 @@ class ConsoleDebugger : public QDialog void closeWindow(void); private slots: void updatePeriodic(void); + void vbarChanged(int value); }; diff --git a/src/drivers/Qt/HexEditor.cpp b/src/drivers/Qt/HexEditor.cpp index f822b40c..6c206ec7 100644 --- a/src/drivers/Qt/HexEditor.cpp +++ b/src/drivers/Qt/HexEditor.cpp @@ -1764,6 +1764,11 @@ void QHexEdit::paintEvent(QPaintEvent *event) // maxLineOffset = mb.numLines() - nrow + 1; + if ( maxLineOffset < 0 ) + { + maxLineOffset = 0; + } + if ( lineOffset > maxLineOffset ) { lineOffset = maxLineOffset; From abf863a6a28d717a6527327f062f8d06bb38f741 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Fri, 4 Sep 2020 06:37:22 -0400 Subject: [PATCH 06/57] Debugger window functionality in work. --- src/drivers/Qt/ConsoleDebugger.cpp | 328 +++++++++++++++++++++++++++-- src/drivers/Qt/ConsoleDebugger.h | 16 +- src/drivers/Qt/HexEditor.cpp | 4 + 3 files changed, 332 insertions(+), 16 deletions(-) diff --git a/src/drivers/Qt/ConsoleDebugger.cpp b/src/drivers/Qt/ConsoleDebugger.cpp index cc9a9474..31d818bd 100644 --- a/src/drivers/Qt/ConsoleDebugger.cpp +++ b/src/drivers/Qt/ConsoleDebugger.cpp @@ -99,29 +99,36 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent) button = new QPushButton( tr("Run") ); grid->addWidget( button, 0, 0, Qt::AlignLeft ); + connect( button, SIGNAL(clicked(void)), this, SLOT(debugRunCB(void)) ); button = new QPushButton( tr("Step Into") ); grid->addWidget( button, 0, 1, Qt::AlignLeft ); + connect( button, SIGNAL(clicked(void)), this, SLOT(debugStepIntoCB(void)) ); button = new QPushButton( tr("Step Out") ); grid->addWidget( button, 1, 0, Qt::AlignLeft ); + connect( button, SIGNAL(clicked(void)), this, SLOT(debugStepOutCB(void)) ); button = new QPushButton( tr("Step Over") ); grid->addWidget( button, 1, 1, Qt::AlignLeft ); + connect( button, SIGNAL(clicked(void)), this, SLOT(debugStepOverCB(void)) ); button = new QPushButton( tr("Run Line") ); grid->addWidget( button, 2, 0, Qt::AlignLeft ); + connect( button, SIGNAL(clicked(void)), this, SLOT(debugRunLineCB(void)) ); button = new QPushButton( tr("128 Lines") ); grid->addWidget( button, 2, 1, Qt::AlignLeft ); + connect( button, SIGNAL(clicked(void)), this, SLOT(debugRunLine128CB(void)) ); button = new QPushButton( tr("Seek To:") ); grid->addWidget( button, 3, 0, Qt::AlignLeft ); + //connect( button, SIGNAL(clicked(void)), this, SLOT(seekPCCB(void)) ); seekEntry = new QLineEdit(); seekEntry->setFont( font ); seekEntry->setMaxLength( 4 ); - seekEntry->setInputMask( ">HHHH;0" ); + seekEntry->setInputMask( ">HHHH;" ); seekEntry->setAlignment(Qt::AlignCenter); seekEntry->setMaximumWidth( 6 * fontCharWidth ); grid->addWidget( seekEntry, 3, 1, Qt::AlignLeft ); @@ -131,7 +138,7 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent) pcEntry = new QLineEdit(); pcEntry->setFont( font ); pcEntry->setMaxLength( 4 ); - pcEntry->setInputMask( ">HHHH;0" ); + pcEntry->setInputMask( ">HHHH;" ); pcEntry->setAlignment(Qt::AlignCenter); pcEntry->setMaximumWidth( 6 * fontCharWidth ); hbox->addWidget( lbl ); @@ -140,13 +147,14 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent) button = new QPushButton( tr("Seek PC") ); grid->addWidget( button, 4, 1, Qt::AlignLeft ); + connect( button, SIGNAL(clicked(void)), this, SLOT(seekPCCB(void)) ); hbox = new QHBoxLayout(); lbl = new QLabel( tr("A:") ); regAEntry = new QLineEdit(); regAEntry->setFont( font ); regAEntry->setMaxLength( 2 ); - regAEntry->setInputMask( ">HH;0" ); + regAEntry->setInputMask( ">HH;" ); regAEntry->setAlignment(Qt::AlignCenter); regAEntry->setMaximumWidth( 4 * fontCharWidth ); hbox->addWidget( lbl ); @@ -155,7 +163,7 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent) regXEntry = new QLineEdit(); regXEntry->setFont( font ); regXEntry->setMaxLength( 2 ); - regXEntry->setInputMask( ">HH;0" ); + regXEntry->setInputMask( ">HH;" ); regXEntry->setAlignment(Qt::AlignCenter); regXEntry->setMaximumWidth( 4 * fontCharWidth ); hbox->addWidget( lbl ); @@ -164,7 +172,7 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent) regYEntry = new QLineEdit(); regYEntry->setFont( font ); regYEntry->setMaxLength( 2 ); - regYEntry->setInputMask( ">HH;0" ); + regYEntry->setInputMask( ">HH;" ); regYEntry->setAlignment(Qt::AlignCenter); regYEntry->setMaximumWidth( 4 * fontCharWidth ); hbox->addWidget( lbl ); @@ -250,21 +258,29 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent) frame->setLayout( vbox ); frame->setFrameShape( QFrame::Box ); - vbox = new QVBoxLayout(); + vbox = new QVBoxLayout(); + cpuCyclesLbl1 = new QLabel( tr("CPU Cycles:") ); + cpuCyclesLbl2 = new QLabel( tr("(+0):") ); + cpuInstrsLbl1 = new QLabel( tr("Instructions:") ); + cpuInstrsLbl2 = new QLabel( tr("(+0):") ); + brkCpuCycExd = new QCheckBox( tr("Break when Exceed") ); + brkInstrsExd = new QCheckBox( tr("Break when Exceed") ); + cpuCycExdVal = new QLineEdit( tr("0") ); + instrExdVal = new QLineEdit( tr("0") ); + hbox = new QHBoxLayout(); + vbox->addLayout( hbox ); + hbox->addWidget( cpuCyclesLbl1 ); + hbox->addWidget( cpuCyclesLbl2 ); hbox = new QHBoxLayout(); - cpuCyclesLbl = new QLabel( tr("CPU Cycles:") ); - cpuInstrsLbl = new QLabel( tr("Instructions:") ); - brkCpuCycExd = new QCheckBox( tr("Break when Exceed") ); - brkInstrsExd = new QCheckBox( tr("Break when Exceed") ); - cpuCycExdVal = new QLineEdit( tr("0") ); - instrExdVal = new QLineEdit( tr("0") ); - vbox->addWidget( cpuCyclesLbl ); vbox->addLayout( hbox ); hbox->addWidget( brkCpuCycExd ); hbox->addWidget( cpuCycExdVal, 1, Qt::AlignLeft ); hbox = new QHBoxLayout(); - vbox->addWidget( cpuInstrsLbl ); + vbox->addLayout( hbox ); + hbox->addWidget( cpuInstrsLbl1 ); + hbox->addWidget( cpuInstrsLbl2 ); + hbox = new QHBoxLayout(); vbox->addLayout( hbox ); hbox->addWidget( brkInstrsExd ); hbox->addWidget( instrExdVal, 1, Qt::AlignLeft ); @@ -318,6 +334,129 @@ void ConsoleDebugger::closeWindow(void) deleteLater(); } //---------------------------------------------------------------------------- +void ConsoleDebugger::debugRunCB(void) +{ + if (FCEUI_EmulationPaused()) + { + setRegsFromEntry(); + FCEUI_ToggleEmulationPause(); + //DebuggerWasUpdated = false done in above function; + } +} +//---------------------------------------------------------------------------- +void ConsoleDebugger::debugStepIntoCB(void) +{ + if (FCEUI_EmulationPaused()) + { + setRegsFromEntry(); + } + FCEUI_Debugger().step = true; + FCEUI_SetEmulationPaused(0); +} +//---------------------------------------------------------------------------- +void ConsoleDebugger::debugStepOutCB(void) +{ + if (FCEUI_EmulationPaused() > 0) + { + DebuggerState &dbgstate = FCEUI_Debugger(); + setRegsFromEntry(); + if (dbgstate.stepout) + { + printf("Step Out is currently in process.\n"); + return; + } + if (GetMem(X.PC) == 0x20) + { + dbgstate.jsrcount = 1; + } + else + { + dbgstate.jsrcount = 0; + } + dbgstate.stepout = 1; + FCEUI_SetEmulationPaused(0); + } +} +//---------------------------------------------------------------------------- +void ConsoleDebugger::debugStepOverCB(void) +{ + if (FCEUI_EmulationPaused()) + { + setRegsFromEntry(); + int tmp=X.PC; + uint8 opcode = GetMem(X.PC); + bool jsr = opcode==0x20; + bool call = jsr; + #ifdef BRK_3BYTE_HACK + //with this hack, treat BRK similar to JSR + if(opcode == 0x00) + { + call = true; + } + #endif + if (call) + { + if (watchpoint[64].flags) + { + printf("Step Over is currently in process.\n"); + return; + } + watchpoint[64].address = (tmp+3); + watchpoint[64].flags = WP_E|WP_X; + } + else + { + FCEUI_Debugger().step = true; + } + FCEUI_SetEmulationPaused(0); + } +} +//---------------------------------------------------------------------------- +void ConsoleDebugger::debugRunLineCB(void) +{ + if (FCEUI_EmulationPaused()) + { + setRegsFromEntry(); + } + uint64 ts=timestampbase; + ts+=timestamp; + ts+=341/3; + //if (scanline == 240) vblankScanLines++; + //else vblankScanLines = 0; + FCEUI_Debugger().runline = true; + FCEUI_Debugger().runline_end_time=ts; + FCEUI_SetEmulationPaused(0); +} +//---------------------------------------------------------------------------- +void ConsoleDebugger::debugRunLine128CB(void) +{ + if (FCEUI_EmulationPaused()) + { + setRegsFromEntry(); + } + FCEUI_Debugger().runline = true; + { + uint64 ts=timestampbase; + ts+=timestamp; + ts+=128*341/3; + FCEUI_Debugger().runline_end_time=ts; + //if (scanline+128 >= 240 && scanline+128 <= 257) vblankScanLines = (scanline+128)-240; + //else vblankScanLines = 0; + } + FCEUI_SetEmulationPaused(0); +} +//---------------------------------------------------------------------------- +void ConsoleDebugger::seekPCCB (void) +{ + if (FCEUI_EmulationPaused()) + { + setRegsFromEntry(); + //updateAllDebugWindows(); + } + windowUpdateReq = true; + //asmView->scrollToPC(); +} +//---------------------------------------------------------------------------- int QAsmView::getAsmLineFromAddr(int addr) { int line = -1; @@ -607,10 +746,159 @@ void QAsmView::updateAssemblyView(void) vbar->setMaximum( asmEntry.size() ); } //---------------------------------------------------------------------------- +void ConsoleDebugger::setRegsFromEntry(void) +{ + std::string s; + long int i; + + s = pcEntry->text().toStdString(); + if ( s.size() > 0 ) + { + i = strtol( s.c_str(), NULL, 16 ); + } + else + { + i = 0; + } + X.PC = i; + //printf("Set PC: '%s' %04X\n", s.c_str(), X.PC ); + + s = regAEntry->text().toStdString(); + if ( s.size() > 0 ) + { + i = strtol( s.c_str(), NULL, 16 ); + } + else + { + i = 0; + } + X.A = i; + //printf("Set A: '%s' %02X\n", s.c_str(), X.A ); + + s = regXEntry->text().toStdString(); + if ( s.size() > 0 ) + { + i = strtol( s.c_str(), NULL, 16 ); + } + else + { + i = 0; + } + X.X = i; + //printf("Set X: '%s' %02X\n", s.c_str(), X.X ); + + s = regYEntry->text().toStdString(); + if ( s.size() > 0 ) + { + i = strtol( s.c_str(), NULL, 16 ); + } + else + { + i = 0; + } + X.Y = i; + //printf("Set Y: '%s' %02X\n", s.c_str(), X.Y ); +} +//---------------------------------------------------------------------------- +void ConsoleDebugger::updateRegisterView(void) +{ + int stackPtr; + char stmp[64]; + char str[32], str2[32]; + std::string stackLine; + + sprintf( stmp, "%04X", X.PC ); + + pcEntry->setText( tr(stmp) ); + + sprintf( stmp, "%02X", X.A ); + + regAEntry->setText( tr(stmp) ); + + sprintf( stmp, "%02X", X.X ); + + regXEntry->setText( tr(stmp) ); + + sprintf( stmp, "%02X", X.Y ); + + regYEntry->setText( tr(stmp) ); + + N_chkbox->setChecked( (X.P & N_FLAG) ? true : false ); + V_chkbox->setChecked( (X.P & V_FLAG) ? true : false ); + U_chkbox->setChecked( (X.P & U_FLAG) ? true : false ); + B_chkbox->setChecked( (X.P & B_FLAG) ? true : false ); + D_chkbox->setChecked( (X.P & D_FLAG) ? true : false ); + I_chkbox->setChecked( (X.P & I_FLAG) ? true : false ); + Z_chkbox->setChecked( (X.P & Z_FLAG) ? true : false ); + C_chkbox->setChecked( (X.P & C_FLAG) ? true : false ); + + stackPtr = X.S | 0x0100; + + sprintf( stmp, "Stack: $%04X", stackPtr ); + stackFrame->setTitle( tr(stmp) ); + + stackPtr++; + + if ( stackPtr <= 0x01FF ) + { + sprintf( stmp, "%02X", GetMem(stackPtr) ); + + stackLine.assign( stmp ); + + for (int i = 1; i < 128; i++) + { + //tmp = ((tmp+1)|0x0100)&0x01FF; //increment and fix pointer to $0100-$01FF range + stackPtr++; + if (stackPtr > 0x1FF) + break; + if ((i & 7) == 0) + sprintf( stmp, ",\r\n%02X", GetMem(stackPtr) ); + else + sprintf( stmp, ",%02X", GetMem(stackPtr) ); + + stackLine.append( stmp ); + } + } + + stackText->setPlainText( tr(stackLine.c_str()) ); + + // update counters + int64 counter_value = timestampbase + (uint64)timestamp - total_cycles_base; + if (counter_value < 0) // sanity check + { + ResetDebugStatisticsCounters(); + counter_value = 0; + } + sprintf( stmp, "CPU Cycles: %llu", counter_value); + + cpuCyclesLbl1->setText( tr(stmp) ); + + counter_value = timestampbase + (uint64)timestamp - delta_cycles_base; + if (counter_value < 0) // sanity check + { + ResetDebugStatisticsCounters(); + counter_value = 0; + } + sprintf(stmp, "(+%llu)", counter_value); + + cpuCyclesLbl2->setText( tr(stmp) ); + + sprintf(stmp, "Instructions: %llu", total_instructions); + cpuInstrsLbl1->setText( tr(stmp) ); + + sprintf(stmp, "(+%llu)", delta_instructions); + cpuInstrsLbl2->setText( tr(stmp) ); + +} +//---------------------------------------------------------------------------- void ConsoleDebugger::updateWindowData(void) { asmView->updateAssemblyView(); + asmView->scrollToPC(); + + updateRegisterView(); + windowUpdateReq = false; } //---------------------------------------------------------------------------- @@ -704,6 +992,14 @@ void QAsmView::setLine(int lineNum) lineOffset = lineNum; } //---------------------------------------------------------------------------- +void QAsmView::scrollToPC(void) +{ + if ( asmPC != NULL ) + { + lineOffset = asmPC->line; + } +} +//---------------------------------------------------------------------------- void QAsmView::calcFontData(void) { this->setFont(font); @@ -797,6 +1093,10 @@ void QAsmView::paintEvent(QPaintEvent *event) maxLineOffset = 0; } + if ( lineOffset < 0 ) + { + lineOffset = 0; + } if ( lineOffset > maxLineOffset ) { lineOffset = maxLineOffset; diff --git a/src/drivers/Qt/ConsoleDebugger.h b/src/drivers/Qt/ConsoleDebugger.h index f4d59822..ca1eeb15 100644 --- a/src/drivers/Qt/ConsoleDebugger.h +++ b/src/drivers/Qt/ConsoleDebugger.h @@ -61,6 +61,7 @@ class QAsmView : public QWidget void asmClear(void); int getAsmLineFromAddr(int addr); void setLine(int lineNum); + void scrollToPC(void); protected: void paintEvent(QPaintEvent *event); void keyPressEvent(QKeyEvent *event); @@ -105,6 +106,7 @@ class ConsoleDebugger : public QDialog ~ConsoleDebugger(void); void updateWindowData(void); + void updateRegisterView(void); void breakPointNotify(int addr); protected: @@ -143,19 +145,29 @@ class ConsoleDebugger : public QDialog QLabel *spriteLbl; QLabel *scanLineLbl; QLabel *pixLbl; - QLabel *cpuCyclesLbl; - QLabel *cpuInstrsLbl; + QLabel *cpuCyclesLbl1; + QLabel *cpuCyclesLbl2; + QLabel *cpuInstrsLbl1; + QLabel *cpuInstrsLbl2; QTimer *periodicTimer; QFont font; bool windowUpdateReq; private: + void setRegsFromEntry(void); public slots: void closeWindow(void); private slots: void updatePeriodic(void); void vbarChanged(int value); + void debugRunCB(void); + void debugStepIntoCB(void); + void debugStepOutCB(void); + void debugStepOverCB(void); + void debugRunLineCB(void); + void debugRunLine128CB(void); + void seekPCCB(void); }; diff --git a/src/drivers/Qt/HexEditor.cpp b/src/drivers/Qt/HexEditor.cpp index 6c206ec7..1906fe7e 100644 --- a/src/drivers/Qt/HexEditor.cpp +++ b/src/drivers/Qt/HexEditor.cpp @@ -1769,6 +1769,10 @@ void QHexEdit::paintEvent(QPaintEvent *event) maxLineOffset = 0; } + if ( lineOffset < 0 ) + { + lineOffset = 0; + } if ( lineOffset > maxLineOffset ) { lineOffset = maxLineOffset; From 4e3e4d2e5446f073a35d45dd2df81f80685b0456 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Fri, 4 Sep 2020 06:48:29 -0400 Subject: [PATCH 07/57] Added logic to update PPU labels on debug window. --- src/drivers/Qt/ConsoleDebugger.cpp | 55 ++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/src/drivers/Qt/ConsoleDebugger.cpp b/src/drivers/Qt/ConsoleDebugger.cpp index 31d818bd..28c6c9dc 100644 --- a/src/drivers/Qt/ConsoleDebugger.cpp +++ b/src/drivers/Qt/ConsoleDebugger.cpp @@ -35,6 +35,10 @@ #include "Qt/fceuWrapper.h" #include "Qt/ConsoleDebugger.h" +// Where are these defined? +extern int vblankScanLines; +extern int vblankPixel; + static std::list dbgWinList; //---------------------------------------------------------------------------- ConsoleDebugger::ConsoleDebugger(QWidget *parent) @@ -889,6 +893,57 @@ void ConsoleDebugger::updateRegisterView(void) sprintf(stmp, "(+%llu)", delta_instructions); cpuInstrsLbl2->setText( tr(stmp) ); + // PPU Labels + sprintf(stmp, "PPU: 0x%04X", (int)FCEUPPU_PeekAddress()); + ppuLbl->setText( tr(stmp) ); + + sprintf(stmp, "Sprite: 0x%02X", PPU[3] ); + spriteLbl->setText( tr(stmp) ); + + extern int linestartts; + #define GETLASTPIXEL (PAL?((timestamp*48-linestartts)/15) : ((timestamp*48-linestartts)/16) ) + + int ppupixel = GETLASTPIXEL; + + if (ppupixel>341) //maximum number of pixels per scanline + ppupixel = 0; //Currently pixel display is borked until Run 128 lines is clicked, this keeps garbage from displaying + + // If not in the 0-239 pixel range, make special cases for display + if (scanline == 240 && vblankScanLines < (PAL?72:22)) + { + if (!vblankScanLines) + { + // Idle scanline (240) + sprintf(str, "%d", scanline); // was "Idle %d" + } else if (scanline + vblankScanLines == (PAL?311:261)) + { + // Pre-render + sprintf(str, "-1"); // was "Prerender -1" + } else + { + // Vblank lines (241-260/310) + sprintf(str, "%d", scanline + vblankScanLines); // was "Vblank %d" + } + sprintf(str2, "%d", vblankPixel); + } else + { + // Scanlines 0 - 239 + sprintf(str, "%d", scanline); + sprintf(str2, "%d", ppupixel); + } + + if(newppu) + { + sprintf(str ,"%d",newppu_get_scanline()); + sprintf(str2,"%d",newppu_get_dot()); + } + + sprintf( stmp, "Scanline: %s", str ); + scanLineLbl->setText( tr(stmp) ); + + sprintf( stmp, "Pixel: %s", str2 ); + pixLbl->setText( tr(stmp) ); + } //---------------------------------------------------------------------------- void ConsoleDebugger::updateWindowData(void) From dd7aa8fc2c8130676dd74b6d22f0a86566981c67 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Tue, 8 Sep 2020 22:18:49 -0400 Subject: [PATCH 08/57] Added initial framework for adding, editing, and removing breakpoints. --- src/drivers/Qt/ConsoleDebugger.cpp | 447 ++++++++++++++++++++++++++++- src/drivers/Qt/ConsoleDebugger.h | 8 + src/drivers/Qt/ConsoleWindow.cpp | 12 +- 3 files changed, 459 insertions(+), 8 deletions(-) diff --git a/src/drivers/Qt/ConsoleDebugger.cpp b/src/drivers/Qt/ConsoleDebugger.cpp index 28c6c9dc..43677586 100644 --- a/src/drivers/Qt/ConsoleDebugger.cpp +++ b/src/drivers/Qt/ConsoleDebugger.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include "../../types.h" #include "../../fceu.h" @@ -32,6 +33,7 @@ #include "Qt/main.h" #include "Qt/dface.h" #include "Qt/config.h" +#include "Qt/nes_shm.h" #include "Qt/fceuWrapper.h" #include "Qt/ConsoleDebugger.h" @@ -52,6 +54,7 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent) QFrame *frame; QLabel *lbl; float fontCharWidth; + QTreeWidgetItem * item; font.setFamily("Courier New"); font.setStyle( QFont::StyleNormal ); @@ -191,6 +194,8 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent) stackFrame->setLayout( hbox ); stackText->setFont(font); stackText->setReadOnly(true); + stackText->setWordWrapMode( QTextOption::WordWrap ); + stackText->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); //stackText->setMaximumWidth( 16 * fontCharWidth ); bpFrame = new QGroupBox(tr("Breakpoints")); @@ -199,19 +204,40 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent) hbox = new QHBoxLayout(); bpTree = new QTreeWidget(); - bpTree->setColumnCount(1); + bpTree->setColumnCount(2); + + item = new QTreeWidgetItem(); + item->setFont( 0, font ); + item->setFont( 1, font ); + item->setFont( 2, font ); + item->setText( 0, QString::fromStdString( "Addr" ) ); + item->setText( 1, QString::fromStdString( "Flags" ) ); + item->setText( 2, QString::fromStdString( "Desc" ) ); + item->setTextAlignment( 0, Qt::AlignCenter); + item->setTextAlignment( 1, Qt::AlignCenter); + item->setTextAlignment( 2, Qt::AlignCenter); + + bpTree->setHeaderItem( item ); + + bpTree->header()->setSectionResizeMode( QHeaderView::ResizeToContents ); + + connect( bpTree, SIGNAL(itemClicked(QTreeWidgetItem*, int)), + this, SLOT(bpItemClicked( QTreeWidgetItem*, int)) ); hbox->addWidget( bpTree ); hbox = new QHBoxLayout(); button = new QPushButton( tr("Add") ); hbox->addWidget( button ); + connect( button, SIGNAL(clicked(void)), this, SLOT(add_BP_CB(void)) ); button = new QPushButton( tr("Delete") ); hbox->addWidget( button ); + connect( button, SIGNAL(clicked(void)), this, SLOT(delete_BP_CB(void)) ); button = new QPushButton( tr("Edit") ); hbox->addWidget( button ); + connect( button, SIGNAL(clicked(void)), this, SLOT(edit_BP_CB(void)) ); brkBadOpsCbox = new QCheckBox( tr("Break on Bad Opcodes") ); @@ -314,6 +340,8 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent) //connect( hbar, SIGNAL(valueChanged(int)), this, SLOT(hbarChanged(int)) ); connect( vbar, SIGNAL(valueChanged(int)), this, SLOT(vbarChanged(int)) ); + bpListUpdate( false ); + periodicTimer->start( 100 ); // 10hz } //---------------------------------------------------------------------------- @@ -338,6 +366,415 @@ void ConsoleDebugger::closeWindow(void) deleteLater(); } //---------------------------------------------------------------------------- +void ConsoleDebugger::bpItemClicked( QTreeWidgetItem *item, int column) +{ + int row = bpTree->indexOfTopLevelItem(item); + + printf("Row: %i Column: %i \n", row, column ); + +} +//---------------------------------------------------------------------------- +void ConsoleDebugger::openBpEditWindow( int editIdx, watchpointinfo *wp ) +{ + int ret; + QDialog dialog(this); + QHBoxLayout *hbox; + QVBoxLayout *mainLayout, *vbox; + QLabel *lbl; + QLineEdit *addr1, *addr2, *cond, *name; + QCheckBox *forbidChkBox, *rbp, *wbp, *xbp; + QGridLayout *grid; + QFrame *frame; + QGroupBox *gbox; + QPushButton *okButton, *cancelButton; + QRadioButton *cpu_radio, *ppu_radio, *sprite_radio; + + dialog.setWindowTitle( tr("Add Breakpoint") ); + + hbox = new QHBoxLayout(); + mainLayout = new QVBoxLayout(); + + mainLayout->addLayout( hbox ); + + lbl = new QLabel( tr("Address") ); + addr1 = new QLineEdit(); + + hbox->addWidget( lbl ); + hbox->addWidget( addr1 ); + + lbl = new QLabel( tr("-") ); + addr2 = new QLineEdit(); + hbox->addWidget( lbl ); + hbox->addWidget( addr2 ); + + forbidChkBox = new QCheckBox( tr("Forbid") ); + hbox->addWidget( forbidChkBox ); + + frame = new QFrame(); + vbox = new QVBoxLayout(); + hbox = new QHBoxLayout(); + gbox = new QGroupBox(); + + rbp = new QCheckBox( tr("Read") ); + wbp = new QCheckBox( tr("Write") ); + xbp = new QCheckBox( tr("Execute") ); + + gbox->setTitle( tr("Memory") ); + mainLayout->addWidget( frame ); + frame->setLayout( vbox ); + frame->setFrameShape( QFrame::Box ); + vbox->addLayout( hbox ); + vbox->addWidget( gbox ); + + hbox->addWidget( rbp ); + hbox->addWidget( wbp ); + hbox->addWidget( xbp ); + + hbox = new QHBoxLayout(); + cpu_radio = new QRadioButton( tr("CPU Mem") ); + ppu_radio = new QRadioButton( tr("PPU Mem") ); + sprite_radio = new QRadioButton( tr("Sprite Mem") ); + cpu_radio->setChecked(true); + + gbox->setLayout( hbox ); + hbox->addWidget( cpu_radio ); + hbox->addWidget( ppu_radio ); + hbox->addWidget( sprite_radio ); + + grid = new QGridLayout(); + + mainLayout->addLayout( grid ); + lbl = new QLabel( tr("Condition") ); + cond = new QLineEdit(); + + grid->addWidget( lbl, 0, 0 ); + grid->addWidget( cond, 0, 1 ); + + lbl = new QLabel( tr("Name") ); + name = new QLineEdit(); + + grid->addWidget( lbl, 1, 0 ); + grid->addWidget( name, 1, 1 ); + + hbox = new QHBoxLayout(); + okButton = new QPushButton( tr("OK") ); + cancelButton = new QPushButton( tr("Cancel") ); + + mainLayout->addLayout( hbox ); + hbox->addWidget( cancelButton ); + hbox->addWidget( okButton ); + + connect( okButton, SIGNAL(clicked(void)), &dialog, SLOT(accept(void)) ); + connect( cancelButton, SIGNAL(clicked(void)), &dialog, SLOT(reject(void)) ); + + if ( wp != NULL ) + { + char stmp[256]; + + if ( wp->flags & BT_P ) + { + ppu_radio->setChecked(true); + } + else if ( wp->flags & BT_S ) + { + sprite_radio->setChecked(true); + } + + sprintf( stmp, "%04X", wp->address ); + + addr1->setText( tr(stmp) ); + + if ( wp->endaddress > 0 ) + { + sprintf( stmp, "%04X", wp->endaddress ); + + addr2->setText( tr(stmp) ); + } + + if ( wp->flags & WP_R ) + { + rbp->setChecked(true); + } + if ( wp->flags & WP_W ) + { + wbp->setChecked(true); + } + if ( wp->flags & WP_X ) + { + xbp->setChecked(true); + } + if ( wp->flags & WP_F ) + { + forbidChkBox->setChecked(true); + } + if ( wp->flags & WP_E ) + { + //forbidChkBox->setChecked(true); + } + + if ( wp->condText ) + { + cond->setText( tr(wp->condText) ); + } + + if ( wp->desc ) + { + name->setText( tr(wp->desc) ); + } + } + + dialog.setLayout( mainLayout ); + + ret = dialog.exec(); + + if ( ret == QDialog::Accepted ) + { + int start_addr = -1, end_addr = -1, type = 0, enable = 1, slot; + std::string s; + printf("Accepted\n"); + + slot = (editIdx < 0) ? numWPs : editIdx; + + if ( cpu_radio->isChecked() ) + { + type |= BT_C; + } + else if ( ppu_radio->isChecked() ) + { + type |= BT_P; + } + else if ( sprite_radio->isChecked() ) + { + type |= BT_S; + } + + s = addr1->text().toStdString(); + + if ( s.size() > 0 ) + { + start_addr = offsetStringToInt( type, s.c_str() ); + } + + s = addr2->text().toStdString(); + + if ( s.size() > 0 ) + { + end_addr = offsetStringToInt( type, s.c_str() ); + } + + if ( rbp->isChecked() ) + { + type |= WP_R; + } + if ( wbp->isChecked() ) + { + type |= WP_W; + } + if ( xbp->isChecked() ) + { + type |= WP_X; + } + + if ( forbidChkBox->isChecked() ) + { + type |= WP_F; + } + + if ( (start_addr >= 0) && (numWPs < 64) ) + { + unsigned int retval; + std::string nameString, condString; + + nameString = name->text().toStdString(); + condString = cond->text().toStdString(); + + retval = NewBreak( nameString.c_str(), start_addr, end_addr, type, condString.c_str(), slot, enable); + + if ( (retval == 1) || (retval == 2) ) + { + printf("Breakpoint Add Failed\n"); + } + else + { + if (editIdx < 0) + { + numWPs++; + } + + bpListUpdate( false ); + } + } + } +} +//---------------------------------------------------------------------------- +void ConsoleDebugger::bpListUpdate( bool reset ) +{ + QTreeWidgetItem *item; + char line[256], addrStr[32], flags[16], enable; + + if ( reset ) + { + bpTree->clear(); + } + + for (int i=0; itopLevelItem(i); + + if ( item == NULL ) + { + item = new QTreeWidgetItem(); + + bpTree->addTopLevelItem( item ); + } + + //item->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsUserCheckable ); + item->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemNeverHasChildren ); + + if ( watchpoint[i].endaddress > 0 ) + { + sprintf( addrStr, "$%04X-%04X:", watchpoint[i].address, watchpoint[i].endaddress ); + } + else + { + sprintf( addrStr, "$%04X:", watchpoint[i].address ); + } + + flags[0] = (watchpoint[i].flags & WP_E) ? 'E' : '-'; + + if ( watchpoint[i].flags & BT_P ) + { + flags[1] = 'P'; + } + else if ( watchpoint[i].flags & BT_S ) + { + flags[1] = 'S'; + } + else + { + flags[1] = 'C'; + } + + flags[2] = (watchpoint[i].flags & WP_R) ? 'R' : '-'; + flags[3] = (watchpoint[i].flags & WP_W) ? 'W' : '-'; + flags[4] = (watchpoint[i].flags & WP_X) ? 'X' : '-'; + flags[5] = (watchpoint[i].flags & WP_F) ? 'F' : '-'; + flags[6] = 0; + + enable = (watchpoint[i].flags & WP_E) ? 1 : 0; + + //strcpy( line, addrStr ); + //strcpy( line, flags ); + line[0] = 0; + + if (watchpoint[i].desc ) + { + strcat( line, watchpoint[i].desc); + } + + if (watchpoint[i].condText ) + { + strcat( line, " Condition:"); + strcat( line, watchpoint[i].condText); + strcat( line, " "); + } + + item->setCheckState( 0, enable ? Qt::Checked : Qt::Unchecked ); + + item->setFont( 0, font ); + item->setFont( 1, font ); + item->setFont( 2, font ); + + item->setText( 0, tr(addrStr)); + item->setText( 1, tr(flags) ); + item->setText( 2, tr(line) ); + + item->setTextAlignment( 0, Qt::AlignLeft); + item->setTextAlignment( 1, Qt::AlignLeft); + item->setTextAlignment( 2, Qt::AlignLeft); + } + + bpTree->update(); +} +//---------------------------------------------------------------------------- +void ConsoleDebugger::add_BP_CB(void) +{ + openBpEditWindow(-1); +} +//---------------------------------------------------------------------------- +void ConsoleDebugger::edit_BP_CB(void) +{ + QTreeWidgetItem *item; + + item = bpTree->currentItem(); + + if ( item == NULL ) + { + printf( "No Item Selected\n"); + return; + } + + int row = bpTree->indexOfTopLevelItem(item); + + openBpEditWindow( row, &watchpoint[row] ); +} +//---------------------------------------------------------------------------- +static void DeleteBreak(int sel) +{ + if(sel<0) return; + if(sel>=numWPs) return; + if (watchpoint[sel].cond) + { + freeTree(watchpoint[sel].cond); + } + if (watchpoint[sel].condText) + { + free(watchpoint[sel].condText); + } + if (watchpoint[sel].desc) + { + free(watchpoint[sel].desc); + } + // move all BP items up in the list + for (int i = sel; i < numWPs; i++) + { + watchpoint[i].address = watchpoint[i+1].address; + watchpoint[i].endaddress = watchpoint[i+1].endaddress; + watchpoint[i].flags = watchpoint[i+1].flags; +// ################################## Start of SP CODE ########################### + watchpoint[i].cond = watchpoint[i+1].cond; + watchpoint[i].condText = watchpoint[i+1].condText; + watchpoint[i].desc = watchpoint[i+1].desc; +// ################################## End of SP CODE ########################### + } + // erase last BP item + watchpoint[numWPs].address = 0; + watchpoint[numWPs].endaddress = 0; + watchpoint[numWPs].flags = 0; + watchpoint[numWPs].cond = 0; + watchpoint[numWPs].condText = 0; + watchpoint[numWPs].desc = 0; + numWPs--; +} +//---------------------------------------------------------------------------- +void ConsoleDebugger::delete_BP_CB(void) +{ + QTreeWidgetItem *item; + + item = bpTree->currentItem(); + + if ( item == NULL ) + { + printf( "No Item Selected\n"); + return; + } + + int row = bpTree->indexOfTopLevelItem(item); + + DeleteBreak( row ); + bpListUpdate( true ); +} +//---------------------------------------------------------------------------- void ConsoleDebugger::debugRunCB(void) { if (FCEUI_EmulationPaused()) @@ -985,7 +1422,11 @@ void FCEUD_DebugBreakpoint( int addr ) { std::list ::iterator it; - printf("Breakpoint Hit: 0x%04X \n", addr ); + if ( !nes_shm->runEmulator ) + { + return; + } + //printf("Breakpoint Hit: 0x%04X \n", addr ); fceuWrapperUnLock(); @@ -994,7 +1435,7 @@ void FCEUD_DebugBreakpoint( int addr ) (*it)->breakPointNotify( addr ); } - while (FCEUI_EmulationPaused() && !FCEUI_EmulationFrameStepped()) + while ( nes_shm->runEmulator && FCEUI_EmulationPaused() && !FCEUI_EmulationFrameStepped()) { usleep(100000); } diff --git a/src/drivers/Qt/ConsoleDebugger.h b/src/drivers/Qt/ConsoleDebugger.h index ca1eeb15..d034cc25 100644 --- a/src/drivers/Qt/ConsoleDebugger.h +++ b/src/drivers/Qt/ConsoleDebugger.h @@ -18,12 +18,14 @@ #include #include #include +#include #include #include #include #include #include "Qt/main.h" +#include "../../debug.h" struct dbg_asm_entry_t { @@ -156,6 +158,8 @@ class ConsoleDebugger : public QDialog private: void setRegsFromEntry(void); + void openBpEditWindow(int editIdx = -1, watchpointinfo *wp = NULL ); + void bpListUpdate( bool reset = false ); public slots: void closeWindow(void); @@ -169,5 +173,9 @@ class ConsoleDebugger : public QDialog void debugRunLineCB(void); void debugRunLine128CB(void); void seekPCCB(void); + void add_BP_CB(void); + void edit_BP_CB(void); + void delete_BP_CB(void); + void bpItemClicked( QTreeWidgetItem *item, int column); }; diff --git a/src/drivers/Qt/ConsoleWindow.cpp b/src/drivers/Qt/ConsoleWindow.cpp index a220ce88..9e06722e 100644 --- a/src/drivers/Qt/ConsoleWindow.cpp +++ b/src/drivers/Qt/ConsoleWindow.cpp @@ -86,14 +86,14 @@ consoleWin_t::~consoleWin_t(void) closeGamePadConfWindow(); + //printf("Thread Finished: %i \n", gameThread->isFinished() ); + emulatorThread->quit(); + emulatorThread->wait( 1000 ); + fceuWrapperLock(); fceuWrapperClose(); fceuWrapperUnLock(); - //printf("Thread Finished: %i \n", gameThread->isFinished() ); - emulatorThread->quit(); - emulatorThread->wait(); - if ( viewport_GL != NULL ) { delete viewport_GL; viewport_GL = NULL; @@ -560,6 +560,9 @@ void consoleWin_t::closeApp(void) { nes_shm->runEmulator = 0; + emulatorThread->quit(); + emulatorThread->wait( 1000 ); + fceuWrapperLock(); fceuWrapperClose(); fceuWrapperUnLock(); @@ -568,7 +571,6 @@ void consoleWin_t::closeApp(void) // clear the NetworkIP field so this doesn't happen unintentionally g_config->setOption ("SDL.NetworkIP", ""); g_config->save (); - //SDL_Quit (); // Already called by fceuWrapperClose //qApp::quit(); qApp->quit(); From 473ef5b7dc26e7787571ab615f6bdf17dc770d65 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Wed, 9 Sep 2020 20:22:31 -0400 Subject: [PATCH 09/57] Added a little more logic to Qt debug window. --- src/drivers/Qt/ConsoleDebugger.cpp | 115 ++++++++++++++++++++++++++++- src/drivers/Qt/ConsoleDebugger.h | 6 ++ 2 files changed, 117 insertions(+), 4 deletions(-) diff --git a/src/drivers/Qt/ConsoleDebugger.cpp b/src/drivers/Qt/ConsoleDebugger.cpp index 43677586..0feeead4 100644 --- a/src/drivers/Qt/ConsoleDebugger.cpp +++ b/src/drivers/Qt/ConsoleDebugger.cpp @@ -130,10 +130,11 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent) button = new QPushButton( tr("Seek To:") ); grid->addWidget( button, 3, 0, Qt::AlignLeft ); - //connect( button, SIGNAL(clicked(void)), this, SLOT(seekPCCB(void)) ); + connect( button, SIGNAL(clicked(void)), this, SLOT(seekToCB(void)) ); seekEntry = new QLineEdit(); seekEntry->setFont( font ); + seekEntry->setText("0000"); seekEntry->setMaxLength( 4 ); seekEntry->setInputMask( ">HHHH;" ); seekEntry->setAlignment(Qt::AlignCenter); @@ -240,6 +241,8 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent) connect( button, SIGNAL(clicked(void)), this, SLOT(edit_BP_CB(void)) ); brkBadOpsCbox = new QCheckBox( tr("Break on Bad Opcodes") ); + brkBadOpsCbox->setChecked( FCEUI_Debugger().badopbreak ); + connect( brkBadOpsCbox, SIGNAL(stateChanged(int)), this, SLOT(breakOnBadOpcodeCB(int)) ); vbox->addWidget( bpTree ); vbox->addLayout( hbox ); @@ -321,12 +324,20 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent) cpuCycExdVal->setInputMask( ">9000000000000000;" ); cpuCycExdVal->setAlignment(Qt::AlignLeft); cpuCycExdVal->setMaximumWidth( 18 * fontCharWidth ); + connect( cpuCycExdVal, SIGNAL(textEdited(const QString &)), this, SLOT(cpuCycleThresChanged(const QString &))); instrExdVal->setFont( font ); instrExdVal->setMaxLength( 16 ); instrExdVal->setInputMask( ">9000000000000000;" ); instrExdVal->setAlignment(Qt::AlignLeft); instrExdVal->setMaximumWidth( 18 * fontCharWidth ); + connect( instrExdVal, SIGNAL(textEdited(const QString &)), this, SLOT(instructionsThresChanged(const QString &))); + + brkCpuCycExd->setChecked( break_on_cycles ); + connect( brkCpuCycExd, SIGNAL(stateChanged(int)), this, SLOT(breakOnCyclesCB(int)) ); + + brkInstrsExd->setChecked( break_on_instructions ); + connect( brkInstrsExd, SIGNAL(stateChanged(int)), this, SLOT(breakOnInstructionsCB(int)) ); setLayout( mainLayout ); @@ -775,6 +786,72 @@ void ConsoleDebugger::delete_BP_CB(void) bpListUpdate( true ); } //---------------------------------------------------------------------------- +void ConsoleDebugger::breakOnBadOpcodeCB(int value) +{ + //printf("Value:%i\n", value); + FCEUI_Debugger().badopbreak = (value != Qt::Unchecked); +} +//---------------------------------------------------------------------------- +void ConsoleDebugger::breakOnCyclesCB( int value ) +{ + std::string s; + + break_on_cycles = (value != Qt::Unchecked); + + s = cpuCycExdVal->text().toStdString(); + + //printf("'%s'\n", txt ); + + if ( s.size() > 0 ) + { + break_cycles_limit = strtoul( s.c_str(), NULL, 10 ); + } +} +//---------------------------------------------------------------------------- +void ConsoleDebugger::cpuCycleThresChanged(const QString &txt) +{ + std::string s; + + s = txt.toStdString(); + + //printf("Cycles: '%s'\n", s.c_str() ); + + if ( s.size() > 0 ) + { + break_cycles_limit = strtoul( s.c_str(), NULL, 10 ); + } +} +//---------------------------------------------------------------------------- +void ConsoleDebugger::breakOnInstructionsCB( int value ) +{ + std::string s; + + break_on_instructions = (value != Qt::Unchecked); + + s = instrExdVal->text().toStdString(); + + //printf("'%s'\n", txt ); + + if ( s.size() > 0 ) + { + break_instructions_limit = strtoul( s.c_str(), NULL, 10 ); + } +} +//---------------------------------------------------------------------------- +void ConsoleDebugger::instructionsThresChanged(const QString &txt) +{ + std::string s; + + s = txt.toStdString(); + + //printf("Instructions: '%s'\n", s.c_str() ); + + if ( s.size() > 0 ) + { + break_instructions_limit = strtoul( s.c_str(), NULL, 10 ); + } +} +//---------------------------------------------------------------------------- void ConsoleDebugger::debugRunCB(void) { if (FCEUI_EmulationPaused()) @@ -887,6 +964,27 @@ void ConsoleDebugger::debugRunLine128CB(void) FCEUI_SetEmulationPaused(0); } //---------------------------------------------------------------------------- +void ConsoleDebugger::seekToCB (void) +{ + std::string s; + + s = seekEntry->text().toStdString(); + + //printf("Seek To: '%s'\n", s.c_str() ); + + if ( s.size() > 0 ) + { + long int addr, line; + + addr = strtol( s.c_str(), NULL, 16 ); + + line = asmView->getAsmLineFromAddr(addr); + + asmView->setLine( line ); + vbar->setValue( line ); + } +} +//---------------------------------------------------------------------------- void ConsoleDebugger::seekPCCB (void) { if (FCEUI_EmulationPaused()) @@ -1418,7 +1516,7 @@ void ConsoleDebugger::vbarChanged(int value) asmView->setLine( value ); } //---------------------------------------------------------------------------- -void FCEUD_DebugBreakpoint( int addr ) +void FCEUD_DebugBreakpoint( int bpNum ) { std::list ::iterator it; @@ -1426,13 +1524,13 @@ void FCEUD_DebugBreakpoint( int addr ) { return; } - //printf("Breakpoint Hit: 0x%04X \n", addr ); + printf("Breakpoint Hit: %i \n", bpNum ); fceuWrapperUnLock(); for (it=dbgWinList.begin(); it!=dbgWinList.end(); it++) { - (*it)->breakPointNotify( addr ); + (*it)->breakPointNotify( bpNum ); } while ( nes_shm->runEmulator && FCEUI_EmulationPaused() && !FCEUI_EmulationFrameStepped()) @@ -1493,6 +1591,7 @@ void QAsmView::scrollToPC(void) if ( asmPC != NULL ) { lineOffset = asmPC->line; + vbar->setValue( lineOffset ); } } //---------------------------------------------------------------------------- @@ -1608,6 +1707,14 @@ void QAsmView::paintEvent(QPaintEvent *event) l = lineOffset + row; painter.setPen( this->palette().color(QPalette::WindowText)); + if ( asmPC != NULL ) + { + if ( l == asmPC->line ) + { + painter.fillRect( 0, y - pxLineSpacing + pxLineLead, viewWidth, pxLineSpacing, QColor("light blue") ); + } + } + if ( l < asmEntry.size() ) { painter.drawText( x, y, tr(asmEntry[l]->text.c_str()) ); diff --git a/src/drivers/Qt/ConsoleDebugger.h b/src/drivers/Qt/ConsoleDebugger.h index d034cc25..1fbf46ce 100644 --- a/src/drivers/Qt/ConsoleDebugger.h +++ b/src/drivers/Qt/ConsoleDebugger.h @@ -172,10 +172,16 @@ class ConsoleDebugger : public QDialog void debugStepOverCB(void); void debugRunLineCB(void); void debugRunLine128CB(void); + void seekToCB(void); void seekPCCB(void); void add_BP_CB(void); void edit_BP_CB(void); void delete_BP_CB(void); + void breakOnBadOpcodeCB(int value); + void breakOnCyclesCB( int value ); + void breakOnInstructionsCB( int value ); void bpItemClicked( QTreeWidgetItem *item, int column); + void cpuCycleThresChanged(const QString &txt); + void instructionsThresChanged(const QString &txt); }; From 1403ab607d4a5b291cdce19f6448252f5c8ea67d Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Wed, 9 Sep 2020 21:58:09 -0400 Subject: [PATCH 10/57] More widget logic added to Qt debug window. --- src/drivers/Qt/ConsoleDebugger.cpp | 126 ++++++++++++++++++++++++++++- src/drivers/Qt/ConsoleDebugger.h | 16 +++- 2 files changed, 139 insertions(+), 3 deletions(-) diff --git a/src/drivers/Qt/ConsoleDebugger.cpp b/src/drivers/Qt/ConsoleDebugger.cpp index 0feeead4..ed9cc4dd 100644 --- a/src/drivers/Qt/ConsoleDebugger.cpp +++ b/src/drivers/Qt/ConsoleDebugger.cpp @@ -48,7 +48,7 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent) { QHBoxLayout *mainLayout; QVBoxLayout *vbox, *vbox1, *vbox2, *vbox3; - QHBoxLayout *hbox, *hbox1, *hbox2; + QHBoxLayout *hbox, *hbox1, *hbox2, *hbox3; QGridLayout *grid; QPushButton *button; QFrame *frame; @@ -227,7 +227,7 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent) hbox->addWidget( bpTree ); - hbox = new QHBoxLayout(); + hbox = new QHBoxLayout(); button = new QPushButton( tr("Add") ); hbox->addWidget( button ); connect( button, SIGNAL(clicked(void)), this, SLOT(add_BP_CB(void)) ); @@ -339,6 +339,86 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent) brkInstrsExd->setChecked( break_on_instructions ); connect( brkInstrsExd, SIGNAL(stateChanged(int)), this, SLOT(breakOnInstructionsCB(int)) ); + hbox3 = new QHBoxLayout(); + hbox = new QHBoxLayout(); + vbox = new QVBoxLayout(); + bmFrame = new QGroupBox( tr("Address Bookmarks") ); + bmTree = new QTreeWidget(); + selBmAddr = new QLineEdit(); + + bmTree->setColumnCount(2); + + item = new QTreeWidgetItem(); + item->setFont( 0, font ); + item->setFont( 1, font ); + item->setText( 0, QString::fromStdString( "Addr" ) ); + item->setText( 1, QString::fromStdString( "Name" ) ); + item->setTextAlignment( 0, Qt::AlignCenter); + item->setTextAlignment( 1, Qt::AlignCenter); + + bmTree->setHeaderItem( item ); + + bmTree->header()->setSectionResizeMode( QHeaderView::ResizeToContents ); + + connect( bmTree, SIGNAL(itemClicked(QTreeWidgetItem*, int)), + this, SLOT(bmItemClicked( QTreeWidgetItem*, int)) ); + + vbox->addWidget( selBmAddr ); + + button = new QPushButton( tr("Add") ); + vbox->addWidget( button ); + + button = new QPushButton( tr("Delete") ); + vbox->addWidget( button ); + + button = new QPushButton( tr("Name") ); + vbox->addWidget( button ); + + hbox->addWidget( bmTree ); + hbox->addLayout( vbox ); + bmFrame->setLayout( hbox ); + hbox3->addWidget( bmFrame ); + vbox1->addLayout( hbox3 ); + + frame = new QFrame(); + vbox = new QVBoxLayout(); + button = new QPushButton( tr("Reset Counters") ); + connect( button, SIGNAL(clicked(void)), this, SLOT(resetCountersCB(void)) ); + vbox->addWidget( button ); + vbox->addWidget( frame ); + hbox3->addLayout( vbox ); + + vbox = new QVBoxLayout(); + romOfsChkBox = new QCheckBox( tr("ROM Offsets") ); + symDbgChkBox = new QCheckBox( tr("Symbolic Debug") ); + regNamChkBox = new QCheckBox( tr("Register Names") ); + vbox->addWidget( romOfsChkBox ); + vbox->addWidget( symDbgChkBox ); + vbox->addWidget( regNamChkBox ); + + connect( romOfsChkBox, SIGNAL(stateChanged(int)), this, SLOT(displayROMoffsetCB(int)) ); + + button = new QPushButton( tr("Reload Symbols") ); + vbox->addWidget( button ); + + button = new QPushButton( tr("ROM Patcher") ); + vbox->addWidget( button ); + + frame->setLayout( vbox ); + frame->setFrameShape( QFrame::Box ); + + hbox = new QHBoxLayout(); + vbox1->addLayout( hbox ); + + button = new QPushButton( tr("Default Window Size") ); + autoOpenChkBox = new QCheckBox( tr("Auto-Open") ); + debFileChkBox = new QCheckBox( tr("DEB Files") ); + idaFontChkBox = new QCheckBox( tr("IDA Font") ); + hbox->addWidget( button ); + hbox->addWidget( autoOpenChkBox ); + hbox->addWidget( debFileChkBox ); + hbox->addWidget( idaFontChkBox ); + setLayout( mainLayout ); windowUpdateReq = true; @@ -383,6 +463,14 @@ void ConsoleDebugger::bpItemClicked( QTreeWidgetItem *item, int column) printf("Row: %i Column: %i \n", row, column ); +} +//---------------------------------------------------------------------------- +void ConsoleDebugger::bmItemClicked( QTreeWidgetItem *item, int column) +{ + int row = bmTree->indexOfTopLevelItem(item); + + printf("Row: %i Column: %i \n", row, column ); + } //---------------------------------------------------------------------------- void ConsoleDebugger::openBpEditWindow( int editIdx, watchpointinfo *wp ) @@ -852,6 +940,11 @@ void ConsoleDebugger::instructionsThresChanged(const QString &txt) } } //---------------------------------------------------------------------------- +void ConsoleDebugger::displayROMoffsetCB( int value ) +{ + asmView->setDisplayROMoffsets(value != Qt::Unchecked); +} +//---------------------------------------------------------------------------- void ConsoleDebugger::debugRunCB(void) { if (FCEUI_EmulationPaused()) @@ -996,6 +1089,13 @@ void ConsoleDebugger::seekPCCB (void) //asmView->scrollToPC(); } //---------------------------------------------------------------------------- +void ConsoleDebugger::resetCountersCB (void) +{ + ResetDebugStatisticsCounters(); + + updateRegisterView(); +} +//---------------------------------------------------------------------------- int QAsmView::getAsmLineFromAddr(int addr) { int line = -1; @@ -1156,6 +1256,8 @@ void QAsmView::updateAssemblyView(void) start_address_lp = starting_address; } + maxLineLen = 0; + asmClear(); addr = starting_address; @@ -1275,6 +1377,11 @@ void QAsmView::updateAssemblyView(void) a->line = asmEntry.size(); + if ( maxLineLen < line.size() ) + { + maxLineLen = line.size(); + } + line.append("\n"); //asmText->insertPlainText( tr(line.c_str()) ); @@ -1282,6 +1389,8 @@ void QAsmView::updateAssemblyView(void) asmEntry.push_back(a); } + setMinimumWidth( maxLineLen * pxCharWidth ); + vbar->setMaximum( asmEntry.size() ); } //---------------------------------------------------------------------------- @@ -1563,8 +1672,11 @@ QAsmView::QAsmView(QWidget *parent) hbar = NULL; asmPC = NULL; displayROMoffsets = false; + maxLineLen = 0; lineOffset = 0; maxLineOffset = 0; + + //setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Expanding ); } //---------------------------------------------------------------------------- QAsmView::~QAsmView(void) @@ -1595,6 +1707,16 @@ void QAsmView::scrollToPC(void) } } //---------------------------------------------------------------------------- +void QAsmView::setDisplayROMoffsets( bool value ) +{ + if ( value != displayROMoffsets ) + { + displayROMoffsets = value; + + updateAssemblyView(); + } +} +//---------------------------------------------------------------------------- void QAsmView::calcFontData(void) { this->setFont(font); diff --git a/src/drivers/Qt/ConsoleDebugger.h b/src/drivers/Qt/ConsoleDebugger.h index 1fbf46ce..9abc2b2c 100644 --- a/src/drivers/Qt/ConsoleDebugger.h +++ b/src/drivers/Qt/ConsoleDebugger.h @@ -64,6 +64,7 @@ class QAsmView : public QWidget int getAsmLineFromAddr(int addr); void setLine(int lineNum); void scrollToPC(void); + void setDisplayROMoffsets( bool value ); protected: void paintEvent(QPaintEvent *event); void keyPressEvent(QKeyEvent *event); @@ -79,6 +80,7 @@ class QAsmView : public QWidget QScrollBar *vbar; QScrollBar *hbar; + int maxLineLen; int pxCharWidth; int pxCharHeight; int pxCursorHeight; @@ -128,10 +130,13 @@ class ConsoleDebugger : public QDialog QLineEdit *regYEntry; QLineEdit *cpuCycExdVal; QLineEdit *instrExdVal; + QLineEdit *selBmAddr; QGroupBox *stackFrame; QGroupBox *bpFrame; QGroupBox *sfFrame; - QTreeWidget * bpTree; + QGroupBox *bmFrame; + QTreeWidget *bpTree; + QTreeWidget *bmTree; QCheckBox *brkBadOpsCbox; QCheckBox *N_chkbox; QCheckBox *V_chkbox; @@ -143,6 +148,12 @@ class ConsoleDebugger : public QDialog QCheckBox *C_chkbox; QCheckBox *brkCpuCycExd; QCheckBox *brkInstrsExd; + QCheckBox *romOfsChkBox; + QCheckBox *symDbgChkBox; + QCheckBox *regNamChkBox; + QCheckBox *autoOpenChkBox; + QCheckBox *debFileChkBox; + QCheckBox *idaFontChkBox; QLabel *ppuLbl; QLabel *spriteLbl; QLabel *scanLineLbl; @@ -177,10 +188,13 @@ class ConsoleDebugger : public QDialog void add_BP_CB(void); void edit_BP_CB(void); void delete_BP_CB(void); + void resetCountersCB (void); + void displayROMoffsetCB(int value); void breakOnBadOpcodeCB(int value); void breakOnCyclesCB( int value ); void breakOnInstructionsCB( int value ); void bpItemClicked( QTreeWidgetItem *item, int column); + void bmItemClicked( QTreeWidgetItem *item, int column); void cpuCycleThresChanged(const QString &txt); void instructionsThresChanged(const QString &txt); From 823e7948c048728e8b1940332fc8146779b42b3e Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Wed, 9 Sep 2020 23:13:53 -0400 Subject: [PATCH 11/57] Debug window breakpoint highlighting when hit in work. --- src/drivers/Qt/ConsoleDebugger.cpp | 46 ++++++++++++++++++++++++++++-- src/drivers/Qt/ConsoleDebugger.h | 2 +- 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/src/drivers/Qt/ConsoleDebugger.cpp b/src/drivers/Qt/ConsoleDebugger.cpp index ed9cc4dd..b0f1e665 100644 --- a/src/drivers/Qt/ConsoleDebugger.cpp +++ b/src/drivers/Qt/ConsoleDebugger.cpp @@ -206,6 +206,7 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent) bpTree = new QTreeWidget(); bpTree->setColumnCount(2); + bpTree->setSelectionMode( QAbstractItemView::SingleSelection ); item = new QTreeWidgetItem(); item->setFont( 0, font ); @@ -871,7 +872,9 @@ void ConsoleDebugger::delete_BP_CB(void) int row = bpTree->indexOfTopLevelItem(item); DeleteBreak( row ); - bpListUpdate( true ); + delete item; + //delete bpTree->takeTopLevelItem(row); + //bpListUpdate( true ); } //---------------------------------------------------------------------------- void ConsoleDebugger::breakOnBadOpcodeCB(int value) @@ -1614,8 +1617,42 @@ void ConsoleDebugger::updatePeriodic(void) asmView->update(); } //---------------------------------------------------------------------------- -void ConsoleDebugger::breakPointNotify( int addr ) +void ConsoleDebugger::breakPointNotify( int bpNum ) { + if ( bpNum >= 0 ) + { + // TODO highlight bp_num item list + QTreeWidgetItem * item; + + item = bpTree->currentItem(); + + if ( item != NULL ) + { + //bpTree->setCurrentItem( item, 0, QItemSelectionModel::Clear ); + item->setSelected(false); + } + + item = bpTree->topLevelItem( bpNum ); + + if ( item != NULL ) + { + item->setSelected(true); + //bpTree->setCurrentItem( item, 0, QItemSelectionModel::Select ); + } + //bpTree->redraw(); + } + else + { + if (bpNum == BREAK_TYPE_CYCLES_EXCEED) + { + // TODO + } + else if (bpNum == BREAK_TYPE_INSTRUCTIONS_EXCEED) + { + // TODO + } + } + windowUpdateReq = true; } //---------------------------------------------------------------------------- @@ -1636,7 +1673,7 @@ void FCEUD_DebugBreakpoint( int bpNum ) printf("Breakpoint Hit: %i \n", bpNum ); fceuWrapperUnLock(); - + for (it=dbgWinList.begin(); it!=dbgWinList.end(); it++) { (*it)->breakPointNotify( bpNum ); @@ -1646,6 +1683,9 @@ void FCEUD_DebugBreakpoint( int bpNum ) { usleep(100000); } + // since we unfreezed emulation, reset delta_cycles counter + ResetDebugStatisticsDeltaCounters(); + fceuWrapperLock(); } //---------------------------------------------------------------------------- diff --git a/src/drivers/Qt/ConsoleDebugger.h b/src/drivers/Qt/ConsoleDebugger.h index 9abc2b2c..ea34bb05 100644 --- a/src/drivers/Qt/ConsoleDebugger.h +++ b/src/drivers/Qt/ConsoleDebugger.h @@ -111,7 +111,7 @@ class ConsoleDebugger : public QDialog void updateWindowData(void); void updateRegisterView(void); - void breakPointNotify(int addr); + void breakPointNotify(int bpNum); protected: void closeEvent(QCloseEvent *event); From 6b79d2003765b4111acfa2080591b736d3e00d33 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Fri, 11 Sep 2020 20:29:45 -0400 Subject: [PATCH 12/57] Added logic to set flags register when resuming from a breakpoint. --- src/drivers/Qt/ConsoleDebugger.cpp | 40 ++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/src/drivers/Qt/ConsoleDebugger.cpp b/src/drivers/Qt/ConsoleDebugger.cpp index b0f1e665..6f29850e 100644 --- a/src/drivers/Qt/ConsoleDebugger.cpp +++ b/src/drivers/Qt/ConsoleDebugger.cpp @@ -794,7 +794,7 @@ void ConsoleDebugger::bpListUpdate( bool reset ) item->setTextAlignment( 2, Qt::AlignLeft); } - bpTree->update(); + bpTree->viewport()->update(); } //---------------------------------------------------------------------------- void ConsoleDebugger::add_BP_CB(void) @@ -1449,6 +1449,42 @@ void ConsoleDebugger::setRegsFromEntry(void) } X.Y = i; //printf("Set Y: '%s' %02X\n", s.c_str(), X.Y ); + + i=0; + if ( N_chkbox->isChecked() ) + { + i |= N_FLAG; + } + if ( V_chkbox->isChecked() ) + { + i |= V_FLAG; + } + if ( U_chkbox->isChecked() ) + { + i |= U_FLAG; + } + if ( B_chkbox->isChecked() ) + { + i |= B_FLAG; + } + if ( D_chkbox->isChecked() ) + { + i |= D_FLAG; + } + if ( I_chkbox->isChecked() ) + { + i |= I_FLAG; + } + if ( Z_chkbox->isChecked() ) + { + i |= Z_FLAG; + } + if ( C_chkbox->isChecked() ) + { + i |= C_FLAG; + } + X.P = i; + } //---------------------------------------------------------------------------- void ConsoleDebugger::updateRegisterView(void) @@ -1639,7 +1675,7 @@ void ConsoleDebugger::breakPointNotify( int bpNum ) item->setSelected(true); //bpTree->setCurrentItem( item, 0, QItemSelectionModel::Select ); } - //bpTree->redraw(); + bpTree->viewport()->update(); } else { From fc81335cc0f0a9f95920674f58580d1ac87a0933 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Fri, 11 Sep 2020 21:26:40 -0400 Subject: [PATCH 13/57] Added a emulator status label to debugger window. --- src/drivers/Qt/ConsoleDebugger.cpp | 29 +++++++++++++++++++++++------ src/drivers/Qt/ConsoleDebugger.h | 2 ++ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/drivers/Qt/ConsoleDebugger.cpp b/src/drivers/Qt/ConsoleDebugger.cpp index 6f29850e..6b9e84b2 100644 --- a/src/drivers/Qt/ConsoleDebugger.cpp +++ b/src/drivers/Qt/ConsoleDebugger.cpp @@ -47,7 +47,7 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent) : QDialog( parent ) { QHBoxLayout *mainLayout; - QVBoxLayout *vbox, *vbox1, *vbox2, *vbox3; + QVBoxLayout *vbox, *vbox1, *vbox2, *vbox3, *vbox4; QHBoxLayout *hbox, *hbox1, *hbox2, *hbox3; QGridLayout *grid; QPushButton *button; @@ -69,10 +69,13 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent) mainLayout = new QHBoxLayout(); - grid = new QGridLayout(); - asmView = new QAsmView(this); - vbar = new QScrollBar( Qt::Vertical, this ); - hbar = new QScrollBar( Qt::Horizontal, this ); + vbox4 = new QVBoxLayout(); + grid = new QGridLayout(); + asmView = new QAsmView(this); + vbar = new QScrollBar( Qt::Vertical, this ); + hbar = new QScrollBar( Qt::Horizontal, this ); + asmLineSelLbl = new QLabel( tr("Line Select") ); + emuStatLbl = new QLabel( tr("Emulator is Running") ); asmView->setScrollBars( hbar, vbar ); @@ -89,13 +92,16 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent) vbar->setMinimum(0); vbar->setMaximum( 0x10000 ); + vbox4->addLayout( grid, 100 ); + vbox4->addWidget( asmLineSelLbl, 1 ); + vbox4->addWidget( emuStatLbl , 1 ); //asmText->setFont(font); //asmText->setReadOnly(true); //asmText->setOverwriteMode(true); //asmText->setMinimumWidth( 20 * fontCharWidth ); //asmText->setLineWrapMode( QPlainTextEdit::NoWrap ); - mainLayout->addLayout( grid, 10 ); + mainLayout->addLayout( vbox4, 10 ); mainLayout->addLayout( vbox1, 1 ); grid = new QGridLayout(); @@ -1651,6 +1657,17 @@ void ConsoleDebugger::updatePeriodic(void) fceuWrapperUnLock(); } asmView->update(); + + if ( FCEUI_EmulationPaused() && !FCEUI_EmulationFrameStepped()) + { + emuStatLbl->setText( tr(" Emulator Stopped / Paused") ); + emuStatLbl->setStyleSheet("background-color: red; color: white;"); + } + else + { + emuStatLbl->setText( tr(" Emulator is Running") ); + emuStatLbl->setStyleSheet("background-color: green; color: white;"); + } } //---------------------------------------------------------------------------- void ConsoleDebugger::breakPointNotify( int bpNum ) diff --git a/src/drivers/Qt/ConsoleDebugger.h b/src/drivers/Qt/ConsoleDebugger.h index ea34bb05..ca0aa49b 100644 --- a/src/drivers/Qt/ConsoleDebugger.h +++ b/src/drivers/Qt/ConsoleDebugger.h @@ -154,6 +154,8 @@ class ConsoleDebugger : public QDialog QCheckBox *autoOpenChkBox; QCheckBox *debFileChkBox; QCheckBox *idaFontChkBox; + QLabel *asmLineSelLbl; + QLabel *emuStatLbl; QLabel *ppuLbl; QLabel *spriteLbl; QLabel *scanLineLbl; From 1a05b2d7d072039d2ba015ce28a9cc8e23aa971d Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Fri, 11 Sep 2020 22:56:04 -0400 Subject: [PATCH 14/57] Added ASM view cursor position label logic to Qt debug window. --- src/drivers/Qt/ConsoleDebugger.cpp | 95 ++++++++++++++++++++++++++++++ src/drivers/Qt/ConsoleDebugger.h | 7 ++- src/ines.cpp | 2 +- src/ines.h | 1 + 4 files changed, 103 insertions(+), 2 deletions(-) diff --git a/src/drivers/Qt/ConsoleDebugger.cpp b/src/drivers/Qt/ConsoleDebugger.cpp index 6b9e84b2..332533e5 100644 --- a/src/drivers/Qt/ConsoleDebugger.cpp +++ b/src/drivers/Qt/ConsoleDebugger.cpp @@ -1757,7 +1757,9 @@ QAsmView::QAsmView(QWidget *parent) pal.setColor(QPalette::Background, bg ); pal.setColor(QPalette::WindowText, fg ); + this->parent = (ConsoleDebugger*)parent; this->setPalette(pal); + this->setMouseTracking(true); calcFontData(); @@ -1866,6 +1868,99 @@ void QAsmView::keyReleaseEvent(QKeyEvent *event) //assignHotkey( event ); } //---------------------------------------------------------------------------- +QPoint QAsmView::convPixToCursor( QPoint p ) +{ + QPoint c(0,0); + + if ( p.x() < 0 ) + { + c.setX(0); + } + else + { + float x = (float)p.x() / pxCharWidth; + + c.setX( (int)x ); + } + + if ( p.y() < 0 ) + { + c.setY( 0 ); + } + else + { + float ly = ( (float)pxLineLead / (float)pxLineSpacing ); + float py = ( (float)p.y() ) / (float)pxLineSpacing; + float ry = fmod( py, 1.0 ); + + if ( ry < ly ) + { + c.setY( ((int)py) - 1 ); + } + else + { + c.setY( (int)py ); + } + } + return c; +} +//---------------------------------------------------------------------------- +void QAsmView::mouseMoveEvent(QMouseEvent * event) +{ + int line; + QPoint c = convPixToCursor( event->pos() ); + char txt[256]; + std::string s; + + line = lineOffset + c.y(); + + //printf("c (%i,%i) : Line %i : %04X \n", c.x(), c.y(), line, asmEntry[line]->addr ); + + if ( line < asmEntry.size() ) + { + int addr; + + addr = asmEntry[line]->addr; + + if (addr >= 0x8000) + { + int bank, romOfs; + bank = getBank(addr); + romOfs = GetNesFileAddress(addr); + + sprintf( txt, "CPU Address: %02X:%04X", bank, addr); + + s.assign( txt ); + + if (romOfs != -1) + { + const char *fileName; + + fileName = iNesShortFName(); + + if ( fileName == NULL ) + { + fileName = "..."; + } + sprintf( txt, ", Offset 0x%06X in File \"%s\" (NL file: %X)", romOfs, fileName, bank); + + s.append( txt ); + } + } + else + { + sprintf( txt, "CPU Address: %04X", addr); + + s.assign( txt ); + } + } + + if ( parent != NULL ) + { + parent->asmLineSelLbl->setText( tr(s.c_str()) ); + } +} +//---------------------------------------------------------------------------- void QAsmView::mousePressEvent(QMouseEvent * event) { // TODO QPoint c = convPixToCursor( event->pos() ); diff --git a/src/drivers/Qt/ConsoleDebugger.h b/src/drivers/Qt/ConsoleDebugger.h index ca0aa49b..4483e74c 100644 --- a/src/drivers/Qt/ConsoleDebugger.h +++ b/src/drivers/Qt/ConsoleDebugger.h @@ -50,6 +50,8 @@ struct dbg_asm_entry_t } }; +class ConsoleDebugger; + class QAsmView : public QWidget { Q_OBJECT @@ -70,12 +72,15 @@ class QAsmView : public QWidget void keyPressEvent(QKeyEvent *event); void keyReleaseEvent(QKeyEvent *event); void mousePressEvent(QMouseEvent * event); + void mouseMoveEvent(QMouseEvent * event); void resizeEvent(QResizeEvent *event); void contextMenuEvent(QContextMenuEvent *event); void calcFontData(void); + QPoint convPixToCursor( QPoint p ); private: + ConsoleDebugger *parent; QFont font; QScrollBar *vbar; QScrollBar *hbar; @@ -113,6 +118,7 @@ class ConsoleDebugger : public QDialog void updateRegisterView(void); void breakPointNotify(int bpNum); + QLabel *asmLineSelLbl; protected: void closeEvent(QCloseEvent *event); //void keyPressEvent(QKeyEvent *event); @@ -154,7 +160,6 @@ class ConsoleDebugger : public QDialog QCheckBox *autoOpenChkBox; QCheckBox *debFileChkBox; QCheckBox *idaFontChkBox; - QLabel *asmLineSelLbl; QLabel *emuStatLbl; QLabel *ppuLbl; QLabel *spriteLbl; diff --git a/src/ines.cpp b/src/ines.cpp index 00abebeb..b6ef2473 100644 --- a/src/ines.cpp +++ b/src/ines.cpp @@ -1002,7 +1002,7 @@ int iNesSaveAs(const char* name) } //para edit: added function below -char *iNesShortFName() { +char *iNesShortFName(void) { char *ret; if (!(ret = strrchr(LoadedRomFName, '\\'))) diff --git a/src/ines.h b/src/ines.h index 6f9d65e8..5561aef9 100644 --- a/src/ines.h +++ b/src/ines.h @@ -46,6 +46,7 @@ extern uint8 *ExtraNTARAM; extern int iNesSave(void); //bbit Edited: line added extern int iNesSaveAs(const char* name); extern char LoadedRomFName[2048]; //bbit Edited: line added +extern char *iNesShortFName(void); extern const TMasterRomInfo* MasterRomInfo; extern TMasterRomInfoParams MasterRomInfoParams; From bb29b73af5da6a773c912f2f846cc3628be11649 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Sat, 12 Sep 2020 08:53:51 -0400 Subject: [PATCH 15/57] Added initial framework for Qt debug window's asm view context menu. --- src/drivers/Qt/ConsoleDebugger.cpp | 60 +++++++++++++++++++++++++++++- src/drivers/Qt/ConsoleDebugger.h | 5 ++- 2 files changed, 62 insertions(+), 3 deletions(-) diff --git a/src/drivers/Qt/ConsoleDebugger.cpp b/src/drivers/Qt/ConsoleDebugger.cpp index 332533e5..ee966fc4 100644 --- a/src/drivers/Qt/ConsoleDebugger.cpp +++ b/src/drivers/Qt/ConsoleDebugger.cpp @@ -7,6 +7,8 @@ #include #include +#include +#include #include #include #include @@ -1105,6 +1107,20 @@ void ConsoleDebugger::resetCountersCB (void) updateRegisterView(); } //---------------------------------------------------------------------------- +void ConsoleDebugger::asmViewCtxMenuAddBP(void) +{ + watchpointinfo wp; + + wp.address = asmView->getCtxMenuAddr(); + wp.endaddress = 0; + wp.flags = WP_X | WP_E; + wp.condText = 0; + wp.desc = NULL; + + openBpEditWindow( -1, &wp ); + +} +//---------------------------------------------------------------------------- int QAsmView::getAsmLineFromAddr(int addr) { int line = -1; @@ -1668,6 +1684,12 @@ void ConsoleDebugger::updatePeriodic(void) emuStatLbl->setText( tr(" Emulator is Running") ); emuStatLbl->setStyleSheet("background-color: green; color: white;"); } + + if ( bpTree->topLevelItemCount() != numWPs ) + { + printf("Breakpoint Tree Update\n"); + bpListUpdate( true ); + } } //---------------------------------------------------------------------------- void ConsoleDebugger::breakPointNotify( int bpNum ) @@ -1770,6 +1792,7 @@ QAsmView::QAsmView(QWidget *parent) maxLineLen = 0; lineOffset = 0; maxLineOffset = 0; + ctxMenuAddr = -1; //setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Expanding ); } @@ -1963,13 +1986,46 @@ void QAsmView::mouseMoveEvent(QMouseEvent * event) //---------------------------------------------------------------------------- void QAsmView::mousePressEvent(QMouseEvent * event) { - // TODO QPoint c = convPixToCursor( event->pos() ); + //int line; + //QPoint c = convPixToCursor( event->pos() ); + //line = lineOffset + c.y(); + // + //if ( line < asmEntry.size() ) + //{ + // int addr; + + // addr = asmEntry[line]->addr; + //} } //---------------------------------------------------------------------------- void QAsmView::contextMenuEvent(QContextMenuEvent *event) { - // TODO + int line; + QAction *act; + QMenu menu(this); + QPoint c = convPixToCursor( event->pos() ); + + line = lineOffset + c.y(); + + ctxMenuAddr = -1; + + if ( line < asmEntry.size() ) + { + int addr; + + ctxMenuAddr = addr = asmEntry[line]->addr; + + act = new QAction(tr("Add Breakpoint"), this); + menu.addAction(act); + connect( act, SIGNAL(triggered(void)), parent, SLOT(asmViewCtxMenuAddBP(void)) ); + + act = new QAction(tr("Add Symbolic Debug Name"), this); + menu.addAction(act); + //connect( act, SIGNAL(triggered(void)), this, SLOT(addBookMarkCB(void)) ); + + menu.exec(event->globalPos()); + } } //---------------------------------------------------------------------------- void QAsmView::paintEvent(QPaintEvent *event) diff --git a/src/drivers/Qt/ConsoleDebugger.h b/src/drivers/Qt/ConsoleDebugger.h index 4483e74c..41a1a4c5 100644 --- a/src/drivers/Qt/ConsoleDebugger.h +++ b/src/drivers/Qt/ConsoleDebugger.h @@ -67,6 +67,7 @@ class QAsmView : public QWidget void setLine(int lineNum); void scrollToPC(void); void setDisplayROMoffsets( bool value ); + int getCtxMenuAddr(void){ return ctxMenuAddr; }; protected: void paintEvent(QPaintEvent *event); void keyPressEvent(QKeyEvent *event); @@ -85,6 +86,7 @@ class QAsmView : public QWidget QScrollBar *vbar; QScrollBar *hbar; + int ctxMenuAddr; int maxLineLen; int pxCharWidth; int pxCharHeight; @@ -117,6 +119,7 @@ class ConsoleDebugger : public QDialog void updateWindowData(void); void updateRegisterView(void); void breakPointNotify(int bpNum); + void openBpEditWindow(int editIdx = -1, watchpointinfo *wp = NULL ); QLabel *asmLineSelLbl; protected: @@ -176,11 +179,11 @@ class ConsoleDebugger : public QDialog private: void setRegsFromEntry(void); - void openBpEditWindow(int editIdx = -1, watchpointinfo *wp = NULL ); void bpListUpdate( bool reset = false ); public slots: void closeWindow(void); + void asmViewCtxMenuAddBP(void); private slots: void updatePeriodic(void); void vbarChanged(int value); From d1f689ef611f267baf421f2ca6ca78f2ace6c9ed Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Sat, 12 Sep 2020 09:31:24 -0400 Subject: [PATCH 16/57] Minor updates to Qt breakpoint add/edit and display functionality. --- src/drivers/Qt/ConsoleDebugger.cpp | 77 ++++++++++++++++++++---------- 1 file changed, 52 insertions(+), 25 deletions(-) diff --git a/src/drivers/Qt/ConsoleDebugger.cpp b/src/drivers/Qt/ConsoleDebugger.cpp index ee966fc4..fab8591f 100644 --- a/src/drivers/Qt/ConsoleDebugger.cpp +++ b/src/drivers/Qt/ConsoleDebugger.cpp @@ -220,12 +220,15 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent) item->setFont( 0, font ); item->setFont( 1, font ); item->setFont( 2, font ); + item->setFont( 3, font ); item->setText( 0, QString::fromStdString( "Addr" ) ); item->setText( 1, QString::fromStdString( "Flags" ) ); - item->setText( 2, QString::fromStdString( "Desc" ) ); + item->setText( 2, QString::fromStdString( "Cond" ) ); + item->setText( 3, QString::fromStdString( "Desc" ) ); item->setTextAlignment( 0, Qt::AlignCenter); item->setTextAlignment( 1, Qt::AlignCenter); item->setTextAlignment( 2, Qt::AlignCenter); + item->setTextAlignment( 3, Qt::AlignCenter); bpTree->setHeaderItem( item ); @@ -624,6 +627,19 @@ void ConsoleDebugger::openBpEditWindow( int editIdx, watchpointinfo *wp ) { cond->setText( tr(wp->condText) ); } + else + { + if ( editIdx < 0 ) + { + // If new breakpoint, suggest condition if in ROM Mapping area of memory. + if ( wp->address >= 0x8000 ) + { + char str[64]; + sprintf(str, "K==#%02X", getBank(wp->address)); + cond->setText( tr(str) ); + } + } + } if ( wp->desc ) { @@ -718,7 +734,7 @@ void ConsoleDebugger::openBpEditWindow( int editIdx, watchpointinfo *wp ) void ConsoleDebugger::bpListUpdate( bool reset ) { QTreeWidgetItem *item; - char line[256], addrStr[32], flags[16], enable; + char cond[128], desc[128], addrStr[32], flags[16], enable; if ( reset ) { @@ -727,7 +743,14 @@ void ConsoleDebugger::bpListUpdate( bool reset ) for (int i=0; itopLevelItem(i); + if ( bpTree->topLevelItemCount() > i ) + { + item = bpTree->topLevelItem(i); + } + else + { + item = NULL; + } if ( item == NULL ) { @@ -771,20 +794,19 @@ void ConsoleDebugger::bpListUpdate( bool reset ) enable = (watchpoint[i].flags & WP_E) ? 1 : 0; - //strcpy( line, addrStr ); - //strcpy( line, flags ); - line[0] = 0; + cond[0] = 0; + desc[0] = 0; if (watchpoint[i].desc ) { - strcat( line, watchpoint[i].desc); + strcat( desc, watchpoint[i].desc); } if (watchpoint[i].condText ) { - strcat( line, " Condition:"); - strcat( line, watchpoint[i].condText); - strcat( line, " "); + strcat( cond, " ("); + strcat( cond, watchpoint[i].condText); + strcat( cond, ") "); } item->setCheckState( 0, enable ? Qt::Checked : Qt::Unchecked ); @@ -792,14 +814,17 @@ void ConsoleDebugger::bpListUpdate( bool reset ) item->setFont( 0, font ); item->setFont( 1, font ); item->setFont( 2, font ); + item->setFont( 3, font ); item->setText( 0, tr(addrStr)); item->setText( 1, tr(flags) ); - item->setText( 2, tr(line) ); + item->setText( 2, tr(cond) ); + item->setText( 3, tr(desc) ); item->setTextAlignment( 0, Qt::AlignLeft); item->setTextAlignment( 1, Qt::AlignLeft); item->setTextAlignment( 2, Qt::AlignLeft); + item->setTextAlignment( 3, Qt::AlignLeft); } bpTree->viewport()->update(); @@ -1696,25 +1721,27 @@ void ConsoleDebugger::breakPointNotify( int bpNum ) { if ( bpNum >= 0 ) { - // TODO highlight bp_num item list - QTreeWidgetItem * item; + // highlight bp_num item list - item = bpTree->currentItem(); - - if ( item != NULL ) + if ( bpTree->topLevelItemCount() > 0 ) { - //bpTree->setCurrentItem( item, 0, QItemSelectionModel::Clear ); - item->setSelected(false); - } + QTreeWidgetItem * item; - item = bpTree->topLevelItem( bpNum ); + item = bpTree->currentItem(); - if ( item != NULL ) - { - item->setSelected(true); - //bpTree->setCurrentItem( item, 0, QItemSelectionModel::Select ); + if ( item != NULL ) + { + item->setSelected(false); + } + + item = bpTree->topLevelItem( bpNum ); + + if ( item != NULL ) + { + item->setSelected(true); + } + bpTree->viewport()->update(); } - bpTree->viewport()->update(); } else { From f4424041498643c5847ea98967d0ed1e3773cd72 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Sun, 13 Sep 2020 21:43:50 -0400 Subject: [PATCH 17/57] Added initial framework for symbolic debug feature in Qt port. --- src/CMakeLists.txt | 1 + src/debug.h | 1 + src/drivers/Qt/SymbolicDebug.cpp | 155 +++++++++++++++++++++++++++++++ src/drivers/Qt/SymbolicDebug.h | 60 ++++++++++++ src/drivers/Qt/fceuWrapper.cpp | 3 + 5 files changed, 220 insertions(+) create mode 100644 src/drivers/Qt/SymbolicDebug.cpp create mode 100644 src/drivers/Qt/SymbolicDebug.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 211f2dca..0e90b19b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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/SymbolicDebug.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleDebugger.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleUtilities.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleVideoConf.cpp diff --git a/src/debug.h b/src/debug.h index ef21f4c1..a3772f32 100644 --- a/src/debug.h +++ b/src/debug.h @@ -59,6 +59,7 @@ typedef struct { //mbg merge 7/18/06 had to make this extern extern watchpointinfo watchpoint[65]; //64 watchpoints, + 1 reserved for step over +extern unsigned int debuggerPageSize; int getBank(int offs); int GetNesFileAddress(int A); int GetPRGAddress(int A); diff --git a/src/drivers/Qt/SymbolicDebug.cpp b/src/drivers/Qt/SymbolicDebug.cpp new file mode 100644 index 00000000..6b9ce82e --- /dev/null +++ b/src/drivers/Qt/SymbolicDebug.cpp @@ -0,0 +1,155 @@ +// SymbolicDebug.cpp +#include +#include +#include + +#include "../../types.h" +#include "../../fceu.h" +#include "../../debug.h" + +#include "Qt/SymbolicDebug.h" +#include "Qt/ConsoleUtilities.h" + +debugSymbolTable_t debugSymbolTable; + +//-------------------------------------------------------------- +// debugSymbolPage_t +//-------------------------------------------------------------- +debugSymbolPage_t::debugSymbolPage_t(void) +{ + pageNum = 0; + +} +//-------------------------------------------------------------- +debugSymbolPage_t::~debugSymbolPage_t(void) +{ + std::map ::iterator it; + + for (it=symMap.begin(); it!=symMap.end(); it++) + { + delete it->second; + } + symMap.clear(); +} +//-------------------------------------------------------------- +// debugSymbolTable_t +//-------------------------------------------------------------- +debugSymbolTable_t::debugSymbolTable_t(void) +{ + +} +//-------------------------------------------------------------- +debugSymbolTable_t::~debugSymbolTable_t(void) +{ + this->clear(); +} +//-------------------------------------------------------------- +void debugSymbolTable_t::clear(void) +{ + std::map ::iterator it; + + for (it=pageMap.begin(); it!=pageMap.end(); it++) + { + delete it->second; + } + pageMap.clear(); +} +//-------------------------------------------------------------- +static int generateNLFilenameForAddress(int address, char *NLfilename) +{ + int i; + const char *romFile; + + romFile = getRomFile(); + + if ( romFile == NULL ) + { + return -1; + } + i=0; + while ( romFile[i] != 0 ) + { + + if ( romFile[i] == '|' ) + { + NLfilename[i] = '.'; + } + else + { + NLfilename[i] = romFile[i]; + } + i++; + } + NLfilename[i] = 0; + + if (address < 0x8000) + { + // The NL file for the RAM addresses has the name nesrom.nes.ram.nl + strcat(NLfilename, ".ram.nl"); + } + else + { + int bank = getBank(address); + char stmp[64]; + #ifdef DW3_NL_0F_1F_HACK + if(bank == 0x0F) + bank = 0x1F; + #endif + sprintf( stmp, ".%X.nl", bank); + strcat(NLfilename, stmp ); + } + return 0; +} +//-------------------------------------------------------------- +int debugSymbolTable_t::loadFileNL( int addr ) +{ + FILE *fp; + char fileName[512], line[256]; + + printf("Looking to Load Debug Addr: $%04X \n", addr ); + + if ( generateNLFilenameForAddress( addr, fileName ) ) + { + return -1; + } + printf("Loading NL File: %s\n", fileName ); + + fp = ::fopen( fileName, "r" ); + + if ( fp == NULL ) + { + return -1; + } + while ( fgets( line, sizeof(line), fp ) != 0 ) + { + printf("%s", line ); + } + + ::fclose(fp); + + return 0; +} +//-------------------------------------------------------------- +int debugSymbolTable_t::loadGameSymbols(void) +{ + int nPages; + + this->clear(); + + loadFileNL( 0x0000 ); + + nPages = 1<<(15-debuggerPageSize); + + for(int i=0;i +#include +#include + +struct debugSymbol_t +{ + int addr; + std::string name; + std::string comment; + + debugSymbol_t(void) + { + addr = 0; + }; +}; + +struct debugSymbolPage_t +{ + int pageNum; + + debugSymbolPage_t(void); + ~debugSymbolPage_t(void); + + std::map symMap; +}; + +class debugSymbolTable_t +{ + + public: + debugSymbolTable_t(void); + ~debugSymbolTable_t(void); + + int loadFileNL( int addr ); + int loadGameSymbols(void); + + void clear(void); + + private: + std::map pageMap; + + +}; + +extern debugSymbolTable_t debugSymbolTable; + +//struct MemoryMappedRegister +//{ +// char* offset; +// char* name; +//}; + + + +#endif diff --git a/src/drivers/Qt/fceuWrapper.cpp b/src/drivers/Qt/fceuWrapper.cpp index 84eb5ae8..08faab7e 100644 --- a/src/drivers/Qt/fceuWrapper.cpp +++ b/src/drivers/Qt/fceuWrapper.cpp @@ -15,6 +15,7 @@ #include "Qt/nes_shm.h" #include "Qt/unix-netplay.h" #include "Qt/HexEditor.h" +#include "Qt/SymbolicDebug.h" #include "Qt/ConsoleWindow.h" #include "Qt/fceux_git_info.h" @@ -229,6 +230,8 @@ int LoadGame(const char *path) hexEditorLoadBookmarks(); + debugSymbolTable.loadGameSymbols(); + int state_to_load; g_config->getOption("SDL.AutoLoadState", &state_to_load); if (state_to_load >= 0 && state_to_load < 10){ From a4df1e3c06c65c087aacb1412dfa64ec7f3a753f Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Mon, 14 Sep 2020 21:08:38 -0400 Subject: [PATCH 18/57] Added logic to load debug symbols from files. --- src/drivers/Qt/ConsoleDebugger.cpp | 103 +++++++++++- src/drivers/Qt/ConsoleDebugger.h | 10 +- src/drivers/Qt/SymbolicDebug.cpp | 255 ++++++++++++++++++++++++++++- src/drivers/Qt/SymbolicDebug.h | 15 +- 4 files changed, 374 insertions(+), 9 deletions(-) diff --git a/src/drivers/Qt/ConsoleDebugger.cpp b/src/drivers/Qt/ConsoleDebugger.cpp index fab8591f..7df7744e 100644 --- a/src/drivers/Qt/ConsoleDebugger.cpp +++ b/src/drivers/Qt/ConsoleDebugger.cpp @@ -1199,6 +1199,20 @@ int QAsmView::getAsmLineFromAddr(int addr) } else { + nextLine = line - 1; + + if ( nextLine >= 0 ) + { + while ( asmEntry[nextLine]->addr == asmEntry[line]->addr ) + { + line = nextLine; + nextLine--; + if ( nextLine < 0 ) + { + break; + } + } + } run = 0; break; } } @@ -1217,6 +1231,20 @@ int QAsmView::getAsmLineFromAddr(int addr) } else { + nextLine = line - 1; + + if ( nextLine >= 0 ) + { + while ( asmEntry[nextLine]->addr == asmEntry[line]->addr ) + { + line = nextLine; + nextLine--; + if ( nextLine < 0 ) + { + break; + } + } + } run = 0; break; } line = nextLine; @@ -1282,7 +1310,7 @@ void QAsmView::updateAssemblyView(void) char chr[64]; uint8 opcode[3]; const char *disassemblyText = NULL; - dbg_asm_entry_t *a; + dbg_asm_entry_t *a, *d; //GtkTextIter iter, next_iter; char pc_found = 0; @@ -1423,6 +1451,70 @@ void QAsmView::updateAssemblyView(void) line.append("-------------------------"); } + if ( symbolicDebugEnable ) + { + debugSymbol_t *dbgSym; + + dbgSym = debugSymbolTable.getSymbolAtBankOffset( a->bank, a->addr ); + + if ( dbgSym != NULL ) + { + int i,j; + const char *c; + char stmp[256]; + printf("Debug symbol Found at $%04X \n", dbgSym->ofs ); + d = new dbg_asm_entry_t(); + + *d = *a; + d->type = dbg_asm_entry_t::SYMBOL_NAME; + d->text.assign( dbgSym->name ); + d->line = asmEntry.size(); + + asmEntry.push_back(d); + + i=0; j=0; + c = dbgSym->comment.c_str(); + + while ( c[i] != 0 ) + { + if ( c[i] == '\n' ) + { + if ( j > 0 ) + { + stmp[j] = 0; + + d = new dbg_asm_entry_t(); + + *d = *a; + d->type = dbg_asm_entry_t::SYMBOL_COMMENT; + d->text.assign( stmp ); + d->line = asmEntry.size(); + + asmEntry.push_back(d); + } + i++; j=0; + } + else + { + stmp[j] = c[i]; j++; i++; + } + } + stmp[j] = 0; + + if ( j > 0 ) + { + d = new dbg_asm_entry_t(); + + *d = *a; + d->type = dbg_asm_entry_t::SYMBOL_COMMENT; + d->text.assign( stmp ); + d->line = asmEntry.size(); + + asmEntry.push_back(d); + } + } + } + a->text.assign( line ); a->line = asmEntry.size(); @@ -1434,8 +1526,6 @@ void QAsmView::updateAssemblyView(void) line.append("\n"); - //asmText->insertPlainText( tr(line.c_str()) ); - asmEntry.push_back(a); } @@ -1816,6 +1906,7 @@ QAsmView::QAsmView(QWidget *parent) hbar = NULL; asmPC = NULL; displayROMoffsets = false; + symbolicDebugEnable = true; maxLineLen = 0; lineOffset = 0; maxLineOffset = 0; @@ -2104,12 +2195,16 @@ void QAsmView::paintEvent(QPaintEvent *event) { if ( l == asmPC->line ) { - painter.fillRect( 0, y - pxLineSpacing + pxLineLead, viewWidth, pxLineSpacing, QColor("light blue") ); + painter.fillRect( 0, y - pxLineSpacing + pxLineLead, viewWidth, pxLineSpacing, QColor("pink") ); } } if ( l < asmEntry.size() ) { + if ( asmEntry[l]->type != dbg_asm_entry_t::ASM_TEXT ) + { + painter.fillRect( 0, y - pxLineSpacing + pxLineLead, viewWidth, pxLineSpacing, QColor("light blue") ); + } painter.drawText( x, y, tr(asmEntry[l]->text.c_str()) ); } y += pxLineSpacing; diff --git a/src/drivers/Qt/ConsoleDebugger.h b/src/drivers/Qt/ConsoleDebugger.h index 41a1a4c5..bf14ed02 100644 --- a/src/drivers/Qt/ConsoleDebugger.h +++ b/src/drivers/Qt/ConsoleDebugger.h @@ -25,6 +25,7 @@ #include #include "Qt/main.h" +#include "Qt/SymbolicDebug.h" #include "../../debug.h" struct dbg_asm_entry_t @@ -37,11 +38,17 @@ struct dbg_asm_entry_t uint8 opcode[3]; std::string text; + enum + { + ASM_TEXT = 0, + SYMBOL_NAME, + SYMBOL_COMMENT + } type; dbg_asm_entry_t(void) { addr = 0; bank = 0; rom = -1; - size = 0; line = 0; + size = 0; line = 0; type = ASM_TEXT; for (int i=0; i<3; i++) { @@ -106,6 +113,7 @@ class QAsmView : public QWidget std::vector asmEntry; bool displayROMoffsets; + bool symbolicDebugEnable; }; class ConsoleDebugger : public QDialog diff --git a/src/drivers/Qt/SymbolicDebug.cpp b/src/drivers/Qt/SymbolicDebug.cpp index 6b9ce82e..548ec6ce 100644 --- a/src/drivers/Qt/SymbolicDebug.cpp +++ b/src/drivers/Qt/SymbolicDebug.cpp @@ -32,6 +32,53 @@ debugSymbolPage_t::~debugSymbolPage_t(void) symMap.clear(); } //-------------------------------------------------------------- +int debugSymbolPage_t::addSymbol( debugSymbol_t*sym ) +{ + std::map ::iterator it; + + it = symMap.find( sym->ofs ); + + if ( it != symMap.end() ) + { + return -1; + } + symMap[ sym->ofs ] = sym; + + return 0; +} +//-------------------------------------------------------------- +debugSymbol_t *debugSymbolPage_t::getSymbolAtOffset( int ofs ) +{ + debugSymbol_t*sym = NULL; + std::map ::iterator it; + + it = symMap.find( ofs ); + + if ( it != symMap.end() ) + { + sym = it->second; + } + return sym; +} +//-------------------------------------------------------------- +void debugSymbolPage_t::print(void) +{ + FILE *fp; + debugSymbol_t *sym; + std::map ::iterator it; + + fp = stdout; + + fprintf( fp, "Page: %X \n", pageNum ); + + for (it=symMap.begin(); it!=symMap.end(); it++) + { + sym = it->second; + + fprintf( fp, " Sym: $%04X '%s' \n", sym->ofs, sym->name.c_str() ); + } +} +//-------------------------------------------------------------- // debugSymbolTable_t //-------------------------------------------------------------- debugSymbolTable_t::debugSymbolTable_t(void) @@ -104,7 +151,11 @@ static int generateNLFilenameForAddress(int address, char *NLfilename) int debugSymbolTable_t::loadFileNL( int addr ) { FILE *fp; - char fileName[512], line[256]; + int i, j, ofs, lineNum = 0, literal = 0; + char fileName[512], line[512]; + char stmp[512]; + debugSymbolPage_t *page = NULL; + debugSymbol_t *sym = NULL; printf("Looking to Load Debug Addr: $%04X \n", addr ); @@ -120,9 +171,180 @@ int debugSymbolTable_t::loadFileNL( int addr ) { return -1; } + page = new debugSymbolPage_t; + + if ( addr >= 0x8000 ) + { + page->pageNum = getBank( addr ); + } + pageMap[ page->pageNum ] = page; + while ( fgets( line, sizeof(line), fp ) != 0 ) { - printf("%s", line ); + i=0; lineNum++; + printf("%4i:%s", lineNum, line ); + + if ( line[i] == '\\' ) + { + // Line is a comment continuation line. + i++; + + j=0; + stmp[j] = '\n'; j++; + + while ( line[i] != 0 ) + { + stmp[j] = line[i]; j++; i++; + } + stmp[j] = 0; + + j--; + while ( j >= 0 ) + { + if ( isspace( stmp[j] ) ) + { + stmp[j] = 0; + } + else + { + break; + } + j--; + } + if ( sym != NULL ) + { + sym->comment.append( stmp ); + } + } + else if ( line[i] == '$' ) + { + // Line is a new debug offset + j=0; i++; + if ( !isxdigit( line[i] ) ) + { + printf("Error: Invalid Offset on Line %i of File %s\n", lineNum, fileName ); + } + while ( isxdigit( line[i] ) ) + { + stmp[j] = line[i]; i++; j++; + } + stmp[j] = 0; + + ofs = strtol( stmp, NULL, 16 ); + + if ( line[i] != '#' ) + { + printf("Error: Missing field delimiter following offset $%X on Line %i of File %s\n", ofs, lineNum, fileName ); + continue; + } + i++; + + while ( isspace(line[i]) ) i++; + + j = 0; + while ( line[i] != 0 ) + { + if ( line[i] == '\\' ) + { + if ( literal ) + { + switch ( line[i] ) + { + case 'r': + stmp[j] = '\r'; + break; + case 'n': + stmp[j] = '\n'; + break; + case 't': + stmp[j] = '\t'; + break; + default: + stmp[j] = line[i]; + break; + } + j++; i++; + literal = 0; + } + else + { + i++; + literal = !literal; + } + } + else if ( line[i] == '#' ) + { + break; + } + else + { + stmp[j] = line[i]; j++; i++; + } + } + stmp[j] = 0; + + j--; + while ( j >= 0 ) + { + if ( isspace( stmp[j] ) ) + { + stmp[j] = 0; + } + else + { + break; + } + j--; + } + + if ( line[i] != '#' ) + { + printf("Error: Missing field delimiter following name '%s' on Line %i of File %s\n", stmp, lineNum, fileName ); + continue; + } + i++; + + sym = new debugSymbol_t(); + + if ( sym == NULL ) + { + printf("Error: Failed to allocate memory for offset $%04X Name '%s' on Line %i of File %s\n", ofs, stmp, lineNum, fileName ); + continue; + } + sym->ofs = ofs; + sym->name.assign( stmp ); + + while ( isspace( line[i] ) ) i++; + + j=0; + while ( line[i] != 0 ) + { + stmp[j] = line[i]; j++; i++; + } + stmp[j] = 0; + + j--; + while ( j >= 0 ) + { + if ( isspace( stmp[j] ) ) + { + stmp[j] = 0; + } + else + { + break; + } + j--; + } + + sym->comment.assign( stmp ); + + if ( page->addSymbol( sym ) ) + { + printf("Error: Failed to add symbol for offset $%04X Name '%s' on Line %i of File %s\n", ofs, stmp, lineNum, fileName ); + delete sym; sym = NULL; // Failed to add symbol + } + } } ::fclose(fp); @@ -150,6 +372,35 @@ int debugSymbolTable_t::loadGameSymbols(void) loadFileNL( pageIndexAddress ); } + print(); + return 0; } //-------------------------------------------------------------- +debugSymbol_t *debugSymbolTable_t::getSymbolAtBankOffset( int bank, int ofs ) +{ + debugSymbol_t*sym = NULL; + std::map ::iterator it; + + it = pageMap.find( bank ); + + if ( it != pageMap.end() ) + { + sym = (it->second)->getSymbolAtOffset( ofs ); + } + return sym; +} +//-------------------------------------------------------------- +void debugSymbolTable_t::print(void) +{ + debugSymbolPage_t *page; + std::map ::iterator it; + + for (it=pageMap.begin(); it!=pageMap.end(); it++) + { + page = it->second; + + page->print(); + } +} +//-------------------------------------------------------------- diff --git a/src/drivers/Qt/SymbolicDebug.h b/src/drivers/Qt/SymbolicDebug.h index 796017a2..62c005a1 100644 --- a/src/drivers/Qt/SymbolicDebug.h +++ b/src/drivers/Qt/SymbolicDebug.h @@ -9,13 +9,13 @@ struct debugSymbol_t { - int addr; + int ofs; std::string name; std::string comment; debugSymbol_t(void) { - addr = 0; + ofs = 0; }; }; @@ -26,6 +26,13 @@ struct debugSymbolPage_t debugSymbolPage_t(void); ~debugSymbolPage_t(void); + void print(void); + int size(void){ return symMap.size(); } + + int addSymbol( debugSymbol_t *sym ); + + debugSymbol_t *getSymbolAtOffset( int ofs ); + std::map symMap; }; @@ -38,8 +45,12 @@ class debugSymbolTable_t int loadFileNL( int addr ); int loadGameSymbols(void); + int numPages(void){ return pageMap.size(); } void clear(void); + void print(void); + + debugSymbol_t *getSymbolAtBankOffset( int bank, int ofs ); private: std::map pageMap; From 097aaa32142af499f7ab8b11360853cb4e40be27 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Mon, 14 Sep 2020 21:18:54 -0400 Subject: [PATCH 19/57] Hooked up symbolic debug asm view checkbox. --- src/drivers/Qt/ConsoleDebugger.cpp | 36 ++++++++++++++++++++++++++++++ src/drivers/Qt/ConsoleDebugger.h | 5 +++++ 2 files changed, 41 insertions(+) diff --git a/src/drivers/Qt/ConsoleDebugger.cpp b/src/drivers/Qt/ConsoleDebugger.cpp index 7df7744e..7dd970b7 100644 --- a/src/drivers/Qt/ConsoleDebugger.cpp +++ b/src/drivers/Qt/ConsoleDebugger.cpp @@ -408,7 +408,12 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent) vbox->addWidget( symDbgChkBox ); vbox->addWidget( regNamChkBox ); + symDbgChkBox->setChecked(true); + regNamChkBox->setChecked(true); + connect( romOfsChkBox, SIGNAL(stateChanged(int)), this, SLOT(displayROMoffsetCB(int)) ); + connect( symDbgChkBox, SIGNAL(stateChanged(int)), this, SLOT(symbolDebugEnableCB(int)) ); + connect( regNamChkBox, SIGNAL(stateChanged(int)), this, SLOT(registerNameEnableCB(int)) ); button = new QPushButton( tr("Reload Symbols") ); vbox->addWidget( button ); @@ -981,6 +986,16 @@ void ConsoleDebugger::displayROMoffsetCB( int value ) asmView->setDisplayROMoffsets(value != Qt::Unchecked); } //---------------------------------------------------------------------------- +void ConsoleDebugger::symbolDebugEnableCB( int value ) +{ + asmView->setSymbolDebugEnable(value != Qt::Unchecked); +} +//---------------------------------------------------------------------------- +void ConsoleDebugger::registerNameEnableCB( int value ) +{ + asmView->setRegisterNameEnable(value != Qt::Unchecked); +} +//---------------------------------------------------------------------------- void ConsoleDebugger::debugRunCB(void) { if (FCEUI_EmulationPaused()) @@ -1907,6 +1922,7 @@ QAsmView::QAsmView(QWidget *parent) asmPC = NULL; displayROMoffsets = false; symbolicDebugEnable = true; + registerNameEnable = true; maxLineLen = 0; lineOffset = 0; maxLineOffset = 0; @@ -1953,6 +1969,26 @@ void QAsmView::setDisplayROMoffsets( bool value ) } } //---------------------------------------------------------------------------- +void QAsmView::setSymbolDebugEnable( bool value ) +{ + if ( value != symbolicDebugEnable ) + { + symbolicDebugEnable = value; + + updateAssemblyView(); + } +} +//---------------------------------------------------------------------------- +void QAsmView::setRegisterNameEnable( bool value ) +{ + if ( value != registerNameEnable ) + { + registerNameEnable = value; + + updateAssemblyView(); + } +} +//---------------------------------------------------------------------------- void QAsmView::calcFontData(void) { this->setFont(font); diff --git a/src/drivers/Qt/ConsoleDebugger.h b/src/drivers/Qt/ConsoleDebugger.h index bf14ed02..3ab363cd 100644 --- a/src/drivers/Qt/ConsoleDebugger.h +++ b/src/drivers/Qt/ConsoleDebugger.h @@ -74,6 +74,8 @@ class QAsmView : public QWidget void setLine(int lineNum); void scrollToPC(void); void setDisplayROMoffsets( bool value ); + void setSymbolDebugEnable( bool value ); + void setRegisterNameEnable( bool value ); int getCtxMenuAddr(void){ return ctxMenuAddr; }; protected: void paintEvent(QPaintEvent *event); @@ -114,6 +116,7 @@ class QAsmView : public QWidget bool displayROMoffsets; bool symbolicDebugEnable; + bool registerNameEnable; }; class ConsoleDebugger : public QDialog @@ -208,6 +211,8 @@ class ConsoleDebugger : public QDialog void delete_BP_CB(void); void resetCountersCB (void); void displayROMoffsetCB(int value); + void symbolDebugEnableCB(int value); + void registerNameEnableCB(int value); void breakOnBadOpcodeCB(int value); void breakOnCyclesCB( int value ); void breakOnInstructionsCB( int value ); From ced49bebc77a0d531941b108c6d7dccf1fe06726 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Mon, 14 Sep 2020 21:42:10 -0400 Subject: [PATCH 20/57] Added logic for debug window reload symbols button. --- src/drivers/Qt/ConsoleDebugger.cpp | 17 ++++++++++++++++- src/drivers/Qt/ConsoleDebugger.h | 1 + 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/drivers/Qt/ConsoleDebugger.cpp b/src/drivers/Qt/ConsoleDebugger.cpp index 7dd970b7..86f8ee0e 100644 --- a/src/drivers/Qt/ConsoleDebugger.cpp +++ b/src/drivers/Qt/ConsoleDebugger.cpp @@ -409,7 +409,8 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent) vbox->addWidget( regNamChkBox ); symDbgChkBox->setChecked(true); - regNamChkBox->setChecked(true); + //regNamChkBox->setChecked(true); + regNamChkBox->setEnabled(false); // TODO connect( romOfsChkBox, SIGNAL(stateChanged(int)), this, SLOT(displayROMoffsetCB(int)) ); connect( symDbgChkBox, SIGNAL(stateChanged(int)), this, SLOT(symbolDebugEnableCB(int)) ); @@ -417,9 +418,11 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent) button = new QPushButton( tr("Reload Symbols") ); vbox->addWidget( button ); + connect( button, SIGNAL(clicked(void)), this, SLOT(reloadSymbolsCB(void)) ); button = new QPushButton( tr("ROM Patcher") ); vbox->addWidget( button ); + button->setEnabled(false); // TODO frame->setLayout( vbox ); frame->setFrameShape( QFrame::Box ); @@ -436,6 +439,11 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent) hbox->addWidget( debFileChkBox ); hbox->addWidget( idaFontChkBox ); + button->setEnabled(false); // TODO + autoOpenChkBox->setEnabled(false); // TODO + debFileChkBox->setEnabled(false); // TODO + idaFontChkBox->setEnabled(false); // TODO + setLayout( mainLayout ); windowUpdateReq = true; @@ -996,6 +1004,13 @@ void ConsoleDebugger::registerNameEnableCB( int value ) asmView->setRegisterNameEnable(value != Qt::Unchecked); } //---------------------------------------------------------------------------- +void ConsoleDebugger::reloadSymbolsCB(void) +{ + debugSymbolTable.loadGameSymbols(); + + asmView->updateAssemblyView(); +} +//---------------------------------------------------------------------------- void ConsoleDebugger::debugRunCB(void) { if (FCEUI_EmulationPaused()) diff --git a/src/drivers/Qt/ConsoleDebugger.h b/src/drivers/Qt/ConsoleDebugger.h index 3ab363cd..4b34dfda 100644 --- a/src/drivers/Qt/ConsoleDebugger.h +++ b/src/drivers/Qt/ConsoleDebugger.h @@ -210,6 +210,7 @@ class ConsoleDebugger : public QDialog void edit_BP_CB(void); void delete_BP_CB(void); void resetCountersCB (void); + void reloadSymbolsCB(void); void displayROMoffsetCB(int value); void symbolDebugEnableCB(int value); void registerNameEnableCB(int value); From d5b6c28df641024b9d0600924766df81a787692d Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Tue, 15 Sep 2020 19:53:47 -0400 Subject: [PATCH 21/57] Added logic to save game debug symbols when closed. --- src/drivers/Qt/SymbolicDebug.cpp | 114 +++++++++++++++++++++++++++++++ src/drivers/Qt/SymbolicDebug.h | 2 + src/drivers/Qt/fceuWrapper.cpp | 3 + 3 files changed, 119 insertions(+) diff --git a/src/drivers/Qt/SymbolicDebug.cpp b/src/drivers/Qt/SymbolicDebug.cpp index 548ec6ce..f48ff8c2 100644 --- a/src/drivers/Qt/SymbolicDebug.cpp +++ b/src/drivers/Qt/SymbolicDebug.cpp @@ -61,6 +61,106 @@ debugSymbol_t *debugSymbolPage_t::getSymbolAtOffset( int ofs ) return sym; } //-------------------------------------------------------------- +int debugSymbolPage_t::save(void) +{ + FILE *fp; + debugSymbol_t *sym; + std::map ::iterator it; + const char *romFile; + char stmp[512]; + int i,j; + + romFile = getRomFile(); + + if ( romFile == NULL ) + { + return -1; + } + i=0; + while ( romFile[i] != 0 ) + { + + if ( romFile[i] == '|' ) + { + stmp[i] = '.'; + } + else + { + stmp[i] = romFile[i]; + } + i++; + } + stmp[i] = 0; + + if ( pageNum > 0 ) + { + char suffix[32]; + + sprintf( suffix, ".%X.nl", pageNum ); + + strcat( stmp, suffix ); + } + else + { + strcat( stmp, ".ram.nl" ); + } + + fp = fopen( stmp, "w" ); + + if ( fp == NULL ) + { + printf("Error: Could not open file '%s' for writing\n", stmp ); + return -1; + } + + for (it=symMap.begin(); it!=symMap.end(); it++) + { + const char *c; + + sym = it->second; + + i=0; j=0; c = sym->comment.c_str(); + + while ( c[i] != 0 ) + { + if ( c[i] == '\n' ) + { + i++; break; + } + else + { + stmp[j] = c[i]; j++; i++; + } + } + stmp[j] = 0; + + fprintf( fp, "$%04X#%s#%s\n", sym->ofs, sym->name.c_str(), stmp ); + + j=0; + while ( c[i] != 0 ) + { + if ( c[i] == '\n' ) + { + i++; stmp[j] = 0; + + if ( j > 0 ) + { + fprintf( fp, "\\%s\n", stmp ); + } + j=0; + } + else + { + stmp[j] = c[i]; j++; i++; + } + } + } + + fclose(fp); + + return 0; +} +//-------------------------------------------------------------- void debugSymbolPage_t::print(void) { FILE *fp; @@ -356,6 +456,7 @@ int debugSymbolTable_t::loadGameSymbols(void) { int nPages; + this->save(); this->clear(); loadFileNL( 0x0000 ); @@ -391,6 +492,19 @@ debugSymbol_t *debugSymbolTable_t::getSymbolAtBankOffset( int bank, int ofs ) return sym; } //-------------------------------------------------------------- +void debugSymbolTable_t::save(void) +{ + debugSymbolPage_t *page; + std::map ::iterator it; + + for (it=pageMap.begin(); it!=pageMap.end(); it++) + { + page = it->second; + + page->save(); + } +} +//-------------------------------------------------------------- void debugSymbolTable_t::print(void) { debugSymbolPage_t *page; diff --git a/src/drivers/Qt/SymbolicDebug.h b/src/drivers/Qt/SymbolicDebug.h index 62c005a1..172074ba 100644 --- a/src/drivers/Qt/SymbolicDebug.h +++ b/src/drivers/Qt/SymbolicDebug.h @@ -26,6 +26,7 @@ struct debugSymbolPage_t debugSymbolPage_t(void); ~debugSymbolPage_t(void); + int save(void); void print(void); int size(void){ return symMap.size(); } @@ -47,6 +48,7 @@ class debugSymbolTable_t int loadGameSymbols(void); int numPages(void){ return pageMap.size(); } + void save(void); void clear(void); void print(void); diff --git a/src/drivers/Qt/fceuWrapper.cpp b/src/drivers/Qt/fceuWrapper.cpp index 08faab7e..b3be02d8 100644 --- a/src/drivers/Qt/fceuWrapper.cpp +++ b/src/drivers/Qt/fceuWrapper.cpp @@ -280,6 +280,9 @@ CloseGame(void) } hexEditorSaveBookmarks(); + debugSymbolTable.save(); + debugSymbolTable.clear(); + int state_to_save; g_config->getOption("SDL.AutoSaveState", &state_to_save); if (state_to_save < 10 && state_to_save >= 0){ From cef4ad4e1d42be6286a4f6c165d2a3291d23ffcf Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Tue, 15 Sep 2020 20:11:17 -0400 Subject: [PATCH 22/57] Added logic for breakpoint tree view enable checkbox. --- src/drivers/Qt/ConsoleDebugger.cpp | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/src/drivers/Qt/ConsoleDebugger.cpp b/src/drivers/Qt/ConsoleDebugger.cpp index 86f8ee0e..8d5738dd 100644 --- a/src/drivers/Qt/ConsoleDebugger.cpp +++ b/src/drivers/Qt/ConsoleDebugger.cpp @@ -486,8 +486,24 @@ void ConsoleDebugger::bpItemClicked( QTreeWidgetItem *item, int column) { int row = bpTree->indexOfTopLevelItem(item); - printf("Row: %i Column: %i \n", row, column ); + //printf("Row: %i Column: %i \n", row, column ); + if ( column == 0 ) + { + if ( (row >= 0) && (row < numWPs) ) + { + int isChecked = item->checkState( column ) != Qt::Unchecked; + + if ( isChecked ) + { + watchpoint[row].flags |= WP_E; + } + else + { + watchpoint[row].flags &= ~WP_E; + } + } + } } //---------------------------------------------------------------------------- void ConsoleDebugger::bmItemClicked( QTreeWidgetItem *item, int column) @@ -506,7 +522,7 @@ void ConsoleDebugger::openBpEditWindow( int editIdx, watchpointinfo *wp ) QVBoxLayout *mainLayout, *vbox; QLabel *lbl; QLineEdit *addr1, *addr2, *cond, *name; - QCheckBox *forbidChkBox, *rbp, *wbp, *xbp; + QCheckBox *forbidChkBox, *rbp, *wbp, *xbp, *ebp; QGridLayout *grid; QFrame *frame; QGroupBox *gbox; @@ -542,6 +558,7 @@ void ConsoleDebugger::openBpEditWindow( int editIdx, watchpointinfo *wp ) rbp = new QCheckBox( tr("Read") ); wbp = new QCheckBox( tr("Write") ); xbp = new QCheckBox( tr("Execute") ); + ebp = new QCheckBox( tr("Enable") ); gbox->setTitle( tr("Memory") ); mainLayout->addWidget( frame ); @@ -553,6 +570,7 @@ void ConsoleDebugger::openBpEditWindow( int editIdx, watchpointinfo *wp ) hbox->addWidget( rbp ); hbox->addWidget( wbp ); hbox->addWidget( xbp ); + hbox->addWidget( ebp ); hbox = new QHBoxLayout(); cpu_radio = new QRadioButton( tr("CPU Mem") ); @@ -633,7 +651,7 @@ void ConsoleDebugger::openBpEditWindow( int editIdx, watchpointinfo *wp ) } if ( wp->flags & WP_E ) { - //forbidChkBox->setChecked(true); + ebp->setChecked(true); } if ( wp->condText ) @@ -717,6 +735,8 @@ void ConsoleDebugger::openBpEditWindow( int editIdx, watchpointinfo *wp ) type |= WP_F; } + enable = ebp->isChecked(); + if ( (start_addr >= 0) && (numWPs < 64) ) { unsigned int retval; From b37fb451729d3b743c243e11d138bcf14704e70d Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Tue, 15 Sep 2020 21:32:54 -0400 Subject: [PATCH 23/57] Added symbolic debug edit window logic. --- src/drivers/Qt/ConsoleDebugger.cpp | 138 ++++++++++++++++++++++++++++- src/drivers/Qt/ConsoleDebugger.h | 2 + src/drivers/Qt/SymbolicDebug.cpp | 24 ++++- src/drivers/Qt/SymbolicDebug.h | 4 +- 4 files changed, 165 insertions(+), 3 deletions(-) diff --git a/src/drivers/Qt/ConsoleDebugger.cpp b/src/drivers/Qt/ConsoleDebugger.cpp index 8d5738dd..a6ab0cda 100644 --- a/src/drivers/Qt/ConsoleDebugger.cpp +++ b/src/drivers/Qt/ConsoleDebugger.cpp @@ -529,7 +529,14 @@ void ConsoleDebugger::openBpEditWindow( int editIdx, watchpointinfo *wp ) QPushButton *okButton, *cancelButton; QRadioButton *cpu_radio, *ppu_radio, *sprite_radio; - dialog.setWindowTitle( tr("Add Breakpoint") ); + if ( editIdx >= 0 ) + { + dialog.setWindowTitle( tr("Edit Breakpoint") ); + } + else + { + dialog.setWindowTitle( tr("Add Breakpoint") ); + } hbox = new QHBoxLayout(); mainLayout = new QVBoxLayout(); @@ -764,6 +771,129 @@ void ConsoleDebugger::openBpEditWindow( int editIdx, watchpointinfo *wp ) } } //---------------------------------------------------------------------------- +void ConsoleDebugger::openDebugSymbolEditWindow( int addr ) +{ + int ret, bank, charWidth; + QDialog dialog(this); + QHBoxLayout *hbox; + QVBoxLayout *mainLayout; + QLabel *lbl; + QLineEdit *filepath, *addrEntry, *nameEntry, *commentEntry; + QPushButton *okButton, *cancelButton; + char stmp[512]; + debugSymbol_t *sym; + QFontMetrics fm(font); + +#if QT_VERSION > QT_VERSION_CHECK(5, 11, 0) + charWidth = fm.horizontalAdvance(QLatin1Char('2')); +#else + charWidth = fm.width(QLatin1Char('2')); +#endif + + if ( addr < 0x8000 ) + { + bank = 0; + } + else + { + bank = getBank( addr ); + } + + sym = debugSymbolTable.getSymbolAtBankOffset( bank, addr ); + + generateNLFilenameForAddress( addr, stmp ); + + dialog.setWindowTitle( tr("Symbolic Debug Naming") ); + + hbox = new QHBoxLayout(); + mainLayout = new QVBoxLayout(); + + lbl = new QLabel( tr("File") ); + filepath = new QLineEdit(); + filepath->setFont( font ); + filepath->setText( tr(stmp) ); + filepath->setReadOnly( true ); + filepath->setMinimumWidth( charWidth * (filepath->text().size() + 4) ); + + hbox->addWidget( lbl ); + hbox->addWidget( filepath ); + + mainLayout->addLayout( hbox ); + + sprintf( stmp, "%04X", addr ); + + hbox = new QHBoxLayout(); + lbl = new QLabel( tr("Address") ); + addrEntry = new QLineEdit(); + addrEntry->setFont( font ); + addrEntry->setText( tr(stmp) ); + addrEntry->setReadOnly( true ); + addrEntry->setAlignment(Qt::AlignCenter); + addrEntry->setMaximumWidth( charWidth * 6 ); + + hbox->addWidget( lbl ); + hbox->addWidget( addrEntry ); + + lbl = new QLabel( tr("Name") ); + nameEntry = new QLineEdit(); + + hbox->addWidget( lbl ); + hbox->addWidget( nameEntry ); + + mainLayout->addLayout( hbox ); + + hbox = new QHBoxLayout(); + lbl = new QLabel( tr("Comment") ); + commentEntry = new QLineEdit(); + + hbox->addWidget( lbl ); + hbox->addWidget( commentEntry ); + + mainLayout->addLayout( hbox ); + + hbox = new QHBoxLayout(); + okButton = new QPushButton( tr("OK") ); + cancelButton = new QPushButton( tr("Cancel") ); + + mainLayout->addLayout( hbox ); + hbox->addWidget( cancelButton ); + hbox->addWidget( okButton ); + + connect( okButton, SIGNAL(clicked(void)), &dialog, SLOT(accept(void)) ); + connect( cancelButton, SIGNAL(clicked(void)), &dialog, SLOT(reject(void)) ); + + if ( sym != NULL ) + { + nameEntry->setText( tr(sym->name.c_str()) ); + commentEntry->setText( tr(sym->comment.c_str()) ); + } + + dialog.setLayout( mainLayout ); + + ret = dialog.exec(); + + if ( ret == QDialog::Accepted ) + { + if ( sym == NULL ) + { + sym = new debugSymbol_t(); + sym->ofs = addr; + sym->name = nameEntry->text().toStdString(); + sym->comment = commentEntry->text().toStdString(); + + debugSymbolTable.addSymbolAtBankOffset( bank, addr, sym ); + } + else + { + sym->name = nameEntry->text().toStdString(); + sym->comment = commentEntry->text().toStdString(); + } + fceuWrapperLock(); + asmView->updateAssemblyView(); + fceuWrapperUnLock(); + } +} +//---------------------------------------------------------------------------- void ConsoleDebugger::bpListUpdate( bool reset ) { QTreeWidgetItem *item; @@ -1196,6 +1326,11 @@ void ConsoleDebugger::asmViewCtxMenuAddBP(void) } //---------------------------------------------------------------------------- +void ConsoleDebugger::asmViewCtxMenuAddSym(void) +{ + openDebugSymbolEditWindow( asmView->getCtxMenuAddr() ); +} +//---------------------------------------------------------------------------- int QAsmView::getAsmLineFromAddr(int addr) { int line = -1; @@ -2211,6 +2346,7 @@ void QAsmView::contextMenuEvent(QContextMenuEvent *event) act = new QAction(tr("Add Symbolic Debug Name"), this); menu.addAction(act); + connect( act, SIGNAL(triggered(void)), parent, SLOT(asmViewCtxMenuAddSym(void)) ); //connect( act, SIGNAL(triggered(void)), this, SLOT(addBookMarkCB(void)) ); menu.exec(event->globalPos()); diff --git a/src/drivers/Qt/ConsoleDebugger.h b/src/drivers/Qt/ConsoleDebugger.h index 4b34dfda..53aae637 100644 --- a/src/drivers/Qt/ConsoleDebugger.h +++ b/src/drivers/Qt/ConsoleDebugger.h @@ -131,6 +131,7 @@ class ConsoleDebugger : public QDialog void updateRegisterView(void); void breakPointNotify(int bpNum); void openBpEditWindow(int editIdx = -1, watchpointinfo *wp = NULL ); + void openDebugSymbolEditWindow( int addr ); QLabel *asmLineSelLbl; protected: @@ -195,6 +196,7 @@ class ConsoleDebugger : public QDialog public slots: void closeWindow(void); void asmViewCtxMenuAddBP(void); + void asmViewCtxMenuAddSym(void); private slots: void updatePeriodic(void); void vbarChanged(int value); diff --git a/src/drivers/Qt/SymbolicDebug.cpp b/src/drivers/Qt/SymbolicDebug.cpp index f48ff8c2..5385c94b 100644 --- a/src/drivers/Qt/SymbolicDebug.cpp +++ b/src/drivers/Qt/SymbolicDebug.cpp @@ -202,7 +202,7 @@ void debugSymbolTable_t::clear(void) pageMap.clear(); } //-------------------------------------------------------------- -static int generateNLFilenameForAddress(int address, char *NLfilename) +int generateNLFilenameForAddress(int address, char *NLfilename) { int i; const char *romFile; @@ -478,6 +478,28 @@ int debugSymbolTable_t::loadGameSymbols(void) return 0; } //-------------------------------------------------------------- +int debugSymbolTable_t::addSymbolAtBankOffset( int bank, int ofs, debugSymbol_t *sym ) +{ + debugSymbolPage_t *page; + std::map ::iterator it; + + it = pageMap.find( bank ); + + if ( it == pageMap.end() ) + { + page = new debugSymbolPage_t(); + page->pageNum = bank; + pageMap[ bank ] = page; + } + else + { + page = it->second; + } + page->addSymbol( sym ); + + return 0; +} +//-------------------------------------------------------------- debugSymbol_t *debugSymbolTable_t::getSymbolAtBankOffset( int bank, int ofs ) { debugSymbol_t*sym = NULL; diff --git a/src/drivers/Qt/SymbolicDebug.h b/src/drivers/Qt/SymbolicDebug.h index 172074ba..79e6800d 100644 --- a/src/drivers/Qt/SymbolicDebug.h +++ b/src/drivers/Qt/SymbolicDebug.h @@ -54,9 +54,10 @@ class debugSymbolTable_t debugSymbol_t *getSymbolAtBankOffset( int bank, int ofs ); + int addSymbolAtBankOffset( int bank, int ofs, debugSymbol_t *sym ); + private: std::map pageMap; - }; @@ -69,5 +70,6 @@ extern debugSymbolTable_t debugSymbolTable; //}; +int generateNLFilenameForAddress(int address, char *NLfilename); #endif From c62dfd464f510e9b2266e535bb0bd14ac290083f Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Tue, 15 Sep 2020 22:53:36 -0400 Subject: [PATCH 24/57] Updates to debug symbol loader. --- src/drivers/Qt/ConsoleDebugger.cpp | 2 +- src/drivers/Qt/ConsoleDebugger.h | 4 +- src/drivers/Qt/SymbolicDebug.cpp | 73 +++++++++++++++++++++--------- src/drivers/Qt/SymbolicDebug.h | 1 + 4 files changed, 55 insertions(+), 25 deletions(-) diff --git a/src/drivers/Qt/ConsoleDebugger.cpp b/src/drivers/Qt/ConsoleDebugger.cpp index a6ab0cda..a11a9ab4 100644 --- a/src/drivers/Qt/ConsoleDebugger.cpp +++ b/src/drivers/Qt/ConsoleDebugger.cpp @@ -792,7 +792,7 @@ void ConsoleDebugger::openDebugSymbolEditWindow( int addr ) if ( addr < 0x8000 ) { - bank = 0; + bank = -1; } else { diff --git a/src/drivers/Qt/ConsoleDebugger.h b/src/drivers/Qt/ConsoleDebugger.h index 53aae637..e9ad2960 100644 --- a/src/drivers/Qt/ConsoleDebugger.h +++ b/src/drivers/Qt/ConsoleDebugger.h @@ -47,8 +47,8 @@ struct dbg_asm_entry_t dbg_asm_entry_t(void) { - addr = 0; bank = 0; rom = -1; - size = 0; line = 0; type = ASM_TEXT; + addr = 0; bank = -1; rom = -1; + size = 0; line = 0; type = ASM_TEXT; for (int i=0; i<3; i++) { diff --git a/src/drivers/Qt/SymbolicDebug.cpp b/src/drivers/Qt/SymbolicDebug.cpp index 5385c94b..2bd4e3ab 100644 --- a/src/drivers/Qt/SymbolicDebug.cpp +++ b/src/drivers/Qt/SymbolicDebug.cpp @@ -6,6 +6,9 @@ #include "../../types.h" #include "../../fceu.h" #include "../../debug.h" +#include "../../driver.h" +#include "../../cart.h" +#include "../../ines.h" #include "Qt/SymbolicDebug.h" #include "Qt/ConsoleUtilities.h" @@ -17,7 +20,7 @@ debugSymbolTable_t debugSymbolTable; //-------------------------------------------------------------- debugSymbolPage_t::debugSymbolPage_t(void) { - pageNum = 0; + pageNum = -1; } //-------------------------------------------------------------- @@ -92,7 +95,11 @@ int debugSymbolPage_t::save(void) } stmp[i] = 0; - if ( pageNum > 0 ) + if ( pageNum < 0 ) + { + strcat( stmp, ".ram.nl" ); + } + else { char suffix[32]; @@ -100,10 +107,6 @@ int debugSymbolPage_t::save(void) strcat( stmp, suffix ); } - else - { - strcat( stmp, ".ram.nl" ); - } fp = fopen( stmp, "w" ); @@ -203,6 +206,25 @@ void debugSymbolTable_t::clear(void) } //-------------------------------------------------------------- int generateNLFilenameForAddress(int address, char *NLfilename) +{ + int bank; + + if (address < 0x8000) + { + bank = -1; + } + else + { + bank = getBank(address); + #ifdef DW3_NL_0F_1F_HACK + if(bank == 0x0F) + bank = 0x1F; + #endif + } + return generateNLFilenameForBank( bank, NLfilename ); +} +//-------------------------------------------------------------- +int generateNLFilenameForBank(int bank, char *NLfilename) { int i; const char *romFile; @@ -229,14 +251,13 @@ int generateNLFilenameForAddress(int address, char *NLfilename) } NLfilename[i] = 0; - if (address < 0x8000) + if (bank < 0) { // The NL file for the RAM addresses has the name nesrom.nes.ram.nl strcat(NLfilename, ".ram.nl"); } else { - int bank = getBank(address); char stmp[64]; #ifdef DW3_NL_0F_1F_HACK if(bank == 0x0F) @@ -248,7 +269,7 @@ int generateNLFilenameForAddress(int address, char *NLfilename) return 0; } //-------------------------------------------------------------- -int debugSymbolTable_t::loadFileNL( int addr ) +int debugSymbolTable_t::loadFileNL( int bank ) { FILE *fp; int i, j, ofs, lineNum = 0, literal = 0; @@ -257,9 +278,9 @@ int debugSymbolTable_t::loadFileNL( int addr ) debugSymbolPage_t *page = NULL; debugSymbol_t *sym = NULL; - printf("Looking to Load Debug Addr: $%04X \n", addr ); + printf("Looking to Load Debug Bank: $%X \n", bank ); - if ( generateNLFilenameForAddress( addr, fileName ) ) + if ( generateNLFilenameForBank( bank, fileName ) ) { return -1; } @@ -273,10 +294,8 @@ int debugSymbolTable_t::loadFileNL( int addr ) } page = new debugSymbolPage_t; - if ( addr >= 0x8000 ) - { - page->pageNum = getBank( addr ); - } + page->pageNum = bank; + pageMap[ page->pageNum ] = page; while ( fgets( line, sizeof(line), fp ) != 0 ) @@ -454,23 +473,33 @@ int debugSymbolTable_t::loadFileNL( int addr ) //-------------------------------------------------------------- int debugSymbolTable_t::loadGameSymbols(void) { - int nPages; + int nPages, pageSize, romSize = 0x10000; this->save(); this->clear(); - loadFileNL( 0x0000 ); + if ( GameInfo != NULL ) + { + romSize = 16 + CHRsize[0] + PRGsize[0]; + } - nPages = 1<<(15-debuggerPageSize); + loadFileNL( -1 ); + + pageSize = (1< Date: Wed, 16 Sep 2020 21:02:43 -0400 Subject: [PATCH 25/57] Added logic to load/save breakpoint data into game specific files. --- src/drivers/Qt/ConsoleDebugger.cpp | 279 ++++++++++++++++++++++++++++- src/drivers/Qt/ConsoleDebugger.h | 3 + src/drivers/Qt/SymbolicDebug.cpp | 9 +- src/drivers/Qt/fceuWrapper.cpp | 3 + 4 files changed, 287 insertions(+), 7 deletions(-) diff --git a/src/drivers/Qt/ConsoleDebugger.cpp b/src/drivers/Qt/ConsoleDebugger.cpp index a11a9ab4..73304211 100644 --- a/src/drivers/Qt/ConsoleDebugger.cpp +++ b/src/drivers/Qt/ConsoleDebugger.cpp @@ -38,6 +38,7 @@ #include "Qt/nes_shm.h" #include "Qt/fceuWrapper.h" #include "Qt/ConsoleDebugger.h" +#include "Qt/ConsoleUtilities.h" // Where are these defined? extern int vblankScanLines; @@ -693,7 +694,6 @@ void ConsoleDebugger::openBpEditWindow( int editIdx, watchpointinfo *wp ) { int start_addr = -1, end_addr = -1, type = 0, enable = 1, slot; std::string s; - printf("Accepted\n"); slot = (editIdx < 0) ? numWPs : editIdx; @@ -2066,6 +2066,283 @@ void FCEUD_DebugBreakpoint( int bpNum ) fceuWrapperLock(); } //---------------------------------------------------------------------------- +static int getGameDebugBreakpointFileName(char *filepath) +{ + int i,j; + const char *romFile; + + romFile = getRomFile(); + + if ( romFile == NULL ) + { + return -1; + } + i=0; j = -1; + while ( romFile[i] != 0 ) + { + + if ( romFile[i] == '|' ) + { + filepath[i] = '.'; + } + else + { + if ( romFile[i] == '/' ) + { + j = -1; + } + else if ( romFile[i] == '.' ) + { + j = i; + } + filepath[i] = romFile[i]; + } + i++; + } + if ( j >= 0 ) + { + filepath[j] = 0; i=j; + } + + filepath[i] = '.'; i++; + filepath[i] = 'd'; i++; + filepath[i] = 'b'; i++; + filepath[i] = 'g'; i++; + filepath[i] = 0; + + return 0; +} +//---------------------------------------------------------------------------- +void saveGameDebugBreakpoints(void) +{ + int i; + FILE *fp; + char stmp[512]; + char flags[8]; + + if ( numWPs == 0 ) + { + return; + } + getGameDebugBreakpointFileName( stmp ); + + printf("Debug Save File: '%s' \n", stmp ); + + fp = fopen( stmp, "w"); + + if ( fp == NULL ) + { + printf("Error: Failed to open file '%s' for writing\n", stmp ); + return; + } + + for (i=0; i= 0) && (numWPs < 64) ) + { + retval = NewBreak( desc, start_addr, end_addr, type, cond, numWPs, enable); + + if ( (retval == 1) || (retval == 2) ) + { + printf("Breakpoint Add Failed\n"); + } + else + { + numWPs++; + } + } + + + } + } + fclose(fp); + + return; +} +//---------------------------------------------------------------------------- QAsmView::QAsmView(QWidget *parent) : QWidget( parent ) { diff --git a/src/drivers/Qt/ConsoleDebugger.h b/src/drivers/Qt/ConsoleDebugger.h index e9ad2960..8135cd1f 100644 --- a/src/drivers/Qt/ConsoleDebugger.h +++ b/src/drivers/Qt/ConsoleDebugger.h @@ -225,3 +225,6 @@ class ConsoleDebugger : public QDialog void instructionsThresChanged(const QString &txt); }; + +void saveGameDebugBreakpoints(void); +void loadGameDebugBreakpoints(void); diff --git a/src/drivers/Qt/SymbolicDebug.cpp b/src/drivers/Qt/SymbolicDebug.cpp index 2bd4e3ab..43925416 100644 --- a/src/drivers/Qt/SymbolicDebug.cpp +++ b/src/drivers/Qt/SymbolicDebug.cpp @@ -278,13 +278,13 @@ int debugSymbolTable_t::loadFileNL( int bank ) debugSymbolPage_t *page = NULL; debugSymbol_t *sym = NULL; - printf("Looking to Load Debug Bank: $%X \n", bank ); + //printf("Looking to Load Debug Bank: $%X \n", bank ); if ( generateNLFilenameForBank( bank, fileName ) ) { return -1; } - printf("Loading NL File: %s\n", fileName ); + //printf("Loading NL File: %s\n", fileName ); fp = ::fopen( fileName, "r" ); @@ -494,10 +494,7 @@ int debugSymbolTable_t::loadGameSymbols(void) for(int i=0;i Date: Thu, 17 Sep 2020 20:44:33 -0400 Subject: [PATCH 26/57] Added logic to selectively load/save breakpoint data from/to files only if a debugger window is open. --- src/drivers/Qt/ConsoleDebugger.cpp | 81 +++++++++++++++++++++++++++--- src/drivers/Qt/ConsoleDebugger.h | 1 + src/drivers/Qt/fceuWrapper.cpp | 1 + 3 files changed, 77 insertions(+), 6 deletions(-) diff --git a/src/drivers/Qt/ConsoleDebugger.cpp b/src/drivers/Qt/ConsoleDebugger.cpp index 73304211..d1495a5e 100644 --- a/src/drivers/Qt/ConsoleDebugger.cpp +++ b/src/drivers/Qt/ConsoleDebugger.cpp @@ -45,6 +45,8 @@ extern int vblankScanLines; extern int vblankPixel; static std::list dbgWinList; + +static void DeleteBreak(int sel); //---------------------------------------------------------------------------- ConsoleDebugger::ConsoleDebugger(QWidget *parent) : QDialog( parent ) @@ -460,12 +462,36 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent) bpListUpdate( false ); periodicTimer->start( 100 ); // 10hz + + // If this is the first debug window to open, load breakpoints fresh + if ( dbgWinList.size() == 1 ) + { + loadGameDebugBreakpoints(); + } } //---------------------------------------------------------------------------- ConsoleDebugger::~ConsoleDebugger(void) { + std::list ::iterator it; + printf("Destroy Debugger Window\n"); periodicTimer->stop(); + + for (it = dbgWinList.begin(); it != dbgWinList.end(); it++) + { + if ( (*it) == this ) + { + dbgWinList.erase(it); + printf("Removing Debugger Window\n"); + break; + } + } + + if ( dbgWinList.size() == 0 ) + { + saveGameDebugBreakpoints(); + debuggerClearAllBreakpoints(); + } } //---------------------------------------------------------------------------- void ConsoleDebugger::closeEvent(QCloseEvent *event) @@ -1019,6 +1045,9 @@ static void DeleteBreak(int sel) { if(sel<0) return; if(sel>=numWPs) return; + + fceuWrapperLock(); + if (watchpoint[sel].cond) { freeTree(watchpoint[sel].cond); @@ -1051,6 +1080,41 @@ static void DeleteBreak(int sel) watchpoint[numWPs].condText = 0; watchpoint[numWPs].desc = 0; numWPs--; + + fceuWrapperUnLock(); +} +//---------------------------------------------------------------------------- +void debuggerClearAllBreakpoints(void) +{ + int i; + + fceuWrapperLock(); + + for (i=0; i Date: Thu, 17 Sep 2020 21:54:47 -0400 Subject: [PATCH 27/57] Added logic for auto debug file load/save checkbox option. --- src/drivers/Qt/ConsoleDebugger.cpp | 43 +++++++++++++++++++++++++++--- src/drivers/Qt/ConsoleDebugger.h | 2 ++ src/drivers/Qt/config.cpp | 4 +++ src/drivers/Qt/fceuWrapper.cpp | 17 ++++++++++-- 4 files changed, 60 insertions(+), 6 deletions(-) diff --git a/src/drivers/Qt/ConsoleDebugger.cpp b/src/drivers/Qt/ConsoleDebugger.cpp index d1495a5e..75f16137 100644 --- a/src/drivers/Qt/ConsoleDebugger.cpp +++ b/src/drivers/Qt/ConsoleDebugger.cpp @@ -60,6 +60,7 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent) QLabel *lbl; float fontCharWidth; QTreeWidgetItem * item; + int opt; font.setFamily("Courier New"); font.setStyle( QFont::StyleNormal ); @@ -419,6 +420,7 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent) connect( symDbgChkBox, SIGNAL(stateChanged(int)), this, SLOT(symbolDebugEnableCB(int)) ); connect( regNamChkBox, SIGNAL(stateChanged(int)), this, SLOT(registerNameEnableCB(int)) ); + button = new QPushButton( tr("Reload Symbols") ); vbox->addWidget( button ); connect( button, SIGNAL(clicked(void)), this, SLOT(reloadSymbolsCB(void)) ); @@ -442,9 +444,18 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent) hbox->addWidget( debFileChkBox ); hbox->addWidget( idaFontChkBox ); + g_config->getOption( "SDL.AutoOpenDebugger", &opt ); + autoOpenChkBox->setChecked( opt ); + + g_config->getOption( "SDL.AutoLoadDebugFiles", &opt ); + debFileChkBox->setChecked( opt ); + + connect( autoOpenChkBox, SIGNAL(stateChanged(int)), this, SLOT(autoOpenDebugCB(int)) ); + connect( debFileChkBox , SIGNAL(stateChanged(int)), this, SLOT(debFileAutoLoadCB(int)) ); + button->setEnabled(false); // TODO autoOpenChkBox->setEnabled(false); // TODO - debFileChkBox->setEnabled(false); // TODO + //debFileChkBox->setEnabled(false); // TODO idaFontChkBox->setEnabled(false); // TODO setLayout( mainLayout ); @@ -465,8 +476,15 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent) // If this is the first debug window to open, load breakpoints fresh if ( dbgWinList.size() == 1 ) - { - loadGameDebugBreakpoints(); + { + int autoLoadDebug; + + g_config->getOption( "SDL.AutoLoadDebugFiles", &autoLoadDebug ); + + if ( autoLoadDebug ) + { + loadGameDebugBreakpoints(); + } } } //---------------------------------------------------------------------------- @@ -1218,6 +1236,23 @@ void ConsoleDebugger::registerNameEnableCB( int value ) asmView->setRegisterNameEnable(value != Qt::Unchecked); } //---------------------------------------------------------------------------- +void ConsoleDebugger::autoOpenDebugCB( int value ) +{ + g_config->setOption( "SDL.AutoOpenDebugger", value != Qt::Unchecked); +} +//---------------------------------------------------------------------------- +void ConsoleDebugger::debFileAutoLoadCB( int value ) +{ + int autoLoadDebug = value != Qt::Unchecked; + + g_config->setOption("SDL.AutoLoadDebugFiles", autoLoadDebug); + + if ( autoLoadDebug && (numWPs == 0) ) + { + loadGameDebugBreakpoints(); + } +} +//---------------------------------------------------------------------------- void ConsoleDebugger::reloadSymbolsCB(void) { debugSymbolTable.loadGameSymbols(); @@ -2349,7 +2384,7 @@ void loadGameDebugBreakpoints(void) data[j] = 0; } - printf("ID:'%s' DATA:'%s' \n", id, data ); + //printf("ID:'%s' DATA:'%s' \n", id, data ); if ( strcmp( id, "startAddr" ) == 0 ) { diff --git a/src/drivers/Qt/ConsoleDebugger.h b/src/drivers/Qt/ConsoleDebugger.h index be172116..07e28f0f 100644 --- a/src/drivers/Qt/ConsoleDebugger.h +++ b/src/drivers/Qt/ConsoleDebugger.h @@ -216,6 +216,8 @@ class ConsoleDebugger : public QDialog void displayROMoffsetCB(int value); void symbolDebugEnableCB(int value); void registerNameEnableCB(int value); + void autoOpenDebugCB( int value ); + void debFileAutoLoadCB( int value ); void breakOnBadOpcodeCB(int value); void breakOnCyclesCB( int value ); void breakOnInstructionsCB( int value ); diff --git a/src/drivers/Qt/config.cpp b/src/drivers/Qt/config.cpp index a161701c..3fec6409 100644 --- a/src/drivers/Qt/config.cpp +++ b/src/drivers/Qt/config.cpp @@ -259,6 +259,10 @@ InitConfig() config->addOption("hexEditBgColor", "SDL.HexEditBgColor", "#000000"); config->addOption("hexEditFgColor", "SDL.HexEditFgColor", "#FFFFFF"); + // Debugger Options + config->addOption("autoLoadDebugFiles", "SDL.AutoLoadDebugFiles", 1); + config->addOption("autoOpenDebugger" , "SDL.AutoOpenDebugger" , 0); + // overwrite the config file? config->addOption("no-config", "SDL.NoConfig", 0); diff --git a/src/drivers/Qt/fceuWrapper.cpp b/src/drivers/Qt/fceuWrapper.cpp index 1acbced5..5ff1d5ac 100644 --- a/src/drivers/Qt/fceuWrapper.cpp +++ b/src/drivers/Qt/fceuWrapper.cpp @@ -212,7 +212,7 @@ DriverKill() */ int LoadGame(const char *path) { - int gg_enabled; + int gg_enabled, autoLoadDebug, autoOpenDebugger; if (isloaded){ CloseGame(); @@ -229,8 +229,21 @@ int LoadGame(const char *path) return 0; } + g_config->getOption( "SDL.AutoOpenDebugger", &autoOpenDebugger ); + + if ( autoOpenDebugger ) + { + // TODO Auto Open Debugger + } + hexEditorLoadBookmarks(); - loadGameDebugBreakpoints(); + + g_config->getOption( "SDL.AutoLoadDebugFiles", &autoLoadDebug ); + + if ( autoLoadDebug ) + { + loadGameDebugBreakpoints(); + } debugSymbolTable.loadGameSymbols(); From e70eb49bf99f50a63b52918a711666e72ca51d18 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Thu, 17 Sep 2020 22:59:56 -0400 Subject: [PATCH 28/57] Added logic for ASM view horizontal scroll. Set debugger bookmark buttons to insensitive until code can be added. --- src/drivers/Qt/ConsoleDebugger.cpp | 46 +++++++++++++++++++++++------- src/drivers/Qt/ConsoleDebugger.h | 3 ++ 2 files changed, 38 insertions(+), 11 deletions(-) diff --git a/src/drivers/Qt/ConsoleDebugger.cpp b/src/drivers/Qt/ConsoleDebugger.cpp index 75f16137..ee4cca05 100644 --- a/src/drivers/Qt/ConsoleDebugger.cpp +++ b/src/drivers/Qt/ConsoleDebugger.cpp @@ -383,12 +383,15 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent) button = new QPushButton( tr("Add") ); vbox->addWidget( button ); + button->setEnabled(false); // TODO button = new QPushButton( tr("Delete") ); vbox->addWidget( button ); + button->setEnabled(false); // TODO button = new QPushButton( tr("Name") ); vbox->addWidget( button ); + button->setEnabled(false); // TODO hbox->addWidget( bmTree ); hbox->addLayout( vbox ); @@ -467,7 +470,7 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent) periodicTimer = new QTimer( this ); connect( periodicTimer, &QTimer::timeout, this, &ConsoleDebugger::updatePeriodic ); - //connect( hbar, SIGNAL(valueChanged(int)), this, SLOT(hbarChanged(int)) ); + connect( hbar, SIGNAL(valueChanged(int)), this, SLOT(hbarChanged(int)) ); connect( vbar, SIGNAL(valueChanged(int)), this, SLOT(vbarChanged(int)) ); bpListUpdate( false ); @@ -1813,7 +1816,9 @@ void QAsmView::updateAssemblyView(void) asmEntry.push_back(a); } - setMinimumWidth( maxLineLen * pxCharWidth ); + pxLineWidth = maxLineLen * pxCharWidth; + + setMinimumWidth( pxLineWidth ); vbar->setMaximum( asmEntry.size() ); } @@ -2132,6 +2137,12 @@ void ConsoleDebugger::breakPointNotify( int bpNum ) windowUpdateReq = true; } //---------------------------------------------------------------------------- +void ConsoleDebugger::hbarChanged(int value) +{ + //printf("HBar Changed: %i\n", value); + asmView->setXScroll( value ); +} +//---------------------------------------------------------------------------- void ConsoleDebugger::vbarChanged(int value) { //printf("VBar Changed: %i\n", value); @@ -2475,6 +2486,7 @@ QAsmView::QAsmView(QWidget *parent) symbolicDebugEnable = true; registerNameEnable = true; maxLineLen = 0; + pxLineWidth = 0; lineOffset = 0; maxLineOffset = 0; ctxMenuAddr = -1; @@ -2501,6 +2513,18 @@ void QAsmView::setLine(int lineNum) lineOffset = lineNum; } //---------------------------------------------------------------------------- +void QAsmView::setXScroll(int value) +{ + if ( viewWidth >= pxLineWidth ) + { + pxLineXScroll = 0; + } + else + { + pxLineXScroll = (int)(0.010f * (float)value * (float)(pxLineWidth - viewWidth) ); + } +} +//---------------------------------------------------------------------------- void QAsmView::scrollToPC(void) { if ( asmPC != NULL ) @@ -2573,14 +2597,14 @@ void QAsmView::resizeEvent(QResizeEvent *event) maxLineOffset = 0; // mb.numLines() - viewLines + 1; - //if ( viewWidth >= pxLineWidth ) - //{ - // pxLineXScroll = 0; - //} - //else - //{ - // pxLineXScroll = (int)(0.010f * (float)hbar->value() * (float)(pxLineWidth - viewWidth) ); - //} + if ( viewWidth >= pxLineWidth ) + { + pxLineXScroll = 0; + } + else + { + pxLineXScroll = (int)(0.010f * (float)hbar->value() * (float)(pxLineWidth - viewWidth) ); + } } //---------------------------------------------------------------------------- @@ -2775,7 +2799,7 @@ void QAsmView::paintEvent(QPaintEvent *event) for (row=0; row < nrow; row++) { - x=0; + x = -pxLineXScroll; l = lineOffset + row; painter.setPen( this->palette().color(QPalette::WindowText)); diff --git a/src/drivers/Qt/ConsoleDebugger.h b/src/drivers/Qt/ConsoleDebugger.h index 07e28f0f..3661e5ac 100644 --- a/src/drivers/Qt/ConsoleDebugger.h +++ b/src/drivers/Qt/ConsoleDebugger.h @@ -72,6 +72,7 @@ class QAsmView : public QWidget void asmClear(void); int getAsmLineFromAddr(int addr); void setLine(int lineNum); + void setXScroll(int value); void scrollToPC(void); void setDisplayROMoffsets( bool value ); void setSymbolDebugEnable( bool value ); @@ -107,6 +108,7 @@ class QAsmView : public QWidget int viewHeight; int lineOffset; int maxLineOffset; + int pxLineWidth; int pxLineXScroll; int cursorPosX; int cursorPosY; @@ -199,6 +201,7 @@ class ConsoleDebugger : public QDialog void asmViewCtxMenuAddSym(void); private slots: void updatePeriodic(void); + void hbarChanged(int value); void vbarChanged(int value); void debugRunCB(void); void debugStepIntoCB(void); From fdd246fcd600d7ff327159cee23cac9ccdab74d6 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Thu, 17 Sep 2020 23:12:01 -0400 Subject: [PATCH 29/57] Updates to README and SDL TODO files. --- README | 2 +- TODO-SDL | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README b/README index e75719a6..59cfcc13 100644 --- a/README +++ b/README @@ -56,7 +56,7 @@ To compile faster with multiple processes in parallel: After a sucessful compilation, the fceux binary will be generated to ./build/src/fceux . You can install fceux to your system with the following command: - make install + sudo make install You can optionally define a install prefix when running cmake from the previous step: diff --git a/TODO-SDL b/TODO-SDL index 90a21899..e6000743 100644 --- a/TODO-SDL +++ b/TODO-SDL @@ -42,10 +42,10 @@ RAM Search Window | NO | NO RAM Watch Window | NO | YES | Memory Watch Window | NO | NO | TAS Editor | NO | NO | -6502 Debugger Window | NO | YES | +6502 Debugger Window | YES | YES | PPU Viewer | NO | NO | Name Table Viewer | NO | NO | -Memory Hex Editor | NO | YES | +Memory Hex Editor | YES | YES | Trace Logger | NO | NO | Code/Data Logger | NO | NO | Game Genie Encoder/Decoder | NO | NO | From dad6ddfe64720387a43417f9a2717f799bc086e9 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Fri, 18 Sep 2020 06:00:19 -0400 Subject: [PATCH 30/57] Added Qt debugger auto open on game load feature. --- src/drivers/Qt/ConsoleDebugger.cpp | 7 ++++++- src/drivers/Qt/ConsoleDebugger.h | 1 + src/drivers/Qt/ConsoleWindow.h | 5 +++-- src/drivers/Qt/fceuWrapper.cpp | 14 +++++++------- 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/drivers/Qt/ConsoleDebugger.cpp b/src/drivers/Qt/ConsoleDebugger.cpp index ee4cca05..81204d9a 100644 --- a/src/drivers/Qt/ConsoleDebugger.cpp +++ b/src/drivers/Qt/ConsoleDebugger.cpp @@ -457,7 +457,7 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent) connect( debFileChkBox , SIGNAL(stateChanged(int)), this, SLOT(debFileAutoLoadCB(int)) ); button->setEnabled(false); // TODO - autoOpenChkBox->setEnabled(false); // TODO + //autoOpenChkBox->setEnabled(false); // TODO //debFileChkBox->setEnabled(false); // TODO idaFontChkBox->setEnabled(false); // TODO @@ -2176,6 +2176,11 @@ void FCEUD_DebugBreakpoint( int bpNum ) fceuWrapperLock(); } //---------------------------------------------------------------------------- +bool debuggerWindowIsOpen(void) +{ + return (dbgWinList.size() > 0); +} +//---------------------------------------------------------------------------- static int getGameDebugBreakpointFileName(char *filepath) { int i,j; diff --git a/src/drivers/Qt/ConsoleDebugger.h b/src/drivers/Qt/ConsoleDebugger.h index 3661e5ac..b3f05f7c 100644 --- a/src/drivers/Qt/ConsoleDebugger.h +++ b/src/drivers/Qt/ConsoleDebugger.h @@ -231,6 +231,7 @@ class ConsoleDebugger : public QDialog }; +bool debuggerWindowIsOpen(void); void saveGameDebugBreakpoints(void); void loadGameDebugBreakpoints(void); void debuggerClearAllBreakpoints(void); diff --git a/src/drivers/Qt/ConsoleWindow.h b/src/drivers/Qt/ConsoleWindow.h index 375aea1f..e2f16e33 100644 --- a/src/drivers/Qt/ConsoleWindow.h +++ b/src/drivers/Qt/ConsoleWindow.h @@ -113,6 +113,9 @@ class consoleWin_t : public QMainWindow private: void createMainMenu(void); + public slots: + void openDebugWindow(void); + void openHexEditor(void); private slots: void closeApp(void); void openROMFile(void); @@ -156,8 +159,6 @@ class consoleWin_t : public QMainWindow void fdsEjectDisk(void); void fdsLoadBiosFile(void); void openCheats(void); - void openDebugWindow(void); - void openHexEditor(void); void openMovie(void); void stopMovie(void); void recordMovie(void); diff --git a/src/drivers/Qt/fceuWrapper.cpp b/src/drivers/Qt/fceuWrapper.cpp index 5ff1d5ac..f618991f 100644 --- a/src/drivers/Qt/fceuWrapper.cpp +++ b/src/drivers/Qt/fceuWrapper.cpp @@ -229,13 +229,6 @@ int LoadGame(const char *path) return 0; } - g_config->getOption( "SDL.AutoOpenDebugger", &autoOpenDebugger ); - - if ( autoOpenDebugger ) - { - // TODO Auto Open Debugger - } - hexEditorLoadBookmarks(); g_config->getOption( "SDL.AutoLoadDebugFiles", &autoLoadDebug ); @@ -245,6 +238,13 @@ int LoadGame(const char *path) loadGameDebugBreakpoints(); } + g_config->getOption( "SDL.AutoOpenDebugger", &autoOpenDebugger ); + + if ( autoOpenDebugger && !debuggerWindowIsOpen() ) + { + consoleWindow->openDebugWindow(); + } + debugSymbolTable.loadGameSymbols(); int state_to_load; From 59e4ca1ff920fa65a67291c5ccb25bc75b23a73a Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Fri, 18 Sep 2020 06:18:09 -0400 Subject: [PATCH 31/57] Added logic to init IDA font checkbox to checked and keep unselectable. I am forcing the font in the Qt debugger assembly view to be a monospace Courier New. For now I plan to keep it this way. --- src/drivers/Qt/ConsoleDebugger.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/drivers/Qt/ConsoleDebugger.cpp b/src/drivers/Qt/ConsoleDebugger.cpp index 81204d9a..223f79cb 100644 --- a/src/drivers/Qt/ConsoleDebugger.cpp +++ b/src/drivers/Qt/ConsoleDebugger.cpp @@ -457,9 +457,13 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent) connect( debFileChkBox , SIGNAL(stateChanged(int)), this, SLOT(debFileAutoLoadCB(int)) ); button->setEnabled(false); // TODO - //autoOpenChkBox->setEnabled(false); // TODO - //debFileChkBox->setEnabled(false); // TODO - idaFontChkBox->setEnabled(false); // TODO + + // IDA font is just a monospace font, we are forcing this anyway. It is just easier to read the assembly. + // If a different font is desired, my thought is to open a QFontDialog and let the user pick a new font, + // rather than use a checkbox that selects between two. But for the moment, I have more important things + // to do. + idaFontChkBox->setEnabled(false); + idaFontChkBox->setChecked(true); setLayout( mainLayout ); From abd4089cbba9af025de126299b3fb110a09745ed Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Sat, 19 Sep 2020 14:38:10 -0400 Subject: [PATCH 32/57] Added logic to highlight ASM view selected line. --- src/drivers/Qt/ConsoleDebugger.cpp | 59 +++++++++++++++++++++++------- src/drivers/Qt/ConsoleDebugger.h | 3 ++ 2 files changed, 49 insertions(+), 13 deletions(-) diff --git a/src/drivers/Qt/ConsoleDebugger.cpp b/src/drivers/Qt/ConsoleDebugger.cpp index 223f79cb..801aa58b 100644 --- a/src/drivers/Qt/ConsoleDebugger.cpp +++ b/src/drivers/Qt/ConsoleDebugger.cpp @@ -361,6 +361,7 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent) bmFrame = new QGroupBox( tr("Address Bookmarks") ); bmTree = new QTreeWidget(); selBmAddr = new QLineEdit(); + selBmAddrVal = 0; bmTree->setColumnCount(2); @@ -383,15 +384,12 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent) button = new QPushButton( tr("Add") ); vbox->addWidget( button ); - button->setEnabled(false); // TODO button = new QPushButton( tr("Delete") ); vbox->addWidget( button ); - button->setEnabled(false); // TODO button = new QPushButton( tr("Name") ); vbox->addWidget( button ); - button->setEnabled(false); // TODO hbox->addWidget( bmTree ); hbox->addLayout( vbox ); @@ -1432,6 +1430,17 @@ void ConsoleDebugger::asmViewCtxMenuAddBP(void) } //---------------------------------------------------------------------------- +void ConsoleDebugger::setBookmarkSelectedAddress( int addr ) +{ + char stmp[32]; + + sprintf( stmp, "%04X", addr ); + + selBmAddr->setText( tr(stmp) ); + + selBmAddrVal = addr; +} +//---------------------------------------------------------------------------- void ConsoleDebugger::asmViewCtxMenuAddSym(void) { openDebugSymbolEditWindow( asmView->getCtxMenuAddr() ); @@ -2724,17 +2733,19 @@ void QAsmView::mouseMoveEvent(QMouseEvent * event) //---------------------------------------------------------------------------- void QAsmView::mousePressEvent(QMouseEvent * event) { - //int line; - //QPoint c = convPixToCursor( event->pos() ); + int line; + QPoint c = convPixToCursor( event->pos() ); - //line = lineOffset + c.y(); - // - //if ( line < asmEntry.size() ) - //{ - // int addr; + line = lineOffset + c.y(); + + if ( line < asmEntry.size() ) + { + int addr; - // addr = asmEntry[line]->addr; - //} + addr = asmEntry[line]->addr; + + parent->setBookmarkSelectedAddress( addr ); + } } //---------------------------------------------------------------------------- void QAsmView::contextMenuEvent(QContextMenuEvent *event) @@ -2769,7 +2780,7 @@ void QAsmView::contextMenuEvent(QContextMenuEvent *event) //---------------------------------------------------------------------------- void QAsmView::paintEvent(QPaintEvent *event) { - int x,y,l, row, nrow; + int x,y,l, row, nrow, selAddr; QPainter painter(this); painter.setFont(font); @@ -2801,6 +2812,7 @@ void QAsmView::paintEvent(QPaintEvent *event) { lineOffset = maxLineOffset; } + selAddr = parent->getBookmarkSelectedAddress(); painter.fillRect( 0, 0, viewWidth, viewHeight, this->palette().color(QPalette::Background) ); @@ -2827,6 +2839,27 @@ void QAsmView::paintEvent(QPaintEvent *event) painter.fillRect( 0, y - pxLineSpacing + pxLineLead, viewWidth, pxLineSpacing, QColor("light blue") ); } painter.drawText( x, y, tr(asmEntry[l]->text.c_str()) ); + + if ( selAddr == asmEntry[l]->addr ) + { // Highlight ASM line for selected address. + if ( asmEntry[l]->type == dbg_asm_entry_t::ASM_TEXT ) + { + int ax; + char addrString[16]; + + ax = 4*pxCharWidth; + + painter.fillRect( ax, y - pxLineSpacing + pxLineLead, 4*pxCharWidth, pxLineSpacing, QColor("blue") ); + + sprintf( addrString, "%04X", selAddr ); + + painter.setPen( this->palette().color(QPalette::Background)); + + painter.drawText( ax, y, tr(addrString) ); + + painter.setPen( this->palette().color(QPalette::WindowText)); + } + } } y += pxLineSpacing; } diff --git a/src/drivers/Qt/ConsoleDebugger.h b/src/drivers/Qt/ConsoleDebugger.h index b3f05f7c..c886067c 100644 --- a/src/drivers/Qt/ConsoleDebugger.h +++ b/src/drivers/Qt/ConsoleDebugger.h @@ -134,6 +134,8 @@ class ConsoleDebugger : public QDialog void breakPointNotify(int bpNum); void openBpEditWindow(int editIdx = -1, watchpointinfo *wp = NULL ); void openDebugSymbolEditWindow( int addr ); + void setBookmarkSelectedAddress( int addr ); + int getBookmarkSelectedAddress(void){ return selBmAddrVal; }; QLabel *asmLineSelLbl; protected: @@ -189,6 +191,7 @@ class ConsoleDebugger : public QDialog QTimer *periodicTimer; QFont font; + int selBmAddrVal; bool windowUpdateReq; private: From 52658aa41c9d00a3329aea585585122a4e0760d8 Mon Sep 17 00:00:00 2001 From: adelikat Date: Sat, 19 Sep 2020 13:52:44 -0500 Subject: [PATCH 33/57] website - attempt at making adds async so they dont' affect page load times --- web/contact.html | 39 +++++++++++++----------------- web/documentation.html | 47 +++++++++++++++---------------------- web/download.html | 44 ++++++++++++++-------------------- web/links.html | 28 ++++++++++++---------- web/movies.html | 39 +++++++++++++----------------- web/osx.html | 45 ++++++++++++++--------------------- web/pressrelease-2.2.3.html | 29 +++++++++++++---------- web/version.html | 39 +++++++++++++----------------- 8 files changed, 136 insertions(+), 174 deletions(-) diff --git a/web/contact.html b/web/contact.html index e730f709..5e039d9b 100644 --- a/web/contact.html +++ b/web/contact.html @@ -21,29 +21,22 @@
- - - - - + + + + + +

Contact

diff --git a/web/documentation.html b/web/documentation.html index 86b5f128..af76c791 100644 --- a/web/documentation.html +++ b/web/documentation.html @@ -29,34 +29,25 @@ Links
-
- - - - - - - -
-
+
+ + + + + + +
+

Getting Started with FCEUX

Tips for performing basic functions

Playing games

diff --git a/web/download.html b/web/download.html index ea94a569..25b841cc 100644 --- a/web/download.html +++ b/web/download.html @@ -20,32 +20,24 @@ Links
-
- - - - - - -
+
+ + + + + + +

Downloads

The FCEUX team maintains two ports: SDL and Win32. diff --git a/web/links.html b/web/links.html index fe5586a0..ff63b798 100644 --- a/web/links.html +++ b/web/links.html @@ -21,18 +21,22 @@

- - - + + + + + +

FCEUX Users

diff --git a/web/movies.html b/web/movies.html index 9f825a98..cff79a6e 100644 --- a/web/movies.html +++ b/web/movies.html @@ -29,30 +29,23 @@
- + + + + + - - - - -
+

Movies

Introduction

diff --git a/web/osx.html b/web/osx.html index cb6670c6..66555757 100644 --- a/web/osx.html +++ b/web/osx.html @@ -31,33 +31,24 @@ Links
-
- - - - - - - -
+
+ + + + + + +
To run FCEUX in Mac OSX, you must have the following library dependencies installed on your system:

diff --git a/web/pressrelease-2.2.3.html b/web/pressrelease-2.2.3.html index bd7cff5e..d534a6bf 100644 --- a/web/pressrelease-2.2.3.html +++ b/web/pressrelease-2.2.3.html @@ -21,18 +21,23 @@

- - -
+ + + + + + +

FCEUX 2.2.3 Release

28 July 2016

diff --git a/web/version.html b/web/version.html index 99d653d1..ba947d8e 100644 --- a/web/version.html +++ b/web/version.html @@ -27,29 +27,22 @@
- - - - - + + + + + +

Version History

From a882125224dd7971ae9631aa0c0282eaa7eef498 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Sun, 20 Sep 2020 14:14:59 -0400 Subject: [PATCH 34/57] Added logic to add,edit, and delete debugger bookmarks --- src/drivers/Qt/ConsoleDebugger.cpp | 273 +++++++++++++++++++++++++++++ src/drivers/Qt/ConsoleDebugger.h | 39 +++++ 2 files changed, 312 insertions(+) diff --git a/src/drivers/Qt/ConsoleDebugger.cpp b/src/drivers/Qt/ConsoleDebugger.cpp index 801aa58b..712b0508 100644 --- a/src/drivers/Qt/ConsoleDebugger.cpp +++ b/src/drivers/Qt/ConsoleDebugger.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include "../../types.h" #include "../../fceu.h" @@ -44,6 +45,7 @@ extern int vblankScanLines; extern int vblankPixel; +debuggerBookmarkManager_t dbgBmMgr; static std::list dbgWinList; static void DeleteBreak(int sel); @@ -384,12 +386,15 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent) button = new QPushButton( tr("Add") ); vbox->addWidget( button ); + connect( button, SIGNAL(clicked(void)), this, SLOT(add_BM_CB(void)) ); button = new QPushButton( tr("Delete") ); vbox->addWidget( button ); + connect( button, SIGNAL(clicked(void)), this, SLOT(delete_BM_CB(void)) ); button = new QPushButton( tr("Name") ); vbox->addWidget( button ); + connect( button, SIGNAL(clicked(void)), this, SLOT(edit_BM_CB(void)) ); hbox->addWidget( bmTree ); hbox->addLayout( vbox ); @@ -1042,6 +1047,135 @@ void ConsoleDebugger::bpListUpdate( bool reset ) bpTree->viewport()->update(); } //---------------------------------------------------------------------------- +void ConsoleDebugger::add_BM_CB(void) +{ + dbgBmMgr.addBookmark( selBmAddrVal ); + + bmListUpdate(false); +} +//---------------------------------------------------------------------------- +void ConsoleDebugger::edit_BM_CB(void) +{ + int addr; + std::string s; + QTreeWidgetItem *item; + + item = bmTree->currentItem(); + + if ( item == NULL ) + { + printf( "No Item Selected\n"); + return; + } + s = item->text(0).toStdString(); + + addr = strtol( s.c_str(), NULL, 16 ); + + edit_BM_name( addr ); + +} +//---------------------------------------------------------------------------- +void ConsoleDebugger::delete_BM_CB(void) +{ + int addr; + std::string s; + QTreeWidgetItem *item; + + item = bmTree->currentItem(); + + if ( item == NULL ) + { + printf( "No Item Selected\n"); + return; + } + s = item->text(0).toStdString(); + + addr = strtol( s.c_str(), NULL, 16 ); + + dbgBmMgr.deleteBookmark( addr ); + + bmListUpdate(true); +} +//---------------------------------------------------------------------------- +void ConsoleDebugger::edit_BM_name( int addr ) +{ + int ret; + debuggerBookmark_t *bm; + QInputDialog dialog(this); + + bm = dbgBmMgr.getAddr( addr ); + + dialog.setWindowTitle( tr("Edit Bookmark") ); + dialog.setLabelText( tr("Specify Bookmark Name") ); + dialog.setOkButtonText( tr("Edit") ); + + if ( bm != NULL ) + { + dialog.setTextValue( tr(bm->name.c_str()) ); + } + + dialog.show(); + ret = dialog.exec(); + + if ( QDialog::Accepted == ret ) + { + bm->name = dialog.textValue().toStdString(); + bmListUpdate(false); + } +} +//---------------------------------------------------------------------------- +void ConsoleDebugger::bmListUpdate( bool reset ) +{ + int i=0; + QTreeWidgetItem *item; + debuggerBookmark_t *bm; + char addrStr[32]; + + if ( reset ) + { + bmTree->clear(); + } + + bm = dbgBmMgr.begin(); + + while ( bm != NULL ) + { + if ( bmTree->topLevelItemCount() > i ) + { + item = bmTree->topLevelItem(i); + } + else + { + item = NULL; + } + + if ( item == NULL ) + { + item = new QTreeWidgetItem(); + + bmTree->addTopLevelItem( item ); + } + + sprintf( addrStr, "%04X", bm->addr ); + + //item->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsUserCheckable ); + item->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemNeverHasChildren ); + + item->setFont( 0, font ); + item->setFont( 1, font ); + + item->setText( 0, tr(addrStr)); + item->setText( 1, tr(bm->name.c_str()) ); + + item->setTextAlignment( 0, Qt::AlignLeft); + item->setTextAlignment( 1, Qt::AlignLeft); + + bm = dbgBmMgr.next(); i++; + } + + bmTree->viewport()->update(); +} +//---------------------------------------------------------------------------- void ConsoleDebugger::add_BP_CB(void) { openBpEditWindow(-1); @@ -2107,6 +2241,12 @@ void ConsoleDebugger::updatePeriodic(void) printf("Breakpoint Tree Update\n"); bpListUpdate( true ); } + + if ( bmTree->topLevelItemCount() != dbgBmMgr.size() ) + { + printf("Bookmark Tree Update\n"); + bmListUpdate( true ); + } } //---------------------------------------------------------------------------- void ConsoleDebugger::breakPointNotify( int bpNum ) @@ -2865,3 +3005,136 @@ void QAsmView::paintEvent(QPaintEvent *event) } } //---------------------------------------------------------------------------- +// Bookmark Manager Methods +//---------------------------------------------------------------------------- +debuggerBookmarkManager_t::debuggerBookmarkManager_t(void) +{ + internal_iter = bmMap.begin(); + +} +//---------------------------------------------------------------------------- +debuggerBookmarkManager_t::~debuggerBookmarkManager_t(void) +{ + this->clear(); +} +//---------------------------------------------------------------------------- +void debuggerBookmarkManager_t::clear(void) +{ + std::map ::iterator it; + + for (it=bmMap.begin(); it!=bmMap.end(); it++) + { + delete it->second; + } + bmMap.clear(); + + internal_iter = bmMap.begin(); +} +//---------------------------------------------------------------------------- +int debuggerBookmarkManager_t::addBookmark( int addr, const char *name ) +{ + int retval = -1; + debuggerBookmark_t *bm = NULL; + std::map ::iterator it; + + it = bmMap.find( addr ); + + if ( it == bmMap.end() ) + { + bm = new debuggerBookmark_t(); + bm->addr = addr; + + if ( name != NULL ) + { + bm->name.assign( name ); + } + bmMap[ addr ] = bm; + + retval = 0; + } + + return retval; +} +//---------------------------------------------------------------------------- +int debuggerBookmarkManager_t::editBookmark( int addr, const char *name ) +{ + int retval = -1; + debuggerBookmark_t *bm = NULL; + std::map ::iterator it; + + it = bmMap.find( addr ); + + if ( it != bmMap.end() ) + { + bm = it->second; + + if ( name != NULL ) + { + bm->name.assign( name ); + } + retval = 0; + } + + return retval; +} +//---------------------------------------------------------------------------- +int debuggerBookmarkManager_t::deleteBookmark( int addr ) +{ + int retval = -1; + std::map ::iterator it; + + it = bmMap.find( addr ); + + if ( it != bmMap.end() ) + { + bmMap.erase(it); + + retval = 0; + } + return retval; +} +//---------------------------------------------------------------------------- +int debuggerBookmarkManager_t::size(void) +{ + return bmMap.size(); +} +//---------------------------------------------------------------------------- +debuggerBookmark_t *debuggerBookmarkManager_t::begin(void) +{ + internal_iter = bmMap.begin(); + + if ( internal_iter == bmMap.end() ) + { + return NULL; + } + return internal_iter->second; +} +//---------------------------------------------------------------------------- +debuggerBookmark_t *debuggerBookmarkManager_t::next(void) +{ + if ( internal_iter == bmMap.end() ) + { + return NULL; + } + internal_iter++; + + if ( internal_iter == bmMap.end() ) + { + return NULL; + } + return internal_iter->second; +} +//---------------------------------------------------------------------------- +debuggerBookmark_t *debuggerBookmarkManager_t::getAddr( int addr ) +{ + std::map ::iterator it; + + it = bmMap.find( addr ); + + if ( it != bmMap.end() ) + { + return it->second; + } + return NULL; +} +//---------------------------------------------------------------------------- diff --git a/src/drivers/Qt/ConsoleDebugger.h b/src/drivers/Qt/ConsoleDebugger.h index c886067c..fff2cdef 100644 --- a/src/drivers/Qt/ConsoleDebugger.h +++ b/src/drivers/Qt/ConsoleDebugger.h @@ -57,6 +57,38 @@ struct dbg_asm_entry_t } }; +class debuggerBookmark_t +{ + public: + int addr; + std::string name; + + debuggerBookmark_t(void) + { + addr = 0; + } +}; + +class debuggerBookmarkManager_t +{ + public: + debuggerBookmarkManager_t(void); + ~debuggerBookmarkManager_t(void); + + int addBookmark( int addr, const char *name = NULL ); + int editBookmark( int addr, const char *name ); + int deleteBookmark( int addr ); + + int size(void); + void clear(void); + debuggerBookmark_t *begin(void); + debuggerBookmark_t *next(void); + debuggerBookmark_t *getAddr( int addr ); + private: + std::map bmMap; + std::map ::iterator internal_iter; +}; + class ConsoleDebugger; class QAsmView : public QWidget @@ -136,6 +168,7 @@ class ConsoleDebugger : public QDialog void openDebugSymbolEditWindow( int addr ); void setBookmarkSelectedAddress( int addr ); int getBookmarkSelectedAddress(void){ return selBmAddrVal; }; + void edit_BM_name( int addr ); QLabel *asmLineSelLbl; protected: @@ -197,6 +230,7 @@ class ConsoleDebugger : public QDialog private: void setRegsFromEntry(void); void bpListUpdate( bool reset = false ); + void bmListUpdate( bool reset = false ); public slots: void closeWindow(void); @@ -217,6 +251,9 @@ class ConsoleDebugger : public QDialog void add_BP_CB(void); void edit_BP_CB(void); void delete_BP_CB(void); + void add_BM_CB(void); + void edit_BM_CB(void); + void delete_BM_CB(void); void resetCountersCB (void); void reloadSymbolsCB(void); void displayROMoffsetCB(int value); @@ -238,3 +275,5 @@ bool debuggerWindowIsOpen(void); void saveGameDebugBreakpoints(void); void loadGameDebugBreakpoints(void); void debuggerClearAllBreakpoints(void); + +extern debuggerBookmarkManager_t dbgBmMgr; From 39a0f24445ad1916bb1b14226ee5f87d07952afe Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Sun, 20 Sep 2020 14:31:21 -0400 Subject: [PATCH 35/57] More debugger bookmarking logic added. --- src/drivers/Qt/ConsoleDebugger.cpp | 30 ++++++++++++++++++++++++++++-- src/drivers/Qt/ConsoleDebugger.h | 2 ++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/drivers/Qt/ConsoleDebugger.cpp b/src/drivers/Qt/ConsoleDebugger.cpp index 712b0508..449c17d9 100644 --- a/src/drivers/Qt/ConsoleDebugger.cpp +++ b/src/drivers/Qt/ConsoleDebugger.cpp @@ -365,6 +365,8 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent) selBmAddr = new QLineEdit(); selBmAddrVal = 0; + connect( selBmAddr, SIGNAL(textChanged(const QString &)), this, SLOT(selBmAddrChanged(const QString &))); + bmTree->setColumnCount(2); item = new QTreeWidgetItem(); @@ -382,6 +384,9 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent) connect( bmTree, SIGNAL(itemClicked(QTreeWidgetItem*, int)), this, SLOT(bmItemClicked( QTreeWidgetItem*, int)) ); + connect( bmTree, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), + this, SLOT(bmItemDoubleClicked( QTreeWidgetItem*, int)) ); + vbox->addWidget( selBmAddr ); button = new QPushButton( tr("Add") ); @@ -563,12 +568,33 @@ void ConsoleDebugger::bpItemClicked( QTreeWidgetItem *item, int column) //---------------------------------------------------------------------------- void ConsoleDebugger::bmItemClicked( QTreeWidgetItem *item, int column) { - int row = bmTree->indexOfTopLevelItem(item); + //int row = bmTree->indexOfTopLevelItem(item); - printf("Row: %i Column: %i \n", row, column ); + //printf("Row: %i Column: %i \n", row, column ); } //---------------------------------------------------------------------------- +void ConsoleDebugger::bmItemDoubleClicked( QTreeWidgetItem *item, int column) +{ + int addr, line; + //int row = bmTree->indexOfTopLevelItem(item); + + //printf("Row: %i Column: %i \n", row, column ); + + addr = strtol( item->text(0).toStdString().c_str(), NULL, 16 ); + + line = asmView->getAsmLineFromAddr( addr ); + + asmView->setLine( line ); +} +//---------------------------------------------------------------------------- +void ConsoleDebugger::selBmAddrChanged(const QString &txt) +{ + selBmAddrVal = strtol( txt.toStdString().c_str(), NULL, 16 ); + + //printf("selBmAddrVal = %04X\n", selBmAddrVal ); +} +//---------------------------------------------------------------------------- void ConsoleDebugger::openBpEditWindow( int editIdx, watchpointinfo *wp ) { int ret; diff --git a/src/drivers/Qt/ConsoleDebugger.h b/src/drivers/Qt/ConsoleDebugger.h index fff2cdef..03c73cdd 100644 --- a/src/drivers/Qt/ConsoleDebugger.h +++ b/src/drivers/Qt/ConsoleDebugger.h @@ -266,8 +266,10 @@ class ConsoleDebugger : public QDialog void breakOnInstructionsCB( int value ); void bpItemClicked( QTreeWidgetItem *item, int column); void bmItemClicked( QTreeWidgetItem *item, int column); + void bmItemDoubleClicked( QTreeWidgetItem *item, int column); void cpuCycleThresChanged(const QString &txt); void instructionsThresChanged(const QString &txt); + void selBmAddrChanged(const QString &txt); }; From 3099a233c33ea2d56ed3d0442bdf119f2cb9c58c Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Sun, 20 Sep 2020 16:37:41 -0400 Subject: [PATCH 36/57] Added debugger bookmark add/edit via ASM view context menu. --- src/drivers/Qt/ConsoleDebugger.cpp | 23 ++++++++++++++++++++--- src/drivers/Qt/ConsoleDebugger.h | 1 + 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/drivers/Qt/ConsoleDebugger.cpp b/src/drivers/Qt/ConsoleDebugger.cpp index 449c17d9..cb8479f2 100644 --- a/src/drivers/Qt/ConsoleDebugger.cpp +++ b/src/drivers/Qt/ConsoleDebugger.cpp @@ -1128,11 +1128,14 @@ void ConsoleDebugger::edit_BM_name( int addr ) int ret; debuggerBookmark_t *bm; QInputDialog dialog(this); + char stmp[128]; bm = dbgBmMgr.getAddr( addr ); + sprintf( stmp, "Specify Bookmark Name for %04X", addr ); + dialog.setWindowTitle( tr("Edit Bookmark") ); - dialog.setLabelText( tr("Specify Bookmark Name") ); + dialog.setLabelText( tr(stmp) ); dialog.setOkButtonText( tr("Edit") ); if ( bm != NULL ) @@ -1590,6 +1593,17 @@ void ConsoleDebugger::asmViewCtxMenuAddBP(void) } //---------------------------------------------------------------------------- +void ConsoleDebugger::asmViewCtxMenuAddBM(void) +{ + int addr = asmView->getCtxMenuAddr(); + + dbgBmMgr.addBookmark( addr ); + + edit_BM_name( addr ); + + bmListUpdate(false); +} +//---------------------------------------------------------------------------- void ConsoleDebugger::setBookmarkSelectedAddress( int addr ) { char stmp[32]; @@ -2935,10 +2949,13 @@ void QAsmView::contextMenuEvent(QContextMenuEvent *event) menu.addAction(act); connect( act, SIGNAL(triggered(void)), parent, SLOT(asmViewCtxMenuAddBP(void)) ); - act = new QAction(tr("Add Symbolic Debug Name"), this); + act = new QAction(tr("Add Symbolic Debug Marker"), this); menu.addAction(act); connect( act, SIGNAL(triggered(void)), parent, SLOT(asmViewCtxMenuAddSym(void)) ); - //connect( act, SIGNAL(triggered(void)), this, SLOT(addBookMarkCB(void)) ); + + act = new QAction(tr("Add Bookmark"), this); + menu.addAction(act); + connect( act, SIGNAL(triggered(void)), parent, SLOT(asmViewCtxMenuAddBM(void)) ); menu.exec(event->globalPos()); } diff --git a/src/drivers/Qt/ConsoleDebugger.h b/src/drivers/Qt/ConsoleDebugger.h index 03c73cdd..515b7cac 100644 --- a/src/drivers/Qt/ConsoleDebugger.h +++ b/src/drivers/Qt/ConsoleDebugger.h @@ -235,6 +235,7 @@ class ConsoleDebugger : public QDialog public slots: void closeWindow(void); void asmViewCtxMenuAddBP(void); + void asmViewCtxMenuAddBM(void); void asmViewCtxMenuAddSym(void); private slots: void updatePeriodic(void); From c2ca5dc9d8e1483c8002506e4a7f12ade9d733c7 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Sun, 20 Sep 2020 17:01:40 -0400 Subject: [PATCH 37/57] Added initial functions for hex editor quick access from debugger. --- src/drivers/Qt/ConsoleDebugger.cpp | 25 +++++++++++++++++++++++++ src/drivers/Qt/ConsoleDebugger.h | 1 + src/drivers/Qt/HexEditor.cpp | 28 ++++++++++++++++++++++++++++ src/drivers/Qt/HexEditor.h | 5 ++++- 4 files changed, 58 insertions(+), 1 deletion(-) diff --git a/src/drivers/Qt/ConsoleDebugger.cpp b/src/drivers/Qt/ConsoleDebugger.cpp index cb8479f2..cd68d794 100644 --- a/src/drivers/Qt/ConsoleDebugger.cpp +++ b/src/drivers/Qt/ConsoleDebugger.cpp @@ -38,6 +38,7 @@ #include "Qt/config.h" #include "Qt/nes_shm.h" #include "Qt/fceuWrapper.h" +#include "Qt/HexEditor.h" #include "Qt/ConsoleDebugger.h" #include "Qt/ConsoleUtilities.h" @@ -1604,6 +1605,26 @@ void ConsoleDebugger::asmViewCtxMenuAddBM(void) bmListUpdate(false); } //---------------------------------------------------------------------------- +void ConsoleDebugger::asmViewCtxMenuOpenHexEdit(void) +{ + int romAddr = -1; + int addr = asmView->getCtxMenuAddr(); + + if (addr >= 0x8000) + { + romAddr = GetNesFileAddress(addr); + } + + if ( romAddr >= 0 ) + { + hexEditorOpenFromDebugger( QHexEdit::MODE_NES_ROM, romAddr ); + } + else + { + hexEditorOpenFromDebugger( QHexEdit::MODE_NES_RAM, addr ); + } +} +//---------------------------------------------------------------------------- void ConsoleDebugger::setBookmarkSelectedAddress( int addr ) { char stmp[32]; @@ -2957,6 +2978,10 @@ void QAsmView::contextMenuEvent(QContextMenuEvent *event) menu.addAction(act); connect( act, SIGNAL(triggered(void)), parent, SLOT(asmViewCtxMenuAddBM(void)) ); + act = new QAction(tr("Open Hex Editor"), this); + menu.addAction(act); + connect( act, SIGNAL(triggered(void)), parent, SLOT(asmViewCtxMenuOpenHexEdit(void)) ); + menu.exec(event->globalPos()); } } diff --git a/src/drivers/Qt/ConsoleDebugger.h b/src/drivers/Qt/ConsoleDebugger.h index 515b7cac..7ee626ea 100644 --- a/src/drivers/Qt/ConsoleDebugger.h +++ b/src/drivers/Qt/ConsoleDebugger.h @@ -237,6 +237,7 @@ class ConsoleDebugger : public QDialog void asmViewCtxMenuAddBP(void); void asmViewCtxMenuAddBM(void); void asmViewCtxMenuAddSym(void); + void asmViewCtxMenuOpenHexEdit(void); private slots: void updatePeriodic(void); void hbarChanged(int value); diff --git a/src/drivers/Qt/HexEditor.cpp b/src/drivers/Qt/HexEditor.cpp index 1906fe7e..1fe9d45d 100644 --- a/src/drivers/Qt/HexEditor.cpp +++ b/src/drivers/Qt/HexEditor.cpp @@ -36,6 +36,7 @@ #include "Qt/fceuWrapper.h" #include "Qt/HexEditor.h" #include "Qt/ConsoleUtilities.h" +#include "Qt/ConsoleWindow.h" static HexBookMarkManager_t hbm; static std::list winList; @@ -1928,3 +1929,30 @@ void hexEditorSaveBookmarks(void) } } //---------------------------------------------------------------------------- +int hexEditorNumWindows(void) +{ + return winList.size(); +} +//---------------------------------------------------------------------------- +int hexEditorOpenFromDebugger( int mode, int addr ) +{ + HexEditorDialog_t *win = NULL; + + if ( winList.size() > 0 ) + { + win = winList.front(); + } + + if ( win == NULL ) + { + win = new HexEditorDialog_t(consoleWindow); + + win->show(); + } + + win->editor->setMode( mode ); + win->editor->setAddr( addr ); + + return 0; +} +//---------------------------------------------------------------------------- diff --git a/src/drivers/Qt/HexEditor.h b/src/drivers/Qt/HexEditor.h index 6c2623a0..cd861f6f 100644 --- a/src/drivers/Qt/HexEditor.h +++ b/src/drivers/Qt/HexEditor.h @@ -195,13 +195,14 @@ class HexEditorDialog_t : public QDialog void gotoAddress(int newAddr); void populateBookmarkMenu(void); + + QHexEdit *editor; protected: void closeEvent(QCloseEvent *bar); QScrollBar *vbar; QScrollBar *hbar; - QHexEdit *editor; QTimer *periodicTimer; QMenu *bookmarkMenu; @@ -227,5 +228,7 @@ class HexEditorDialog_t : public QDialog void removeAllBookmarks(void); }; +int hexEditorNumWindows(void); void hexEditorLoadBookmarks(void); void hexEditorSaveBookmarks(void); +int hexEditorOpenFromDebugger( int mode, int addr ); From a458f7526be8eae8c3a636c8ed162369627577ee Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Sun, 20 Sep 2020 21:03:41 -0400 Subject: [PATCH 38/57] Added logic to update hex editor title with view mode and selected address included in text. --- src/drivers/Qt/ConsoleDebugger.cpp | 10 +++--- src/drivers/Qt/HexEditor.cpp | 51 ++++++++++++++++++++++++++++-- src/drivers/Qt/HexEditor.h | 7 ++++ 3 files changed, 61 insertions(+), 7 deletions(-) diff --git a/src/drivers/Qt/ConsoleDebugger.cpp b/src/drivers/Qt/ConsoleDebugger.cpp index cd68d794..8b680e93 100644 --- a/src/drivers/Qt/ConsoleDebugger.cpp +++ b/src/drivers/Qt/ConsoleDebugger.cpp @@ -2967,19 +2967,19 @@ void QAsmView::contextMenuEvent(QContextMenuEvent *event) ctxMenuAddr = addr = asmEntry[line]->addr; act = new QAction(tr("Add Breakpoint"), this); - menu.addAction(act); + menu.addAction(act); connect( act, SIGNAL(triggered(void)), parent, SLOT(asmViewCtxMenuAddBP(void)) ); act = new QAction(tr("Add Symbolic Debug Marker"), this); - menu.addAction(act); + menu.addAction(act); connect( act, SIGNAL(triggered(void)), parent, SLOT(asmViewCtxMenuAddSym(void)) ); act = new QAction(tr("Add Bookmark"), this); - menu.addAction(act); + menu.addAction(act); connect( act, SIGNAL(triggered(void)), parent, SLOT(asmViewCtxMenuAddBM(void)) ); act = new QAction(tr("Open Hex Editor"), this); - menu.addAction(act); + menu.addAction(act); connect( act, SIGNAL(triggered(void)), parent, SLOT(asmViewCtxMenuOpenHexEdit(void)) ); menu.exec(event->globalPos()); @@ -3050,7 +3050,7 @@ void QAsmView::paintEvent(QPaintEvent *event) if ( selAddr == asmEntry[l]->addr ) { // Highlight ASM line for selected address. - if ( asmEntry[l]->type == dbg_asm_entry_t::ASM_TEXT ) + if ( !displayROMoffsets && (asmEntry[l]->type == dbg_asm_entry_t::ASM_TEXT) ) { int ax; char addrString[16]; diff --git a/src/drivers/Qt/HexEditor.cpp b/src/drivers/Qt/HexEditor.cpp index 1fe9d45d..8a20818a 100644 --- a/src/drivers/Qt/HexEditor.cpp +++ b/src/drivers/Qt/HexEditor.cpp @@ -538,12 +538,11 @@ HexEditorDialog_t::HexEditorDialog_t(QWidget *parent) QMenuBar *menuBar; QMenu *fileMenu, *viewMenu, *colorMenu; QAction *saveROM, *closeAct; - QAction *viewRAM, *viewPPU, *viewOAM, *viewROM; QAction *actHlgt, *actHlgtRV, *actColorFG, *actColorBG; QActionGroup *group; int useNativeMenuBar; - setWindowTitle("Hex Editor"); + QDialog::setWindowTitle( tr("Hex Editor") ); resize( 512, 512 ); @@ -738,6 +737,19 @@ HexEditorDialog_t::~HexEditorDialog_t(void) } } //---------------------------------------------------------------------------- +void HexEditorDialog_t::setWindowTitle(void) +{ + const char *modeString; + char stmp[128]; + + modeString = memViewNames[ editor->getMode() ]; + + sprintf( stmp, "Hex Editor - %s: 0x%04X", modeString, editor->getAddr() ); + + QDialog::setWindowTitle( tr(stmp) ); + +} +//---------------------------------------------------------------------------- void HexEditorDialog_t::removeAllBookmarks(void) { int ret; @@ -957,6 +969,36 @@ void HexEditorDialog_t::updatePeriodic(void) editor->memModeUpdate(); editor->update(); + + setWindowTitle(); + + switch ( editor->getMode() ) + { + case QHexEdit::MODE_NES_RAM: + if ( !viewRAM->isChecked() ) + { + viewRAM->setChecked(true); + } + break; + case QHexEdit::MODE_NES_PPU: + if ( !viewPPU->isChecked() ) + { + viewPPU->setChecked(true); + } + break; + case QHexEdit::MODE_NES_OAM: + if ( !viewOAM->isChecked() ) + { + viewOAM->setChecked(true); + } + break; + case QHexEdit::MODE_NES_ROM: + if ( !viewROM->isChecked() ) + { + viewROM->setChecked(true); + } + break; + } } //---------------------------------------------------------------------------- QHexEdit::QHexEdit(QWidget *parent) @@ -993,6 +1035,7 @@ QHexEdit::QHexEdit(QWidget *parent) lineOffset = 0; cursorPosX = 0; cursorPosY = 0; + cursorAddr = 0; cursorBlink = true; cursorBlinkCount = 0; maxLineOffset = 0; @@ -1733,6 +1776,9 @@ void QHexEdit::memModeUpdate(void) printf("Error: Failed to allocate memview buffer size\n"); return; } + maxLineOffset = mb.numLines() - viewLines + 1; + + vbar->setMaximum( memSize / 16 ); } } //---------------------------------------------------------------------------- @@ -1808,6 +1854,7 @@ void QHexEdit::paintEvent(QPaintEvent *event) ca = 16*(lineOffset + cursorPosY) + a; } + cursorAddr = ca; if ( cursorBlink ) { diff --git a/src/drivers/Qt/HexEditor.h b/src/drivers/Qt/HexEditor.h index cd861f6f..61262b96 100644 --- a/src/drivers/Qt/HexEditor.h +++ b/src/drivers/Qt/HexEditor.h @@ -114,6 +114,7 @@ class QHexEdit : public QWidget void setBackGroundColor( QColor bg ); void memModeUpdate(void); int checkMemActivity(void); + int getAddr(void){ return cursorAddr; }; enum { MODE_NES_RAM = 0, @@ -164,6 +165,7 @@ class QHexEdit : public QWidget int pxHexAscii; int cursorPosX; int cursorPosY; + int cursorAddr; int cursorBlinkCount; int viewLines; int viewWidth; @@ -195,6 +197,7 @@ class HexEditorDialog_t : public QDialog void gotoAddress(int newAddr); void populateBookmarkMenu(void); + void setWindowTitle(void); QHexEdit *editor; protected: @@ -205,6 +208,10 @@ class HexEditorDialog_t : public QDialog QScrollBar *hbar; QTimer *periodicTimer; QMenu *bookmarkMenu; + QAction *viewRAM; + QAction *viewPPU; + QAction *viewOAM; + QAction *viewROM; private: From 97784ec09bcce3a6dc9211572c125759939006f0 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Sun, 20 Sep 2020 21:40:31 -0400 Subject: [PATCH 39/57] Added quick breakpoint add via hex editor context menu. --- src/drivers/Qt/HexEditor.cpp | 150 +++++++++++++++++++++++++++++++++-- src/drivers/Qt/HexEditor.h | 5 ++ 2 files changed, 149 insertions(+), 6 deletions(-) diff --git a/src/drivers/Qt/HexEditor.cpp b/src/drivers/Qt/HexEditor.cpp index 8a20818a..76cd17de 100644 --- a/src/drivers/Qt/HexEditor.cpp +++ b/src/drivers/Qt/HexEditor.cpp @@ -1578,17 +1578,20 @@ void QHexEdit::contextMenuEvent(QContextMenuEvent *event) act = new QAction(tr("TODO Add Symbolic Debug Name"), this); menu.addAction(act); - sprintf( stmp, "TODO Add Read Breakpoint for Address $%04X", addr ); + sprintf( stmp, "Add Read Breakpoint for Address $%04X", addr ); act = new QAction(tr(stmp), this); - menu.addAction(act); + menu.addAction(act); + connect( act, SIGNAL(triggered(void)), this, SLOT(addRamReadBP(void)) ); - sprintf( stmp, "TODO Add Write Breakpoint for Address $%04X", addr ); + sprintf( stmp, "Add Write Breakpoint for Address $%04X", addr ); act = new QAction(tr(stmp), this); - menu.addAction(act); + menu.addAction(act); + connect( act, SIGNAL(triggered(void)), this, SLOT(addRamWriteBP(void)) ); - sprintf( stmp, "TODO Add Execute Breakpoint for Address $%04X", addr ); + sprintf( stmp, "Add Execute Breakpoint for Address $%04X", addr ); act = new QAction(tr(stmp), this); - menu.addAction(act); + menu.addAction(act); + connect( act, SIGNAL(triggered(void)), this, SLOT(addRamExecuteBP(void)) ); if ( addr > 0x6000 ) { @@ -1611,6 +1614,16 @@ void QHexEdit::contextMenuEvent(QContextMenuEvent *event) break; case MODE_NES_PPU: { + sprintf( stmp, "Add Read Breakpoint for Address $%04X", addr ); + act = new QAction(tr(stmp), this); + menu.addAction(act); + connect( act, SIGNAL(triggered(void)), this, SLOT(addPpuReadBP(void)) ); + + sprintf( stmp, "Add Write Breakpoint for Address $%04X", addr ); + act = new QAction(tr(stmp), this); + menu.addAction(act); + connect( act, SIGNAL(triggered(void)), this, SLOT(addPpuWriteBP(void)) ); + act = new QAction(tr("Add Bookmark"), this); menu.addAction(act); connect( act, SIGNAL(triggered(void)), this, SLOT(addBookMarkCB(void)) ); @@ -1674,6 +1687,131 @@ void QHexEdit::addBookMarkCB(void) } } //---------------------------------------------------------------------------- +void QHexEdit::addRamReadBP(void) +{ + int retval, type; + char cond[64], name[64]; + + type = BT_C | WP_R; + + cond[0] = 0; + name[0] = 0; + + if ( ctxAddr >= 0x8000 ) + { + sprintf(cond, "K==#%02X", getBank(ctxAddr)); + } + + retval = NewBreak( name, ctxAddr, -1, type, cond, numWPs, true); + + if ( (retval == 1) || (retval == 2) ) + { + printf("Breakpoint Add Failed\n"); + } + else + { + numWPs++; + } +} +//---------------------------------------------------------------------------- +void QHexEdit::addRamWriteBP(void) +{ + int retval, type; + char cond[64], name[64]; + + type = BT_C | WP_W; + + cond[0] = 0; + name[0] = 0; + + if ( ctxAddr >= 0x8000 ) + { + sprintf(cond, "K==#%02X", getBank(ctxAddr)); + } + + retval = NewBreak( name, ctxAddr, -1, type, cond, numWPs, true); + + if ( (retval == 1) || (retval == 2) ) + { + printf("Breakpoint Add Failed\n"); + } + else + { + numWPs++; + } +} +//---------------------------------------------------------------------------- +void QHexEdit::addRamExecuteBP(void) +{ + int retval, type; + char cond[64], name[64]; + + type = BT_C | WP_X; + + cond[0] = 0; + name[0] = 0; + + if ( ctxAddr >= 0x8000 ) + { + sprintf(cond, "K==#%02X", getBank(ctxAddr)); + } + + retval = NewBreak( name, ctxAddr, -1, type, cond, numWPs, true); + + if ( (retval == 1) || (retval == 2) ) + { + printf("Breakpoint Add Failed\n"); + } + else + { + numWPs++; + } +} +//---------------------------------------------------------------------------- +void QHexEdit::addPpuReadBP(void) +{ + int retval, type; + char cond[64], name[64]; + + type = BT_P | WP_R; + + cond[0] = 0; + name[0] = 0; + + retval = NewBreak( name, ctxAddr, -1, type, cond, numWPs, true); + + if ( (retval == 1) || (retval == 2) ) + { + printf("Breakpoint Add Failed\n"); + } + else + { + numWPs++; + } +} +//---------------------------------------------------------------------------- +void QHexEdit::addPpuWriteBP(void) +{ + int retval, type; + char cond[64], name[64]; + + type = BT_P | WP_W; + + cond[0] = 0; + name[0] = 0; + + retval = NewBreak( name, ctxAddr, -1, type, cond, numWPs, true); + + if ( (retval == 1) || (retval == 2) ) + { + printf("Breakpoint Add Failed\n"); + } + else + { + numWPs++; + } +} +//---------------------------------------------------------------------------- void QHexEdit::jumpToROM(void) { setMode( MODE_NES_ROM ); diff --git a/src/drivers/Qt/HexEditor.h b/src/drivers/Qt/HexEditor.h index 61262b96..8fe6a67a 100644 --- a/src/drivers/Qt/HexEditor.h +++ b/src/drivers/Qt/HexEditor.h @@ -184,6 +184,11 @@ class QHexEdit : public QWidget private slots: void jumpToROM(void); void addBookMarkCB(void); + void addRamReadBP(void); + void addRamWriteBP(void); + void addRamExecuteBP(void); + void addPpuReadBP(void); + void addPpuWriteBP(void); }; From a4b45fc2523d255459e14ca094485bd2fb5b37aa Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Sun, 20 Sep 2020 22:00:48 -0400 Subject: [PATCH 40/57] Added symbolic debug popup window capability to hex editor. --- src/drivers/Qt/ConsoleDebugger.cpp | 15 ++++ src/drivers/Qt/ConsoleDebugger.h | 2 + src/drivers/Qt/HexEditor.cpp | 138 ++++++++++++++++++++++++++++- src/drivers/Qt/HexEditor.h | 2 + 4 files changed, 156 insertions(+), 1 deletion(-) diff --git a/src/drivers/Qt/ConsoleDebugger.cpp b/src/drivers/Qt/ConsoleDebugger.cpp index 8b680e93..c0210468 100644 --- a/src/drivers/Qt/ConsoleDebugger.cpp +++ b/src/drivers/Qt/ConsoleDebugger.cpp @@ -2274,6 +2274,11 @@ void ConsoleDebugger::updateWindowData(void) windowUpdateReq = false; } //---------------------------------------------------------------------------- +void ConsoleDebugger::queueUpdate(void) +{ + windowUpdateReq = true; +} +//---------------------------------------------------------------------------- void ConsoleDebugger::updatePeriodic(void) { //printf("Update Periodic\n"); @@ -2395,6 +2400,16 @@ bool debuggerWindowIsOpen(void) return (dbgWinList.size() > 0); } //---------------------------------------------------------------------------- +void updateAllDebuggerWindows( void ) +{ + std::list ::iterator it; + + for (it=dbgWinList.begin(); it!=dbgWinList.end(); it++) + { + (*it)->queueUpdate(); + } +} +//---------------------------------------------------------------------------- static int getGameDebugBreakpointFileName(char *filepath) { int i,j; diff --git a/src/drivers/Qt/ConsoleDebugger.h b/src/drivers/Qt/ConsoleDebugger.h index 7ee626ea..51b6d40c 100644 --- a/src/drivers/Qt/ConsoleDebugger.h +++ b/src/drivers/Qt/ConsoleDebugger.h @@ -169,6 +169,7 @@ class ConsoleDebugger : public QDialog void setBookmarkSelectedAddress( int addr ); int getBookmarkSelectedAddress(void){ return selBmAddrVal; }; void edit_BM_name( int addr ); + void queueUpdate(void); QLabel *asmLineSelLbl; protected: @@ -279,5 +280,6 @@ bool debuggerWindowIsOpen(void); void saveGameDebugBreakpoints(void); void loadGameDebugBreakpoints(void); void debuggerClearAllBreakpoints(void); +void updateAllDebuggerWindows(void); extern debuggerBookmarkManager_t dbgBmMgr; diff --git a/src/drivers/Qt/HexEditor.cpp b/src/drivers/Qt/HexEditor.cpp index 76cd17de..ebb77223 100644 --- a/src/drivers/Qt/HexEditor.cpp +++ b/src/drivers/Qt/HexEditor.cpp @@ -35,6 +35,8 @@ #include "Qt/keyscan.h" #include "Qt/fceuWrapper.h" #include "Qt/HexEditor.h" +#include "Qt/SymbolicDebug.h" +#include "Qt/ConsoleDebugger.h" #include "Qt/ConsoleUtilities.h" #include "Qt/ConsoleWindow.h" @@ -960,6 +962,134 @@ void HexEditorDialog_t::actvHighlightRVCB(bool enable) editor->setHighlightReverseVideo( enable ); } //---------------------------------------------------------------------------- +void HexEditorDialog_t::openDebugSymbolEditWindow( int addr ) +{ + int ret, bank, charWidth; + QDialog dialog(this); + QHBoxLayout *hbox; + QVBoxLayout *mainLayout; + QLabel *lbl; + QLineEdit *filepath, *addrEntry, *nameEntry, *commentEntry; + QPushButton *okButton, *cancelButton; + char stmp[512]; + debugSymbol_t *sym; + QFont font; + font.setFamily("Courier New"); + font.setStyle( QFont::StyleNormal ); + font.setStyleHint( QFont::Monospace ); + + QFontMetrics fm(font); + +#if QT_VERSION > QT_VERSION_CHECK(5, 11, 0) + charWidth = fm.horizontalAdvance(QLatin1Char('2')); +#else + charWidth = fm.width(QLatin1Char('2')); +#endif + + if ( addr < 0x8000 ) + { + bank = -1; + } + else + { + bank = getBank( addr ); + } + + sym = debugSymbolTable.getSymbolAtBankOffset( bank, addr ); + + generateNLFilenameForAddress( addr, stmp ); + + dialog.setWindowTitle( tr("Symbolic Debug Naming") ); + + hbox = new QHBoxLayout(); + mainLayout = new QVBoxLayout(); + + lbl = new QLabel( tr("File") ); + filepath = new QLineEdit(); + filepath->setFont( font ); + filepath->setText( tr(stmp) ); + filepath->setReadOnly( true ); + filepath->setMinimumWidth( charWidth * (filepath->text().size() + 4) ); + + hbox->addWidget( lbl ); + hbox->addWidget( filepath ); + + mainLayout->addLayout( hbox ); + + sprintf( stmp, "%04X", addr ); + + hbox = new QHBoxLayout(); + lbl = new QLabel( tr("Address") ); + addrEntry = new QLineEdit(); + addrEntry->setFont( font ); + addrEntry->setText( tr(stmp) ); + addrEntry->setReadOnly( true ); + addrEntry->setAlignment(Qt::AlignCenter); + addrEntry->setMaximumWidth( charWidth * 6 ); + + hbox->addWidget( lbl ); + hbox->addWidget( addrEntry ); + + lbl = new QLabel( tr("Name") ); + nameEntry = new QLineEdit(); + + hbox->addWidget( lbl ); + hbox->addWidget( nameEntry ); + + mainLayout->addLayout( hbox ); + + hbox = new QHBoxLayout(); + lbl = new QLabel( tr("Comment") ); + commentEntry = new QLineEdit(); + + hbox->addWidget( lbl ); + hbox->addWidget( commentEntry ); + + mainLayout->addLayout( hbox ); + + hbox = new QHBoxLayout(); + okButton = new QPushButton( tr("OK") ); + cancelButton = new QPushButton( tr("Cancel") ); + + mainLayout->addLayout( hbox ); + hbox->addWidget( cancelButton ); + hbox->addWidget( okButton ); + + connect( okButton, SIGNAL(clicked(void)), &dialog, SLOT(accept(void)) ); + connect( cancelButton, SIGNAL(clicked(void)), &dialog, SLOT(reject(void)) ); + + if ( sym != NULL ) + { + nameEntry->setText( tr(sym->name.c_str()) ); + commentEntry->setText( tr(sym->comment.c_str()) ); + } + + dialog.setLayout( mainLayout ); + + ret = dialog.exec(); + + if ( ret == QDialog::Accepted ) + { + if ( sym == NULL ) + { + sym = new debugSymbol_t(); + sym->ofs = addr; + sym->name = nameEntry->text().toStdString(); + sym->comment = commentEntry->text().toStdString(); + + debugSymbolTable.addSymbolAtBankOffset( bank, addr, sym ); + } + else + { + sym->name = nameEntry->text().toStdString(); + sym->comment = commentEntry->text().toStdString(); + } + //fceuWrapperLock(); + updateAllDebuggerWindows(); + //fceuWrapperUnLock(); + } +} +//---------------------------------------------------------------------------- void HexEditorDialog_t::updatePeriodic(void) { //printf("Update Periodic\n"); @@ -1575,8 +1705,9 @@ void QHexEdit::contextMenuEvent(QContextMenuEvent *event) { case MODE_NES_RAM: { - act = new QAction(tr("TODO Add Symbolic Debug Name"), this); + act = new QAction(tr("Add Symbolic Debug Name"), this); menu.addAction(act); + connect( act, SIGNAL(triggered(void)), this, SLOT(addDebugSym(void)) ); sprintf( stmp, "Add Read Breakpoint for Address $%04X", addr ); act = new QAction(tr(stmp), this); @@ -1687,6 +1818,11 @@ void QHexEdit::addBookMarkCB(void) } } //---------------------------------------------------------------------------- +void QHexEdit::addDebugSym(void) +{ + parent->openDebugSymbolEditWindow( ctxAddr ); +} +//---------------------------------------------------------------------------- void QHexEdit::addRamReadBP(void) { int retval, type; diff --git a/src/drivers/Qt/HexEditor.h b/src/drivers/Qt/HexEditor.h index 8fe6a67a..04925bc6 100644 --- a/src/drivers/Qt/HexEditor.h +++ b/src/drivers/Qt/HexEditor.h @@ -184,6 +184,7 @@ class QHexEdit : public QWidget private slots: void jumpToROM(void); void addBookMarkCB(void); + void addDebugSym(void); void addRamReadBP(void); void addRamWriteBP(void); void addRamExecuteBP(void); @@ -203,6 +204,7 @@ class HexEditorDialog_t : public QDialog void gotoAddress(int newAddr); void populateBookmarkMenu(void); void setWindowTitle(void); + void openDebugSymbolEditWindow( int addr ); QHexEdit *editor; protected: From 7003f6c01a36c5d8c478f978960fd357a426e38e Mon Sep 17 00:00:00 2001 From: mjbudd77 Date: Thu, 24 Sep 2020 06:10:48 -0400 Subject: [PATCH 41/57] Added code to load/save debugger bookmarks in game specific debug files. --- src/drivers/Qt/ConsoleDebugger.cpp | 167 +++++++++++++++++++---------- 1 file changed, 110 insertions(+), 57 deletions(-) diff --git a/src/drivers/Qt/ConsoleDebugger.cpp b/src/drivers/Qt/ConsoleDebugger.cpp index c0210468..9462f4bf 100644 --- a/src/drivers/Qt/ConsoleDebugger.cpp +++ b/src/drivers/Qt/ConsoleDebugger.cpp @@ -2463,6 +2463,7 @@ void saveGameDebugBreakpoints(void) FILE *fp; char stmp[512]; char flags[8]; + debuggerBookmark_t *bm; // If no breakpoints are loaded, skip saving if ( numWPs == 0 ) @@ -2510,18 +2511,94 @@ void saveGameDebugBreakpoints(void) (watchpoint[i].desc != NULL) ? watchpoint[i].desc : ""); } + bm = dbgBmMgr.begin(); + + while ( bm != NULL ) + { + fprintf( fp, "Bookmark: addr=%04X desc=\"%s\" \n", bm->addr, bm->name.c_str() ); + + bm = dbgBmMgr.next(); + } + fclose(fp); return; } //---------------------------------------------------------------------------- +static int getKeyValuePair( int i, const char *stmp, char *id, char *data ) +{ + int j=0; + char literal=0; + + id[0] = 0; data[0] = 0; + + if ( stmp[i] == 0 ) return i; + + while ( isspace(stmp[i]) ) i++; + + j=0; + while ( isalnum(stmp[i]) ) + { + id[j] = stmp[i]; j++; i++; + } + id[j] = 0; + + if ( j == 0 ) + { + return i; + } + if ( stmp[i] != '=' ) + { + return i; + } + i++; j=0; + if ( stmp[i] == '\"' ) + { + literal = 0; + i++; + while ( stmp[i] != 0 ) + { + if ( literal ) + { + data[j] = stmp[i]; i++; j++; + literal = 0; + } + else + { + if ( stmp[i] == '\\' ) + { + literal = 1; i++; + } + else if ( stmp[i] == '\"' ) + { + i++; break; + } + else + { + data[j] = stmp[i]; j++; i++; + } + } + } + data[j] = 0; + } + else + { + j=0; + while ( !isspace(stmp[i]) ) + { + data[j] = stmp[i]; j++; i++; + } + data[j] = 0; + } + return i; +} +//---------------------------------------------------------------------------- void loadGameDebugBreakpoints(void) { int i,j; FILE *fp; char stmp[512]; char id[64], data[128]; - char literal; // If no debug windows are open, skip loading breakpoints if ( dbgWinList.size() == 0 ) @@ -2572,62 +2649,7 @@ void loadGameDebugBreakpoints(void) while ( stmp[i] != 0 ) { - while ( isspace(stmp[i]) ) i++; - - j=0; - while ( isalnum(stmp[i]) ) - { - id[j] = stmp[i]; j++; i++; - } - id[j] = 0; - - if ( j == 0 ) - { - break; - } - if ( stmp[i] != '=' ) - { - break; - } - i++; j=0; - if ( stmp[i] == '\"' ) - { - literal = 0; - i++; - while ( stmp[i] != 0 ) - { - if ( literal ) - { - data[j] = stmp[i]; i++; j++; - literal = 0; - } - else - { - if ( stmp[i] == '\\' ) - { - literal = 1; i++; - } - else if ( stmp[i] == '\"' ) - { - i++; break; - } - else - { - data[j] = stmp[i]; j++; i++; - } - } - } - data[j] = 0; - } - else - { - j=0; - while ( !isspace(stmp[i]) ) - { - data[j] = stmp[i]; j++; i++; - } - data[j] = 0; - } + i = getKeyValuePair( i, stmp, id, data ); //printf("ID:'%s' DATA:'%s' \n", id, data ); @@ -2686,6 +2708,37 @@ void loadGameDebugBreakpoints(void) } } } + else if ( strcmp( id, "Bookmark" ) == 0 ) + { + int addr = -1; + char desc[256]; + + desc[0] = 0; + + while ( stmp[i] != 0 ) + { + i = getKeyValuePair( i, stmp, id, data ); + + //printf("ID:'%s' DATA:'%s' \n", id, data ); + + if ( strcmp( id, "addr" ) == 0 ) + { + addr = strtol( data, NULL, 16 ); + } + else if ( strcmp( id, "desc" ) == 0 ) + { + strcpy( desc, data ); + } + } + + if ( addr >= 0 ) + { + if ( dbgBmMgr.addBookmark( addr, desc ) ) + { + printf("Error:Failed to add debug bookmark: $%04X '%s' \n", addr, desc ); + } + } + } } fclose(fp); From 55e34bd0c86bc6aa92a1fe9f967dc20533c02be6 Mon Sep 17 00:00:00 2001 From: Alexey 'Cluster' Avdyukhin Date: Fri, 25 Sep 2020 20:07:07 +0300 Subject: [PATCH 42/57] Header editor bugfix --- src/drivers/win/header_editor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/drivers/win/header_editor.cpp b/src/drivers/win/header_editor.cpp index 797e4b52..d9fba610 100644 --- a/src/drivers/win/header_editor.cpp +++ b/src/drivers/win/header_editor.cpp @@ -628,7 +628,7 @@ void SetHeaderData(HWND hwnd, iNES_HEADER* header) { // Mapper# int mapper = header->ROM_type >> 4 | header->ROM_type2 & 0xF0; if (ines20) - mapper |= (header->ROM_type3 & 0xF0) << 4; + mapper |= (header->ROM_type3 & 0x0F) << 8; sprintf(buf, "%d ", mapper); if (SendDlgItemMessage(hwnd, IDC_MAPPER_COMBO, CB_SELECTSTRING, 0, (LPARAM)buf) == CB_ERR) SetDlgItemText(hwnd, IDC_MAPPER_COMBO, buf); From 086d523566cff669db2a1534bce248ce6d757ee7 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Sun, 27 Sep 2020 10:59:24 -0400 Subject: [PATCH 43/57] Added initial code data logger window layout for Qt GUI. --- src/CMakeLists.txt | 1 + src/drivers/Qt/CodeDataLogger.cpp | 168 ++++++++++++++++++++++++++++++ src/drivers/Qt/CodeDataLogger.h | 48 +++++++++ src/drivers/Qt/ConsoleWindow.cpp | 22 +++- src/drivers/Qt/ConsoleWindow.h | 2 + 5 files changed, 240 insertions(+), 1 deletion(-) create mode 100644 src/drivers/Qt/CodeDataLogger.cpp create mode 100644 src/drivers/Qt/CodeDataLogger.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0e90b19b..04c266e1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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 diff --git a/src/drivers/Qt/CodeDataLogger.cpp b/src/drivers/Qt/CodeDataLogger.cpp new file mode 100644 index 00000000..4ec7a510 --- /dev/null +++ b/src/drivers/Qt/CodeDataLogger.cpp @@ -0,0 +1,168 @@ +// CodeDataLogger.cpp +// +#include +#include +#include + +#include "Qt/CodeDataLogger.h" +#include "Qt/main.h" +#include "Qt/dface.h" +#include "Qt/input.h" +#include "Qt/config.h" +#include "Qt/fceuWrapper.h" + +//---------------------------------------------------- +CodeDataLoggerDialog_t::CodeDataLoggerDialog_t(QWidget *parent) + : QDialog( parent ) +{ + QVBoxLayout *mainLayout, *vbox1, *vbox; + QHBoxLayout *hbox; + QGridLayout *grid; + QGroupBox *frame, *subframe; + QPushButton *btn; + QLabel *lbl; + + updateTimer = new QTimer( this ); + + connect( updateTimer, &QTimer::timeout, this, &CodeDataLoggerDialog_t::updatePeriodic ); + + setWindowTitle( tr("Code Data Logger") ); + + mainLayout = new QVBoxLayout(); + vbox1 = new QVBoxLayout(); + grid = new QGridLayout(); + lbl = new QLabel( tr("Press Start to Run Logger") ); + cdlFileLabel = new QLabel( tr("CDL File:") ); + + vbox1->addLayout( grid ); + vbox1->addWidget( lbl ); + vbox1->addWidget( cdlFileLabel ); + + frame = new QGroupBox(tr("Code/Data Log Status")); + frame->setLayout( vbox1 ); + + prgLoggedCodeLabel = new QLabel( tr("0x00000 0.00%") ); + prgLoggedDataLabel = new QLabel( tr("0x00000 0.00%") ); + prgUnloggedLabel = new QLabel( tr("0x00000 0.00%") ); + chrLoggedCodeLabel = new QLabel( tr("0x00000 0.00%") ); + chrLoggedDataLabel = new QLabel( tr("0x00000 0.00%") ); + chrUnloggedLabel = new QLabel( tr("0x00000 0.00%") ); + 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") ); + + 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 ); + + btn = new QPushButton( tr("Start") ); + grid->addWidget( btn, 0, 1, Qt::AlignCenter ); + + btn = new QPushButton( tr("Save") ); + grid->addWidget( btn, 0, 2, Qt::AlignCenter ); + + btn = new QPushButton( tr("Load") ); + grid->addWidget( btn, 1, 0, Qt::AlignCenter ); + + btn = new QPushButton( tr("Save As") ); + grid->addWidget( btn, 1, 2, Qt::AlignCenter ); + + 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 ); + btn = new QPushButton( tr("Save Unused Data") ); + vbox->addWidget( btn ); + subframe->setLayout( vbox ); + hbox->addWidget( subframe ); + + mainLayout->addWidget( frame ); + + setLayout( mainLayout ); + + updateTimer->start( 100 ); // 10hz + +} +//---------------------------------------------------- +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::updatePeriodic(void) +{ + +} +//---------------------------------------------------- diff --git a/src/drivers/Qt/CodeDataLogger.h b/src/drivers/Qt/CodeDataLogger.h new file mode 100644 index 00000000..301e710e --- /dev/null +++ b/src/drivers/Qt/CodeDataLogger.h @@ -0,0 +1,48 @@ +// CodeDataLogger.h +// + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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; + QCheckBox *autoSaveCdlCbox; + QCheckBox *autoLoadCdlCbox; + QCheckBox *autoResumeLogCbox; + void closeEvent(QCloseEvent *bar); + private: + + public slots: + void closeWindow(void); + private slots: + void updatePeriodic(void); + +}; + diff --git a/src/drivers/Qt/ConsoleWindow.cpp b/src/drivers/Qt/ConsoleWindow.cpp index 9e06722e..44e701e1 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/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() ); diff --git a/src/drivers/Qt/ConsoleWindow.h b/src/drivers/Qt/ConsoleWindow.h index e2f16e33..501c018a 100644 --- a/src/drivers/Qt/ConsoleWindow.h +++ b/src/drivers/Qt/ConsoleWindow.h @@ -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); From 445b17104a7ed12ab01aacb4f82ec17b905a635e Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Mon, 28 Sep 2020 21:23:47 -0400 Subject: [PATCH 44/57] Successful initial test of Qt Code/Data Logger Window. --- src/debug.cpp | 8 +- src/drivers/Qt/CodeDataLogger.cpp | 386 +++++++++++++++++++++++++++- src/drivers/Qt/CodeDataLogger.h | 41 ++- src/drivers/Qt/ConsoleUtilities.cpp | 60 +++++ src/drivers/Qt/ConsoleUtilities.h | 2 + src/drivers/Qt/config.cpp | 5 + src/drivers/Qt/fceuWrapper.cpp | 21 +- src/ppu.h | 4 + 8 files changed, 496 insertions(+), 31 deletions(-) diff --git a/src/debug.cpp b/src/debug.cpp index 47e873ed..89bcafa8 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -421,12 +421,12 @@ int condition(watchpointinfo* wp) //--------------------- -volatile int codecount, datacount, undefinedcount; -unsigned char *cdloggerdata; +volatile int codecount = 0, datacount = 0, undefinedcount = 0; +unsigned char *cdloggerdata = NULL; unsigned int cdloggerdataSize = 0; -static int indirectnext; +static int indirectnext = 0; -int debug_loggingCD; +int debug_loggingCD = 0; //called by the cpu to perform logging if CDLogging is enabled void LogCDVectors(int which){ diff --git a/src/drivers/Qt/CodeDataLogger.cpp b/src/drivers/Qt/CodeDataLogger.cpp index 4ec7a510..55e6a584 100644 --- a/src/drivers/Qt/CodeDataLogger.cpp +++ b/src/drivers/Qt/CodeDataLogger.cpp @@ -4,6 +4,14 @@ #include #include +#include "../../types.h" +#include "../../fceu.h" +#include "../../cart.h" +#include "../../x6502.h" +#include "../../debug.h" +#include "../../ppu.h" + +#include "Qt/ConsoleUtilities.h" #include "Qt/CodeDataLogger.h" #include "Qt/main.h" #include "Qt/dface.h" @@ -11,6 +19,12 @@ #include "Qt/config.h" #include "Qt/fceuWrapper.h" +static int autoSaveCDL = true; +static int autoLoadCDL = true; +static int autoResumeCDL = false; +static char loadedcdfile[512] = {0}; + +static int getDefaultCDLFile( char *filepath ); //---------------------------------------------------- CodeDataLoggerDialog_t::CodeDataLoggerDialog_t(QWidget *parent) : QDialog( parent ) @@ -20,7 +34,6 @@ CodeDataLoggerDialog_t::CodeDataLoggerDialog_t(QWidget *parent) QGridLayout *grid; QGroupBox *frame, *subframe; QPushButton *btn; - QLabel *lbl; updateTimer = new QTimer( this ); @@ -30,27 +43,42 @@ CodeDataLoggerDialog_t::CodeDataLoggerDialog_t(QWidget *parent) mainLayout = new QVBoxLayout(); vbox1 = new QVBoxLayout(); + hbox = new QHBoxLayout(); grid = new QGridLayout(); - lbl = new QLabel( tr("Press Start to Run Logger") ); + statLabel = new QLabel( tr(" Logger is Paused: Press Start to Run ") ); cdlFileLabel = new QLabel( tr("CDL File:") ); vbox1->addLayout( grid ); - vbox1->addWidget( lbl ); + vbox1->addLayout( hbox ); vbox1->addWidget( cdlFileLabel ); + hbox->addWidget( statLabel, 0, Qt::AlignHCenter ); + frame = new QGroupBox(tr("Code/Data Log Status")); frame->setLayout( vbox1 ); - prgLoggedCodeLabel = new QLabel( tr("0x00000 0.00%") ); - prgLoggedDataLabel = new QLabel( tr("0x00000 0.00%") ); - prgUnloggedLabel = new QLabel( tr("0x00000 0.00%") ); - chrLoggedCodeLabel = new QLabel( tr("0x00000 0.00%") ); - chrLoggedDataLabel = new QLabel( tr("0x00000 0.00%") ); - chrUnloggedLabel = new QLabel( tr("0x00000 0.00%") ); + prgLoggedCodeLabel = new QLabel( tr("0x000000 0.00%") ); + prgLoggedDataLabel = new QLabel( tr("0x000000 0.00%") ); + prgUnloggedLabel = new QLabel( tr("0x000000 0.00%") ); + chrLoggedCodeLabel = new QLabel( tr("0x000000 0.00%") ); + chrLoggedDataLabel = new QLabel( tr("0x000000 0.00%") ); + chrUnloggedLabel = new QLabel( tr("0x000000 0.00%") ); autoSaveCdlCbox = new QCheckBox( tr("Auto-save .CDL when closing ROMs") ); autoLoadCdlCbox = new QCheckBox( tr("Auto-load .CDL when opening this window") ); autoResumeLogCbox = new QCheckBox( tr("Auto-resume logging when loading ROMs") ); + g_config->getOption("SDL.AutoSaveCDL", &autoSaveCDL); + g_config->getOption("SDL.AutoLoadCDL", &autoLoadCDL); + g_config->getOption("SDL.AutoResumeCDL", &autoResumeCDL); + + autoSaveCdlCbox->setChecked( autoSaveCDL ); + autoLoadCdlCbox->setChecked( autoLoadCDL ); + autoResumeLogCbox->setChecked( autoResumeCDL ); + + connect(autoSaveCdlCbox , SIGNAL(stateChanged(int)), this, SLOT(autoSaveCdlStateChange(int)) ); + connect(autoLoadCdlCbox , SIGNAL(stateChanged(int)), this, SLOT(autoLoadCdlStateChange(int)) ); + connect(autoResumeLogCbox, SIGNAL(stateChanged(int)), this, SLOT(autoResumeCdlStateChange(int)) ); + subframe = new QGroupBox(tr("PRG Logged as Code")); vbox = new QVBoxLayout(); vbox->addWidget( prgLoggedCodeLabel ); @@ -97,9 +125,11 @@ CodeDataLoggerDialog_t::CodeDataLoggerDialog_t(QWidget *parent) vbox1->addLayout( grid ); btn = new QPushButton( tr("Reset Log") ); grid->addWidget( btn, 0, 0, Qt::AlignCenter ); + connect( btn, SIGNAL(clicked(void)), this, SLOT(ResetCDLogClicked(void))); - btn = new QPushButton( tr("Start") ); - grid->addWidget( btn, 0, 1, Qt::AlignCenter ); + startPauseButton = new QPushButton( tr("Start") ); + grid->addWidget( startPauseButton, 0, 1, Qt::AlignCenter ); + connect( startPauseButton, SIGNAL(clicked(void)), this, SLOT(StartPauseCDLogClicked(void))); btn = new QPushButton( tr("Save") ); grid->addWidget( btn, 0, 2, Qt::AlignCenter ); @@ -137,6 +167,12 @@ CodeDataLoggerDialog_t::CodeDataLoggerDialog_t(QWidget *parent) updateTimer->start( 100 ); // 10hz + if (autoLoadCDL) + { + char nameo[2048]; + getDefaultCDLFile( nameo ); + LoadCDLog(nameo); + } } //---------------------------------------------------- CodeDataLoggerDialog_t::~CodeDataLoggerDialog_t(void) @@ -161,8 +197,334 @@ void CodeDataLoggerDialog_t::closeWindow(void) deleteLater(); } //---------------------------------------------------- -void CodeDataLoggerDialog_t::updatePeriodic(void) +void CodeDataLoggerDialog_t::autoSaveCdlStateChange(int state) { + autoSaveCDL = state != Qt::Unchecked; + g_config->setOption("SDL.AutoSaveCDL", autoSaveCDL); +} +//---------------------------------------------------- +void CodeDataLoggerDialog_t::autoLoadCdlStateChange(int state) +{ + autoLoadCDL = state != Qt::Unchecked; + + g_config->setOption("SDL.AutoLoadCDL", autoLoadCDL); +} +//---------------------------------------------------- +void CodeDataLoggerDialog_t::autoResumeCdlStateChange(int state) +{ + autoResumeCDL = state != Qt::Unchecked; + + g_config->setOption("SDL.AutoResumeCDL", autoResumeCDL); +} +//---------------------------------------------------- +void CodeDataLoggerDialog_t::updatePeriodic(void) +{ + char str[768]; + float fcodecount = codecount; + float fdatacount = datacount; + float frendercount = rendercount; + float fvromreadcount = vromreadcount; + float fundefinedcount = undefinedcount; + float fundefinedvromcount = undefinedvromcount; + float fromsize = cdloggerdataSize; + float fvromsize = (cdloggerVideoDataSize != 0) ? cdloggerVideoDataSize : 1; + + if ( FCEUI_GetLoggingCD() ) + { + startPauseButton->setText( tr("Pause") ); + statLabel->setText( tr(" Logger is Running: Press Pause to Stop ") ); + statLabel->setStyleSheet("background-color: green; color: white;"); + } + else + { + startPauseButton->setText( tr("Start") ); + statLabel->setText( tr(" Logger is Paused: Press Start to Run ") ); + statLabel->setStyleSheet("background-color: red; color: white;"); + } + + if ( cdloggerdataSize > 0 ) + { + sprintf(str,"0x%06x %.2f%%", codecount, (fcodecount / fromsize) * 100); + prgLoggedCodeLabel->setText( tr(str) ); + + sprintf(str,"0x%06x %.2f%%", datacount,(fdatacount / fromsize) * 100); + prgLoggedDataLabel->setText( tr(str) ); + + sprintf(str,"0x%06x %.2f%%", undefinedcount, (fundefinedcount / fromsize) * 100); + prgUnloggedLabel->setText( tr(str) ); + + sprintf(str,"0x%06x %.2f%%", rendercount, (frendercount / fvromsize) * 100); + chrLoggedCodeLabel->setText( tr(str) ); + + sprintf(str,"0x%06x %.2f%%", vromreadcount, (fvromreadcount / fvromsize) * 100); + chrLoggedDataLabel->setText( tr(str) ); + + sprintf(str,"0x%06x %.2f%%", undefinedvromcount, (fundefinedvromcount / fvromsize) * 100); + chrUnloggedLabel->setText( tr(str) ); + } + else + { + prgLoggedCodeLabel->setText( tr("------") ); + prgLoggedDataLabel->setText( tr("------") ); + prgUnloggedLabel->setText( tr("------") ); + chrLoggedCodeLabel->setText( tr("------") ); + chrLoggedDataLabel->setText( tr("------") ); + chrUnloggedLabel->setText( tr("------") ); + } + + sprintf( str, "CDL File: %s", loadedcdfile ); + + cdlFileLabel->setText( tr(str) ); +} +//---------------------------------------------------- +void CodeDataLoggerDialog_t::ResetCDLogClicked(void) +{ + ::ResetCDLog(); +} +//---------------------------------------------------- +void CodeDataLoggerDialog_t::StartPauseCDLogClicked(void) +{ + if ( FCEUI_GetLoggingCD() ) + { + printf("CD Logging Paused\n"); + PauseCDLogging(); + startPauseButton->setText( tr("Start") ); + } + else + { + printf("CD Logging Started\n"); + StartCDLogging(); + startPauseButton->setText( tr("Pause") ); + } +} +//---------------------------------------------------- +static int getDefaultCDLFile( char *filepath ) +{ + const char *romFile; + char dir[512], baseFile[256]; + + filepath[0] = 0; + + romFile = getRomFile(); + + if ( romFile == NULL ) + { + return -1; + } + + parseFilepath( romFile, dir, baseFile ); + + sprintf( filepath, "%s/%s.cdl", dir, baseFile ); + + //printf("%s\n", filepath ); + + return 0; +} +//---------------------------------------------------- +void FreeCDLog(void) +{ + fceuWrapperLock(); + if (cdloggerdata) + { + free(cdloggerdata); + cdloggerdata = NULL; + cdloggerdataSize = 0; + } + if (cdloggervdata) + { + free(cdloggervdata); + cdloggervdata = NULL; + cdloggerVideoDataSize = 0; + } + fceuWrapperUnLock(); +} +//---------------------------------------------------- +void InitCDLog(void) +{ + fceuWrapperLock(); + cdloggerdataSize = PRGsize[0]; + cdloggerdata = (unsigned char*)malloc(cdloggerdataSize); + if (!CHRram[0] || (CHRptr[0] == PRGptr[0])) { // Some kind of workaround for my OneBus VRAM hack, will remove it if I find another solution for that + cdloggerVideoDataSize = CHRsize[0]; + cdloggervdata = (unsigned char*)malloc(cdloggerVideoDataSize); + } else { + if (GameInfo->type != GIT_NSF) { + cdloggerVideoDataSize = 0; + cdloggervdata = (unsigned char*)malloc(8192); + } + } + fceuWrapperUnLock(); +} +//---------------------------------------------------- +void ResetCDLog(void) +{ + if ( GameInfo == NULL ) + { + return; + } + fceuWrapperLock(); + + codecount = datacount = rendercount = vromreadcount = 0; + undefinedcount = cdloggerdataSize; + + if ( cdloggerdata != NULL ) + { + memset(cdloggerdata, 0, cdloggerdataSize); + } + if (cdloggerVideoDataSize != 0) + { + undefinedvromcount = cdloggerVideoDataSize; + + if ( cdloggervdata != NULL ) + { + memset(cdloggervdata, 0, cdloggerVideoDataSize); + } + } + else + { + if (GameInfo->type != GIT_NSF) + { + undefinedvromcount = 8192; + memset(cdloggervdata, 0, 8192); + } + } + fceuWrapperUnLock(); +} +//---------------------------------------------------- +bool LoadCDLog(const char* nameo) +{ + FILE *FP; + int i,j; + + FP = fopen(nameo, "rb"); + if (FP == NULL) + return false; + + for(i = 0;i < (int)cdloggerdataSize;i++) + { + j = fgetc(FP); + if (j == EOF) + break; + if ((j & 1) && !(cdloggerdata[i] & 1)) + codecount++; //if the new byte has something logged and + if ((j & 2) && !(cdloggerdata[i] & 2)) + datacount++; //and the old one doesn't. Then increment + if ((j & 3) && !(cdloggerdata[i] & 3)) + undefinedcount--; //the appropriate counter. + cdloggerdata[i] |= j; + } + + if(cdloggerVideoDataSize != 0) + { + for(i = 0;i < (int)cdloggerVideoDataSize;i++) + { + j = fgetc(FP); + if(j == EOF)break; + if((j & 1) && !(cdloggervdata[i] & 1))rendercount++; //if the new byte has something logged and + if((j & 2) && !(cdloggervdata[i] & 2))vromreadcount++; //if the new byte has something logged and + if((j & 3) && !(cdloggervdata[i] & 3))undefinedvromcount--; //the appropriate counter. + cdloggervdata[i] |= j; + } + } + + fclose(FP); + RenameCDLog(nameo); + + return true; +} +//---------------------------------------------------- +void StartCDLogging(void) +{ + fceuWrapperLock(); + FCEUI_SetLoggingCD(1); + //EnableTracerMenuItems(); + //SetDlgItemText(hCDLogger, BTN_CDLOGGER_START_PAUSE, "Pause"); + fceuWrapperUnLock(); +} +//---------------------------------------------------- +bool PauseCDLogging(void) +{ + // can't pause while Trace Logger is using + //if ((logging) && (logging_options & LOG_NEW_INSTRUCTIONS)) + //{ + // MessageBox(hCDLogger, "The Trace Logger is currently using this for some of its features.\nPlease turn the Trace Logger off and try again.","Unable to Pause Code/Data Logger", MB_OK); + // return false; + //} + fceuWrapperLock(); + FCEUI_SetLoggingCD(0); + //EnableTracerMenuItems(); + //SetDlgItemText(hCDLogger, BTN_CDLOGGER_START_PAUSE, "Start"); + fceuWrapperUnLock(); + return true; +} +//---------------------------------------------------- +void CDLoggerROMClosed(void) +{ + PauseCDLogging(); + if (autoSaveCDL) + { + SaveCDLogFile(); + } +} +//---------------------------------------------------- +void CDLoggerROMChanged(void) +{ + FreeCDLog(); + InitCDLog(); + ResetCDLog(); + RenameCDLog(""); + + if (!autoResumeCDL) + return; + + // try to load respective CDL file + char nameo[1024]; + getDefaultCDLFile( nameo ); + + FILE *FP; + FP = fopen(nameo, "rb"); + if (FP != NULL) + { + // .cdl file with this ROM name exists + fclose(FP); + //if (!hCDLogger) + //{ + // DoCDLogger(); + //} + if (LoadCDLog(nameo)) + { + StartCDLogging(); + } + } +} +//---------------------------------------------------- +void RenameCDLog(const char* newName) +{ + strcpy(loadedcdfile, newName); +} +//---------------------------------------------------- +void SaveCDLogFile(void) +{ + if (loadedcdfile[0] == 0) + { + char nameo[1024]; + getDefaultCDLFile( nameo ); + RenameCDLog(nameo); + } + + FILE *FP; + FP = fopen(loadedcdfile, "wb"); + if (FP == NULL) + { + FCEUD_PrintError("Error Saving File"); + return; + } + fwrite(cdloggerdata, cdloggerdataSize, 1, FP); + if (cdloggerVideoDataSize != 0) + { + fwrite(cdloggervdata, cdloggerVideoDataSize, 1, FP); + } + fclose(FP); } //---------------------------------------------------- diff --git a/src/drivers/Qt/CodeDataLogger.h b/src/drivers/Qt/CodeDataLogger.h index 301e710e..c1782041 100644 --- a/src/drivers/Qt/CodeDataLogger.h +++ b/src/drivers/Qt/CodeDataLogger.h @@ -25,24 +25,43 @@ class CodeDataLoggerDialog_t : public QDialog ~CodeDataLoggerDialog_t(void); protected: - QTimer *updateTimer; - QLabel *prgLoggedCodeLabel; - QLabel *prgLoggedDataLabel; - QLabel *prgUnloggedLabel; - QLabel *chrLoggedCodeLabel; - QLabel *chrLoggedDataLabel; - QLabel *chrUnloggedLabel; - QLabel *cdlFileLabel; - QCheckBox *autoSaveCdlCbox; - QCheckBox *autoLoadCdlCbox; - QCheckBox *autoResumeLogCbox; + QTimer *updateTimer; + QLabel *prgLoggedCodeLabel; + QLabel *prgLoggedDataLabel; + QLabel *prgUnloggedLabel; + QLabel *chrLoggedCodeLabel; + QLabel *chrLoggedDataLabel; + QLabel *chrUnloggedLabel; + QLabel *cdlFileLabel; + QLabel *statLabel; + QCheckBox *autoSaveCdlCbox; + QCheckBox *autoLoadCdlCbox; + QCheckBox *autoResumeLogCbox; + QPushButton *startPauseButton; void closeEvent(QCloseEvent *bar); + private: public slots: void closeWindow(void); private slots: void updatePeriodic(void); + void ResetCDLogClicked(void); + void StartPauseCDLogClicked(void); + void autoSaveCdlStateChange(int state); + void autoLoadCdlStateChange(int state); + void autoResumeCdlStateChange(int state); }; +void InitCDLog(void); +void ResetCDLog(void); +void FreeCDLog(void); +void StartCDLogging(void); +bool PauseCDLogging(void); +bool LoadCDLog(const char* nameo); +void RenameCDLog(const char* newName); +void CDLoggerROMClosed(void); +void CDLoggerROMChanged(void); +void SaveCDLogFile(void); + diff --git a/src/drivers/Qt/ConsoleUtilities.cpp b/src/drivers/Qt/ConsoleUtilities.cpp index d118dd7d..c9fa3a48 100644 --- a/src/drivers/Qt/ConsoleUtilities.cpp +++ b/src/drivers/Qt/ConsoleUtilities.cpp @@ -83,3 +83,63 @@ int getFileBaseName( const char *filepath, char *base ) return end; } //--------------------------------------------------------------------------- +int parseFilepath( const char *filepath, char *dir, char *base, char *suffix ) +{ + int i=0,j=0,end=0; + if ( filepath == NULL ) + { + base[0] = 0; + return 0; + } + i=0; j=0; + while ( filepath[i] != 0 ) + { + if ( (filepath[i] == '/') || (filepath[i] == '\\') ) + { + j = i+1; + } + if ( dir ) + { + dir[i] = filepath[i]; + } + i++; + } + if ( dir ) + { + dir[j] = 0; + } + i = j; + + if ( base == NULL ) + { + return end; + } + + j=0; + while ( filepath[i] != 0 ) + { + base[j] = filepath[i]; i++; j++; + } + base[j] = 0; end=j; + + if ( suffix ) + { + suffix[0] = 0; + } + + while ( j > 1 ) + { + j--; + if ( base[j] == '.' ) + { + if ( suffix ) + { + strcpy( suffix, &base[j] ); + } + end=j; base[j] = 0; + break; + } + } + return end; +} +//--------------------------------------------------------------------------- diff --git a/src/drivers/Qt/ConsoleUtilities.h b/src/drivers/Qt/ConsoleUtilities.h index e55e0361..12838ddc 100644 --- a/src/drivers/Qt/ConsoleUtilities.h +++ b/src/drivers/Qt/ConsoleUtilities.h @@ -5,3 +5,5 @@ int getDirFromFile( const char *path, char *dir ); const char *getRomFile( void ); int getFileBaseName( const char *filepath, char *base ); + +int parseFilepath( const char *filepath, char *dir, char *base, char *suffix = NULL ); diff --git a/src/drivers/Qt/config.cpp b/src/drivers/Qt/config.cpp index 3fec6409..35d6b0f2 100644 --- a/src/drivers/Qt/config.cpp +++ b/src/drivers/Qt/config.cpp @@ -263,6 +263,11 @@ InitConfig() config->addOption("autoLoadDebugFiles", "SDL.AutoLoadDebugFiles", 1); config->addOption("autoOpenDebugger" , "SDL.AutoOpenDebugger" , 0); + // Code Data Logger Options + config->addOption("autoSaveCDL" , "SDL.AutoSaveCDL", 1); + config->addOption("autoLoadCDL" , "SDL.AutoLoadCDL", 1); + config->addOption("autoResumeCDL", "SDL.AutoResumeCDL", 0); + // overwrite the config file? config->addOption("no-config", "SDL.NoConfig", 0); diff --git a/src/drivers/Qt/fceuWrapper.cpp b/src/drivers/Qt/fceuWrapper.cpp index f618991f..0f204e16 100644 --- a/src/drivers/Qt/fceuWrapper.cpp +++ b/src/drivers/Qt/fceuWrapper.cpp @@ -16,6 +16,7 @@ #include "Qt/unix-netplay.h" #include "Qt/HexEditor.h" #include "Qt/SymbolicDebug.h" +#include "Qt/CodeDataLogger.h" #include "Qt/ConsoleDebugger.h" #include "Qt/ConsoleWindow.h" #include "Qt/fceux_git_info.h" @@ -247,6 +248,8 @@ int LoadGame(const char *path) debugSymbolTable.loadGameSymbols(); + CDLoggerROMChanged(); + int state_to_load; g_config->getOption("SDL.AutoLoadState", &state_to_load); if (state_to_load >= 0 && state_to_load < 10){ @@ -299,6 +302,7 @@ CloseGame(void) debugSymbolTable.save(); debugSymbolTable.clear(); + CDLoggerROMClosed(); int state_to_save; g_config->getOption("SDL.AutoSaveState", &state_to_save); @@ -946,17 +950,23 @@ static void DoFun(int frameskip, int periodic_saves) void fceuWrapperLock(void) { mutexPending++; - consoleWindow->mutex->lock(); + if ( consoleWindow != NULL ) + { + consoleWindow->mutex->lock(); + } mutexPending--; mutexLocks++; } bool fceuWrapperTryLock(int timeout) { - bool lockAcq; + bool lockAcq = false; mutexPending++; - lockAcq = consoleWindow->mutex->tryLock( timeout ); + if ( consoleWindow != NULL ) + { + lockAcq = consoleWindow->mutex->tryLock( timeout ); + } mutexPending--; if ( lockAcq ) @@ -970,7 +980,10 @@ void fceuWrapperUnLock(void) { if ( mutexLocks > 0 ) { - consoleWindow->mutex->unlock(); + if ( consoleWindow != NULL ) + { + consoleWindow->mutex->unlock(); + } mutexLocks--; } else diff --git a/src/ppu.h b/src/ppu.h index a3d2ded5..4555264d 100644 --- a/src/ppu.h +++ b/src/ppu.h @@ -48,3 +48,7 @@ enum PPUPHASE { }; extern PPUPHASE ppuphase; + +extern unsigned char *cdloggervdata; +extern unsigned int cdloggerVideoDataSize; +extern volatile int rendercount, vromreadcount, undefinedvromcount; From 63933a1821312f4fad4fd088efaf6a327069853b Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Mon, 28 Sep 2020 21:51:14 -0400 Subject: [PATCH 45/57] Added CDL File load/save logic. --- src/drivers/Qt/CodeDataLogger.cpp | 134 +++++++++++++++++++++++++++- src/drivers/Qt/CodeDataLogger.h | 3 + src/drivers/Qt/ConsoleUtilities.cpp | 4 +- 3 files changed, 138 insertions(+), 3 deletions(-) diff --git a/src/drivers/Qt/CodeDataLogger.cpp b/src/drivers/Qt/CodeDataLogger.cpp index 55e6a584..cd272d0d 100644 --- a/src/drivers/Qt/CodeDataLogger.cpp +++ b/src/drivers/Qt/CodeDataLogger.cpp @@ -1,6 +1,7 @@ // CodeDataLogger.cpp // #include +#include #include #include @@ -133,12 +134,15 @@ CodeDataLoggerDialog_t::CodeDataLoggerDialog_t(QWidget *parent) 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 ); @@ -287,18 +291,142 @@ void CodeDataLoggerDialog_t::StartPauseCDLogClicked(void) { if ( FCEUI_GetLoggingCD() ) { - printf("CD Logging Paused\n"); + //printf("CD Logging Paused\n"); PauseCDLogging(); startPauseButton->setText( tr("Start") ); } else { - printf("CD Logging Started\n"); + //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; +} +//---------------------------------------------------- static int getDefaultCDLFile( char *filepath ) { const char *romFile; @@ -399,7 +527,9 @@ bool LoadCDLog(const char* nameo) FP = fopen(nameo, "rb"); if (FP == NULL) + { return false; + } for(i = 0;i < (int)cdloggerdataSize;i++) { diff --git a/src/drivers/Qt/CodeDataLogger.h b/src/drivers/Qt/CodeDataLogger.h index c1782041..c768c8a9 100644 --- a/src/drivers/Qt/CodeDataLogger.h +++ b/src/drivers/Qt/CodeDataLogger.h @@ -45,6 +45,9 @@ class CodeDataLoggerDialog_t : public QDialog 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); diff --git a/src/drivers/Qt/ConsoleUtilities.cpp b/src/drivers/Qt/ConsoleUtilities.cpp index c9fa3a48..9bedc75f 100644 --- a/src/drivers/Qt/ConsoleUtilities.cpp +++ b/src/drivers/Qt/ConsoleUtilities.cpp @@ -88,7 +88,9 @@ int parseFilepath( const char *filepath, char *dir, char *base, char *suffix ) int i=0,j=0,end=0; if ( filepath == NULL ) { - base[0] = 0; + if ( dir ) dir[0] = 0; + if ( base ) base[0] = 0; + if ( suffix) suffix[0] = 0; return 0; } i=0; j=0; From 92007f8467f06060d08734f6113a8133af1559a3 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Mon, 28 Sep 2020 22:18:25 -0400 Subject: [PATCH 46/57] Added CDL generated ROM functionality. --- src/drivers/Qt/CodeDataLogger.cpp | 182 +++++++++++++++++++++++++++++- src/drivers/Qt/CodeDataLogger.h | 5 +- 2 files changed, 185 insertions(+), 2 deletions(-) diff --git a/src/drivers/Qt/CodeDataLogger.cpp b/src/drivers/Qt/CodeDataLogger.cpp index cd272d0d..3f209fb4 100644 --- a/src/drivers/Qt/CodeDataLogger.cpp +++ b/src/drivers/Qt/CodeDataLogger.cpp @@ -11,6 +11,8 @@ #include "../../x6502.h" #include "../../debug.h" #include "../../ppu.h" +#include "../../ines.h" +#include "../../nsf.h" #include "Qt/ConsoleUtilities.h" #include "Qt/CodeDataLogger.h" @@ -160,8 +162,10 @@ CodeDataLoggerDialog_t::CodeDataLoggerDialog_t(QWidget *parent) 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 ); @@ -169,7 +173,7 @@ CodeDataLoggerDialog_t::CodeDataLoggerDialog_t(QWidget *parent) setLayout( mainLayout ); - updateTimer->start( 100 ); // 10hz + updateTimer->start( 200 ); // 5hz if (autoLoadCDL) { @@ -427,6 +431,182 @@ void CodeDataLoggerDialog_t::loadCdlFile(void) 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; diff --git a/src/drivers/Qt/CodeDataLogger.h b/src/drivers/Qt/CodeDataLogger.h index c768c8a9..ff8241b6 100644 --- a/src/drivers/Qt/CodeDataLogger.h +++ b/src/drivers/Qt/CodeDataLogger.h @@ -40,6 +40,8 @@ class CodeDataLoggerDialog_t : public QDialog QPushButton *startPauseButton; void closeEvent(QCloseEvent *bar); + void SaveStrippedROM(int invert); + private: public slots: @@ -54,7 +56,8 @@ class CodeDataLoggerDialog_t : public QDialog void autoSaveCdlStateChange(int state); void autoLoadCdlStateChange(int state); void autoResumeCdlStateChange(int state); - + void SaveStrippedROMClicked(void); + void SaveUnusedROMClicked(void); }; void InitCDLog(void); From de2fd3eef3abfc973c093ea65bdc021236939a46 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Mon, 28 Sep 2020 23:40:13 -0400 Subject: [PATCH 47/57] Added Qt hex editor logic to color ROM bytes from CD Logger data. --- src/drivers/Qt/HexEditor.cpp | 120 ++++++++++++++++++++++++++++++++++- src/drivers/Qt/HexEditor.h | 2 + 2 files changed, 121 insertions(+), 1 deletion(-) diff --git a/src/drivers/Qt/HexEditor.cpp b/src/drivers/Qt/HexEditor.cpp index ebb77223..e5dd46a1 100644 --- a/src/drivers/Qt/HexEditor.cpp +++ b/src/drivers/Qt/HexEditor.cpp @@ -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 ) { diff --git a/src/drivers/Qt/HexEditor.h b/src/drivers/Qt/HexEditor.h index 04925bc6..a7f5a8b1 100644 --- a/src/drivers/Qt/HexEditor.h +++ b/src/drivers/Qt/HexEditor.h @@ -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); From c288c60c688709eef69a91d672642ccbe54b8167 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Wed, 30 Sep 2020 20:56:50 -0400 Subject: [PATCH 48/57] 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 49/57] 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 50/57] 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 51/57] 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 52/57] 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 53/57] 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 54/57] 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 55/57] 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 56/57] 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 57/57] 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;