diff --git a/src/drivers/Qt/ConsoleDebugger.cpp b/src/drivers/Qt/ConsoleDebugger.cpp index ee4cca05..9462f4bf 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" @@ -37,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" @@ -44,6 +46,7 @@ extern int vblankScanLines; extern int vblankPixel; +debuggerBookmarkManager_t dbgBmMgr; static std::list dbgWinList; static void DeleteBreak(int sel); @@ -361,6 +364,9 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent) bmFrame = new QGroupBox( tr("Address Bookmarks") ); bmTree = new QTreeWidget(); selBmAddr = new QLineEdit(); + selBmAddrVal = 0; + + connect( selBmAddr, SIGNAL(textChanged(const QString &)), this, SLOT(selBmAddrChanged(const QString &))); bmTree->setColumnCount(2); @@ -379,19 +385,22 @@ 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") ); vbox->addWidget( button ); - button->setEnabled(false); // TODO + connect( button, SIGNAL(clicked(void)), this, SLOT(add_BM_CB(void)) ); button = new QPushButton( tr("Delete") ); vbox->addWidget( button ); - button->setEnabled(false); // TODO + connect( button, SIGNAL(clicked(void)), this, SLOT(delete_BM_CB(void)) ); button = new QPushButton( tr("Name") ); vbox->addWidget( button ); - button->setEnabled(false); // TODO + connect( button, SIGNAL(clicked(void)), this, SLOT(edit_BM_CB(void)) ); hbox->addWidget( bmTree ); hbox->addLayout( vbox ); @@ -457,9 +466,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 ); @@ -556,12 +569,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; @@ -1040,6 +1074,138 @@ 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); + char stmp[128]; + + bm = dbgBmMgr.getAddr( addr ); + + sprintf( stmp, "Specify Bookmark Name for %04X", addr ); + + dialog.setWindowTitle( tr("Edit Bookmark") ); + dialog.setLabelText( tr(stmp) ); + 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); @@ -1428,6 +1594,48 @@ void ConsoleDebugger::asmViewCtxMenuAddBP(void) } //---------------------------------------------------------------------------- +void ConsoleDebugger::asmViewCtxMenuAddBM(void) +{ + int addr = asmView->getCtxMenuAddr(); + + dbgBmMgr.addBookmark( addr ); + + edit_BM_name( addr ); + + 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]; + + sprintf( stmp, "%04X", addr ); + + selBmAddr->setText( tr(stmp) ); + + selBmAddrVal = addr; +} +//---------------------------------------------------------------------------- void ConsoleDebugger::asmViewCtxMenuAddSym(void) { openDebugSymbolEditWindow( asmView->getCtxMenuAddr() ); @@ -2066,6 +2274,11 @@ void ConsoleDebugger::updateWindowData(void) windowUpdateReq = false; } //---------------------------------------------------------------------------- +void ConsoleDebugger::queueUpdate(void) +{ + windowUpdateReq = true; +} +//---------------------------------------------------------------------------- void ConsoleDebugger::updatePeriodic(void) { //printf("Update Periodic\n"); @@ -2094,6 +2307,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 ) @@ -2176,6 +2395,21 @@ void FCEUD_DebugBreakpoint( int bpNum ) fceuWrapperLock(); } //---------------------------------------------------------------------------- +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; @@ -2229,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 ) @@ -2276,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 ) @@ -2338,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 ); @@ -2452,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); @@ -2715,17 +3002,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) @@ -2746,13 +3035,20 @@ 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 Name"), this); - menu.addAction(act); + 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)) ); + + act = new QAction(tr("Open Hex Editor"), this); + menu.addAction(act); + connect( act, SIGNAL(triggered(void)), parent, SLOT(asmViewCtxMenuOpenHexEdit(void)) ); menu.exec(event->globalPos()); } @@ -2760,7 +3056,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); @@ -2792,6 +3088,7 @@ void QAsmView::paintEvent(QPaintEvent *event) { lineOffset = maxLineOffset; } + selAddr = parent->getBookmarkSelectedAddress(); painter.fillRect( 0, 0, viewWidth, viewHeight, this->palette().color(QPalette::Background) ); @@ -2818,8 +3115,162 @@ 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 ( !displayROMoffsets && (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; } } //---------------------------------------------------------------------------- +// 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 3661e5ac..51b6d40c 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 @@ -134,6 +166,10 @@ 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; }; + void edit_BM_name( int addr ); + void queueUpdate(void); QLabel *asmLineSelLbl; protected: @@ -189,16 +225,20 @@ class ConsoleDebugger : public QDialog QTimer *periodicTimer; QFont font; + int selBmAddrVal; bool windowUpdateReq; private: void setRegsFromEntry(void); void bpListUpdate( bool reset = false ); + void bmListUpdate( bool reset = false ); public slots: void closeWindow(void); void asmViewCtxMenuAddBP(void); + void asmViewCtxMenuAddBM(void); void asmViewCtxMenuAddSym(void); + void asmViewCtxMenuOpenHexEdit(void); private slots: void updatePeriodic(void); void hbarChanged(int value); @@ -214,6 +254,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); @@ -226,11 +269,17 @@ 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); }; +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/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/HexEditor.cpp b/src/drivers/Qt/HexEditor.cpp index 1906fe7e..ebb77223 100644 --- a/src/drivers/Qt/HexEditor.cpp +++ b/src/drivers/Qt/HexEditor.cpp @@ -35,7 +35,10 @@ #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" static HexBookMarkManager_t hbm; static std::list winList; @@ -537,12 +540,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 ); @@ -737,6 +739,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; @@ -947,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"); @@ -956,6 +1099,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) @@ -992,6 +1165,7 @@ QHexEdit::QHexEdit(QWidget *parent) lineOffset = 0; cursorPosX = 0; cursorPosY = 0; + cursorAddr = 0; cursorBlink = true; cursorBlinkCount = 0; maxLineOffset = 0; @@ -1531,20 +1705,24 @@ 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, "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 ) { @@ -1567,6 +1745,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)) ); @@ -1630,6 +1818,136 @@ void QHexEdit::addBookMarkCB(void) } } //---------------------------------------------------------------------------- +void QHexEdit::addDebugSym(void) +{ + parent->openDebugSymbolEditWindow( ctxAddr ); +} +//---------------------------------------------------------------------------- +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 ); @@ -1732,6 +2050,9 @@ void QHexEdit::memModeUpdate(void) printf("Error: Failed to allocate memview buffer size\n"); return; } + maxLineOffset = mb.numLines() - viewLines + 1; + + vbar->setMaximum( memSize / 16 ); } } //---------------------------------------------------------------------------- @@ -1807,6 +2128,7 @@ void QHexEdit::paintEvent(QPaintEvent *event) ca = 16*(lineOffset + cursorPosY) + a; } + cursorAddr = ca; if ( cursorBlink ) { @@ -1928,3 +2250,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..04925bc6 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; @@ -182,6 +184,12 @@ class QHexEdit : public QWidget private slots: void jumpToROM(void); void addBookMarkCB(void); + void addDebugSym(void); + void addRamReadBP(void); + void addRamWriteBP(void); + void addRamExecuteBP(void); + void addPpuReadBP(void); + void addPpuWriteBP(void); }; @@ -195,15 +203,22 @@ class HexEditorDialog_t : public QDialog void gotoAddress(int newAddr); void populateBookmarkMenu(void); + void setWindowTitle(void); + void openDebugSymbolEditWindow( int addr ); + + QHexEdit *editor; protected: void closeEvent(QCloseEvent *bar); QScrollBar *vbar; QScrollBar *hbar; - QHexEdit *editor; QTimer *periodicTimer; QMenu *bookmarkMenu; + QAction *viewRAM; + QAction *viewPPU; + QAction *viewOAM; + QAction *viewROM; private: @@ -227,5 +242,7 @@ class HexEditorDialog_t : public QDialog void removeAllBookmarks(void); }; +int hexEditorNumWindows(void); void hexEditorLoadBookmarks(void); void hexEditorSaveBookmarks(void); +int hexEditorOpenFromDebugger( int mode, int addr ); 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;