diff --git a/src/drivers/Qt/ConsoleDebugger.cpp b/src/drivers/Qt/ConsoleDebugger.cpp index b113c50c..bcf480c7 100644 --- a/src/drivers/Qt/ConsoleDebugger.cpp +++ b/src/drivers/Qt/ConsoleDebugger.cpp @@ -89,6 +89,10 @@ static void DeleteBreak(int sel); static bool waitingAtBp = false; static bool bpDebugEnable = true; static int lastBpIdx = 0; +static bool breakOnCycleOneShot = 0; +static bool breakOnInstrOneShot = 0; +static int breakOnCycleMode = 0; +static int breakOnInstrMode = 0; //---------------------------------------------------------------------------- ConsoleDebugger::ConsoleDebugger(QWidget *parent) : QDialog( parent, Qt::Window ) @@ -581,35 +585,59 @@ QMenuBar *ConsoleDebugger::buildMenuBar(void) debugMenu->addSeparator(); - // Debug -> Break on Bad Opcodes - act = new QAction(tr("Break on Bad &Opcodes"), this); + subMenu = debugMenu->addMenu(tr("&Break On...")); + + // Debug -> Break on -> Bad Opcodes + act = new QAction(tr("Bad &Opcodes"), this); //act->setShortcut(QKeySequence( tr("F7") ) ); - act->setStatusTip(tr("Break on Bad Opcodes")); + act->setStatusTip(tr("Bad Opcodes")); act->setCheckable(true); act->setChecked( FCEUI_Debugger().badopbreak ); connect( act, SIGNAL(triggered(bool)), this, SLOT(breakOnBadOpcodeCB(bool)) ); - debugMenu->addAction(act); + subMenu->addAction(act); - // Debug -> Break on Unlogged Code - act = new QAction(tr("Break on Unlogged &Code"), this); + // Debug -> Break on -> Unlogged Code + act = new QAction(tr("Unlogged &Code"), this); //act->setShortcut(QKeySequence( tr("F7") ) ); - act->setStatusTip(tr("Break on Unlogged Code")); + act->setStatusTip(tr("Unlogged Code")); act->setCheckable(true); act->setChecked( break_on_unlogged_code ); connect( act, SIGNAL(triggered(bool)), this, SLOT(breakOnNewCodeCB(bool)) ); - debugMenu->addAction(act); + subMenu->addAction(act); - // Debug -> Break on Unlogged Data - act = new QAction(tr("Break on Unlogged &Data"), this); + // Debug -> Break on -> Unlogged Data + act = new QAction(tr("Unlogged &Data"), this); //act->setShortcut(QKeySequence( tr("F7") ) ); - act->setStatusTip(tr("Break on Unlogged Data")); + act->setStatusTip(tr("Unlogged Data")); act->setCheckable(true); act->setChecked( break_on_unlogged_data ); connect( act, SIGNAL(triggered(bool)), this, SLOT(breakOnNewDataCB(bool)) ); - debugMenu->addAction(act); + subMenu->addAction(act); + + // Debug -> Break on -> Cycle Count Exceeded + act = new QAction(tr("&Cycle Count Exceeded"), this); + //act->setShortcut(QKeySequence( tr("F7") ) ); + act->setStatusTip(tr("CPU Cycle Count Exceeded")); + act->setCheckable(true); + act->setChecked( break_on_cycles ); + connect( act, SIGNAL(triggered(bool)), this, SLOT(breakOnCyclesCB(bool)) ); + + subMenu->addAction(act); + + // Debug -> Break on -> Instruction Count Exceeded + act = new QAction(tr("&Instruction Count Exceeded"), this); + //act->setShortcut(QKeySequence( tr("F7") ) ); + act->setStatusTip(tr("CPU Instruction Count Exceeded")); + act->setCheckable(true); + act->setChecked( break_on_instructions ); + connect( act, SIGNAL(triggered(bool)), this, SLOT(breakOnInstructionsCB(bool)) ); + + subMenu->addAction(act); + + debugMenu->addSeparator(); // Debug -> Reset Counters act = new QAction(tr("Reset &Counters"), this); @@ -2244,11 +2272,16 @@ void ConsoleDebugger::breakOnNewDataCB(bool value) break_on_unlogged_data = value; } //---------------------------------------------------------------------------- -void ConsoleDebugger::breakOnCyclesCB( int value ) +void ConsoleDebugger::breakOnCyclesCB( bool value ) { std::string s; - break_on_cycles = (value != Qt::Unchecked); + if ( value ) + { + DebugBreakOnDialog *win = new DebugBreakOnDialog(0, this); + win->exec(); + } + break_on_cycles = value; //s = cpuCycExdVal->text().toStdString(); @@ -2274,11 +2307,16 @@ void ConsoleDebugger::cpuCycleThresChanged(const QString &txt) } } //---------------------------------------------------------------------------- -void ConsoleDebugger::breakOnInstructionsCB( int value ) +void ConsoleDebugger::breakOnInstructionsCB( bool value ) { std::string s; - break_on_instructions = (value != Qt::Unchecked); + if ( value ) + { + DebugBreakOnDialog *win = new DebugBreakOnDialog(1, this); + win->exec(); + } + break_on_instructions = value; //s = instrExdVal->text().toStdString(); @@ -6909,3 +6947,266 @@ void DebuggerTabBar::contextMenuEvent(QContextMenuEvent *event) } } //---------------------------------------------------------------------------- +//---------------------------------------------------------------------------- +//--- Break On Count Setup Dialog +//---------------------------------------------------------------------------- +//---------------------------------------------------------------------------- +DebugBreakOnDialog::DebugBreakOnDialog(int type, QWidget *parent ) + : QDialog(parent) +{ + + QVBoxLayout *mainLayout, *vbox; + QHBoxLayout *hbox; + QGroupBox *gbox; + QGridLayout *grid; + fceuDecIntValidtor *validator; + int refMode; + bool oneShotMode; + char stmp[128]; + QPushButton *btn; + + fceuWrapperLock(); + + prevPauseState = FCEUI_EmulationPaused(); + + if (prevPauseState == 0) + { + FCEUI_ToggleEmulationPause(); + } + fceuWrapperUnLock(); + + currLbl = new QLabel(); + + this->type = type; + + if ( type ) + { + totalCount = total_instructions; + deltaCount = delta_instructions; + + setWindowTitle( tr("Break on CPU Instruction Exceedance") ); + oneShotMode = breakOnInstrOneShot; + refMode = breakOnInstrMode; + threshold = break_instructions_limit; + + if (totalCount < 0) // sanity check + { + ResetDebugStatisticsCounters(); + totalCount = 0; + } + if (deltaCount < 0) // sanity check + { + ResetDebugStatisticsCounters(); + deltaCount = 0; + } + sprintf(stmp, "Current Instruction Count: %10llu (+%llu)", totalCount, deltaCount); + currLbl->setText( tr(stmp) ); + + } + else + { + totalCount = timestampbase + (uint64)timestamp - total_cycles_base; + deltaCount = timestampbase + (uint64)timestamp - delta_cycles_base; + + setWindowTitle( tr("Break on CPU Cycle Exceedance") ); + oneShotMode = breakOnCycleOneShot; + refMode = breakOnCycleMode; + threshold = break_cycles_limit; + + sprintf(stmp, "Current Cycle Count: %10llu (+%llu)", totalCount, deltaCount); + currLbl->setText( tr(stmp) ); + } + + mainLayout = new QVBoxLayout(); + hbox = new QHBoxLayout(); + + mainLayout->addLayout(hbox); + + gbox = new QGroupBox( tr("Mode") ); + vbox = new QVBoxLayout(); + oneShotBtn = new QRadioButton( tr("One-Shot") ); + contBtn = new QRadioButton( tr("Continuous") ); + + oneShotBtn->setChecked( oneShotMode ); + contBtn->setChecked( !oneShotMode ); + + hbox->addWidget(gbox); + gbox->setLayout(vbox); + vbox->addWidget( oneShotBtn ); + vbox->addWidget( contBtn ); + + gbox = new QGroupBox( tr("Reference") ); + vbox = new QVBoxLayout(); + absBtn = new QRadioButton( tr("Absolute") ); + relBtn = new QRadioButton( tr("Relative") ); + + absBtn->setChecked( refMode == 0 ); + relBtn->setChecked( refMode == 1 ); + + hbox->addWidget(gbox); + gbox->setLayout(vbox); + vbox->addWidget( absBtn ); + vbox->addWidget( relBtn ); + + mainLayout->addWidget(currLbl); + + hbox = new QHBoxLayout(); + mainLayout->addLayout(hbox); + + validator = new fceuDecIntValidtor( 0, 0x7FFFFFFFFFFFFFFFLL, this); + + countEntryBox = new QLineEdit(); + countEntryBox->setValidator( validator ); + countEntryBox->setAlignment(Qt::AlignCenter); + + hbox->addWidget( new QLabel( tr("Threshold:") ), 1 ); + hbox->addWidget( countEntryBox, 100 ); + + grid = new QGridLayout(); + mainLayout->addLayout( grid ); + + for (int row=0; row<2; row++) + { + int b = row == 0 ? 1 : -1; + + for (int col=0; col<5; col++) + { + btn = new QPushButton(); + + grid->addWidget( btn, row, col ); + + sprintf( stmp, "%+i", b); + + b = b * 10; + + btn->setText( tr(stmp) ); + } + } + + descLbl = new QLabel(); + mainLayout->addWidget( descLbl ); + + setLayout( mainLayout ); + + setThreshold( threshold ); + + connect( countEntryBox, SIGNAL(textChanged(const QString &)), this, SLOT(setThreshold(const QString &)) ); + + connect( absBtn, SIGNAL(clicked(bool)), this, SLOT(refModeChanged(bool)) ); + connect( relBtn, SIGNAL(clicked(bool)), this, SLOT(refModeChanged(bool)) ); +} +//---------------------------------------------------------------------------- +DebugBreakOnDialog::~DebugBreakOnDialog(void) +{ + FCEUI_SetEmulationPaused(prevPauseState); +} +//---------------------------------------------------------------------------- +void DebugBreakOnDialog::closeEvent(QCloseEvent *event) +{ + //printf("Close Window Event\n"); + done(0); + deleteLater(); + event->accept(); +} +//---------------------------------------------------------------------------- +void DebugBreakOnDialog::closeWindow(void) +{ + //printf("Close Window\n"); + done(0); + deleteLater(); +} +//---------------------------------------------------------------------------- +void DebugBreakOnDialog::setThreshold( unsigned long long int val ) +{ + char stmp[64]; + + threshold = val; + + sprintf( stmp, "%llu", threshold ); + + countEntryBox->setText( tr(stmp) ); + + updateLabel(); +} +//---------------------------------------------------------------------------- +void DebugBreakOnDialog::setThreshold( const QString &text ) +{ + threshold = strtoull( text.toStdString().c_str(), NULL, 10 ); + + updateLabel(); +} +//---------------------------------------------------------------------------- +void DebugBreakOnDialog::refModeChanged(bool val) +{ + updateLabel(); +} +//---------------------------------------------------------------------------- +void DebugBreakOnDialog::updateLabel(void) +{ + long long delta; + char stmp[256]; + + stmp[0] = 0; + + if ( type ) + { + if ( absBtn->isChecked() ) + { + delta = threshold - total_instructions; + + if ( delta > 0 ) + { + sprintf( stmp, "Will break in %lli CPU Instruction%s", delta, (delta > 1) ? "s":"" ); + } + else + { + sprintf( stmp, "Will break immediately, CPU instruction count already exceeds value."); + } + } + else + { + delta = threshold - delta_instructions; + + if ( delta > 0 ) + { + sprintf( stmp, "Will break in %lli CPU Instruction%s", delta, (delta > 1) ? "s":"" ); + } + else + { + sprintf( stmp, "Will break immediately, CPU instruction count already exceeds value."); + } + } + } + else + { + if ( absBtn->isChecked() ) + { + delta = threshold - totalCount; + + if ( delta > 0 ) + { + sprintf( stmp, "Will break in %lli CPU cycle%s", delta, (delta > 1) ? "s":"" ); + } + else + { + sprintf( stmp, "Will break immediately, CPU cycle count already exceeds value."); + } + } + else + { + delta = threshold - deltaCount; + + if ( delta > 0 ) + { + sprintf( stmp, "Will break in %lli CPU cycle%s", delta, (delta > 1) ? "s":"" ); + } + else + { + sprintf( stmp, "Will break immediately, CPU cycle count already exceeds value."); + } + } + } + descLbl->setText( tr(stmp) ); + +} +//---------------------------------------------------------------------------- diff --git a/src/drivers/Qt/ConsoleDebugger.h b/src/drivers/Qt/ConsoleDebugger.h index bc7f415d..03550e8f 100644 --- a/src/drivers/Qt/ConsoleDebugger.h +++ b/src/drivers/Qt/ConsoleDebugger.h @@ -11,10 +11,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include @@ -369,6 +371,41 @@ class DebuggerTabWidget : public QTabWidget int _col; }; +class DebugBreakOnDialog : public QDialog +{ + Q_OBJECT + + public: + DebugBreakOnDialog(int type, QWidget *parent = 0); + ~DebugBreakOnDialog(void); + + unsigned long long int getThreshold(void){ return threshold; } + + protected: + void closeEvent(QCloseEvent *event) override; + void updateLabel(void); + + int type; + QRadioButton *oneShotBtn; + QRadioButton *contBtn; + QRadioButton *absBtn; + QRadioButton *relBtn; + QLineEdit *countEntryBox; + QLabel *currLbl; + QLabel *descLbl; + int prevPauseState; + long long int totalCount; + long long int deltaCount; + unsigned long long int threshold; + + public slots: + void closeWindow(void); + void setThreshold( unsigned long long int val ); + void setThreshold( const QString &text ); + void refModeChanged(bool); + +}; + class ConsoleDebugger : public QDialog { Q_OBJECT @@ -447,6 +484,9 @@ class ConsoleDebugger : public QDialog QCheckBox *iGrn_cbox; QCheckBox *iBlu_cbox; + QAction *brkOnCycleExcAct; + QAction *brkOnInstrExcAct; + DebuggerTabWidget *tabView[2][4]; QWidget *asmViewContainerWidget; QWidget *bpTreeContainerWidget; @@ -535,8 +575,8 @@ class ConsoleDebugger : public QDialog void breakOnBadOpcodeCB(bool value); void breakOnNewCodeCB(bool value); void breakOnNewDataCB(bool value); - void breakOnCyclesCB( int value ); - void breakOnInstructionsCB( int value ); + void breakOnCyclesCB( bool value ); + void breakOnInstructionsCB( bool value ); void bpItemClicked( QTreeWidgetItem *item, int column); void bmItemClicked( QTreeWidgetItem *item, int column); void bmItemDoubleClicked( QTreeWidgetItem *item, int column); diff --git a/src/drivers/Qt/ConsoleUtilities.cpp b/src/drivers/Qt/ConsoleUtilities.cpp index 7bd0719f..9dbbf2c8 100644 --- a/src/drivers/Qt/ConsoleUtilities.cpp +++ b/src/drivers/Qt/ConsoleUtilities.cpp @@ -508,14 +508,14 @@ void fceuCustomToolTip::mouseMoveEvent(QMouseEvent *event) //--------------------------------------------------------------------------- // FCEU Data Entry Custom Validators //--------------------------------------------------------------------------- -fceuDecIntValidtor::fceuDecIntValidtor( int min, int max, QObject *parent) +fceuDecIntValidtor::fceuDecIntValidtor( long long int min, long long int max, QObject *parent) : QValidator(parent) { this->min = min; this->max = max; } //--------------------------------------------------------------------------- -void fceuDecIntValidtor::setMinMax( int min, int max) +void fceuDecIntValidtor::setMinMax( long long int min, long long int max) { this->min = min; this->max = max; @@ -523,7 +523,7 @@ void fceuDecIntValidtor::setMinMax( int min, int max) //--------------------------------------------------------------------------- QValidator::State fceuDecIntValidtor::validate(QString &input, int &pos) const { - int i, v; + long long int i, v; //printf("Validate: %i '%s'\n", input.size(), input.toStdString().c_str() ); if ( input.size() == 0 ) @@ -557,7 +557,7 @@ QValidator::State fceuDecIntValidtor::validate(QString &input, int &pos) const if ( s[i] == 0 ) { - v = strtol( s.c_str(), NULL, 0 ); + v = strtoll( s.c_str(), NULL, 0 ); if ( v < min ) { @@ -575,14 +575,14 @@ QValidator::State fceuDecIntValidtor::validate(QString &input, int &pos) const //--------------------------------------------------------------------------- // FCEU Data Entry Custom Validators //--------------------------------------------------------------------------- -fceuHexIntValidtor::fceuHexIntValidtor( int min, int max, QObject *parent) +fceuHexIntValidtor::fceuHexIntValidtor( long long int min, long long int max, QObject *parent) : QValidator(parent) { this->min = min; this->max = max; } //--------------------------------------------------------------------------- -void fceuHexIntValidtor::setMinMax( int min, int max) +void fceuHexIntValidtor::setMinMax( long long int min, long long int max) { this->min = min; this->max = max; @@ -590,7 +590,7 @@ void fceuHexIntValidtor::setMinMax( int min, int max) //--------------------------------------------------------------------------- QValidator::State fceuHexIntValidtor::validate(QString &input, int &pos) const { - int i, v; + long long int i, v; //printf("Validate: %i '%s'\n", input.size(), input.toStdString().c_str() ); if ( input.size() == 0 ) @@ -625,7 +625,7 @@ QValidator::State fceuHexIntValidtor::validate(QString &input, int &pos) const if ( s[i] == 0 ) { - v = strtol( s.c_str(), NULL, 16 ); + v = strtoll( s.c_str(), NULL, 16 ); if ( v < min ) { diff --git a/src/drivers/Qt/ConsoleUtilities.h b/src/drivers/Qt/ConsoleUtilities.h index 37db5860..14a302cb 100644 --- a/src/drivers/Qt/ConsoleUtilities.h +++ b/src/drivers/Qt/ConsoleUtilities.h @@ -23,27 +23,27 @@ int fceuLoadConfigColor( const char *confName, QColor *color ); class fceuDecIntValidtor : public QValidator { public: - fceuDecIntValidtor( int min, int max, QObject *parent); + fceuDecIntValidtor( long long int min, long long int max, QObject *parent); QValidator::State validate(QString &input, int &pos) const; - void setMinMax( int min, int max ); + void setMinMax( long long int min, long long int max ); private: - int min; - int max; + long long int min; + long long int max; }; class fceuHexIntValidtor : public QValidator { public: - fceuHexIntValidtor( int min, int max, QObject *parent); + fceuHexIntValidtor( long long int min, long long int max, QObject *parent); QValidator::State validate(QString &input, int &pos) const; - void setMinMax( int min, int max ); + void setMinMax( long long int min, long long int max ); private: - int min; - int max; + long long int min; + long long int max; }; class fceuCustomToolTip : public QDialog