Added initial framework for adding, editing, and removing breakpoints.
This commit is contained in:
parent
4e3e4d2e54
commit
dd7aa8fc2c
|
@ -11,6 +11,7 @@
|
|||
#include <QHeaderView>
|
||||
#include <QCloseEvent>
|
||||
#include <QGridLayout>
|
||||
#include <QRadioButton>
|
||||
|
||||
#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; i<numWPs; i++)
|
||||
{
|
||||
item = bpTree->topLevelItem(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 <ConsoleDebugger*>::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);
|
||||
}
|
||||
|
|
|
@ -18,12 +18,14 @@
|
|||
#include <QGroupBox>
|
||||
#include <QTreeView>
|
||||
#include <QTreeWidget>
|
||||
#include <QTreeWidgetItem>
|
||||
#include <QLineEdit>
|
||||
#include <QTextEdit>
|
||||
#include <QPlainTextEdit>
|
||||
#include <QScrollBar>
|
||||
|
||||
#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);
|
||||
|
||||
};
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue