From baa724ed14b02ba47b95c6ba65662de0a8748279 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Sun, 11 Oct 2020 10:40:27 -0400 Subject: [PATCH 01/17] Added initial layout of Qt RAM Search window. --- src/CMakeLists.txt | 1 + src/drivers/Qt/ConsoleWindow.cpp | 20 +++ src/drivers/Qt/ConsoleWindow.h | 2 + src/drivers/Qt/RamSearch.cpp | 287 +++++++++++++++++++++++++++++++ src/drivers/Qt/RamSearch.h | 89 ++++++++++ 5 files changed, 399 insertions(+) create mode 100644 src/drivers/Qt/RamSearch.cpp create mode 100644 src/drivers/Qt/RamSearch.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a21663ab..1b848f01 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -445,6 +445,7 @@ set(SRC_DRIVERS_SDL ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ppuViewer.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/NameTableViewer.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/RamWatch.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/RamSearch.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/config.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/input.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/nes_shm.cpp diff --git a/src/drivers/Qt/ConsoleWindow.cpp b/src/drivers/Qt/ConsoleWindow.cpp index a785e037..5321636c 100644 --- a/src/drivers/Qt/ConsoleWindow.cpp +++ b/src/drivers/Qt/ConsoleWindow.cpp @@ -36,6 +36,7 @@ #include "Qt/ppuViewer.h" #include "Qt/NameTableViewer.h" #include "Qt/RamWatch.h" +#include "Qt/RamSearch.h" #include "Qt/keyscan.h" #include "Qt/nes_shm.h" @@ -484,6 +485,14 @@ void consoleWin_t::createMainMenu(void) toolsMenu->addAction(cheatsAct); + // Tools -> RAM Search + ramSearchAct = new QAction(tr("RAM Search..."), this); + //ramSearchAct->setShortcut( QKeySequence(tr("Shift+F7"))); + ramSearchAct->setStatusTip(tr("Open RAM Search Window")); + connect(ramSearchAct, SIGNAL(triggered()), this, SLOT(openRamSearch(void)) ); + + toolsMenu->addAction(ramSearchAct); + // Tools -> RAM Watch ramWatchAct = new QAction(tr("RAM Watch..."), this); //ramWatchAct->setShortcut( QKeySequence(tr("Shift+F7"))); @@ -1037,6 +1046,17 @@ void consoleWin_t::openRamWatch(void) ramWatchWin->show(); } +void consoleWin_t::openRamSearch(void) +{ + RamSearchDialog_t *ramSearchWin; + + //printf("Open GUI RAM Search Window\n"); + + ramSearchWin = new RamSearchDialog_t(this); + + ramSearchWin->show(); +} + void consoleWin_t::openDebugWindow(void) { ConsoleDebugger *debugWin; diff --git a/src/drivers/Qt/ConsoleWindow.h b/src/drivers/Qt/ConsoleWindow.h index 08ea48dd..f91f34dd 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 *ramWatchAct; + QAction *ramSearchAct; QAction *debuggerAct; QAction *codeDataLogAct; QAction *traceLogAct; @@ -169,6 +170,7 @@ class consoleWin_t : public QMainWindow void openNTViewer(void); void openCheats(void); void openRamWatch(void); + void openRamSearch(void); void openMovie(void); void stopMovie(void); void recordMovie(void); diff --git a/src/drivers/Qt/RamSearch.cpp b/src/drivers/Qt/RamSearch.cpp new file mode 100644 index 00000000..b7a149ee --- /dev/null +++ b/src/drivers/Qt/RamSearch.cpp @@ -0,0 +1,287 @@ +// HotKeyConf.cpp +// +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../../types.h" +#include "../../fceu.h" +#include "../../cheat.h" +#include "../../debug.h" + +#include "Qt/main.h" +#include "Qt/dface.h" +#include "Qt/input.h" +#include "Qt/config.h" +#include "Qt/keyscan.h" +#include "Qt/fceuWrapper.h" +#include "Qt/RamWatch.h" +#include "Qt/RamSearch.h" +#include "Qt/ConsoleUtilities.h" + +//---------------------------------------------------------------------------- +RamSearchDialog_t::RamSearchDialog_t(QWidget *parent) + : QDialog( parent ) +{ + QVBoxLayout *mainLayout; + QHBoxLayout *hbox, *hbox1, *hbox2, *hbox3; + QVBoxLayout *vbox, *vbox1, *vbox2; + QTreeWidgetItem *item; + QGridLayout *grid; + QGroupBox *frame; + + font.setFamily("Courier New"); + font.setStyle( QFont::StyleNormal ); + font.setStyleHint( QFont::Monospace ); + + QFontMetrics fm(font); + +#if QT_VERSION > QT_VERSION_CHECK(5, 11, 0) + fontCharWidth = 2 * fm.horizontalAdvance(QLatin1Char('2')); +#else + fontCharWidth = 2 * fm.width(QLatin1Char('2')); +#endif + + setWindowTitle("RAM Search"); + + resize( 512, 512 ); + + mainLayout = new QVBoxLayout(); + hbox1 = new QHBoxLayout(); + + mainLayout->addLayout( hbox1 ); + + tree = new QTreeWidget(); + + tree->setColumnCount(4); + + item = new QTreeWidgetItem(); + item->setText( 0, QString::fromStdString( "Address" ) ); + item->setText( 1, QString::fromStdString( "Value" ) ); + item->setText( 2, QString::fromStdString( "Previous" ) ); + item->setText( 3, QString::fromStdString( "Changes" ) ); + item->setTextAlignment( 0, Qt::AlignLeft); + item->setTextAlignment( 1, Qt::AlignLeft); + item->setTextAlignment( 2, Qt::AlignLeft); + item->setTextAlignment( 3, Qt::AlignLeft); + + //connect( tree, SIGNAL(itemClicked(QTreeWidgetItem*, int)), + // this, SLOT(watchClicked( QTreeWidgetItem*, int)) ); + + tree->setHeaderItem( item ); + + //tree->header()->setSectionResizeMode( QHeaderView::ResizeToContents ); + + vbox = new QVBoxLayout(); + hbox1->addWidget( tree ); + hbox1->addLayout( vbox ); + + searchButton = new QPushButton( tr("Search") ); + vbox->addWidget( searchButton ); + //connect( searchButton, SIGNAL(clicked(void)), this, SLOT(moveWatchUpClicked(void))); + //searchButton->setEnabled(false); + + resetButton = new QPushButton( tr("Reset") ); + vbox->addWidget( resetButton ); + //connect( resetButton, SIGNAL(clicked(void)), this, SLOT(moveWatchDownClicked(void))); + //down_btn->setEnabled(false); + + clearChangeButton = new QPushButton( tr("Clear Change") ); + vbox->addWidget( clearChangeButton ); + //connect( clearChangeButton, SIGNAL(clicked(void)), this, SLOT(editWatchClicked(void))); + //clearChangeButton->setEnabled(false); + + undoButton = new QPushButton( tr("Remove") ); + vbox->addWidget( undoButton ); + //connect( undoButton, SIGNAL(clicked(void)), this, SLOT(removeWatchClicked(void))); + //undoButton->setEnabled(false); + + searchROMCbox = new QCheckBox( tr("Search ROM") ); + vbox->addWidget( searchROMCbox ); + //connect( undoButton, SIGNAL(clicked(void)), this, SLOT(removeWatchClicked(void))); + //undoButton->setEnabled(false); + + elimButton = new QPushButton( tr("Eliminate") ); + vbox->addWidget( elimButton ); + //connect( elimButton, SIGNAL(clicked(void)), this, SLOT(newWatchClicked(void))); + //elimButton->setEnabled(false); + + watchButton = new QPushButton( tr("Watch") ); + vbox->addWidget( watchButton ); + //connect( watchButton, SIGNAL(clicked(void)), this, SLOT(dupWatchClicked(void))); + watchButton->setEnabled(false); + + addCheatButton = new QPushButton( tr("Add Cheat") ); + vbox->addWidget( addCheatButton ); + //connect( addCheatButton, SIGNAL(clicked(void)), this, SLOT(sepWatchClicked(void))); + addCheatButton->setEnabled(false); + + hexEditButton = new QPushButton( tr("Hex Editor") ); + vbox->addWidget( hexEditButton ); + //connect( hexEditButton, SIGNAL(clicked(void)), this, SLOT(sepWatchClicked(void))); + hexEditButton->setEnabled(false); + + hbox2 = new QHBoxLayout(); + mainLayout->addLayout( hbox2 ); + frame = new QGroupBox( tr("Comparison Operator") ); + vbox = new QVBoxLayout(); + + hbox2->addWidget( frame ); + frame->setLayout(vbox); + + lt_btn = new QRadioButton( tr("Less Than") ); + gt_btn = new QRadioButton( tr("Greater Than") ); + le_btn = new QRadioButton( tr("Less Than or Equal To") ); + ge_btn = new QRadioButton( tr("Greater Than or Equal To") ); + eq_btn = new QRadioButton( tr("Equal To") ); + ne_btn = new QRadioButton( tr("Not Equal To") ); + df_btn = new QRadioButton( tr("Different By:") ); + md_btn = new QRadioButton( tr("Modulo") ); + + eq_btn->setChecked(true); + + diffByEdit = new QLineEdit(); + moduloEdit = new QLineEdit(); + + vbox->addWidget( lt_btn ); + vbox->addWidget( gt_btn ); + vbox->addWidget( le_btn ); + vbox->addWidget( ge_btn ); + vbox->addWidget( eq_btn ); + vbox->addWidget( ne_btn ); + + hbox = new QHBoxLayout(); + vbox->addLayout( hbox ); + hbox->addWidget( df_btn ); + hbox->addWidget( diffByEdit ); + + hbox = new QHBoxLayout(); + vbox->addLayout( hbox ); + hbox->addWidget( md_btn ); + hbox->addWidget( moduloEdit ); + + vbox1 = new QVBoxLayout(); + grid = new QGridLayout(); + hbox2->addLayout( vbox1 ); + frame = new QGroupBox( tr("Compare To/By") ); + frame->setLayout( grid ); + vbox1->addWidget( frame ); + + pv_btn = new QRadioButton( tr("Previous Value") ); + sv_btn = new QRadioButton( tr("Specific Value:") ); + sa_btn = new QRadioButton( tr("Specific Address:") ); + nc_btn = new QRadioButton( tr("Number of Changes:") ); + + pv_btn->setChecked(true); + + specValEdit = new QLineEdit(); + specAddrEdit = new QLineEdit(); + numChangeEdit = new QLineEdit(); + + grid->addWidget( pv_btn , 0, 0, Qt::AlignLeft ); + grid->addWidget( sv_btn , 1, 0, Qt::AlignLeft ); + grid->addWidget( specValEdit , 1, 1, Qt::AlignLeft ); + grid->addWidget( sa_btn , 2, 0, Qt::AlignLeft ); + grid->addWidget( specAddrEdit , 2, 1, Qt::AlignLeft ); + grid->addWidget( nc_btn , 3, 0, Qt::AlignLeft ); + grid->addWidget( numChangeEdit, 3, 1, Qt::AlignLeft ); + + vbox = new QVBoxLayout(); + hbox3 = new QHBoxLayout(); + frame = new QGroupBox( tr("Data Size") ); + frame->setLayout( vbox ); + vbox1->addLayout( hbox3 ); + hbox3->addWidget( frame ); + + ds1_btn = new QRadioButton( tr("1 Byte") ); + ds2_btn = new QRadioButton( tr("2 Byte") ); + ds4_btn = new QRadioButton( tr("4 Byte") ); + misalignedCbox = new QCheckBox( tr("Check Misaligned") ); + misalignedCbox->setEnabled(false); + + ds1_btn->setChecked(true); + + vbox->addWidget( ds1_btn ); + vbox->addWidget( ds2_btn ); + vbox->addWidget( ds4_btn ); + vbox->addWidget( misalignedCbox ); + + vbox = new QVBoxLayout(); + vbox2 = new QVBoxLayout(); + frame = new QGroupBox( tr("Data Type / Display") ); + frame->setLayout( vbox ); + vbox2->addWidget( frame ); + hbox3->addLayout( vbox2 ); + + signed_btn = new QRadioButton( tr("Signed") ); + unsigned_btn = new QRadioButton( tr("Unsigned") ); + hex_btn = new QRadioButton( tr("Hexadecimal") ); + + vbox->addWidget( signed_btn ); + vbox->addWidget( unsigned_btn ); + vbox->addWidget( hex_btn ); + signed_btn->setChecked(true); + + autoSearchCbox = new QCheckBox( tr("Auto-Search") ); + autoSearchCbox->setEnabled(true); + vbox2->addWidget( autoSearchCbox ); + + setLayout( mainLayout ); + + updateTimer = new QTimer( this ); + + connect( updateTimer, &QTimer::timeout, this, &RamSearchDialog_t::periodicUpdate ); + + updateTimer->start( 100 ); // 10hz +} +//---------------------------------------------------------------------------- +RamSearchDialog_t::~RamSearchDialog_t(void) +{ + updateTimer->stop(); + printf("Destroy RAM Watch Config Window\n"); +} +//---------------------------------------------------------------------------- +void RamSearchDialog_t::closeEvent(QCloseEvent *event) +{ + printf("RAM Watch Close Window Event\n"); + done(0); + deleteLater(); + event->accept(); +} +//---------------------------------------------------------------------------- +void RamSearchDialog_t::closeWindow(void) +{ + //printf("Close Window\n"); + done(0); + deleteLater(); +} +//---------------------------------------------------------------------------- +void RamSearchDialog_t::periodicUpdate(void) +{ + bool buttonEnable; + QTreeWidgetItem *item; + + item = tree->currentItem(); + + if ( item == NULL ) + { + buttonEnable = false; + } + else + { + buttonEnable = true; + } +} +//---------------------------------------------------------------------------- diff --git a/src/drivers/Qt/RamSearch.h b/src/drivers/Qt/RamSearch.h new file mode 100644 index 00000000..0df1091e --- /dev/null +++ b/src/drivers/Qt/RamSearch.h @@ -0,0 +1,89 @@ +// RamSearch.h +// + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Qt/main.h" + +class RamSearchDialog_t : public QDialog +{ + Q_OBJECT + + public: + RamSearchDialog_t(QWidget *parent = 0); + ~RamSearchDialog_t(void); + + protected: + void closeEvent(QCloseEvent *event); + + QFont font; + QTreeWidget *tree; + QTimer *updateTimer; + QPushButton *searchButton; + QPushButton *resetButton; + QPushButton *clearChangeButton; + QPushButton *undoButton; + QPushButton *elimButton; + QPushButton *watchButton; + QPushButton *addCheatButton; + QPushButton *hexEditButton; + + QRadioButton *lt_btn; + QRadioButton *gt_btn; + QRadioButton *le_btn; + QRadioButton *ge_btn; + QRadioButton *eq_btn; + QRadioButton *ne_btn; + QRadioButton *df_btn; + QRadioButton *md_btn; + + QRadioButton *pv_btn; + QRadioButton *sv_btn; + QRadioButton *sa_btn; + QRadioButton *nc_btn; + + QRadioButton *ds1_btn; + QRadioButton *ds2_btn; + QRadioButton *ds4_btn; + + QRadioButton *signed_btn; + QRadioButton *unsigned_btn; + QRadioButton *hex_btn; + + QLineEdit *diffByEdit; + QLineEdit *moduloEdit; + QLineEdit *specValEdit; + QLineEdit *specAddrEdit; + QLineEdit *numChangeEdit; + + QCheckBox *searchROMCbox; + QCheckBox *misalignedCbox; + QCheckBox *autoSearchCbox; + + int fontCharWidth; + + private: + + public slots: + void closeWindow(void); + private slots: + void periodicUpdate(void); + //void watchClicked( QTreeWidgetItem *item, int column); + +}; + From 0f506dc348c7715a494bfd86627b841c92977642 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Sun, 11 Oct 2020 11:25:35 -0400 Subject: [PATCH 02/17] Qt Ram search logic in work. --- src/drivers/Qt/ConsoleWindow.cpp | 7 +- src/drivers/Qt/RamSearch.cpp | 1056 +++++++++++++++++++++++++++++- src/drivers/Qt/RamSearch.h | 1 + src/drivers/Qt/RamWatch.cpp | 2 +- 4 files changed, 1058 insertions(+), 8 deletions(-) diff --git a/src/drivers/Qt/ConsoleWindow.cpp b/src/drivers/Qt/ConsoleWindow.cpp index 5321636c..bb5bda85 100644 --- a/src/drivers/Qt/ConsoleWindow.cpp +++ b/src/drivers/Qt/ConsoleWindow.cpp @@ -1048,13 +1048,8 @@ void consoleWin_t::openRamWatch(void) void consoleWin_t::openRamSearch(void) { - RamSearchDialog_t *ramSearchWin; - //printf("Open GUI RAM Search Window\n"); - - ramSearchWin = new RamSearchDialog_t(this); - - ramSearchWin->show(); + openRamSearchWindow(this); } void consoleWin_t::openDebugWindow(void) diff --git a/src/drivers/Qt/RamSearch.cpp b/src/drivers/Qt/RamSearch.cpp index b7a149ee..52a835af 100644 --- a/src/drivers/Qt/RamSearch.cpp +++ b/src/drivers/Qt/RamSearch.cpp @@ -1,7 +1,8 @@ -// HotKeyConf.cpp +// RamSearch.cpp // #include #include +#include #include #include #include @@ -31,6 +32,1058 @@ #include "Qt/RamSearch.h" #include "Qt/ConsoleUtilities.h" +static bool ShowROM = false; +static RamSearchDialog_t *ramSearchWin = NULL; +// Too much work to do for resorting the values, and finding the biggest number +// by sorting in ram list doesn't help too much in usually use, so I gave it up. +// whitch column does the sort based on, the default status is 0 which means sorted by address +// static int ramSearchSortCol = 0; +// whether it's asc or desc sorting +// static bool ramSearchSortAsc = true; + +// used for changing colors of cheated address. +extern int numsubcheats; +extern CHEATF_SUBFAST SubCheats[256]; + +typedef unsigned int HWAddressType; + +//--------------------------------------------------------------------------------------- +// Static Prototypes +static void CompactAddrs(void); +static void signal_new_frame (void); +static void SetRamSearchUndoType(int type); +static unsigned int ReadValueAtHardwareAddress(HWAddressType address, unsigned int size); + +//--------------------------------------------------------------------------------------- + +static bool IsHardwareAddressValid(HWAddressType address) +{ + if (!GameInfo) + return false; + + if(!ShowROM) + if ((address >= 0x0000 && address < 0x0800) || (address >= 0x6000 && address < 0x8000)) + return true; + else + return false; + else + if (address >= 0x8000 && address < 0x10000) + return true; + else + return false; +} +#define INVALID_HARDWARE_ADDRESS ((HWAddressType) -1) + +struct MemoryRegion +{ + HWAddressType hardwareAddress; // hardware address of the start of this region + unsigned int size; // number of bytes to the end of this region + + unsigned int virtualIndex; // index into s_prevValues, s_curValues, and s_numChanges, valid after being initialized in ResetMemoryRegions() + unsigned int itemIndex; // index into listbox items, valid when s_itemIndicesInvalid is false + unsigned int cheatCount; // how many bytes affected by the cheats. 0 indicates for free, max value is the size. +}; + +static int MAX_RAM_SIZE = 0; +static unsigned char* s_prevValues = 0; // values at last search or reset +static unsigned char* s_curValues = 0; // values at last frame update +static unsigned short* s_numChanges = 0; // number of changes of the item starting at this virtual index address +static MemoryRegion** s_itemIndexToRegionPointer = 0; // used for random access into the memory list (trading memory size to get speed here, too bad it's so much memory), only valid when s_itemIndicesInvalid is false +static bool s_itemIndicesInvalid = true; // if true, the link from listbox items to memory regions (s_itemIndexToRegionPointer) and the link from memory regions to list box items (MemoryRegion::itemIndex) both need to be recalculated +static bool s_prevValuesNeedUpdate = true; // if true, the "prev" values should be updated using the "cur" values on the next frame update signaled +static unsigned int s_maxItemIndex = 0; // max currently valid item index, the listbox sometimes tries to update things past the end of the list so we need to know this to ignore those attempts + +static int disableRamSearchUpdate = false; + +// list of contiguous uneliminated memory regions +typedef std::list MemoryList; +static MemoryList s_activeMemoryRegions; +//static CRITICAL_SECTION s_activeMemoryRegionsCS; + +// for undo support (could be better, but this way was really easy) +static MemoryList s_activeMemoryRegionsBackup; +static int s_undoType = 0; // 0 means can't undo, 1 means can undo, 2 means can redo + +//void RamSearchSaveUndoStateIfNotTooBig(HWND hDlg); +static const int tooManyRegionsForUndo = 10000; + +static void ResetMemoryRegions(void) +{ +// Clear_Sound_Buffer(); + fceuWrapperLock(); + + s_activeMemoryRegions.clear(); + + // use IsHardwareAddressValid to figure out what all the possible memory regions are, + // split up wherever there's a discontinuity in the address in our software RAM. + static const int regionSearchGranularity = 1; // if this is too small, we'll waste time (in this function only), but if any region in RAM isn't evenly divisible by this, we might crash. + HWAddressType hwRegionStart = INVALID_HARDWARE_ADDRESS; + HWAddressType hwRegionEnd = INVALID_HARDWARE_ADDRESS; + for(HWAddressType addr = 0; addr != 0x10000+regionSearchGranularity; addr += regionSearchGranularity) + { + if (!IsHardwareAddressValid(addr)) { + // create the region + if (hwRegionStart != INVALID_HARDWARE_ADDRESS && hwRegionEnd != INVALID_HARDWARE_ADDRESS) { + MemoryRegion region = { hwRegionStart, regionSearchGranularity + (hwRegionEnd - hwRegionStart) }; + s_activeMemoryRegions.push_back(region); + } + + hwRegionStart = INVALID_HARDWARE_ADDRESS; + hwRegionEnd = INVALID_HARDWARE_ADDRESS; + } + else { + if (hwRegionStart != INVALID_HARDWARE_ADDRESS) { + // continue region + hwRegionEnd = addr; + } + else { + // start new region + hwRegionStart = addr; + hwRegionEnd = addr; + } + } + } + + + int nextVirtualIndex = 0; + for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ++iter) + { + MemoryRegion& region = *iter; + region.virtualIndex = nextVirtualIndex; + nextVirtualIndex = region.virtualIndex + region.size + 4; + } + //assert(nextVirtualIndex <= MAX_RAM_SIZE); + + if(nextVirtualIndex > MAX_RAM_SIZE) + { + s_prevValues = (unsigned char*)realloc(s_prevValues, sizeof(unsigned char)*nextVirtualIndex); + memset(s_prevValues, 0, sizeof(unsigned char)*nextVirtualIndex); + + s_curValues = (unsigned char*)realloc(s_curValues, sizeof(unsigned char)*nextVirtualIndex); + memset(s_curValues, 0, sizeof(unsigned char)*nextVirtualIndex); + + s_numChanges = (unsigned short*)realloc(s_numChanges, sizeof(unsigned short)*nextVirtualIndex); + memset(s_numChanges, 0, sizeof(unsigned short)*nextVirtualIndex); + + s_itemIndexToRegionPointer = (MemoryRegion**)realloc(s_itemIndexToRegionPointer, sizeof(MemoryRegion*)*nextVirtualIndex); + memset(s_itemIndexToRegionPointer, 0, sizeof(MemoryRegion*)*nextVirtualIndex); + + MAX_RAM_SIZE = nextVirtualIndex; + } + fceuWrapperUnLock(); +} + +// eliminates a range of hardware addresses from the search results +// returns 2 if it changed the region and moved the iterator to another region +// returns 1 if it changed the region but didn't move the iterator +// returns 0 if it had no effect +// warning: don't call anything that takes an itemIndex in a loop that calls DeactivateRegion... +// doing so would be tremendously slow because DeactivateRegion invalidates the index cache +static int DeactivateRegion(MemoryRegion& region, MemoryList::iterator& iter, HWAddressType hardwareAddress, unsigned int size) +{ + if(hardwareAddress + size <= region.hardwareAddress || hardwareAddress >= region.hardwareAddress + region.size) + { + // region is unaffected + return 0; + } + else if(hardwareAddress > region.hardwareAddress && hardwareAddress + size >= region.hardwareAddress + region.size) + { + // erase end of region + region.size = hardwareAddress - region.hardwareAddress; + return 1; + } + else if(hardwareAddress <= region.hardwareAddress && hardwareAddress + size < region.hardwareAddress + region.size) + { + // erase start of region + int eraseSize = (hardwareAddress + size) - region.hardwareAddress; + region.hardwareAddress += eraseSize; + region.size -= eraseSize; + region.virtualIndex += eraseSize; + return 1; + } + else if(hardwareAddress <= region.hardwareAddress && hardwareAddress + size >= region.hardwareAddress + region.size) + { + // erase entire region + iter = s_activeMemoryRegions.erase(iter); + s_itemIndicesInvalid = true; + return 2; + } + else //if(hardwareAddress > region.hardwareAddress && hardwareAddress + size < region.hardwareAddress + region.size) + { + // split region + int eraseSize = (hardwareAddress + size) - region.hardwareAddress; + MemoryRegion region2 = {region.hardwareAddress + eraseSize, region.size - eraseSize, region.virtualIndex + eraseSize}; + region.size = hardwareAddress - region.hardwareAddress; + iter = s_activeMemoryRegions.insert(++iter, region2); + s_itemIndicesInvalid = true; + return 2; + } +} + +/* +// eliminates a range of hardware addresses from the search results +// this is a simpler but usually slower interface for the above function +void DeactivateRegion(HWAddressType hardwareAddress, unsigned int size) +{ + for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ) + { + MemoryRegion& region = *iter; + if(2 != DeactivateRegion(region, iter, hardwareAddress, size)) + ++iter; + } +} +*/ + +struct AutoCritSect +{ + AutoCritSect() { fceuWrapperLock(); } + ~AutoCritSect() { fceuWrapperUnLock(); } +}; + +// warning: can be slow +void CalculateItemIndices(int itemSize) +{ + AutoCritSect cs(); + unsigned int itemIndex = 0; + for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ++iter) + { + MemoryRegion& region = *iter; + region.itemIndex = itemIndex; + int startSkipSize = ((unsigned int)(itemSize - (unsigned int)region.hardwareAddress)) % itemSize; // FIXME: is this still ok? + unsigned int start = startSkipSize; + unsigned int end = region.size; + for (unsigned int i = start; i < end; i += itemSize) + s_itemIndexToRegionPointer[itemIndex++] = ®ion; + } + s_maxItemIndex = itemIndex; + s_itemIndicesInvalid = false; +} + +template +void UpdateRegionT(const MemoryRegion& region, const MemoryRegion* nextRegionPtr) +{ + //if(GetAsyncKeyState(VK_SHIFT) & 0x8000) // speed hack + // return; + + if(s_prevValuesNeedUpdate) + memcpy(s_prevValues + region.virtualIndex, s_curValues + region.virtualIndex, region.size + sizeof(compareType) - sizeof(stepType)); + + unsigned int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType); + + + HWAddressType hwSourceAddr = region.hardwareAddress - region.virtualIndex; + + unsigned int indexStart = region.virtualIndex + startSkipSize; + unsigned int indexEnd = region.virtualIndex + region.size; + + if(sizeof(compareType) == 1) + { + for(unsigned int i = indexStart; i < indexEnd; i++) + { + if(s_curValues[i] != ReadValueAtHardwareAddress(hwSourceAddr+i, 1)) // if value changed + { + s_curValues[i] = ReadValueAtHardwareAddress(hwSourceAddr+i, 1); // update value + //if(s_numChanges[i] != 0xFFFF) + s_numChanges[i]++; // increase change count + } + } + } + else // it's more complicated for non-byte sizes because: + { // - more than one byte can affect a given change count entry + // - when more than one of those bytes changes simultaneously the entry's change count should only increase by 1 + // - a few of those bytes can be outside the region + + unsigned int endSkipSize = ((unsigned int)(startSkipSize - region.size)) % sizeof(stepType); + unsigned int lastIndexToRead = indexEnd + endSkipSize + sizeof(compareType) - sizeof(stepType); + unsigned int lastIndexToCopy = lastIndexToRead; + if(nextRegionPtr) + { + const MemoryRegion& nextRegion = *nextRegionPtr; + int nextStartSkipSize = ((unsigned int)(sizeof(stepType) - nextRegion.hardwareAddress)) % sizeof(stepType); + unsigned int nextIndexStart = nextRegion.virtualIndex + nextStartSkipSize; + if(lastIndexToCopy > nextIndexStart) + lastIndexToCopy = nextIndexStart; + } + + unsigned int nextValidChange [sizeof(compareType)]; + for(unsigned int i = 0; i < sizeof(compareType); i++) + nextValidChange[i] = indexStart + i; + + for(unsigned int i = indexStart, j = 0; i < lastIndexToRead; i++, j++) + { + if(s_curValues[i] != ReadValueAtHardwareAddress(hwSourceAddr+i, 1)) // if value of this byte changed + { + if(i < lastIndexToCopy) + s_curValues[i] = ReadValueAtHardwareAddress(hwSourceAddr+i, 1); // update value + for(int k = 0; k < sizeof(compareType); k++) // loop through the previous entries that contain this byte + { + if(i >= indexEnd+k) + continue; + int m = (j-k+sizeof(compareType)) & (sizeof(compareType)-1); + if(nextValidChange[m] <= i) // if we didn't already increase the change count for this entry + { + //if(s_numChanges[i-k] != 0xFFFF) + s_numChanges[i-k]++; // increase the change count for this entry + nextValidChange[m] = i-k+sizeof(compareType); // and remember not to increase it again + } + } + } + } + } +} + +template +void UpdateRegionsT() +{ + for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end();) + { + const MemoryRegion& region = *iter; + ++iter; + const MemoryRegion* nextRegion = (iter == s_activeMemoryRegions.end()) ? NULL : &*iter; + + UpdateRegionT(region, nextRegion); + } + + s_prevValuesNeedUpdate = false; +} + +template +int CountRegionItemsT() +{ + AutoCritSect cs(); + if(sizeof(stepType) == 1) + { + if(s_activeMemoryRegions.empty()) + return 0; + + if(s_itemIndicesInvalid) + CalculateItemIndices(sizeof(stepType)); + + MemoryRegion& lastRegion = s_activeMemoryRegions.back(); + return lastRegion.itemIndex + lastRegion.size; + } + else // the branch above is faster but won't work if the step size isn't 1 + { + int total = 0; + for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ++iter) + { + MemoryRegion& region = *iter; + int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType); + total += (region.size - startSkipSize + (sizeof(stepType)-1)) / sizeof(stepType); + } + return total; + } +} + +// returns information about the item in the form of a "fake" region +// that has the item in it and nothing else +template +void ItemIndexToVirtualRegion(unsigned int itemIndex, MemoryRegion& virtualRegion) +{ + if(s_itemIndicesInvalid) + CalculateItemIndices(sizeof(stepType)); + + if(itemIndex >= s_maxItemIndex) + { + memset(&virtualRegion, 0, sizeof(MemoryRegion)); + return; + } + + MemoryRegion* region = s_itemIndexToRegionPointer[itemIndex]; + + int bytesWithinRegion = (itemIndex - region->itemIndex) * sizeof(stepType); + int startSkipSize = ((unsigned int)(sizeof(stepType) - region->hardwareAddress)) % sizeof(stepType); + bytesWithinRegion += startSkipSize; + + virtualRegion.size = sizeof(compareType); + virtualRegion.hardwareAddress = region->hardwareAddress + bytesWithinRegion; + virtualRegion.virtualIndex = region->virtualIndex + bytesWithinRegion; + virtualRegion.itemIndex = itemIndex; + + virtualRegion.cheatCount = FCEU_CalcCheatAffectedBytes(virtualRegion.hardwareAddress, virtualRegion.size); +} + +template +unsigned int ItemIndexToVirtualIndex(unsigned int itemIndex) +{ + MemoryRegion virtualRegion; + ItemIndexToVirtualRegion(itemIndex, virtualRegion); + return virtualRegion.virtualIndex; +} + +template +T ReadLocalValue(const unsigned char* data) +{ + return *(const T*)data; +} +//template<> signed char ReadLocalValue(const unsigned char* data) { return *data; } +//template<> unsigned char ReadLocalValue(const unsigned char* data) { return *data; } + + +template +compareType GetPrevValueFromVirtualIndex(unsigned int virtualIndex) +{ + return ReadLocalValue(s_prevValues + virtualIndex); + //return *(compareType*)(s_prevValues+virtualIndex); +} +template +compareType GetCurValueFromVirtualIndex(unsigned int virtualIndex) +{ + return ReadLocalValue(s_curValues + virtualIndex); +// return *(compareType*)(s_curValues+virtualIndex); +} +template +unsigned short GetNumChangesFromVirtualIndex(unsigned int virtualIndex) +{ + unsigned short num = s_numChanges[virtualIndex]; + //for(unsigned int i = 1; i < sizeof(stepType); i++) + // if(num < s_numChanges[virtualIndex+i]) + // num = s_numChanges[virtualIndex+i]; + return num; +} + +template +compareType GetPrevValueFromItemIndex(unsigned int itemIndex) +{ + int virtualIndex = ItemIndexToVirtualIndex(itemIndex); + return GetPrevValueFromVirtualIndex(virtualIndex); +} +template +compareType GetCurValueFromItemIndex(unsigned int itemIndex) +{ + int virtualIndex = ItemIndexToVirtualIndex(itemIndex); + return GetCurValueFromVirtualIndex(virtualIndex); +} +template +unsigned short GetNumChangesFromItemIndex(unsigned int itemIndex) +{ + int virtualIndex = ItemIndexToVirtualIndex(itemIndex); + return GetNumChangesFromVirtualIndex(virtualIndex); +} +template +unsigned int GetHardwareAddressFromItemIndex(unsigned int itemIndex) +{ + MemoryRegion virtualRegion; + ItemIndexToVirtualRegion(itemIndex, virtualRegion); + return virtualRegion.hardwareAddress; +} +template +unsigned int GetNumCheatsFromIndex(unsigned int itemIndex) +{ + MemoryRegion virtualRegion; + ItemIndexToVirtualRegion(itemIndex, virtualRegion); + return virtualRegion.cheatCount; +} + +// this one might be unreliable, haven't used it much +template +unsigned int HardwareAddressToItemIndex(HWAddressType hardwareAddress) +{ + if(s_itemIndicesInvalid) + CalculateItemIndices(sizeof(stepType)); + + for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ++iter) + { + MemoryRegion& region = *iter; + if(hardwareAddress >= region.hardwareAddress && hardwareAddress < region.hardwareAddress + region.size) + { + int indexWithinRegion = (hardwareAddress - region.hardwareAddress) / sizeof(stepType); + return region.itemIndex + indexWithinRegion; + } + } + + return -1; +} + + + +// workaround for MSVC 7 that doesn't support varadic C99 macros +#define CALL_WITH_T_SIZE_TYPES_0(functionName, sizeTypeID, isSigned, requiresAligned) \ + (sizeTypeID == 'b' \ + ? (isSigned \ + ? functionName() \ + : functionName()) \ + : sizeTypeID == 'w' \ + ? (isSigned \ + ? (requiresAligned \ + ? functionName() \ + : functionName()) \ + : (requiresAligned \ + ? functionName() \ + : functionName())) \ + : sizeTypeID == 'd' \ + ? (isSigned \ + ? (requiresAligned \ + ? functionName() \ + : functionName()) \ + : (requiresAligned \ + ? functionName() \ + : functionName())) \ + : functionName()) + +#define CALL_WITH_T_SIZE_TYPES_1(functionName, sizeTypeID, isSigned, requiresAligned, p0) \ + (sizeTypeID == 'b' \ + ? (isSigned \ + ? functionName(p0) \ + : functionName(p0)) \ + : sizeTypeID == 'w' \ + ? (isSigned \ + ? (requiresAligned \ + ? functionName(p0) \ + : functionName(p0)) \ + : (requiresAligned \ + ? functionName(p0) \ + : functionName(p0))) \ + : sizeTypeID == 'd' \ + ? (isSigned \ + ? (requiresAligned \ + ? functionName(p0) \ + : functionName(p0)) \ + : (requiresAligned \ + ? functionName(p0) \ + : functionName(p0))) \ + : functionName(p0)) + +#define CALL_WITH_T_SIZE_TYPES_3(functionName, sizeTypeID, isSigned, requiresAligned, p0, p1, p2) \ + (sizeTypeID == 'b' \ + ? (isSigned \ + ? functionName(p0, p1, p2) \ + : functionName(p0, p1, p2)) \ + : sizeTypeID == 'w' \ + ? (isSigned \ + ? (requiresAligned \ + ? functionName(p0, p1, p2) \ + : functionName(p0, p1, p2)) \ + : (requiresAligned \ + ? functionName(p0, p1, p2) \ + : functionName(p0, p1, p2))) \ + : sizeTypeID == 'd' \ + ? (isSigned \ + ? (requiresAligned \ + ? functionName(p0, p1, p2) \ + : functionName(p0, p1, p2)) \ + : (requiresAligned \ + ? functionName(p0, p1, p2) \ + : functionName(p0, p1, p2))) \ + : functionName(p0, p1, p2)) + +#define CALL_WITH_T_SIZE_TYPES_4(functionName, sizeTypeID, isSigned, requiresAligned, p0, p1, p2, p3) \ + (sizeTypeID == 'b' \ + ? (isSigned \ + ? functionName(p0, p1, p2, p3) \ + : functionName(p0, p1, p2, p3)) \ + : sizeTypeID == 'w' \ + ? (isSigned \ + ? (requiresAligned \ + ? functionName(p0, p1, p2, p3) \ + : functionName(p0, p1, p2, p3)) \ + : (requiresAligned \ + ? functionName(p0, p1, p2, p3) \ + : functionName(p0, p1, p2, p3))) \ + : sizeTypeID == 'd' \ + ? (isSigned \ + ? (requiresAligned \ + ? functionName(p0, p1, p2, p3) \ + : functionName(p0, p1, p2, p3)) \ + : (requiresAligned \ + ? functionName(p0, p1, p2, p3) \ + : functionName(p0, p1, p2, p3))) \ + : functionName(p0, p1, p2, p3)) + +// version that takes a forced comparison type +#define CALL_WITH_T_STEP_3(functionName, sizeTypeID, type, requiresAligned, p0, p1, p2) \ + (sizeTypeID == 'b' \ + ? functionName(p0, p1, p2) \ + : sizeTypeID == 'w' \ + ? (requiresAligned \ + ? functionName(p0, p1, p2) \ + : functionName(p0, p1, p2)) \ + : sizeTypeID == 'd' \ + ? (requiresAligned \ + ? functionName(p0, p1, p2) \ + : functionName(p0, p1, p2)) \ + : functionName(p0, p1, p2)) + +// version that takes a forced comparison type +#define CALL_WITH_T_STEP_4(functionName, sizeTypeID, type, requiresAligned, p0, p1, p2, p3) \ + (sizeTypeID == 'b' \ + ? functionName(p0, p1, p2, p3) \ + : sizeTypeID == 'w' \ + ? (requiresAligned \ + ? functionName(p0, p1, p2, p3) \ + : functionName(p0, p1, p2, p3)) \ + : sizeTypeID == 'd' \ + ? (requiresAligned \ + ? functionName(p0, p1, p2, p3) \ + : functionName(p0, p1, p2, p3)) \ + : functionName(p0, p1, p2, p3)) + +#define CONV_VAL_TO_STR(sizeTypeID, type, val, buf) (sprintf(buf, type == 's' ? "%d" : type == 'u' ? "%u" : type == 'd' ? "%08X" : type == 'w' ? "%04X" : "%02X", sizeTypeID == 'd' ? (type == 's' ? (long)(val & 0xFFFFFFFF) : (unsigned long)(val & 0xFFFFFFFF)) : sizeTypeID == 'w' ? (type == 's' ? (short)(val & 0xFFFF) : (unsigned short)(val & 0xFFFF)) : (type == 's' ? (char)(val & 0xFF) : (unsigned char)(val & 0xFF))), buf) + +#define ConvEditTextNum(hDlg, id, sizeTypeID, type) \ +{ \ + BOOL success = false; \ + int val = ReadControlInt(id, type == 'h', success); \ + if (success) \ + { \ + char num[11]; \ + SetDlgItemText(hDlg, id, CONV_VAL_TO_STR(sizeTypeID, type, val, num)); \ + } else SetDlgItemText(hDlg, id, ""); \ +} +// basic comparison functions: +template inline bool LessCmp (T x, T y, T i) { return x < y; } +template inline bool MoreCmp (T x, T y, T i) { return x > y; } +template inline bool LessEqualCmp (T x, T y, T i) { return x <= y; } +template inline bool MoreEqualCmp (T x, T y, T i) { return x >= y; } +template inline bool EqualCmp (T x, T y, T i) { return x == y; } +template inline bool UnequalCmp (T x, T y, T i) { return x != y; } +template inline bool DiffByCmp (T x, T y, T p) { return x - y == p || y - x == p; } +template inline bool ModIsCmp (T x, T y, T p) { return p && x % p == y; } + +// compare-to type functions: +template +void SearchRelative (bool(*cmpFun)(T,T,T), T ignored, T param) +{ + for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ) + { + MemoryRegion& region = *iter; + int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType); + unsigned int start = region.virtualIndex + startSkipSize; + unsigned int end = region.virtualIndex + region.size; + for(unsigned int i = start, hwaddr = region.hardwareAddress; i < end; i += sizeof(stepType), hwaddr += sizeof(stepType)) + if(!cmpFun(GetCurValueFromVirtualIndex(i), GetPrevValueFromVirtualIndex(i), param)) + if(2 == DeactivateRegion(region, iter, hwaddr, sizeof(stepType))) + goto outerContinue; + ++iter; +outerContinue: + continue; + } +} +template +void SearchSpecific (bool(*cmpFun)(T,T,T), T value, T param) +{ + for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ) + { + MemoryRegion& region = *iter; + int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType); + unsigned int start = region.virtualIndex + startSkipSize; + unsigned int end = region.virtualIndex + region.size; + for(unsigned int i = start, hwaddr = region.hardwareAddress; i < end; i += sizeof(stepType), hwaddr += sizeof(stepType)) + if(!cmpFun(GetCurValueFromVirtualIndex(i), value, param)) + if(2 == DeactivateRegion(region, iter, hwaddr, sizeof(stepType))) + goto outerContinue; + ++iter; +outerContinue: + continue; + } +} +template +void SearchAddress (bool(*cmpFun)(T,T,T), T address, T param) +{ + for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ) + { + MemoryRegion& region = *iter; + int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType); + unsigned int start = region.virtualIndex + startSkipSize; + unsigned int end = region.virtualIndex + region.size; + for(unsigned int i = start, hwaddr = region.hardwareAddress; i < end; i += sizeof(stepType), hwaddr += sizeof(stepType)) + if(!cmpFun(hwaddr, address, param)) + if(2 == DeactivateRegion(region, iter, hwaddr, sizeof(stepType))) + goto outerContinue; + ++iter; +outerContinue: + continue; + } +} +template +void SearchChanges (bool(*cmpFun)(T,T,T), T changes, T param) +{ + for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ) + { + MemoryRegion& region = *iter; + int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType); + unsigned int start = region.virtualIndex + startSkipSize; + unsigned int end = region.virtualIndex + region.size; + for(unsigned int i = start, hwaddr = region.hardwareAddress; i < end; i += sizeof(stepType), hwaddr += sizeof(stepType)) + if(!cmpFun(GetNumChangesFromVirtualIndex(i), changes, param)) + if(2 == DeactivateRegion(region, iter, hwaddr, sizeof(stepType))) + goto outerContinue; + ++iter; +outerContinue: + continue; + } +} + +static char rs_c='s'; +static char rs_o='='; +static char rs_t='s'; +static int rs_param=0, rs_val=0, rs_val_valid=0; +static char rs_type_size = 'b', rs_last_type_size = rs_type_size; +static bool noMisalign = true, rs_last_no_misalign = noMisalign; +//static bool littleEndian = false; +static int last_rs_possible = -1; +static int last_rs_regions = -1; + +static void prune(char c,char o,char t,int v,int p) +{ + // repetition-reducing macros + #define DO_SEARCH(sf) \ + switch (o) \ + { \ + case '<': DO_SEARCH_2(LessCmp,sf); break; \ + case '>': DO_SEARCH_2(MoreCmp,sf); break; \ + case '=': DO_SEARCH_2(EqualCmp,sf); break; \ + case '!': DO_SEARCH_2(UnequalCmp,sf); break; \ + case 'l': DO_SEARCH_2(LessEqualCmp,sf); break; \ + case 'm': DO_SEARCH_2(MoreEqualCmp,sf); break; \ + case 'd': DO_SEARCH_2(DiffByCmp,sf); break; \ + case '%': DO_SEARCH_2(ModIsCmp,sf); break; \ + default: assert(!"Invalid operator for this search type."); break; \ + } + + // perform the search, eliminating nonmatching values + switch (c) + { + #define DO_SEARCH_2(CmpFun,sf) CALL_WITH_T_SIZE_TYPES_3(sf, rs_type_size, t, noMisalign, CmpFun,v,p) + case 'r': DO_SEARCH(SearchRelative); break; + case 's': DO_SEARCH(SearchSpecific); break; + + #undef DO_SEARCH_2 + #define DO_SEARCH_2(CmpFun,sf) CALL_WITH_T_STEP_3(sf, rs_type_size, unsigned int, noMisalign, CmpFun,v,p) + case 'a': DO_SEARCH(SearchAddress); break; + + #undef DO_SEARCH_2 + #define DO_SEARCH_2(CmpFun,sf) CALL_WITH_T_STEP_3(sf, rs_type_size, unsigned short, noMisalign, CmpFun,v,p) + case 'n': DO_SEARCH(SearchChanges); break; + + default: assert(!"Invalid search comparison type."); break; + } + + s_prevValuesNeedUpdate = true; + + int prevNumItems = last_rs_possible; + + CompactAddrs(); + + if(prevNumItems == last_rs_possible) + { + SetRamSearchUndoType(0); // nothing to undo + } +} + + + + +template +bool CompareRelativeAtItem (bool(*cmpFun)(T,T,T), int itemIndex, T ignored, T param) +{ + return cmpFun(GetCurValueFromItemIndex(itemIndex), GetPrevValueFromItemIndex(itemIndex), param); +} +template +bool CompareSpecificAtItem (bool(*cmpFun)(T,T,T), int itemIndex, T value, T param) +{ + return cmpFun(GetCurValueFromItemIndex(itemIndex), value, param); +} +template +bool CompareAddressAtItem (bool(*cmpFun)(T,T,T), int itemIndex, T address, T param) +{ + return cmpFun(GetHardwareAddressFromItemIndex(itemIndex), address, param); +} +template +bool CompareChangesAtItem (bool(*cmpFun)(T,T,T), int itemIndex, T changes, T param) +{ + return cmpFun(GetNumChangesFromItemIndex(itemIndex), changes, param); +} + +static int cmpVal = 0; +static int cmpAddr = 0; +static int cmpChgs = 0; +static int diffByVal = 0; +static int moduloVal = 0; + +static bool Set_RS_Val(void) +{ + bool success = true; + + // update rs_val + switch(rs_c) + { + case 'r': + default: + rs_val = 0; + break; + case 's': + rs_val = cmpVal; success = true; + if(!success) + return false; + if((rs_type_size == 'b' && rs_t == 's' && (rs_val < -128 || rs_val > 127)) || + (rs_type_size == 'b' && rs_t != 's' && (rs_val < 0 || rs_val > 255)) || + (rs_type_size == 'w' && rs_t == 's' && (rs_val < -32768 || rs_val > 32767)) || + (rs_type_size == 'w' && rs_t != 's' && (rs_val < 0 || rs_val > 65535))) + return false; + break; + case 'a': + rs_val = cmpAddr; success = true; + if(!success || rs_val < 0 || rs_val > 0x06040000) + return false; + break; + case 'n': { + rs_val = cmpChgs; success = true; + if(!success || rs_val < 0 || rs_val > 0xFFFF) + return false; + } break; + } + + // also update rs_param + switch(rs_o) + { + default: + rs_param = 0; + break; + case 'd': + rs_param = diffByVal; success = true; + if(!success) + return false; + if(rs_param < 0) + rs_param = -rs_param; + break; + case '%': + rs_param = moduloVal; success = true; + if(!success || rs_param == 0) + return false; + break; + } + + // validate that rs_param fits in the comparison data type + { + int appliedSize = rs_type_size; + int appliedSign = rs_t; + if(rs_c == 'n') + appliedSize = 'w', appliedSign = 'u'; + if(rs_c == 'a') + appliedSize = 'd', appliedSign = 'u'; + if((appliedSize == 'b' && appliedSign == 's' && (rs_param < -128 || rs_param > 127)) || + (appliedSize == 'b' && appliedSign != 's' && (rs_param < 0 || rs_param > 255)) || + (appliedSize == 'w' && appliedSign == 's' && (rs_param < -32768 || rs_param > 32767)) || + (appliedSize == 'w' && appliedSign != 's' && (rs_param < 0 || rs_param > 65535))) + return false; + } + + return true; +} + +static bool IsSatisfied(int itemIndex) +{ + if(!rs_val_valid) + return true; + int o = rs_o; + switch (rs_c) + { + #undef DO_SEARCH_2 + #define DO_SEARCH_2(CmpFun,sf) return CALL_WITH_T_SIZE_TYPES_4(sf, rs_type_size,(rs_t=='s'),noMisalign, CmpFun,itemIndex,rs_val,rs_param); + case 'r': DO_SEARCH(CompareRelativeAtItem); break; + case 's': DO_SEARCH(CompareSpecificAtItem); break; + + #undef DO_SEARCH_2 + #define DO_SEARCH_2(CmpFun,sf) return CALL_WITH_T_STEP_4(sf, rs_type_size, unsigned int, noMisalign, CmpFun,itemIndex,rs_val,rs_param); + case 'a': DO_SEARCH(CompareAddressAtItem); break; + + #undef DO_SEARCH_2 + #define DO_SEARCH_2(CmpFun,sf) return CALL_WITH_T_STEP_4(sf, rs_type_size, unsigned short, noMisalign, CmpFun,itemIndex,rs_val,rs_param); + case 'n': DO_SEARCH(CompareChangesAtItem); break; + } + return false; +} + + + +static unsigned int ReadValueAtSoftwareAddress(const unsigned char* address, unsigned int size) +{ + unsigned int value = 0; + //if(!byteSwapped) + { + // assumes we're little-endian + memcpy(&value, address, size); + } + return value; +} +static void WriteValueAtSoftwareAddress(unsigned char* address, unsigned int value, unsigned int size) +{ + //if(!byteSwapped) + { + // assumes we're little-endian + memcpy(address, &value, size); + } +} +static unsigned int ReadValueAtHardwareAddress(HWAddressType address, unsigned int size) +{ + unsigned int value = 0; + + // read as little endian + for(unsigned int i = 0; i < size; i++) + { + value <<= 8; + value |= (IsHardwareAddressValid(address) ? GetMem(address) : 0); + address++; + } + return value; +} +static bool WriteValueAtHardwareAddress(HWAddressType address, unsigned int value, unsigned int size) +{ + // TODO: NYI + return false; +} + + + +static int ResultCount=0; +static bool AutoSearch=false; +static bool AutoSearchAutoRetry=false; +static void UpdatePossibilities(int rs_possible, int regions); + + +static void CompactAddrs(void) +{ + int size = (rs_type_size=='b' || !noMisalign) ? 1 : 2; + int prevResultCount = ResultCount; + + CalculateItemIndices(size); + ResultCount = CALL_WITH_T_SIZE_TYPES_0(CountRegionItemsT, rs_type_size,rs_t=='s',noMisalign); + + UpdatePossibilities(ResultCount, (int)s_activeMemoryRegions.size()); + + // FIXME + //if(ResultCount != prevResultCount) + // ListView_SetItemCount(GetDlgItem(RamSearchHWnd,IDC_RAMLIST),ResultCount); +} + +static void soft_reset_address_info (void) +{ + /* + if (resetPrevValues) { + if(s_prevValues) + memcpy(s_prevValues, s_curValues, (sizeof(*s_prevValues)*(MAX_RAM_SIZE))); + s_prevValuesNeedUpdate = false; + }*/ + s_prevValuesNeedUpdate = false; + ResetMemoryRegions(); +// UpdateMemoryCheatStatus(); + if(ramSearchWin == NULL) + { + fceuWrapperLock(); + s_activeMemoryRegions.clear(); + fceuWrapperUnLock(); + ResultCount = 0; + } + else + { + // force s_prevValues to be valid + signal_new_frame(); + s_prevValuesNeedUpdate = true; + signal_new_frame(); + } + if(s_numChanges) + memset(s_numChanges, 0, (sizeof(*s_numChanges)*(MAX_RAM_SIZE))); + CompactAddrs(); +} +static void reset_address_info (void) +{ + SetRamSearchUndoType(0); + fceuWrapperLock(); + s_activeMemoryRegionsBackup.clear(); // not necessary, but we'll take the time hit here instead of at the next thing that sets up an undo + fceuWrapperUnLock(); + if(s_prevValues) + memcpy(s_prevValues, s_curValues, (sizeof(*s_prevValues)*(MAX_RAM_SIZE))); + s_prevValuesNeedUpdate = false; + ResetMemoryRegions(); +// UpdateMemoryCheatStatus(); + if (ramSearchWin == NULL) + { + fceuWrapperLock(); + s_activeMemoryRegions.clear(); + fceuWrapperUnLock(); + ResultCount = 0; + } + else + { + // force s_prevValues to be valid + signal_new_frame(); + s_prevValuesNeedUpdate = true; + signal_new_frame(); + } + memset(s_numChanges, 0, (sizeof(*s_numChanges)*(MAX_RAM_SIZE))); + CompactAddrs(); +} + +static void signal_new_frame (void) +{ + fceuWrapperLock(); + CALL_WITH_T_SIZE_TYPES_0(UpdateRegionsT, rs_type_size, rs_t=='s', noMisalign); + fceuWrapperUnLock(); +} + +static void SetRamSearchUndoType(int type) +{ + if (s_undoType != type) + { + //if((s_undoType!=2 && s_undoType!=-1)!=(type!=2 && type!=-1)) + // SendDlgItemMessage(hDlg,IDC_C_UNDO,WM_SETTEXT,0,(LPARAM)((type == 2 || type == -1) ? "Redo" : "Undo")); + //if((s_undoType>0)!=(type>0)) + // EnableWindow(GetDlgItem(hDlg,IDC_C_UNDO),type>0); + s_undoType = type; + } +} + +static void UpdateRamSearchTitleBar(int percent = -1) +{ + char Str_Tmp[128]; +#define HEADER_STR " RAM Search - " +#define PROGRESS_STR " %d%% ... " +#define STATUS_STR "%d Possibilit%s (%d Region%s)" + + int poss = last_rs_possible; + int regions = last_rs_regions; + if (poss <= 0) + { + strcpy(Str_Tmp," RAM Search"); + } + else if (percent <= 0) + { + sprintf(Str_Tmp, HEADER_STR STATUS_STR, poss, poss==1?"y":"ies", regions, regions==1?"":"s"); + } + else + { + sprintf(Str_Tmp, PROGRESS_STR STATUS_STR, percent, poss, poss==1?"y":"ies", regions, regions==1?"":"s"); + } + + if ( ramSearchWin ) + { + ramSearchWin->setWindowTitle("RAM Search"); + } +} + +static void UpdatePossibilities(int rs_possible, int regions) +{ + if (rs_possible != last_rs_possible) + { + last_rs_possible = rs_possible; + last_rs_regions = regions; + UpdateRamSearchTitleBar(); + } +} + +//---------------------------------------------------------------------------- +void openRamSearchWindow( QWidget *parent ) +{ + if ( ramSearchWin != NULL ) + { + return; + } + ramSearchWin = new RamSearchDialog_t(parent); + + ramSearchWin->show(); +} + //---------------------------------------------------------------------------- RamSearchDialog_t::RamSearchDialog_t(QWidget *parent) : QDialog( parent ) @@ -251,6 +1304,7 @@ RamSearchDialog_t::~RamSearchDialog_t(void) { updateTimer->stop(); printf("Destroy RAM Watch Config Window\n"); + ramSearchWin = NULL; } //---------------------------------------------------------------------------- void RamSearchDialog_t::closeEvent(QCloseEvent *event) diff --git a/src/drivers/Qt/RamSearch.h b/src/drivers/Qt/RamSearch.h index 0df1091e..c026acad 100644 --- a/src/drivers/Qt/RamSearch.h +++ b/src/drivers/Qt/RamSearch.h @@ -87,3 +87,4 @@ class RamSearchDialog_t : public QDialog }; +void openRamSearchWindow(QWidget *parent); diff --git a/src/drivers/Qt/RamWatch.cpp b/src/drivers/Qt/RamWatch.cpp index 63b6b5ab..ea1cf86b 100644 --- a/src/drivers/Qt/RamWatch.cpp +++ b/src/drivers/Qt/RamWatch.cpp @@ -1,4 +1,4 @@ -// HotKeyConf.cpp +// RamWatch.cpp // #include #include From cfa752a69312b4099998db3db76d44d80154aa84 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Sun, 11 Oct 2020 21:36:26 -0400 Subject: [PATCH 03/17] Qt Ram Search window in work. QTreeWidget does not handle large data sets very efficiently. Going to have to make a custom widget. --- src/drivers/Qt/RamSearch.cpp | 1220 +++++----------------------------- src/drivers/Qt/RamSearch.h | 3 + 2 files changed, 184 insertions(+), 1039 deletions(-) diff --git a/src/drivers/Qt/RamSearch.cpp b/src/drivers/Qt/RamSearch.cpp index 52a835af..379f6436 100644 --- a/src/drivers/Qt/RamSearch.cpp +++ b/src/drivers/Qt/RamSearch.cpp @@ -30,1047 +30,53 @@ #include "Qt/fceuWrapper.h" #include "Qt/RamWatch.h" #include "Qt/RamSearch.h" +#include "Qt/CheatsConf.h" #include "Qt/ConsoleUtilities.h" static bool ShowROM = false; static RamSearchDialog_t *ramSearchWin = NULL; -// Too much work to do for resorting the values, and finding the biggest number -// by sorting in ram list doesn't help too much in usually use, so I gave it up. -// whitch column does the sort based on, the default status is 0 which means sorted by address -// static int ramSearchSortCol = 0; -// whether it's asc or desc sorting -// static bool ramSearchSortAsc = true; -// used for changing colors of cheated address. -extern int numsubcheats; -extern CHEATF_SUBFAST SubCheats[256]; +static uint64_t iterMask = 0x01; -typedef unsigned int HWAddressType; - -//--------------------------------------------------------------------------------------- -// Static Prototypes -static void CompactAddrs(void); -static void signal_new_frame (void); -static void SetRamSearchUndoType(int type); -static unsigned int ReadValueAtHardwareAddress(HWAddressType address, unsigned int size); - -//--------------------------------------------------------------------------------------- - -static bool IsHardwareAddressValid(HWAddressType address) +struct memoryState_t { - if (!GameInfo) - return false; - - if(!ShowROM) - if ((address >= 0x0000 && address < 0x0800) || (address >= 0x6000 && address < 0x8000)) - return true; - else - return false; - else - if (address >= 0x8000 && address < 0x10000) - return true; - else - return false; -} -#define INVALID_HARDWARE_ADDRESS ((HWAddressType) -1) - -struct MemoryRegion -{ - HWAddressType hardwareAddress; // hardware address of the start of this region - unsigned int size; // number of bytes to the end of this region - - unsigned int virtualIndex; // index into s_prevValues, s_curValues, and s_numChanges, valid after being initialized in ResetMemoryRegions() - unsigned int itemIndex; // index into listbox items, valid when s_itemIndicesInvalid is false - unsigned int cheatCount; // how many bytes affected by the cheats. 0 indicates for free, max value is the size. + union { + int8_t i; + uint8_t u; + } v8; + union { + int16_t i; + uint16_t u; + } v16; + union { + int32_t i; + uint32_t u; + } v32; }; -static int MAX_RAM_SIZE = 0; -static unsigned char* s_prevValues = 0; // values at last search or reset -static unsigned char* s_curValues = 0; // values at last frame update -static unsigned short* s_numChanges = 0; // number of changes of the item starting at this virtual index address -static MemoryRegion** s_itemIndexToRegionPointer = 0; // used for random access into the memory list (trading memory size to get speed here, too bad it's so much memory), only valid when s_itemIndicesInvalid is false -static bool s_itemIndicesInvalid = true; // if true, the link from listbox items to memory regions (s_itemIndexToRegionPointer) and the link from memory regions to list box items (MemoryRegion::itemIndex) both need to be recalculated -static bool s_prevValuesNeedUpdate = true; // if true, the "prev" values should be updated using the "cur" values on the next frame update signaled -static unsigned int s_maxItemIndex = 0; // max currently valid item index, the listbox sometimes tries to update things past the end of the list so we need to know this to ignore those attempts - -static int disableRamSearchUpdate = false; - -// list of contiguous uneliminated memory regions -typedef std::list MemoryList; -static MemoryList s_activeMemoryRegions; -//static CRITICAL_SECTION s_activeMemoryRegionsCS; - -// for undo support (could be better, but this way was really easy) -static MemoryList s_activeMemoryRegionsBackup; -static int s_undoType = 0; // 0 means can't undo, 1 means can undo, 2 means can redo - -//void RamSearchSaveUndoStateIfNotTooBig(HWND hDlg); -static const int tooManyRegionsForUndo = 10000; - -static void ResetMemoryRegions(void) +struct memoryLocation_t { -// Clear_Sound_Buffer(); - fceuWrapperLock(); + int addr; - s_activeMemoryRegions.clear(); + memoryState_t val; - // use IsHardwareAddressValid to figure out what all the possible memory regions are, - // split up wherever there's a discontinuity in the address in our software RAM. - static const int regionSearchGranularity = 1; // if this is too small, we'll waste time (in this function only), but if any region in RAM isn't evenly divisible by this, we might crash. - HWAddressType hwRegionStart = INVALID_HARDWARE_ADDRESS; - HWAddressType hwRegionEnd = INVALID_HARDWARE_ADDRESS; - for(HWAddressType addr = 0; addr != 0x10000+regionSearchGranularity; addr += regionSearchGranularity) + std::vector hist; + + uint32_t chgCount; + uint64_t elimMask; + + memoryLocation_t(void) { - if (!IsHardwareAddressValid(addr)) { - // create the region - if (hwRegionStart != INVALID_HARDWARE_ADDRESS && hwRegionEnd != INVALID_HARDWARE_ADDRESS) { - MemoryRegion region = { hwRegionStart, regionSearchGranularity + (hwRegionEnd - hwRegionStart) }; - s_activeMemoryRegions.push_back(region); - } - - hwRegionStart = INVALID_HARDWARE_ADDRESS; - hwRegionEnd = INVALID_HARDWARE_ADDRESS; - } - else { - if (hwRegionStart != INVALID_HARDWARE_ADDRESS) { - // continue region - hwRegionEnd = addr; - } - else { - // start new region - hwRegionStart = addr; - hwRegionEnd = addr; - } - } + addr = 0; val.v32.u = 0; + chgCount = 0; elimMask = 0; } - - - int nextVirtualIndex = 0; - for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ++iter) - { - MemoryRegion& region = *iter; - region.virtualIndex = nextVirtualIndex; - nextVirtualIndex = region.virtualIndex + region.size + 4; - } - //assert(nextVirtualIndex <= MAX_RAM_SIZE); - - if(nextVirtualIndex > MAX_RAM_SIZE) - { - s_prevValues = (unsigned char*)realloc(s_prevValues, sizeof(unsigned char)*nextVirtualIndex); - memset(s_prevValues, 0, sizeof(unsigned char)*nextVirtualIndex); - - s_curValues = (unsigned char*)realloc(s_curValues, sizeof(unsigned char)*nextVirtualIndex); - memset(s_curValues, 0, sizeof(unsigned char)*nextVirtualIndex); - - s_numChanges = (unsigned short*)realloc(s_numChanges, sizeof(unsigned short)*nextVirtualIndex); - memset(s_numChanges, 0, sizeof(unsigned short)*nextVirtualIndex); - - s_itemIndexToRegionPointer = (MemoryRegion**)realloc(s_itemIndexToRegionPointer, sizeof(MemoryRegion*)*nextVirtualIndex); - memset(s_itemIndexToRegionPointer, 0, sizeof(MemoryRegion*)*nextVirtualIndex); - - MAX_RAM_SIZE = nextVirtualIndex; - } - fceuWrapperUnLock(); -} - -// eliminates a range of hardware addresses from the search results -// returns 2 if it changed the region and moved the iterator to another region -// returns 1 if it changed the region but didn't move the iterator -// returns 0 if it had no effect -// warning: don't call anything that takes an itemIndex in a loop that calls DeactivateRegion... -// doing so would be tremendously slow because DeactivateRegion invalidates the index cache -static int DeactivateRegion(MemoryRegion& region, MemoryList::iterator& iter, HWAddressType hardwareAddress, unsigned int size) -{ - if(hardwareAddress + size <= region.hardwareAddress || hardwareAddress >= region.hardwareAddress + region.size) - { - // region is unaffected - return 0; - } - else if(hardwareAddress > region.hardwareAddress && hardwareAddress + size >= region.hardwareAddress + region.size) - { - // erase end of region - region.size = hardwareAddress - region.hardwareAddress; - return 1; - } - else if(hardwareAddress <= region.hardwareAddress && hardwareAddress + size < region.hardwareAddress + region.size) - { - // erase start of region - int eraseSize = (hardwareAddress + size) - region.hardwareAddress; - region.hardwareAddress += eraseSize; - region.size -= eraseSize; - region.virtualIndex += eraseSize; - return 1; - } - else if(hardwareAddress <= region.hardwareAddress && hardwareAddress + size >= region.hardwareAddress + region.size) - { - // erase entire region - iter = s_activeMemoryRegions.erase(iter); - s_itemIndicesInvalid = true; - return 2; - } - else //if(hardwareAddress > region.hardwareAddress && hardwareAddress + size < region.hardwareAddress + region.size) - { - // split region - int eraseSize = (hardwareAddress + size) - region.hardwareAddress; - MemoryRegion region2 = {region.hardwareAddress + eraseSize, region.size - eraseSize, region.virtualIndex + eraseSize}; - region.size = hardwareAddress - region.hardwareAddress; - iter = s_activeMemoryRegions.insert(++iter, region2); - s_itemIndicesInvalid = true; - return 2; - } -} - -/* -// eliminates a range of hardware addresses from the search results -// this is a simpler but usually slower interface for the above function -void DeactivateRegion(HWAddressType hardwareAddress, unsigned int size) -{ - for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ) - { - MemoryRegion& region = *iter; - if(2 != DeactivateRegion(region, iter, hardwareAddress, size)) - ++iter; - } -} -*/ - -struct AutoCritSect -{ - AutoCritSect() { fceuWrapperLock(); } - ~AutoCritSect() { fceuWrapperUnLock(); } }; +static struct memoryLocation_t memLoc[0x8000]; -// warning: can be slow -void CalculateItemIndices(int itemSize) -{ - AutoCritSect cs(); - unsigned int itemIndex = 0; - for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ++iter) - { - MemoryRegion& region = *iter; - region.itemIndex = itemIndex; - int startSkipSize = ((unsigned int)(itemSize - (unsigned int)region.hardwareAddress)) % itemSize; // FIXME: is this still ok? - unsigned int start = startSkipSize; - unsigned int end = region.size; - for (unsigned int i = start; i < end; i += itemSize) - s_itemIndexToRegionPointer[itemIndex++] = ®ion; - } - s_maxItemIndex = itemIndex; - s_itemIndicesInvalid = false; -} +static std::list actvSrchList; -template -void UpdateRegionT(const MemoryRegion& region, const MemoryRegion* nextRegionPtr) -{ - //if(GetAsyncKeyState(VK_SHIFT) & 0x8000) // speed hack - // return; - - if(s_prevValuesNeedUpdate) - memcpy(s_prevValues + region.virtualIndex, s_curValues + region.virtualIndex, region.size + sizeof(compareType) - sizeof(stepType)); - - unsigned int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType); - - - HWAddressType hwSourceAddr = region.hardwareAddress - region.virtualIndex; - - unsigned int indexStart = region.virtualIndex + startSkipSize; - unsigned int indexEnd = region.virtualIndex + region.size; - - if(sizeof(compareType) == 1) - { - for(unsigned int i = indexStart; i < indexEnd; i++) - { - if(s_curValues[i] != ReadValueAtHardwareAddress(hwSourceAddr+i, 1)) // if value changed - { - s_curValues[i] = ReadValueAtHardwareAddress(hwSourceAddr+i, 1); // update value - //if(s_numChanges[i] != 0xFFFF) - s_numChanges[i]++; // increase change count - } - } - } - else // it's more complicated for non-byte sizes because: - { // - more than one byte can affect a given change count entry - // - when more than one of those bytes changes simultaneously the entry's change count should only increase by 1 - // - a few of those bytes can be outside the region - - unsigned int endSkipSize = ((unsigned int)(startSkipSize - region.size)) % sizeof(stepType); - unsigned int lastIndexToRead = indexEnd + endSkipSize + sizeof(compareType) - sizeof(stepType); - unsigned int lastIndexToCopy = lastIndexToRead; - if(nextRegionPtr) - { - const MemoryRegion& nextRegion = *nextRegionPtr; - int nextStartSkipSize = ((unsigned int)(sizeof(stepType) - nextRegion.hardwareAddress)) % sizeof(stepType); - unsigned int nextIndexStart = nextRegion.virtualIndex + nextStartSkipSize; - if(lastIndexToCopy > nextIndexStart) - lastIndexToCopy = nextIndexStart; - } - - unsigned int nextValidChange [sizeof(compareType)]; - for(unsigned int i = 0; i < sizeof(compareType); i++) - nextValidChange[i] = indexStart + i; - - for(unsigned int i = indexStart, j = 0; i < lastIndexToRead; i++, j++) - { - if(s_curValues[i] != ReadValueAtHardwareAddress(hwSourceAddr+i, 1)) // if value of this byte changed - { - if(i < lastIndexToCopy) - s_curValues[i] = ReadValueAtHardwareAddress(hwSourceAddr+i, 1); // update value - for(int k = 0; k < sizeof(compareType); k++) // loop through the previous entries that contain this byte - { - if(i >= indexEnd+k) - continue; - int m = (j-k+sizeof(compareType)) & (sizeof(compareType)-1); - if(nextValidChange[m] <= i) // if we didn't already increase the change count for this entry - { - //if(s_numChanges[i-k] != 0xFFFF) - s_numChanges[i-k]++; // increase the change count for this entry - nextValidChange[m] = i-k+sizeof(compareType); // and remember not to increase it again - } - } - } - } - } -} - -template -void UpdateRegionsT() -{ - for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end();) - { - const MemoryRegion& region = *iter; - ++iter; - const MemoryRegion* nextRegion = (iter == s_activeMemoryRegions.end()) ? NULL : &*iter; - - UpdateRegionT(region, nextRegion); - } - - s_prevValuesNeedUpdate = false; -} - -template -int CountRegionItemsT() -{ - AutoCritSect cs(); - if(sizeof(stepType) == 1) - { - if(s_activeMemoryRegions.empty()) - return 0; - - if(s_itemIndicesInvalid) - CalculateItemIndices(sizeof(stepType)); - - MemoryRegion& lastRegion = s_activeMemoryRegions.back(); - return lastRegion.itemIndex + lastRegion.size; - } - else // the branch above is faster but won't work if the step size isn't 1 - { - int total = 0; - for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ++iter) - { - MemoryRegion& region = *iter; - int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType); - total += (region.size - startSkipSize + (sizeof(stepType)-1)) / sizeof(stepType); - } - return total; - } -} - -// returns information about the item in the form of a "fake" region -// that has the item in it and nothing else -template -void ItemIndexToVirtualRegion(unsigned int itemIndex, MemoryRegion& virtualRegion) -{ - if(s_itemIndicesInvalid) - CalculateItemIndices(sizeof(stepType)); - - if(itemIndex >= s_maxItemIndex) - { - memset(&virtualRegion, 0, sizeof(MemoryRegion)); - return; - } - - MemoryRegion* region = s_itemIndexToRegionPointer[itemIndex]; - - int bytesWithinRegion = (itemIndex - region->itemIndex) * sizeof(stepType); - int startSkipSize = ((unsigned int)(sizeof(stepType) - region->hardwareAddress)) % sizeof(stepType); - bytesWithinRegion += startSkipSize; - - virtualRegion.size = sizeof(compareType); - virtualRegion.hardwareAddress = region->hardwareAddress + bytesWithinRegion; - virtualRegion.virtualIndex = region->virtualIndex + bytesWithinRegion; - virtualRegion.itemIndex = itemIndex; - - virtualRegion.cheatCount = FCEU_CalcCheatAffectedBytes(virtualRegion.hardwareAddress, virtualRegion.size); -} - -template -unsigned int ItemIndexToVirtualIndex(unsigned int itemIndex) -{ - MemoryRegion virtualRegion; - ItemIndexToVirtualRegion(itemIndex, virtualRegion); - return virtualRegion.virtualIndex; -} - -template -T ReadLocalValue(const unsigned char* data) -{ - return *(const T*)data; -} -//template<> signed char ReadLocalValue(const unsigned char* data) { return *data; } -//template<> unsigned char ReadLocalValue(const unsigned char* data) { return *data; } - - -template -compareType GetPrevValueFromVirtualIndex(unsigned int virtualIndex) -{ - return ReadLocalValue(s_prevValues + virtualIndex); - //return *(compareType*)(s_prevValues+virtualIndex); -} -template -compareType GetCurValueFromVirtualIndex(unsigned int virtualIndex) -{ - return ReadLocalValue(s_curValues + virtualIndex); -// return *(compareType*)(s_curValues+virtualIndex); -} -template -unsigned short GetNumChangesFromVirtualIndex(unsigned int virtualIndex) -{ - unsigned short num = s_numChanges[virtualIndex]; - //for(unsigned int i = 1; i < sizeof(stepType); i++) - // if(num < s_numChanges[virtualIndex+i]) - // num = s_numChanges[virtualIndex+i]; - return num; -} - -template -compareType GetPrevValueFromItemIndex(unsigned int itemIndex) -{ - int virtualIndex = ItemIndexToVirtualIndex(itemIndex); - return GetPrevValueFromVirtualIndex(virtualIndex); -} -template -compareType GetCurValueFromItemIndex(unsigned int itemIndex) -{ - int virtualIndex = ItemIndexToVirtualIndex(itemIndex); - return GetCurValueFromVirtualIndex(virtualIndex); -} -template -unsigned short GetNumChangesFromItemIndex(unsigned int itemIndex) -{ - int virtualIndex = ItemIndexToVirtualIndex(itemIndex); - return GetNumChangesFromVirtualIndex(virtualIndex); -} -template -unsigned int GetHardwareAddressFromItemIndex(unsigned int itemIndex) -{ - MemoryRegion virtualRegion; - ItemIndexToVirtualRegion(itemIndex, virtualRegion); - return virtualRegion.hardwareAddress; -} -template -unsigned int GetNumCheatsFromIndex(unsigned int itemIndex) -{ - MemoryRegion virtualRegion; - ItemIndexToVirtualRegion(itemIndex, virtualRegion); - return virtualRegion.cheatCount; -} - -// this one might be unreliable, haven't used it much -template -unsigned int HardwareAddressToItemIndex(HWAddressType hardwareAddress) -{ - if(s_itemIndicesInvalid) - CalculateItemIndices(sizeof(stepType)); - - for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ++iter) - { - MemoryRegion& region = *iter; - if(hardwareAddress >= region.hardwareAddress && hardwareAddress < region.hardwareAddress + region.size) - { - int indexWithinRegion = (hardwareAddress - region.hardwareAddress) / sizeof(stepType); - return region.itemIndex + indexWithinRegion; - } - } - - return -1; -} - - - -// workaround for MSVC 7 that doesn't support varadic C99 macros -#define CALL_WITH_T_SIZE_TYPES_0(functionName, sizeTypeID, isSigned, requiresAligned) \ - (sizeTypeID == 'b' \ - ? (isSigned \ - ? functionName() \ - : functionName()) \ - : sizeTypeID == 'w' \ - ? (isSigned \ - ? (requiresAligned \ - ? functionName() \ - : functionName()) \ - : (requiresAligned \ - ? functionName() \ - : functionName())) \ - : sizeTypeID == 'd' \ - ? (isSigned \ - ? (requiresAligned \ - ? functionName() \ - : functionName()) \ - : (requiresAligned \ - ? functionName() \ - : functionName())) \ - : functionName()) - -#define CALL_WITH_T_SIZE_TYPES_1(functionName, sizeTypeID, isSigned, requiresAligned, p0) \ - (sizeTypeID == 'b' \ - ? (isSigned \ - ? functionName(p0) \ - : functionName(p0)) \ - : sizeTypeID == 'w' \ - ? (isSigned \ - ? (requiresAligned \ - ? functionName(p0) \ - : functionName(p0)) \ - : (requiresAligned \ - ? functionName(p0) \ - : functionName(p0))) \ - : sizeTypeID == 'd' \ - ? (isSigned \ - ? (requiresAligned \ - ? functionName(p0) \ - : functionName(p0)) \ - : (requiresAligned \ - ? functionName(p0) \ - : functionName(p0))) \ - : functionName(p0)) - -#define CALL_WITH_T_SIZE_TYPES_3(functionName, sizeTypeID, isSigned, requiresAligned, p0, p1, p2) \ - (sizeTypeID == 'b' \ - ? (isSigned \ - ? functionName(p0, p1, p2) \ - : functionName(p0, p1, p2)) \ - : sizeTypeID == 'w' \ - ? (isSigned \ - ? (requiresAligned \ - ? functionName(p0, p1, p2) \ - : functionName(p0, p1, p2)) \ - : (requiresAligned \ - ? functionName(p0, p1, p2) \ - : functionName(p0, p1, p2))) \ - : sizeTypeID == 'd' \ - ? (isSigned \ - ? (requiresAligned \ - ? functionName(p0, p1, p2) \ - : functionName(p0, p1, p2)) \ - : (requiresAligned \ - ? functionName(p0, p1, p2) \ - : functionName(p0, p1, p2))) \ - : functionName(p0, p1, p2)) - -#define CALL_WITH_T_SIZE_TYPES_4(functionName, sizeTypeID, isSigned, requiresAligned, p0, p1, p2, p3) \ - (sizeTypeID == 'b' \ - ? (isSigned \ - ? functionName(p0, p1, p2, p3) \ - : functionName(p0, p1, p2, p3)) \ - : sizeTypeID == 'w' \ - ? (isSigned \ - ? (requiresAligned \ - ? functionName(p0, p1, p2, p3) \ - : functionName(p0, p1, p2, p3)) \ - : (requiresAligned \ - ? functionName(p0, p1, p2, p3) \ - : functionName(p0, p1, p2, p3))) \ - : sizeTypeID == 'd' \ - ? (isSigned \ - ? (requiresAligned \ - ? functionName(p0, p1, p2, p3) \ - : functionName(p0, p1, p2, p3)) \ - : (requiresAligned \ - ? functionName(p0, p1, p2, p3) \ - : functionName(p0, p1, p2, p3))) \ - : functionName(p0, p1, p2, p3)) - -// version that takes a forced comparison type -#define CALL_WITH_T_STEP_3(functionName, sizeTypeID, type, requiresAligned, p0, p1, p2) \ - (sizeTypeID == 'b' \ - ? functionName(p0, p1, p2) \ - : sizeTypeID == 'w' \ - ? (requiresAligned \ - ? functionName(p0, p1, p2) \ - : functionName(p0, p1, p2)) \ - : sizeTypeID == 'd' \ - ? (requiresAligned \ - ? functionName(p0, p1, p2) \ - : functionName(p0, p1, p2)) \ - : functionName(p0, p1, p2)) - -// version that takes a forced comparison type -#define CALL_WITH_T_STEP_4(functionName, sizeTypeID, type, requiresAligned, p0, p1, p2, p3) \ - (sizeTypeID == 'b' \ - ? functionName(p0, p1, p2, p3) \ - : sizeTypeID == 'w' \ - ? (requiresAligned \ - ? functionName(p0, p1, p2, p3) \ - : functionName(p0, p1, p2, p3)) \ - : sizeTypeID == 'd' \ - ? (requiresAligned \ - ? functionName(p0, p1, p2, p3) \ - : functionName(p0, p1, p2, p3)) \ - : functionName(p0, p1, p2, p3)) - -#define CONV_VAL_TO_STR(sizeTypeID, type, val, buf) (sprintf(buf, type == 's' ? "%d" : type == 'u' ? "%u" : type == 'd' ? "%08X" : type == 'w' ? "%04X" : "%02X", sizeTypeID == 'd' ? (type == 's' ? (long)(val & 0xFFFFFFFF) : (unsigned long)(val & 0xFFFFFFFF)) : sizeTypeID == 'w' ? (type == 's' ? (short)(val & 0xFFFF) : (unsigned short)(val & 0xFFFF)) : (type == 's' ? (char)(val & 0xFF) : (unsigned char)(val & 0xFF))), buf) - -#define ConvEditTextNum(hDlg, id, sizeTypeID, type) \ -{ \ - BOOL success = false; \ - int val = ReadControlInt(id, type == 'h', success); \ - if (success) \ - { \ - char num[11]; \ - SetDlgItemText(hDlg, id, CONV_VAL_TO_STR(sizeTypeID, type, val, num)); \ - } else SetDlgItemText(hDlg, id, ""); \ -} -// basic comparison functions: -template inline bool LessCmp (T x, T y, T i) { return x < y; } -template inline bool MoreCmp (T x, T y, T i) { return x > y; } -template inline bool LessEqualCmp (T x, T y, T i) { return x <= y; } -template inline bool MoreEqualCmp (T x, T y, T i) { return x >= y; } -template inline bool EqualCmp (T x, T y, T i) { return x == y; } -template inline bool UnequalCmp (T x, T y, T i) { return x != y; } -template inline bool DiffByCmp (T x, T y, T p) { return x - y == p || y - x == p; } -template inline bool ModIsCmp (T x, T y, T p) { return p && x % p == y; } - -// compare-to type functions: -template -void SearchRelative (bool(*cmpFun)(T,T,T), T ignored, T param) -{ - for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ) - { - MemoryRegion& region = *iter; - int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType); - unsigned int start = region.virtualIndex + startSkipSize; - unsigned int end = region.virtualIndex + region.size; - for(unsigned int i = start, hwaddr = region.hardwareAddress; i < end; i += sizeof(stepType), hwaddr += sizeof(stepType)) - if(!cmpFun(GetCurValueFromVirtualIndex(i), GetPrevValueFromVirtualIndex(i), param)) - if(2 == DeactivateRegion(region, iter, hwaddr, sizeof(stepType))) - goto outerContinue; - ++iter; -outerContinue: - continue; - } -} -template -void SearchSpecific (bool(*cmpFun)(T,T,T), T value, T param) -{ - for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ) - { - MemoryRegion& region = *iter; - int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType); - unsigned int start = region.virtualIndex + startSkipSize; - unsigned int end = region.virtualIndex + region.size; - for(unsigned int i = start, hwaddr = region.hardwareAddress; i < end; i += sizeof(stepType), hwaddr += sizeof(stepType)) - if(!cmpFun(GetCurValueFromVirtualIndex(i), value, param)) - if(2 == DeactivateRegion(region, iter, hwaddr, sizeof(stepType))) - goto outerContinue; - ++iter; -outerContinue: - continue; - } -} -template -void SearchAddress (bool(*cmpFun)(T,T,T), T address, T param) -{ - for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ) - { - MemoryRegion& region = *iter; - int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType); - unsigned int start = region.virtualIndex + startSkipSize; - unsigned int end = region.virtualIndex + region.size; - for(unsigned int i = start, hwaddr = region.hardwareAddress; i < end; i += sizeof(stepType), hwaddr += sizeof(stepType)) - if(!cmpFun(hwaddr, address, param)) - if(2 == DeactivateRegion(region, iter, hwaddr, sizeof(stepType))) - goto outerContinue; - ++iter; -outerContinue: - continue; - } -} -template -void SearchChanges (bool(*cmpFun)(T,T,T), T changes, T param) -{ - for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ) - { - MemoryRegion& region = *iter; - int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType); - unsigned int start = region.virtualIndex + startSkipSize; - unsigned int end = region.virtualIndex + region.size; - for(unsigned int i = start, hwaddr = region.hardwareAddress; i < end; i += sizeof(stepType), hwaddr += sizeof(stepType)) - if(!cmpFun(GetNumChangesFromVirtualIndex(i), changes, param)) - if(2 == DeactivateRegion(region, iter, hwaddr, sizeof(stepType))) - goto outerContinue; - ++iter; -outerContinue: - continue; - } -} - -static char rs_c='s'; -static char rs_o='='; -static char rs_t='s'; -static int rs_param=0, rs_val=0, rs_val_valid=0; -static char rs_type_size = 'b', rs_last_type_size = rs_type_size; -static bool noMisalign = true, rs_last_no_misalign = noMisalign; -//static bool littleEndian = false; -static int last_rs_possible = -1; -static int last_rs_regions = -1; - -static void prune(char c,char o,char t,int v,int p) -{ - // repetition-reducing macros - #define DO_SEARCH(sf) \ - switch (o) \ - { \ - case '<': DO_SEARCH_2(LessCmp,sf); break; \ - case '>': DO_SEARCH_2(MoreCmp,sf); break; \ - case '=': DO_SEARCH_2(EqualCmp,sf); break; \ - case '!': DO_SEARCH_2(UnequalCmp,sf); break; \ - case 'l': DO_SEARCH_2(LessEqualCmp,sf); break; \ - case 'm': DO_SEARCH_2(MoreEqualCmp,sf); break; \ - case 'd': DO_SEARCH_2(DiffByCmp,sf); break; \ - case '%': DO_SEARCH_2(ModIsCmp,sf); break; \ - default: assert(!"Invalid operator for this search type."); break; \ - } - - // perform the search, eliminating nonmatching values - switch (c) - { - #define DO_SEARCH_2(CmpFun,sf) CALL_WITH_T_SIZE_TYPES_3(sf, rs_type_size, t, noMisalign, CmpFun,v,p) - case 'r': DO_SEARCH(SearchRelative); break; - case 's': DO_SEARCH(SearchSpecific); break; - - #undef DO_SEARCH_2 - #define DO_SEARCH_2(CmpFun,sf) CALL_WITH_T_STEP_3(sf, rs_type_size, unsigned int, noMisalign, CmpFun,v,p) - case 'a': DO_SEARCH(SearchAddress); break; - - #undef DO_SEARCH_2 - #define DO_SEARCH_2(CmpFun,sf) CALL_WITH_T_STEP_3(sf, rs_type_size, unsigned short, noMisalign, CmpFun,v,p) - case 'n': DO_SEARCH(SearchChanges); break; - - default: assert(!"Invalid search comparison type."); break; - } - - s_prevValuesNeedUpdate = true; - - int prevNumItems = last_rs_possible; - - CompactAddrs(); - - if(prevNumItems == last_rs_possible) - { - SetRamSearchUndoType(0); // nothing to undo - } -} - - - - -template -bool CompareRelativeAtItem (bool(*cmpFun)(T,T,T), int itemIndex, T ignored, T param) -{ - return cmpFun(GetCurValueFromItemIndex(itemIndex), GetPrevValueFromItemIndex(itemIndex), param); -} -template -bool CompareSpecificAtItem (bool(*cmpFun)(T,T,T), int itemIndex, T value, T param) -{ - return cmpFun(GetCurValueFromItemIndex(itemIndex), value, param); -} -template -bool CompareAddressAtItem (bool(*cmpFun)(T,T,T), int itemIndex, T address, T param) -{ - return cmpFun(GetHardwareAddressFromItemIndex(itemIndex), address, param); -} -template -bool CompareChangesAtItem (bool(*cmpFun)(T,T,T), int itemIndex, T changes, T param) -{ - return cmpFun(GetNumChangesFromItemIndex(itemIndex), changes, param); -} - -static int cmpVal = 0; -static int cmpAddr = 0; -static int cmpChgs = 0; -static int diffByVal = 0; -static int moduloVal = 0; - -static bool Set_RS_Val(void) -{ - bool success = true; - - // update rs_val - switch(rs_c) - { - case 'r': - default: - rs_val = 0; - break; - case 's': - rs_val = cmpVal; success = true; - if(!success) - return false; - if((rs_type_size == 'b' && rs_t == 's' && (rs_val < -128 || rs_val > 127)) || - (rs_type_size == 'b' && rs_t != 's' && (rs_val < 0 || rs_val > 255)) || - (rs_type_size == 'w' && rs_t == 's' && (rs_val < -32768 || rs_val > 32767)) || - (rs_type_size == 'w' && rs_t != 's' && (rs_val < 0 || rs_val > 65535))) - return false; - break; - case 'a': - rs_val = cmpAddr; success = true; - if(!success || rs_val < 0 || rs_val > 0x06040000) - return false; - break; - case 'n': { - rs_val = cmpChgs; success = true; - if(!success || rs_val < 0 || rs_val > 0xFFFF) - return false; - } break; - } - - // also update rs_param - switch(rs_o) - { - default: - rs_param = 0; - break; - case 'd': - rs_param = diffByVal; success = true; - if(!success) - return false; - if(rs_param < 0) - rs_param = -rs_param; - break; - case '%': - rs_param = moduloVal; success = true; - if(!success || rs_param == 0) - return false; - break; - } - - // validate that rs_param fits in the comparison data type - { - int appliedSize = rs_type_size; - int appliedSign = rs_t; - if(rs_c == 'n') - appliedSize = 'w', appliedSign = 'u'; - if(rs_c == 'a') - appliedSize = 'd', appliedSign = 'u'; - if((appliedSize == 'b' && appliedSign == 's' && (rs_param < -128 || rs_param > 127)) || - (appliedSize == 'b' && appliedSign != 's' && (rs_param < 0 || rs_param > 255)) || - (appliedSize == 'w' && appliedSign == 's' && (rs_param < -32768 || rs_param > 32767)) || - (appliedSize == 'w' && appliedSign != 's' && (rs_param < 0 || rs_param > 65535))) - return false; - } - - return true; -} - -static bool IsSatisfied(int itemIndex) -{ - if(!rs_val_valid) - return true; - int o = rs_o; - switch (rs_c) - { - #undef DO_SEARCH_2 - #define DO_SEARCH_2(CmpFun,sf) return CALL_WITH_T_SIZE_TYPES_4(sf, rs_type_size,(rs_t=='s'),noMisalign, CmpFun,itemIndex,rs_val,rs_param); - case 'r': DO_SEARCH(CompareRelativeAtItem); break; - case 's': DO_SEARCH(CompareSpecificAtItem); break; - - #undef DO_SEARCH_2 - #define DO_SEARCH_2(CmpFun,sf) return CALL_WITH_T_STEP_4(sf, rs_type_size, unsigned int, noMisalign, CmpFun,itemIndex,rs_val,rs_param); - case 'a': DO_SEARCH(CompareAddressAtItem); break; - - #undef DO_SEARCH_2 - #define DO_SEARCH_2(CmpFun,sf) return CALL_WITH_T_STEP_4(sf, rs_type_size, unsigned short, noMisalign, CmpFun,itemIndex,rs_val,rs_param); - case 'n': DO_SEARCH(CompareChangesAtItem); break; - } - return false; -} - - - -static unsigned int ReadValueAtSoftwareAddress(const unsigned char* address, unsigned int size) -{ - unsigned int value = 0; - //if(!byteSwapped) - { - // assumes we're little-endian - memcpy(&value, address, size); - } - return value; -} -static void WriteValueAtSoftwareAddress(unsigned char* address, unsigned int value, unsigned int size) -{ - //if(!byteSwapped) - { - // assumes we're little-endian - memcpy(address, &value, size); - } -} -static unsigned int ReadValueAtHardwareAddress(HWAddressType address, unsigned int size) -{ - unsigned int value = 0; - - // read as little endian - for(unsigned int i = 0; i < size; i++) - { - value <<= 8; - value |= (IsHardwareAddressValid(address) ? GetMem(address) : 0); - address++; - } - return value; -} -static bool WriteValueAtHardwareAddress(HWAddressType address, unsigned int value, unsigned int size) -{ - // TODO: NYI - return false; -} - - - -static int ResultCount=0; -static bool AutoSearch=false; -static bool AutoSearchAutoRetry=false; -static void UpdatePossibilities(int rs_possible, int regions); - - -static void CompactAddrs(void) -{ - int size = (rs_type_size=='b' || !noMisalign) ? 1 : 2; - int prevResultCount = ResultCount; - - CalculateItemIndices(size); - ResultCount = CALL_WITH_T_SIZE_TYPES_0(CountRegionItemsT, rs_type_size,rs_t=='s',noMisalign); - - UpdatePossibilities(ResultCount, (int)s_activeMemoryRegions.size()); - - // FIXME - //if(ResultCount != prevResultCount) - // ListView_SetItemCount(GetDlgItem(RamSearchHWnd,IDC_RAMLIST),ResultCount); -} - -static void soft_reset_address_info (void) -{ - /* - if (resetPrevValues) { - if(s_prevValues) - memcpy(s_prevValues, s_curValues, (sizeof(*s_prevValues)*(MAX_RAM_SIZE))); - s_prevValuesNeedUpdate = false; - }*/ - s_prevValuesNeedUpdate = false; - ResetMemoryRegions(); -// UpdateMemoryCheatStatus(); - if(ramSearchWin == NULL) - { - fceuWrapperLock(); - s_activeMemoryRegions.clear(); - fceuWrapperUnLock(); - ResultCount = 0; - } - else - { - // force s_prevValues to be valid - signal_new_frame(); - s_prevValuesNeedUpdate = true; - signal_new_frame(); - } - if(s_numChanges) - memset(s_numChanges, 0, (sizeof(*s_numChanges)*(MAX_RAM_SIZE))); - CompactAddrs(); -} -static void reset_address_info (void) -{ - SetRamSearchUndoType(0); - fceuWrapperLock(); - s_activeMemoryRegionsBackup.clear(); // not necessary, but we'll take the time hit here instead of at the next thing that sets up an undo - fceuWrapperUnLock(); - if(s_prevValues) - memcpy(s_prevValues, s_curValues, (sizeof(*s_prevValues)*(MAX_RAM_SIZE))); - s_prevValuesNeedUpdate = false; - ResetMemoryRegions(); -// UpdateMemoryCheatStatus(); - if (ramSearchWin == NULL) - { - fceuWrapperLock(); - s_activeMemoryRegions.clear(); - fceuWrapperUnLock(); - ResultCount = 0; - } - else - { - // force s_prevValues to be valid - signal_new_frame(); - s_prevValuesNeedUpdate = true; - signal_new_frame(); - } - memset(s_numChanges, 0, (sizeof(*s_numChanges)*(MAX_RAM_SIZE))); - CompactAddrs(); -} - -static void signal_new_frame (void) -{ - fceuWrapperLock(); - CALL_WITH_T_SIZE_TYPES_0(UpdateRegionsT, rs_type_size, rs_t=='s', noMisalign); - fceuWrapperUnLock(); -} - -static void SetRamSearchUndoType(int type) -{ - if (s_undoType != type) - { - //if((s_undoType!=2 && s_undoType!=-1)!=(type!=2 && type!=-1)) - // SendDlgItemMessage(hDlg,IDC_C_UNDO,WM_SETTEXT,0,(LPARAM)((type == 2 || type == -1) ? "Redo" : "Undo")); - //if((s_undoType>0)!=(type>0)) - // EnableWindow(GetDlgItem(hDlg,IDC_C_UNDO),type>0); - s_undoType = type; - } -} - -static void UpdateRamSearchTitleBar(int percent = -1) -{ - char Str_Tmp[128]; -#define HEADER_STR " RAM Search - " -#define PROGRESS_STR " %d%% ... " -#define STATUS_STR "%d Possibilit%s (%d Region%s)" - - int poss = last_rs_possible; - int regions = last_rs_regions; - if (poss <= 0) - { - strcpy(Str_Tmp," RAM Search"); - } - else if (percent <= 0) - { - sprintf(Str_Tmp, HEADER_STR STATUS_STR, poss, poss==1?"y":"ies", regions, regions==1?"":"s"); - } - else - { - sprintf(Str_Tmp, PROGRESS_STR STATUS_STR, percent, poss, poss==1?"y":"ies", regions, regions==1?"":"s"); - } - - if ( ramSearchWin ) - { - ramSearchWin->setWindowTitle("RAM Search"); - } -} - -static void UpdatePossibilities(int rs_possible, int regions) -{ - if (rs_possible != last_rs_possible) - { - last_rs_possible = rs_possible; - last_rs_regions = regions; - UpdateRamSearchTitleBar(); - } -} +static int dpySize = 'b'; +static int dpyType = 's'; //---------------------------------------------------------------------------- void openRamSearchWindow( QWidget *parent ) @@ -1143,12 +149,12 @@ RamSearchDialog_t::RamSearchDialog_t(QWidget *parent) searchButton = new QPushButton( tr("Search") ); vbox->addWidget( searchButton ); - //connect( searchButton, SIGNAL(clicked(void)), this, SLOT(moveWatchUpClicked(void))); + connect( searchButton, SIGNAL(clicked(void)), this, SLOT(runSearch(void))); //searchButton->setEnabled(false); resetButton = new QPushButton( tr("Reset") ); vbox->addWidget( resetButton ); - //connect( resetButton, SIGNAL(clicked(void)), this, SLOT(moveWatchDownClicked(void))); + connect( resetButton, SIGNAL(clicked(void)), this, SLOT(resetSearch(void))); //down_btn->setEnabled(false); clearChangeButton = new QPushButton( tr("Clear Change") ); @@ -1293,6 +299,8 @@ RamSearchDialog_t::RamSearchDialog_t(QWidget *parent) setLayout( mainLayout ); + resetSearch(); + updateTimer = new QTimer( this ); connect( updateTimer, &QTimer::timeout, this, &RamSearchDialog_t::periodicUpdate ); @@ -1305,6 +313,13 @@ RamSearchDialog_t::~RamSearchDialog_t(void) updateTimer->stop(); printf("Destroy RAM Watch Config Window\n"); ramSearchWin = NULL; + + actvSrchList.clear(); + + for (unsigned int addr=0; addr<0x08000; addr++) + { + memLoc[addr].hist.clear(); + } } //---------------------------------------------------------------------------- void RamSearchDialog_t::closeEvent(QCloseEvent *event) @@ -1324,18 +339,145 @@ void RamSearchDialog_t::closeWindow(void) //---------------------------------------------------------------------------- void RamSearchDialog_t::periodicUpdate(void) { - bool buttonEnable; - QTreeWidgetItem *item; - - item = tree->currentItem(); - - if ( item == NULL ) - { - buttonEnable = false; - } - else - { - buttonEnable = true; - } + refreshRamList(); +} +//---------------------------------------------------------------------------- +static unsigned int ReadValueAtHardwareAddress(int address, unsigned int size) +{ + unsigned int value = 0; + + // read as little endian + for (unsigned int i = 0; i < size; i++) + { + value <<= 8; + value |= GetMem(address); + address++; + } + return value; +} +//---------------------------------------------------------------------------- +void RamSearchDialog_t::runSearch(void) +{ +} +//---------------------------------------------------------------------------- +void RamSearchDialog_t::resetSearch(void) +{ + actvSrchList.clear(); + + for (unsigned int addr=0; addr<0x08000; addr++) + { + memLoc[addr].hist.clear(); + memLoc[addr].addr = addr; + memLoc[addr].val.v8.u = GetMem(addr); + memLoc[addr].val.v16.u = ReadValueAtHardwareAddress(addr, 2); + memLoc[addr].val.v32.u = ReadValueAtHardwareAddress(addr, 4); + memLoc[addr].elimMask = 0; + memLoc[addr].hist.push_back( memLoc[addr].val ); + + actvSrchList.push_back( &memLoc[addr] ); + } + iterMask = 0x01; + + refreshRamList(); +} +//---------------------------------------------------------------------------- +void RamSearchDialog_t::refreshRamList(void) +{ + int idx=0; + QTreeWidgetItem *item; + std::list ::iterator it; + char addrStr[32], valStr[32], prevStr[32], chgStr[32]; + memoryLocation_t *loc; + + for (it=actvSrchList.begin(); it != actvSrchList.end(); it++) + { + loc = *it; + + item = tree->topLevelItem(idx); + + if ( item == NULL ) + { + item = new QTreeWidgetItem(); + + tree->addTopLevelItem( item ); + + item->setFont( 0, font); + item->setFont( 1, font); + item->setFont( 2, font); + item->setFont( 3, font); + } + + sprintf (addrStr, "$%04X", loc->addr); + + if ( dpySize == 'd' ) + { + if ( dpyType == 'h' ) + { + sprintf( valStr , "0x%08X", loc->val.v32.u ); + sprintf( prevStr, "0x%08X", loc->hist.back().v32.u ); + } + else if ( dpyType == 'u' ) + { + sprintf( valStr , "%u", loc->val.v32.u ); + sprintf( prevStr, "%u", loc->hist.back().v32.u ); + } + else + { + sprintf( valStr , "%i", loc->val.v32.i ); + sprintf( prevStr, "%i", loc->hist.back().v32.i ); + } + } + else if ( dpySize == 'w' ) + { + if ( dpyType == 'h' ) + { + sprintf( valStr , "0x%04X", loc->val.v16.u ); + sprintf( prevStr, "0x%04X", loc->hist.back().v16.u ); + } + else if ( dpyType == 'u' ) + { + sprintf( valStr , "%u", loc->val.v16.u ); + sprintf( prevStr, "%u", loc->hist.back().v16.u ); + } + else + { + sprintf( valStr , "%i", loc->val.v16.i ); + sprintf( prevStr, "%i", loc->hist.back().v16.i ); + } + } + else + { + if ( dpyType == 'h' ) + { + sprintf( valStr , "0x%02X", loc->val.v8.u ); + sprintf( prevStr, "0x%02X", loc->hist.back().v8.u ); + } + else if ( dpyType == 'u' ) + { + sprintf( valStr , "%u", loc->val.v8.u ); + sprintf( prevStr, "%u", loc->hist.back().v8.u ); + } + else + { + sprintf( valStr , "%i", loc->val.v8.i ); + sprintf( prevStr, "%i", loc->hist.back().v8.i ); + } + } + sprintf( chgStr, "%i", loc->chgCount ); + + item->setText( 0, tr(addrStr) ); + item->setText( 1, tr(valStr) ); + item->setText( 2, tr(prevStr) ); + item->setText( 3, tr(chgStr) ); + + + item->setTextAlignment( 0, Qt::AlignLeft); + item->setTextAlignment( 1, Qt::AlignCenter); + item->setTextAlignment( 2, Qt::AlignCenter); + item->setTextAlignment( 3, Qt::AlignCenter); + + idx++; + } + } //---------------------------------------------------------------------------- diff --git a/src/drivers/Qt/RamSearch.h b/src/drivers/Qt/RamSearch.h index c026acad..78f13025 100644 --- a/src/drivers/Qt/RamSearch.h +++ b/src/drivers/Qt/RamSearch.h @@ -82,6 +82,9 @@ class RamSearchDialog_t : public QDialog public slots: void closeWindow(void); private slots: + void runSearch(void); + void resetSearch(void); + void refreshRamList(void); void periodicUpdate(void); //void watchClicked( QTreeWidgetItem *item, int column); From 5dc72e7924b039aa4e35ef16b3c2e948c47e2e7e Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Sun, 11 Oct 2020 22:54:19 -0400 Subject: [PATCH 04/17] Added custom widget to optimize Qt ram search view --- src/drivers/Qt/RamSearch.cpp | 274 +++++++++++++++++++++++++++-------- src/drivers/Qt/RamSearch.h | 50 ++++++- 2 files changed, 257 insertions(+), 67 deletions(-) diff --git a/src/drivers/Qt/RamSearch.cpp b/src/drivers/Qt/RamSearch.cpp index 379f6436..d73c6e3f 100644 --- a/src/drivers/Qt/RamSearch.cpp +++ b/src/drivers/Qt/RamSearch.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include "../../types.h" #include "../../fceu.h" @@ -97,22 +98,9 @@ RamSearchDialog_t::RamSearchDialog_t(QWidget *parent) QVBoxLayout *mainLayout; QHBoxLayout *hbox, *hbox1, *hbox2, *hbox3; QVBoxLayout *vbox, *vbox1, *vbox2; - QTreeWidgetItem *item; QGridLayout *grid; QGroupBox *frame; - font.setFamily("Courier New"); - font.setStyle( QFont::StyleNormal ); - font.setStyleHint( QFont::Monospace ); - - QFontMetrics fm(font); - -#if QT_VERSION > QT_VERSION_CHECK(5, 11, 0) - fontCharWidth = 2 * fm.horizontalAdvance(QLatin1Char('2')); -#else - fontCharWidth = 2 * fm.width(QLatin1Char('2')); -#endif - setWindowTitle("RAM Search"); resize( 512, 512 ); @@ -122,30 +110,27 @@ RamSearchDialog_t::RamSearchDialog_t(QWidget *parent) mainLayout->addLayout( hbox1 ); - tree = new QTreeWidget(); + grid = new QGridLayout(); + ramView = new QRamSearchView(this); + vbar = new QScrollBar( Qt::Vertical, this ); + hbar = new QScrollBar( Qt::Horizontal, this ); + grid->addWidget( ramView, 0, 0 ); + grid->addWidget( vbar , 0, 1 ); + grid->addWidget( hbar , 1, 0 ); - tree->setColumnCount(4); + connect( hbar, SIGNAL(valueChanged(int)), this, SLOT(hbarChanged(int)) ); + connect( vbar, SIGNAL(valueChanged(int)), this, SLOT(vbarChanged(int)) ); - item = new QTreeWidgetItem(); - item->setText( 0, QString::fromStdString( "Address" ) ); - item->setText( 1, QString::fromStdString( "Value" ) ); - item->setText( 2, QString::fromStdString( "Previous" ) ); - item->setText( 3, QString::fromStdString( "Changes" ) ); - item->setTextAlignment( 0, Qt::AlignLeft); - item->setTextAlignment( 1, Qt::AlignLeft); - item->setTextAlignment( 2, Qt::AlignLeft); - item->setTextAlignment( 3, Qt::AlignLeft); - - //connect( tree, SIGNAL(itemClicked(QTreeWidgetItem*, int)), - // this, SLOT(watchClicked( QTreeWidgetItem*, int)) ); - - tree->setHeaderItem( item ); - - //tree->header()->setSectionResizeMode( QHeaderView::ResizeToContents ); + ramView->setScrollBars( hbar, vbar ); + hbar->setMinimum(0); + hbar->setMaximum(100); + vbar->setMinimum(0); + vbar->setMaximum(0x8000); + vbar->setValue(0); vbox = new QVBoxLayout(); - hbox1->addWidget( tree ); - hbox1->addLayout( vbox ); + hbox1->addLayout( grid, 100); + hbox1->addLayout( vbox, 1 ); searchButton = new QPushButton( tr("Search") ); vbox->addWidget( searchButton ); @@ -339,7 +324,19 @@ void RamSearchDialog_t::closeWindow(void) //---------------------------------------------------------------------------- void RamSearchDialog_t::periodicUpdate(void) { - refreshRamList(); + //refreshRamList(); + + ramView->update(); +} +//---------------------------------------------------- +void RamSearchDialog_t::hbarChanged(int val) +{ + ramView->update(); +} +//---------------------------------------------------- +void RamSearchDialog_t::vbarChanged(int val) +{ + ramView->update(); } //---------------------------------------------------------------------------- static unsigned int ReadValueAtHardwareAddress(int address, unsigned int size) @@ -378,34 +375,191 @@ void RamSearchDialog_t::resetSearch(void) } iterMask = 0x01; - refreshRamList(); + //refreshRamList(); } //---------------------------------------------------------------------------- -void RamSearchDialog_t::refreshRamList(void) +QRamSearchView::QRamSearchView(QWidget *parent) + : QWidget(parent) { - int idx=0; - QTreeWidgetItem *item; + QPalette pal; + QColor fg(0,0,0), bg(255,255,255); + + pal = this->palette(); + pal.setColor(QPalette::Base , bg ); + pal.setColor(QPalette::Background, bg ); + pal.setColor(QPalette::WindowText, fg ); + this->setPalette(pal); + + font.setFamily("Courier New"); + font.setStyle( QFont::StyleNormal ); + font.setStyleHint( QFont::Monospace ); + + calcFontData(); + + lineOffset = 0; + maxLineOffset = 0; +} +//---------------------------------------------------------------------------- +QRamSearchView::~QRamSearchView(void) +{ + +} +//---------------------------------------------------------------------------- +void QRamSearchView::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; + pxColWidth[0] = pxCharWidth * 10; + pxColWidth[1] = pxCharWidth * 15; + pxColWidth[2] = pxCharWidth * 15; + pxColWidth[3] = pxCharWidth * 15; + pxLineWidth = pxColWidth[0] + pxColWidth[1] + pxColWidth[2] + pxColWidth[3]; + + viewLines = (viewHeight / pxLineSpacing) + 1; +} +//---------------------------------------------------------------------------- +void QRamSearchView::setScrollBars( QScrollBar *hbar, QScrollBar *vbar ) +{ + this->hbar = hbar; this->vbar = vbar; +} +//---------------------------------------------------- +void QRamSearchView::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 QRamSearchView::paintEvent(QPaintEvent *event) +{ + int i,x,y, v, ofs, row, start, end, nrow; std::list ::iterator it; char addrStr[32], valStr[32], prevStr[32], chgStr[32]; - memoryLocation_t *loc; + QPainter painter(this); + char line[256]; + memoryLocation_t *loc = NULL; + int fieldWidth, fieldPad[4], fieldLen[4], fieldStart[4]; + const char *fieldText[4]; - for (it=actvSrchList.begin(); it != actvSrchList.end(); it++) + painter.setFont(font); + viewWidth = event->rect().width(); + viewHeight = event->rect().height(); + fieldWidth = viewWidth / 4; + + for (i=0; i<4; i++) { - loc = *it; + fieldStart[i] = fieldWidth * i; + } - item = tree->topLevelItem(idx); + nrow = (viewHeight / pxLineSpacing)-1; - if ( item == NULL ) + if (nrow < 1 ) nrow = 1; + + viewLines = nrow; + + maxLineOffset = actvSrchList.size() - nrow; + + if ( maxLineOffset < 1 ) maxLineOffset = 1; + + lineOffset = vbar->value(); + + if ( lineOffset > maxLineOffset ) + { + lineOffset = maxLineOffset; + vbar->setValue( lineOffset ); + } + if ( lineOffset < 0 ) + { + lineOffset = 0; + vbar->setValue( 0 ); + } + + i=0; + it = actvSrchList.begin(); + while ( it != actvSrchList.end() ) + { + if ( i == lineOffset ) { - item = new QTreeWidgetItem(); - - tree->addTopLevelItem( item ); - - item->setFont( 0, font); - item->setFont( 1, font); - item->setFont( 2, font); - item->setFont( 3, font); + break; } + i++; it++; + } + + painter.fillRect( 0, 0, viewWidth, viewHeight, this->palette().color(QPalette::Background) ); + + painter.setPen( this->palette().color(QPalette::WindowText)); + + pxLineXScroll = (int)(0.010f * (float)hbar->value() * (float)(pxLineWidth - viewWidth) ); + + x = -pxLineXScroll; + y = pxLineSpacing; + + strcpy( addrStr, "Address"); + strcpy( valStr , "Value"); + strcpy( prevStr, "Previous"); + strcpy( chgStr , "Changes"); + + fieldText[0] = addrStr; + fieldText[1] = valStr; + fieldText[2] = prevStr; + fieldText[3] = chgStr; + + for (i=0; i<4; i++) + { + fieldLen[i] = strlen(fieldText[i]) * pxCharWidth; + + fieldPad[i] = (fieldWidth - fieldLen[i]) / 2; + + painter.drawText( x+fieldStart[i]+fieldPad[i], y, tr(fieldText[i]) ); + + } + painter.drawLine( 0, y+pxLineLead, viewWidth, y+pxLineLead ); + painter.drawLine( x+fieldStart[1], 0, x+fieldStart[1], viewHeight ); + painter.drawLine( x+fieldStart[2], 0, x+fieldStart[2], viewHeight ); + painter.drawLine( x+fieldStart[3], 0, x+fieldStart[3], viewHeight ); + + y += pxLineSpacing; + + for (row=0; rowaddr); @@ -465,19 +619,17 @@ void RamSearchDialog_t::refreshRamList(void) } sprintf( chgStr, "%i", loc->chgCount ); - item->setText( 0, tr(addrStr) ); - item->setText( 1, tr(valStr) ); - item->setText( 2, tr(prevStr) ); - item->setText( 3, tr(chgStr) ); + for (i=0; i<4; i++) + { + fieldLen[i] = strlen(fieldText[i]) * pxCharWidth; - item->setTextAlignment( 0, Qt::AlignLeft); - item->setTextAlignment( 1, Qt::AlignCenter); - item->setTextAlignment( 2, Qt::AlignCenter); - item->setTextAlignment( 3, Qt::AlignCenter); + fieldPad[i] = (fieldWidth - fieldLen[i]) / 2; - idx++; + painter.drawText( x+fieldStart[i]+fieldPad[i], y, tr(fieldText[i]) ); + } + + y += pxLineSpacing; } - } //---------------------------------------------------------------------------- diff --git a/src/drivers/Qt/RamSearch.h b/src/drivers/Qt/RamSearch.h index 78f13025..debf2f8c 100644 --- a/src/drivers/Qt/RamSearch.h +++ b/src/drivers/Qt/RamSearch.h @@ -15,11 +15,48 @@ #include #include #include -#include -#include +#include #include "Qt/main.h" +class QRamSearchView : public QWidget +{ + Q_OBJECT + + public: + QRamSearchView(QWidget *parent = 0); + ~QRamSearchView(void); + + void setScrollBars( QScrollBar *hbar, QScrollBar *vbar ); + + protected: + void paintEvent(QPaintEvent *event); + //void keyPressEvent(QKeyEvent *event); + //void keyReleaseEvent(QKeyEvent *event); + //void mousePressEvent(QMouseEvent * event); + void resizeEvent(QResizeEvent *event); + + void calcFontData(void); + + QFont font; + QScrollBar *vbar; + QScrollBar *hbar; + + int lineOffset; + int maxLineOffset; + int pxCharWidth; + int pxCharHeight; + int pxLineSpacing; + int pxLineLead; + int pxCursorHeight; + int pxLineXScroll; + int pxLineWidth; + int pxColWidth[4]; + int viewLines; + int viewWidth; + int viewHeight; +}; + class RamSearchDialog_t : public QDialog { Q_OBJECT @@ -31,8 +68,9 @@ class RamSearchDialog_t : public QDialog protected: void closeEvent(QCloseEvent *event); - QFont font; - QTreeWidget *tree; + QRamSearchView *ramView; + QScrollBar *vbar; + QScrollBar *hbar; QTimer *updateTimer; QPushButton *searchButton; QPushButton *resetButton; @@ -84,9 +122,9 @@ class RamSearchDialog_t : public QDialog private slots: void runSearch(void); void resetSearch(void); - void refreshRamList(void); void periodicUpdate(void); - //void watchClicked( QTreeWidgetItem *item, int column); + void hbarChanged(int val); + void vbarChanged(int val); }; From 25152af42a5dc160af77934307506b4c5cce2e7d Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Mon, 12 Oct 2020 00:09:00 -0400 Subject: [PATCH 05/17] Qt RAM search window in work. --- src/drivers/Qt/RamSearch.cpp | 222 +++++++++++++++++++++++++++++++---- src/drivers/Qt/RamSearch.h | 11 ++ 2 files changed, 209 insertions(+), 24 deletions(-) diff --git a/src/drivers/Qt/RamSearch.cpp b/src/drivers/Qt/RamSearch.cpp index d73c6e3f..4caa9d49 100644 --- a/src/drivers/Qt/RamSearch.cpp +++ b/src/drivers/Qt/RamSearch.cpp @@ -72,12 +72,13 @@ struct memoryLocation_t chgCount = 0; elimMask = 0; } }; -static struct memoryLocation_t memLoc[0x8000]; +static struct memoryLocation_t memLoc[0x10000]; static std::list actvSrchList; static int dpySize = 'b'; static int dpyType = 's'; +static bool chkMisAligned = false; //---------------------------------------------------------------------------- void openRamSearchWindow( QWidget *parent ) @@ -125,7 +126,7 @@ RamSearchDialog_t::RamSearchDialog_t(QWidget *parent) hbar->setMinimum(0); hbar->setMaximum(100); vbar->setMinimum(0); - vbar->setMaximum(0x8000); + vbar->setMaximum(ShowROM ? 0x10000 : 0x8000); vbar->setValue(0); vbox = new QVBoxLayout(); @@ -135,32 +136,29 @@ RamSearchDialog_t::RamSearchDialog_t(QWidget *parent) searchButton = new QPushButton( tr("Search") ); vbox->addWidget( searchButton ); connect( searchButton, SIGNAL(clicked(void)), this, SLOT(runSearch(void))); - //searchButton->setEnabled(false); resetButton = new QPushButton( tr("Reset") ); vbox->addWidget( resetButton ); connect( resetButton, SIGNAL(clicked(void)), this, SLOT(resetSearch(void))); - //down_btn->setEnabled(false); clearChangeButton = new QPushButton( tr("Clear Change") ); vbox->addWidget( clearChangeButton ); - //connect( clearChangeButton, SIGNAL(clicked(void)), this, SLOT(editWatchClicked(void))); - //clearChangeButton->setEnabled(false); + connect( clearChangeButton, SIGNAL(clicked(void)), this, SLOT(clearChangeCounts(void))); - undoButton = new QPushButton( tr("Remove") ); + undoButton = new QPushButton( tr("Undo") ); vbox->addWidget( undoButton ); //connect( undoButton, SIGNAL(clicked(void)), this, SLOT(removeWatchClicked(void))); //undoButton->setEnabled(false); searchROMCbox = new QCheckBox( tr("Search ROM") ); vbox->addWidget( searchROMCbox ); - //connect( undoButton, SIGNAL(clicked(void)), this, SLOT(removeWatchClicked(void))); - //undoButton->setEnabled(false); + searchROMCbox->setChecked( ShowROM ); + connect( searchROMCbox, SIGNAL(stateChanged(int)), this, SLOT(searchROMChanged(int))); elimButton = new QPushButton( tr("Eliminate") ); vbox->addWidget( elimButton ); //connect( elimButton, SIGNAL(clicked(void)), this, SLOT(newWatchClicked(void))); - //elimButton->setEnabled(false); + elimButton->setEnabled(false); watchButton = new QPushButton( tr("Watch") ); vbox->addWidget( watchButton ); @@ -253,9 +251,17 @@ RamSearchDialog_t::RamSearchDialog_t(QWidget *parent) ds2_btn = new QRadioButton( tr("2 Byte") ); ds4_btn = new QRadioButton( tr("4 Byte") ); misalignedCbox = new QCheckBox( tr("Check Misaligned") ); - misalignedCbox->setEnabled(false); + misalignedCbox->setEnabled(dpySize != 'b'); + misalignedCbox->setChecked(chkMisAligned); + connect( misalignedCbox, SIGNAL(stateChanged(int)), this, SLOT(misalignedChanged(int))); - ds1_btn->setChecked(true); + ds1_btn->setChecked( dpySize == 'b' ); + ds2_btn->setChecked( dpySize == 'w' ); + ds4_btn->setChecked( dpySize == 'd' ); + + connect( ds1_btn, SIGNAL(clicked(void)), this, SLOT(ds1Clicked(void))); + connect( ds2_btn, SIGNAL(clicked(void)), this, SLOT(ds2Clicked(void))); + connect( ds4_btn, SIGNAL(clicked(void)), this, SLOT(ds4Clicked(void))); vbox->addWidget( ds1_btn ); vbox->addWidget( ds2_btn ); @@ -276,7 +282,14 @@ RamSearchDialog_t::RamSearchDialog_t(QWidget *parent) vbox->addWidget( signed_btn ); vbox->addWidget( unsigned_btn ); vbox->addWidget( hex_btn ); - signed_btn->setChecked(true); + + signed_btn->setChecked( dpyType == 's' ); + unsigned_btn->setChecked( dpyType == 'u' ); + hex_btn->setChecked( dpyType == 'h' ); + + connect( signed_btn , SIGNAL(clicked(void)), this, SLOT(signedTypeClicked(void))); + connect( unsigned_btn, SIGNAL(clicked(void)), this, SLOT(unsignedTypeClicked(void))); + connect( hex_btn , SIGNAL(clicked(void)), this, SLOT(hexTypeClicked(void))); autoSearchCbox = new QCheckBox( tr("Auto-Search") ); autoSearchCbox->setEnabled(true); @@ -324,7 +337,7 @@ void RamSearchDialog_t::closeWindow(void) //---------------------------------------------------------------------------- void RamSearchDialog_t::periodicUpdate(void) { - //refreshRamList(); + updateRamValues(); ramView->update(); } @@ -338,17 +351,33 @@ void RamSearchDialog_t::vbarChanged(int val) { ramView->update(); } +//---------------------------------------------------- +void RamSearchDialog_t::searchROMChanged(int state) +{ + ShowROM = (state != Qt::Unchecked); +} +//---------------------------------------------------- +void RamSearchDialog_t::misalignedChanged(int state) +{ + chkMisAligned = (state != Qt::Unchecked); + + calcRamList(); +} //---------------------------------------------------------------------------- static unsigned int ReadValueAtHardwareAddress(int address, unsigned int size) { unsigned int value = 0; + int maxAddr = ShowROM ? 0x10000 : 0x8000; // read as little endian for (unsigned int i = 0; i < size; i++) { - value <<= 8; - value |= GetMem(address); - address++; + if ( address < maxAddr ) + { + value <<= 8; + value |= GetMem(address); + address++; + } } return value; } @@ -361,7 +390,7 @@ void RamSearchDialog_t::resetSearch(void) { actvSrchList.clear(); - for (unsigned int addr=0; addr<0x08000; addr++) + for (unsigned int addr=0; addr<0x10000; addr++) { memLoc[addr].hist.clear(); memLoc[addr].addr = addr; @@ -369,13 +398,160 @@ void RamSearchDialog_t::resetSearch(void) memLoc[addr].val.v16.u = ReadValueAtHardwareAddress(addr, 2); memLoc[addr].val.v32.u = ReadValueAtHardwareAddress(addr, 4); memLoc[addr].elimMask = 0; + memLoc[addr].chgCount = 0; memLoc[addr].hist.push_back( memLoc[addr].val ); - - actvSrchList.push_back( &memLoc[addr] ); } iterMask = 0x01; - //refreshRamList(); + calcRamList(); +} +//---------------------------------------------------------------------------- +void RamSearchDialog_t::clearChangeCounts(void) +{ + for (unsigned int addr=0; addr<0x10000; addr++) + { + memLoc[addr].chgCount = 0; + } +} +//---------------------------------------------------------------------------- +void RamSearchDialog_t::ds1Clicked(void) +{ + dpySize = 'b'; + misalignedCbox->setEnabled(false); + calcRamList(); +} +//---------------------------------------------------------------------------- +void RamSearchDialog_t::ds2Clicked(void) +{ + dpySize = 'w'; + misalignedCbox->setEnabled(true); + calcRamList(); +} +//---------------------------------------------------------------------------- +void RamSearchDialog_t::ds4Clicked(void) +{ + dpySize = 'd'; + misalignedCbox->setEnabled(true); + calcRamList(); +} +//---------------------------------------------------------------------------- +void RamSearchDialog_t::signedTypeClicked(void) +{ + dpyType = 's'; +} +//---------------------------------------------------------------------------- +void RamSearchDialog_t::unsignedTypeClicked(void) +{ + dpyType = 'u'; +} +//---------------------------------------------------------------------------- +void RamSearchDialog_t::hexTypeClicked(void) +{ + dpyType = 'h'; +} +//---------------------------------------------------------------------------- +void RamSearchDialog_t::calcRamList(void) +{ + int addr; + int dataSize = 1; + int endAddr = ShowROM ? 0x10000 : 0x8000; + + if ( chkMisAligned ) + { + dataSize = 1; + } + else if ( dpySize == 'd' ) + { + dataSize = 4; + } + else if ( dpySize == 'w' ) + { + dataSize = 2; + } + else + { + dataSize = 1; + } + + actvSrchList.clear(); + + for (addr=0; addrsetMaximum( actvSrchList.size() ); +} +//---------------------------------------------------------------------------- +void RamSearchDialog_t::updateRamValues(void) +{ + std::list ::iterator it; + memoryLocation_t *loc = NULL; + memoryState_t val; + + for (it = actvSrchList.begin(); it != actvSrchList.end(); it++) + { + loc = *it; + + val.v8.u = GetMem(loc->addr); + val.v16.u = ReadValueAtHardwareAddress(loc->addr, 2); + val.v32.u = ReadValueAtHardwareAddress(loc->addr, 4); + + if ( dpySize == 'd' ) + { + if ( memLoc[loc->addr].val.v32.u != val.v32.u ) + { + memLoc[loc->addr].val = val; + memLoc[loc->addr].chgCount++; + } + } + else if ( dpySize == 'w' ) + { + if ( memLoc[loc->addr].val.v16.u != val.v16.u ) + { + memLoc[loc->addr].val = val; + memLoc[loc->addr].chgCount++; + } + } + else + { + if ( memLoc[loc->addr].val.v8.u != val.v8.u ) + { + memLoc[loc->addr].val = val; + memLoc[loc->addr].chgCount++; + } + } + } } //---------------------------------------------------------------------------- QRamSearchView::QRamSearchView(QWidget *parent) @@ -456,11 +632,10 @@ void QRamSearchView::resizeEvent(QResizeEvent *event) //---------------------------------------------------------------------------- void QRamSearchView::paintEvent(QPaintEvent *event) { - int i,x,y, v, ofs, row, start, end, nrow; + int i,x,y,row,nrow; std::list ::iterator it; char addrStr[32], valStr[32], prevStr[32], chgStr[32]; QPainter painter(this); - char line[256]; memoryLocation_t *loc = NULL; int fieldWidth, fieldPad[4], fieldLen[4], fieldStart[4]; const char *fieldText[4]; @@ -535,7 +710,6 @@ void QRamSearchView::paintEvent(QPaintEvent *event) fieldPad[i] = (fieldWidth - fieldLen[i]) / 2; painter.drawText( x+fieldStart[i]+fieldPad[i], y, tr(fieldText[i]) ); - } painter.drawLine( 0, y+pxLineLead, viewWidth, y+pxLineLead ); painter.drawLine( x+fieldStart[1], 0, x+fieldStart[1], viewHeight ); diff --git a/src/drivers/Qt/RamSearch.h b/src/drivers/Qt/RamSearch.h index debf2f8c..0e986c3c 100644 --- a/src/drivers/Qt/RamSearch.h +++ b/src/drivers/Qt/RamSearch.h @@ -116,15 +116,26 @@ class RamSearchDialog_t : public QDialog int fontCharWidth; private: + void updateRamValues(void); + void calcRamList(void); public slots: void closeWindow(void); private slots: void runSearch(void); void resetSearch(void); + void clearChangeCounts(void); void periodicUpdate(void); void hbarChanged(int val); void vbarChanged(int val); + void searchROMChanged(int state); + void misalignedChanged(int state); + void ds1Clicked(void); + void ds2Clicked(void); + void ds4Clicked(void); + void signedTypeClicked(void); + void unsignedTypeClicked(void); + void hexTypeClicked(void); }; From 1368d0550eca19baec4ee430b6c4bceb6b55a64a Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Mon, 12 Oct 2020 15:51:24 -0400 Subject: [PATCH 06/17] Bug fix for Qt GUI frame advance logic. Updated RamSearch to run after ever completed frame. --- src/drivers/Qt/RamSearch.cpp | 43 ++++++++++++++++++++++++++++------ src/drivers/Qt/RamSearch.h | 3 +++ src/drivers/Qt/fceuWrapper.cpp | 5 +++- src/drivers/Qt/input.cpp | 5 +++- 4 files changed, 47 insertions(+), 9 deletions(-) diff --git a/src/drivers/Qt/RamSearch.cpp b/src/drivers/Qt/RamSearch.cpp index 4caa9d49..aa1a9720 100644 --- a/src/drivers/Qt/RamSearch.cpp +++ b/src/drivers/Qt/RamSearch.cpp @@ -22,6 +22,7 @@ #include "../../fceu.h" #include "../../cheat.h" #include "../../debug.h" +#include "../../movie.h" #include "Qt/main.h" #include "Qt/dface.h" @@ -74,7 +75,9 @@ struct memoryLocation_t }; static struct memoryLocation_t memLoc[0x10000]; -static std::list actvSrchList; +static std::list actvSrchList; +static std::list deactvSrchList; +static std::vector deactvFrameStack; static int dpySize = 'b'; static int dpyType = 's'; @@ -148,7 +151,7 @@ RamSearchDialog_t::RamSearchDialog_t(QWidget *parent) undoButton = new QPushButton( tr("Undo") ); vbox->addWidget( undoButton ); //connect( undoButton, SIGNAL(clicked(void)), this, SLOT(removeWatchClicked(void))); - //undoButton->setEnabled(false); + undoButton->setEnabled(false); searchROMCbox = new QCheckBox( tr("Search ROM") ); vbox->addWidget( searchROMCbox ); @@ -297,22 +300,26 @@ RamSearchDialog_t::RamSearchDialog_t(QWidget *parent) setLayout( mainLayout ); + cycleCounter = 0; + resetSearch(); updateTimer = new QTimer( this ); connect( updateTimer, &QTimer::timeout, this, &RamSearchDialog_t::periodicUpdate ); - updateTimer->start( 100 ); // 10hz + updateTimer->start( 8 ); // ~120hz } //---------------------------------------------------------------------------- RamSearchDialog_t::~RamSearchDialog_t(void) { updateTimer->stop(); - printf("Destroy RAM Watch Config Window\n"); + printf("Destroy RAM Search Window\n"); ramSearchWin = NULL; actvSrchList.clear(); + deactvSrchList.clear(); + deactvFrameStack.clear(); for (unsigned int addr=0; addr<0x08000; addr++) { @@ -322,7 +329,7 @@ RamSearchDialog_t::~RamSearchDialog_t(void) //---------------------------------------------------------------------------- void RamSearchDialog_t::closeEvent(QCloseEvent *event) { - printf("RAM Watch Close Window Event\n"); + printf("RAM Search Close Window Event\n"); done(0); deleteLater(); event->accept(); @@ -337,9 +344,18 @@ void RamSearchDialog_t::closeWindow(void) //---------------------------------------------------------------------------- void RamSearchDialog_t::periodicUpdate(void) { - updateRamValues(); + if ( currFrameCounter != frameCounterLastPass ) + { + updateRamValues(); + + frameCounterLastPass = currFrameCounter; + } - ramView->update(); + if ( (cycleCounter % 10) == 0) + { + ramView->update(); + } + cycleCounter++; } //---------------------------------------------------- void RamSearchDialog_t::hbarChanged(int val) @@ -364,6 +380,15 @@ void RamSearchDialog_t::misalignedChanged(int state) calcRamList(); } //---------------------------------------------------------------------------- +static bool memoryAddrCompare( memoryLocation_t *loc1, memoryLocation_t *loc2 ) +{ + return loc1->addr < loc2->addr; +} +static void sortActvMemList(void) +{ + actvSrchList.sort( memoryAddrCompare ); +} +//---------------------------------------------------------------------------- static unsigned int ReadValueAtHardwareAddress(int address, unsigned int size) { unsigned int value = 0; @@ -389,6 +414,8 @@ void RamSearchDialog_t::runSearch(void) void RamSearchDialog_t::resetSearch(void) { actvSrchList.clear(); + deactvSrchList.clear(); + deactvFrameStack.clear(); for (unsigned int addr=0; addr<0x10000; addr++) { @@ -601,6 +628,8 @@ void QRamSearchView::calcFontData(void) pxLineWidth = pxColWidth[0] + pxColWidth[1] + pxColWidth[2] + pxColWidth[3]; viewLines = (viewHeight / pxLineSpacing) + 1; + + setMinimumWidth( pxLineWidth ); } //---------------------------------------------------------------------------- void QRamSearchView::setScrollBars( QScrollBar *hbar, QScrollBar *vbar ) diff --git a/src/drivers/Qt/RamSearch.h b/src/drivers/Qt/RamSearch.h index 0e986c3c..014b1f9e 100644 --- a/src/drivers/Qt/RamSearch.h +++ b/src/drivers/Qt/RamSearch.h @@ -114,6 +114,9 @@ class RamSearchDialog_t : public QDialog QCheckBox *autoSearchCbox; int fontCharWidth; + int frameCounterLastPass; + unsigned int cycleCounter; + private: void updateRamValues(void); diff --git a/src/drivers/Qt/fceuWrapper.cpp b/src/drivers/Qt/fceuWrapper.cpp index 0f204e16..ddc1b0e2 100644 --- a/src/drivers/Qt/fceuWrapper.cpp +++ b/src/drivers/Qt/fceuWrapper.cpp @@ -64,6 +64,7 @@ static int periodic_saves = 0; static int mutexLocks = 0; static int mutexPending = 0; static bool emulatorHasMutux = 0; +static unsigned int emulatorCycleCount = 0; extern double g_fpsScale; @@ -945,6 +946,8 @@ static void DoFun(int frameskip, int periodic_saves) // opause=FCEUI_EmulationPaused(); // SilenceSound(opause); //} + + emulatorCycleCount++; } void fceuWrapperLock(void) @@ -1019,7 +1022,7 @@ int fceuWrapperUpdate( void ) } emulatorHasMutux = 1; - if ( GameInfo && !FCEUI_EmulationPaused() ) + if ( GameInfo /*&& !FCEUI_EmulationPaused()*/ ) { DoFun(frameskip, periodic_saves); diff --git a/src/drivers/Qt/input.cpp b/src/drivers/Qt/input.cpp index 1510857b..30f4c715 100644 --- a/src/drivers/Qt/input.cpp +++ b/src/drivers/Qt/input.cpp @@ -139,6 +139,7 @@ static uint8 keyonce[SDL_NUM_SCANCODES]; int getKeyState( int k ) { + k = SDL_GetScancodeFromKey(k); if ( (k >= 0) && (k < SDL_NUM_SCANCODES) ) { return g_keyState[k]; @@ -661,12 +662,13 @@ static void KeyboardCommands (void) } static bool frameAdvancing = false; - if ( _keyonly(Hotkeys[HK_FRAME_ADVANCE])) + if ( getKeyState(Hotkeys[HK_FRAME_ADVANCE])) { if (frameAdvancing == false) { FCEUI_FrameAdvance (); frameAdvancing = true; + //printf("Frame Advance Start\n"); } } else @@ -675,6 +677,7 @@ static void KeyboardCommands (void) { FCEUI_FrameAdvanceEnd (); frameAdvancing = false; + //printf("Frame Advance End\n"); } } From 9412b850cb8a0ead1718f27e3e6ab1d7054e6928 Mon Sep 17 00:00:00 2001 From: mjbudd77 Date: Thu, 15 Oct 2020 20:39:56 -0400 Subject: [PATCH 07/17] Ram search by relative value in work. --- src/drivers/Qt/RamSearch.cpp | 211 ++++++++++++++++++++++++++++++++++- src/drivers/Qt/RamSearch.h | 9 ++ 2 files changed, 219 insertions(+), 1 deletion(-) diff --git a/src/drivers/Qt/RamSearch.cpp b/src/drivers/Qt/RamSearch.cpp index aa1a9720..3f24bfc9 100644 --- a/src/drivers/Qt/RamSearch.cpp +++ b/src/drivers/Qt/RamSearch.cpp @@ -79,6 +79,7 @@ static std::list actvSrchList; static std::list deactvSrchList; static std::vector deactvFrameStack; +static int cmpOp = '='; static int dpySize = 'b'; static int dpyType = 's'; static bool chkMisAligned = false; @@ -195,11 +196,30 @@ RamSearchDialog_t::RamSearchDialog_t(QWidget *parent) df_btn = new QRadioButton( tr("Different By:") ); md_btn = new QRadioButton( tr("Modulo") ); - eq_btn->setChecked(true); + lt_btn->setChecked( cmpOp == '<' ); + gt_btn->setChecked( cmpOp == '>' ); + le_btn->setChecked( cmpOp == 'l' ); + ge_btn->setChecked( cmpOp == 'm' ); + eq_btn->setChecked( cmpOp == '=' ); + ne_btn->setChecked( cmpOp == '!' ); + df_btn->setChecked( cmpOp == 'd' ); + md_btn->setChecked( cmpOp == '%' ); + + connect( lt_btn, SIGNAL(clicked(void)), this, SLOT(opLtClicked(void)) ); + connect( gt_btn, SIGNAL(clicked(void)), this, SLOT(opGtClicked(void)) ); + connect( le_btn, SIGNAL(clicked(void)), this, SLOT(opLeClicked(void)) ); + connect( ge_btn, SIGNAL(clicked(void)), this, SLOT(opGeClicked(void)) ); + connect( eq_btn, SIGNAL(clicked(void)), this, SLOT(opEqClicked(void)) ); + connect( ne_btn, SIGNAL(clicked(void)), this, SLOT(opNeClicked(void)) ); + connect( df_btn, SIGNAL(clicked(void)), this, SLOT(opDfClicked(void)) ); + connect( md_btn, SIGNAL(clicked(void)), this, SLOT(opMdClicked(void)) ); diffByEdit = new QLineEdit(); moduloEdit = new QLineEdit(); + diffByEdit->setEnabled( cmpOp == 'd' ); + moduloEdit->setEnabled( cmpOp == '%' ); + vbox->addWidget( lt_btn ); vbox->addWidget( gt_btn ); vbox->addWidget( le_btn ); @@ -301,6 +321,7 @@ RamSearchDialog_t::RamSearchDialog_t(QWidget *parent) setLayout( mainLayout ); cycleCounter = 0; + frameCounterLastPass = currFrameCounter; resetSearch(); @@ -346,6 +367,10 @@ void RamSearchDialog_t::periodicUpdate(void) { if ( currFrameCounter != frameCounterLastPass ) { + //if ( currFrameCounter != (frameCounterLastPass+1) ) + //{ + // printf("Warning: Ram Search Missed Frame: %i \n", currFrameCounter ); + //} updateRamValues(); frameCounterLastPass = currFrameCounter; @@ -388,6 +413,133 @@ static void sortActvMemList(void) { actvSrchList.sort( memoryAddrCompare ); } + +template +T ReadLocalValue(const unsigned char* data) +{ + return *(const T*)data; +} +// basic comparison functions: +static bool LessCmp (int64_t x, int64_t y, int64_t i) { return x < y; } +static bool MoreCmp (int64_t x, int64_t y, int64_t i) { return x > y; } +static bool LessEqualCmp (int64_t x, int64_t y, int64_t i) { return x <= y; } +static bool MoreEqualCmp (int64_t x, int64_t y, int64_t i) { return x >= y; } +static bool EqualCmp (int64_t x, int64_t y, int64_t i) { return x == y; } +static bool UnequalCmp (int64_t x, int64_t y, int64_t i) { return x != y; } +static bool DiffByCmp (int64_t x, int64_t y, int64_t p) { return x - y == p || y - x == p; } +static bool ModIsCmp (int64_t x, int64_t y, int64_t p) { return p && x % p == y; } + +void RamSearchDialog_t::SearchRelative(void) +{ + std::list ::iterator it; + memoryLocation_t *loc = NULL; + int64_t x = 0, y = 0, p = 0; + bool (*cmpFun)(int64_t x, int64_t y, int64_t p) = NULL; + + switch ( cmpOp ) + { + case '<': + cmpFun = LessCmp; + break; + case '>': + cmpFun = MoreCmp; + break; + case '=': + cmpFun = EqualCmp; + break; + case '!': + cmpFun = UnequalCmp; + break; + case 'l': + cmpFun = LessEqualCmp; + break; + case 'm': + cmpFun = MoreEqualCmp; + break; + case 'd': + cmpFun = DiffByCmp; + break; + case '%': + cmpFun = ModIsCmp; + break; + default: + cmpFun = NULL; + break; + } + + if ( cmpFun == NULL ) + { + return; + } + + it = actvSrchList.begin(); + + while (it != actvSrchList.end()) + { + loc = *it; + + switch ( dpySize ) + { + default: + case 'b': + { + if ( dpyType == 's') + { + x = loc->val.v8.i; + y = loc->hist.back().v8.i; + } + else + { + x = loc->val.v8.u; + y = loc->hist.back().v8.u; + } + } + break; + case 'w': + { + if ( dpyType == 's') + { + x = loc->val.v16.i; + y = loc->hist.back().v16.i; + } + else + { + x = loc->val.v16.u; + y = loc->hist.back().v16.u; + } + } + break; + case 'd': + { + if ( dpyType == 's') + { + x = loc->val.v32.i; + y = loc->hist.back().v32.i; + } + else + { + x = loc->val.v32.u; + y = loc->hist.back().v32.u; + } + } + break; + } + + if ( cmpFun( x, y, p ) == false ) + { + //printf("Function: Returns False %li %c %li \n", x, cmpOp, y ); + printf("Eliminated Address: $%04X\n", loc->addr ); + it = actvSrchList.erase(it); + } + else + { + loc->hist.push_back( loc->val ); + it++; + } + } + + vbar->setMaximum( actvSrchList.size() ); +} //---------------------------------------------------------------------------- static unsigned int ReadValueAtHardwareAddress(int address, unsigned int size) { @@ -409,6 +561,7 @@ static unsigned int ReadValueAtHardwareAddress(int address, unsigned int size) //---------------------------------------------------------------------------- void RamSearchDialog_t::runSearch(void) { + SearchRelative(); } //---------------------------------------------------------------------------- void RamSearchDialog_t::resetSearch(void) @@ -441,6 +594,62 @@ void RamSearchDialog_t::clearChangeCounts(void) } } //---------------------------------------------------------------------------- +void RamSearchDialog_t::opLtClicked(void) +{ + cmpOp = '<'; + diffByEdit->setEnabled(false); + moduloEdit->setEnabled(false); +} +//---------------------------------------------------------------------------- +void RamSearchDialog_t::opGtClicked(void) +{ + cmpOp = '>'; + diffByEdit->setEnabled(false); + moduloEdit->setEnabled(false); +} +//---------------------------------------------------------------------------- +void RamSearchDialog_t::opLeClicked(void) +{ + cmpOp = 'l'; + diffByEdit->setEnabled(false); + moduloEdit->setEnabled(false); +} +//---------------------------------------------------------------------------- +void RamSearchDialog_t::opGeClicked(void) +{ + cmpOp = 'm'; + diffByEdit->setEnabled(false); + moduloEdit->setEnabled(false); +} +//---------------------------------------------------------------------------- +void RamSearchDialog_t::opEqClicked(void) +{ + cmpOp = '='; + diffByEdit->setEnabled(false); + moduloEdit->setEnabled(false); +} +//---------------------------------------------------------------------------- +void RamSearchDialog_t::opNeClicked(void) +{ + cmpOp = '!'; + diffByEdit->setEnabled(false); + moduloEdit->setEnabled(false); +} +//---------------------------------------------------------------------------- +void RamSearchDialog_t::opDfClicked(void) +{ + cmpOp = 'd'; + diffByEdit->setEnabled(true); + moduloEdit->setEnabled(false); +} +//---------------------------------------------------------------------------- +void RamSearchDialog_t::opMdClicked(void) +{ + cmpOp = '%'; + diffByEdit->setEnabled(false); + moduloEdit->setEnabled(true); +} +//---------------------------------------------------------------------------- void RamSearchDialog_t::ds1Clicked(void) { dpySize = 'b'; diff --git a/src/drivers/Qt/RamSearch.h b/src/drivers/Qt/RamSearch.h index 014b1f9e..f6cff670 100644 --- a/src/drivers/Qt/RamSearch.h +++ b/src/drivers/Qt/RamSearch.h @@ -121,6 +121,7 @@ class RamSearchDialog_t : public QDialog private: void updateRamValues(void); void calcRamList(void); + void SearchRelative(void); public slots: void closeWindow(void); @@ -139,6 +140,14 @@ class RamSearchDialog_t : public QDialog void signedTypeClicked(void); void unsignedTypeClicked(void); void hexTypeClicked(void); + void opLtClicked(void); + void opGtClicked(void); + void opLeClicked(void); + void opGeClicked(void); + void opEqClicked(void); + void opNeClicked(void); + void opDfClicked(void); + void opMdClicked(void); }; From ebfe3702f97c46ac972485401442a6e20da6065d Mon Sep 17 00:00:00 2001 From: mjbudd77 Date: Thu, 15 Oct 2020 22:22:44 -0400 Subject: [PATCH 08/17] Qt RAM search input validation in work. --- src/drivers/Qt/ConsoleDebugger.cpp | 2 ++ src/drivers/Qt/RamSearch.cpp | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/src/drivers/Qt/ConsoleDebugger.cpp b/src/drivers/Qt/ConsoleDebugger.cpp index cce01c85..fecb09ce 100644 --- a/src/drivers/Qt/ConsoleDebugger.cpp +++ b/src/drivers/Qt/ConsoleDebugger.cpp @@ -343,6 +343,7 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent) cpuCycExdVal->setInputMask( ">9000000000000000;" ); cpuCycExdVal->setAlignment(Qt::AlignLeft); cpuCycExdVal->setMaximumWidth( 18 * fontCharWidth ); + cpuCycExdVal->setCursorPosition(0); connect( cpuCycExdVal, SIGNAL(textEdited(const QString &)), this, SLOT(cpuCycleThresChanged(const QString &))); instrExdVal->setFont( font ); @@ -350,6 +351,7 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent) instrExdVal->setInputMask( ">9000000000000000;" ); instrExdVal->setAlignment(Qt::AlignLeft); instrExdVal->setMaximumWidth( 18 * fontCharWidth ); + instrExdVal->setCursorPosition(0); connect( instrExdVal, SIGNAL(textEdited(const QString &)), this, SLOT(instructionsThresChanged(const QString &))); brkCpuCycExd->setChecked( break_on_cycles ); diff --git a/src/drivers/Qt/RamSearch.cpp b/src/drivers/Qt/RamSearch.cpp index 3f24bfc9..8a633f79 100644 --- a/src/drivers/Qt/RamSearch.cpp +++ b/src/drivers/Qt/RamSearch.cpp @@ -220,6 +220,14 @@ RamSearchDialog_t::RamSearchDialog_t(QWidget *parent) diffByEdit->setEnabled( cmpOp == 'd' ); moduloEdit->setEnabled( cmpOp == '%' ); + diffByEdit->setMaxLength( 16 ); + //diffByEdit->setInputMask( ">H000000000000000;" ); + diffByEdit->setCursorPosition(0); + + moduloEdit->setMaxLength( 16 ); + //moduloEdit->setInputMask( ">H000000000000000;" ); + moduloEdit->setCursorPosition(0); + vbox->addWidget( lt_btn ); vbox->addWidget( gt_btn ); vbox->addWidget( le_btn ); @@ -900,6 +908,8 @@ void QRamSearchView::paintEvent(QPaintEvent *event) lineOffset = vbar->value(); + vbar->setMaximum( maxLineOffset ); + if ( lineOffset > maxLineOffset ) { lineOffset = maxLineOffset; From 7803cc32942e1c776c6d3189492eaf52cadca165 Mon Sep 17 00:00:00 2001 From: mjbudd77 Date: Fri, 16 Oct 2020 20:05:51 -0400 Subject: [PATCH 09/17] Successful test of ram relative search functionality. --- src/drivers/Qt/RamSearch.cpp | 167 ++++++++++++++++++++++++++++++++--- src/drivers/Qt/RamSearch.h | 1 + 2 files changed, 157 insertions(+), 11 deletions(-) diff --git a/src/drivers/Qt/RamSearch.cpp b/src/drivers/Qt/RamSearch.cpp index 8a633f79..baaa5ee3 100644 --- a/src/drivers/Qt/RamSearch.cpp +++ b/src/drivers/Qt/RamSearch.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include "../../types.h" @@ -84,6 +85,76 @@ static int dpySize = 'b'; static int dpyType = 's'; static bool chkMisAligned = false; +class ramSearchInputValidator : public QValidator +{ + public: + ramSearchInputValidator(QObject *parent) + : QValidator(parent) + { + } + + QValidator::State validate(QString &input, int &pos) const + { + int i; + //printf("Validate: %i '%s'\n", input.size(), input.toStdString().c_str() ); + + if ( input.size() == 0 ) + { + return QValidator::Acceptable; + } + std::string s = input.toStdString(); + i=0; + + if ( (s[i] == '-') || (s[i] == '+') ) + { + i++; + } + if ( s[i] == 0 ) + { + return QValidator::Acceptable; + } + + if ( (s[i] == '$') || ((s[i] == '0') && ( tolower(s[i+1]) == 'x')) ) + { + if ( s[i] == '$' ) + { + i++; + } + else + { + i += 2; + } + + if ( s[i] == 0 ) + { + return QValidator::Acceptable; + } + + if ( !isxdigit(s[i]) ) + { + return QValidator::Invalid; + } + while ( isxdigit(s[i]) ) i++; + + if ( s[i] == 0 ) + { + return QValidator::Acceptable; + } + } + else if ( isdigit(s[i]) ) + { + while ( isdigit(s[i]) ) i++; + + if ( s[i] == 0 ) + { + return QValidator::Acceptable; + } + } + return QValidator::Invalid; + } + +}; + //---------------------------------------------------------------------------- void openRamSearchWindow( QWidget *parent ) { @@ -105,6 +176,7 @@ RamSearchDialog_t::RamSearchDialog_t(QWidget *parent) QVBoxLayout *vbox, *vbox1, *vbox2; QGridLayout *grid; QGroupBox *frame; + ramSearchInputValidator *inpValidator; setWindowTitle("RAM Search"); @@ -151,7 +223,7 @@ RamSearchDialog_t::RamSearchDialog_t(QWidget *parent) undoButton = new QPushButton( tr("Undo") ); vbox->addWidget( undoButton ); - //connect( undoButton, SIGNAL(clicked(void)), this, SLOT(removeWatchClicked(void))); + connect( undoButton, SIGNAL(clicked(void)), this, SLOT(undoSearch(void))); undoButton->setEnabled(false); searchROMCbox = new QCheckBox( tr("Search ROM") ); @@ -220,13 +292,14 @@ RamSearchDialog_t::RamSearchDialog_t(QWidget *parent) diffByEdit->setEnabled( cmpOp == 'd' ); moduloEdit->setEnabled( cmpOp == '%' ); + inpValidator = new ramSearchInputValidator(this); diffByEdit->setMaxLength( 16 ); - //diffByEdit->setInputMask( ">H000000000000000;" ); diffByEdit->setCursorPosition(0); + diffByEdit->setValidator( inpValidator ); moduloEdit->setMaxLength( 16 ); - //moduloEdit->setInputMask( ">H000000000000000;" ); moduloEdit->setCursorPosition(0); + moduloEdit->setValidator( inpValidator ); vbox->addWidget( lt_btn ); vbox->addWidget( gt_btn ); @@ -383,7 +456,9 @@ void RamSearchDialog_t::periodicUpdate(void) frameCounterLastPass = currFrameCounter; } - + + undoButton->setEnabled( deactvFrameStack.size() > 0 ); + if ( (cycleCounter % 10) == 0) { ramView->update(); @@ -422,11 +497,6 @@ static void sortActvMemList(void) actvSrchList.sort( memoryAddrCompare ); } -template -T ReadLocalValue(const unsigned char* data) -{ - return *(const T*)data; -} // basic comparison functions: static bool LessCmp (int64_t x, int64_t y, int64_t i) { return x < y; } static bool MoreCmp (int64_t x, int64_t y, int64_t i) { return x > y; } @@ -437,8 +507,23 @@ static bool UnequalCmp (int64_t x, int64_t y, int64_t i) { return x != y; } static bool DiffByCmp (int64_t x, int64_t y, int64_t p) { return x - y == p || y - x == p; } static bool ModIsCmp (int64_t x, int64_t y, int64_t p) { return p && x % p == y; } +static int64_t getLineEditValue( QLineEdit *edit ) +{ + int64_t val=0; + std::string s; + + s = edit->text().toStdString(); + + if ( s.size() > 0 ) + { + val = strtoll( s.c_str(), NULL, 0 ); + } + return val; +} + void RamSearchDialog_t::SearchRelative(void) { + int elimCount = 0; std::list ::iterator it; memoryLocation_t *loc = NULL; int64_t x = 0, y = 0, p = 0; @@ -466,9 +551,11 @@ void RamSearchDialog_t::SearchRelative(void) break; case 'd': cmpFun = DiffByCmp; + p = getLineEditValue( diffByEdit ); break; case '%': cmpFun = ModIsCmp; + p = getLineEditValue( moduloEdit ); break; default: cmpFun = NULL; @@ -479,6 +566,7 @@ void RamSearchDialog_t::SearchRelative(void) { return; } + printf("Performing Search Operation %zi: '%c' '%lli' '0x%llx' \n", deactvFrameStack.size()+1, cmpOp, (long long int)p, (unsigned long long int)p ); it = actvSrchList.begin(); @@ -535,9 +623,10 @@ void RamSearchDialog_t::SearchRelative(void) if ( cmpFun( x, y, p ) == false ) { - //printf("Function: Returns False %li %c %li \n", x, cmpOp, y ); - printf("Eliminated Address: $%04X\n", loc->addr ); + //printf("Eliminated Address: $%04X\n", loc->addr ); it = actvSrchList.erase(it); + + deactvSrchList.push_back( loc ); elimCount++; } else { @@ -546,6 +635,8 @@ void RamSearchDialog_t::SearchRelative(void) } } + deactvFrameStack.push_back( elimCount ); + vbar->setMaximum( actvSrchList.size() ); } //---------------------------------------------------------------------------- @@ -570,6 +661,8 @@ static unsigned int ReadValueAtHardwareAddress(int address, unsigned int size) void RamSearchDialog_t::runSearch(void) { SearchRelative(); + + undoButton->setEnabled( deactvFrameStack.size() > 0 ); } //---------------------------------------------------------------------------- void RamSearchDialog_t::resetSearch(void) @@ -592,6 +685,58 @@ void RamSearchDialog_t::resetSearch(void) iterMask = 0x01; calcRamList(); + + undoButton->setEnabled(false); +} +//---------------------------------------------------------------------------- +void RamSearchDialog_t::undoSearch(void) +{ + int elimCount = 0; + memoryLocation_t *loc = NULL; + std::list ::iterator it; + + if ( deactvFrameStack.empty() ) + { + printf("Error: UNDO Stack is empty\n"); + return; + } + printf("UNDO Search Operation: %zi \n", deactvFrameStack.size() ); + // To Undo a search operation: + // 1. Loop through all current active values and revert previous value back to what it was before the search + // 2. Get the number of eliminated values from the deactivate search stack and tranfer those values back into the active search list. + + it = actvSrchList.begin(); + + while (it != actvSrchList.end()) + { + loc = *it; + + if ( !loc->hist.empty() ) + { + loc->hist.pop_back(); + } + it++; + } + + elimCount = deactvFrameStack.back(); + deactvFrameStack.pop_back(); + + while ( elimCount > 0 ) + { + if ( deactvSrchList.empty() ) + { + printf("Error: Something went wrong with UNDO operation\n"); + break; + } + loc = deactvSrchList.back(); + deactvSrchList.pop_back(); + actvSrchList.push_back( loc ); + elimCount--; + } + + sortActvMemList(); + + undoButton->setEnabled( deactvFrameStack.size() > 0 ); } //---------------------------------------------------------------------------- void RamSearchDialog_t::clearChangeCounts(void) diff --git a/src/drivers/Qt/RamSearch.h b/src/drivers/Qt/RamSearch.h index f6cff670..e495520d 100644 --- a/src/drivers/Qt/RamSearch.h +++ b/src/drivers/Qt/RamSearch.h @@ -128,6 +128,7 @@ class RamSearchDialog_t : public QDialog private slots: void runSearch(void); void resetSearch(void); + void undoSearch(void); void clearChangeCounts(void); void periodicUpdate(void); void hbarChanged(int val); From abe66aceeca1d17c015c4d6ec54d50e87d3d67c2 Mon Sep 17 00:00:00 2001 From: mjbudd77 Date: Fri, 16 Oct 2020 20:20:29 -0400 Subject: [PATCH 10/17] Successful test of RAM specific value search --- src/drivers/Qt/RamSearch.cpp | 179 ++++++++++++++++++++++++++++++++++- src/drivers/Qt/RamSearch.h | 5 + 2 files changed, 182 insertions(+), 2 deletions(-) diff --git a/src/drivers/Qt/RamSearch.cpp b/src/drivers/Qt/RamSearch.cpp index baaa5ee3..6c67045d 100644 --- a/src/drivers/Qt/RamSearch.cpp +++ b/src/drivers/Qt/RamSearch.cpp @@ -332,10 +332,23 @@ RamSearchDialog_t::RamSearchDialog_t(QWidget *parent) pv_btn->setChecked(true); + connect( pv_btn, SIGNAL(clicked(void)), this, SLOT(pvBtnClicked(void)) ); + connect( sv_btn, SIGNAL(clicked(void)), this, SLOT(svBtnClicked(void)) ); + connect( sa_btn, SIGNAL(clicked(void)), this, SLOT(saBtnClicked(void)) ); + connect( nc_btn, SIGNAL(clicked(void)), this, SLOT(ncBtnClicked(void)) ); + specValEdit = new QLineEdit(); specAddrEdit = new QLineEdit(); numChangeEdit = new QLineEdit(); + specValEdit->setValidator( inpValidator ); + specAddrEdit->setValidator( inpValidator ); + numChangeEdit->setValidator( inpValidator ); + + specValEdit->setEnabled(false); + specAddrEdit->setEnabled(false); + numChangeEdit->setEnabled(false); + grid->addWidget( pv_btn , 0, 0, Qt::AlignLeft ); grid->addWidget( sv_btn , 1, 0, Qt::AlignLeft ); grid->addWidget( specValEdit , 1, 1, Qt::AlignLeft ); @@ -521,6 +534,7 @@ static int64_t getLineEditValue( QLineEdit *edit ) return val; } +//---------------------------------------------------------------------------- void RamSearchDialog_t::SearchRelative(void) { int elimCount = 0; @@ -566,7 +580,7 @@ void RamSearchDialog_t::SearchRelative(void) { return; } - printf("Performing Search Operation %zi: '%c' '%lli' '0x%llx' \n", deactvFrameStack.size()+1, cmpOp, (long long int)p, (unsigned long long int)p ); + printf("Performing Relative Search Operation %zi: '%c' '%lli' '0x%llx' \n", deactvFrameStack.size()+1, cmpOp, (long long int)p, (unsigned long long int)p ); it = actvSrchList.begin(); @@ -640,6 +654,122 @@ void RamSearchDialog_t::SearchRelative(void) vbar->setMaximum( actvSrchList.size() ); } //---------------------------------------------------------------------------- +void RamSearchDialog_t::SearchSpecificValue(void) +{ + int elimCount = 0; + std::list ::iterator it; + memoryLocation_t *loc = NULL; + int64_t x = 0, y = 0, p = 0; + bool (*cmpFun)(int64_t x, int64_t y, int64_t p) = NULL; + + switch ( cmpOp ) + { + case '<': + cmpFun = LessCmp; + break; + case '>': + cmpFun = MoreCmp; + break; + case '=': + cmpFun = EqualCmp; + break; + case '!': + cmpFun = UnequalCmp; + break; + case 'l': + cmpFun = LessEqualCmp; + break; + case 'm': + cmpFun = MoreEqualCmp; + break; + case 'd': + cmpFun = DiffByCmp; + p = getLineEditValue( diffByEdit ); + break; + case '%': + cmpFun = ModIsCmp; + p = getLineEditValue( moduloEdit ); + break; + default: + cmpFun = NULL; + break; + } + + if ( cmpFun == NULL ) + { + return; + } + y = getLineEditValue( specValEdit ); + + printf("Performing Specific Value Search Operation %zi: 'x %c %lli' '%lli' '0x%llx' \n", deactvFrameStack.size()+1, cmpOp, + (long long int)y, (long long int)p, (unsigned long long int)p ); + + it = actvSrchList.begin(); + + while (it != actvSrchList.end()) + { + loc = *it; + + switch ( dpySize ) + { + default: + case 'b': + { + if ( dpyType == 's') + { + x = loc->val.v8.i; + } + else + { + x = loc->val.v8.u; + } + } + break; + case 'w': + { + if ( dpyType == 's') + { + x = loc->val.v16.i; + } + else + { + x = loc->val.v16.u; + } + } + break; + case 'd': + { + if ( dpyType == 's') + { + x = loc->val.v32.i; + } + else + { + x = loc->val.v32.u; + } + } + break; + } + + if ( cmpFun( x, y, p ) == false ) + { + //printf("Eliminated Address: $%04X\n", loc->addr ); + it = actvSrchList.erase(it); + + deactvSrchList.push_back( loc ); elimCount++; + } + else + { + loc->hist.push_back( loc->val ); + it++; + } + } + + deactvFrameStack.push_back( elimCount ); + + vbar->setMaximum( actvSrchList.size() ); +} +//---------------------------------------------------------------------------- static unsigned int ReadValueAtHardwareAddress(int address, unsigned int size) { unsigned int value = 0; @@ -660,7 +790,24 @@ static unsigned int ReadValueAtHardwareAddress(int address, unsigned int size) //---------------------------------------------------------------------------- void RamSearchDialog_t::runSearch(void) { - SearchRelative(); + if ( pv_btn->isChecked() ) + { + // Relative Value + SearchRelative(); + } + else if ( sv_btn->isChecked() ) + { + // Specific Value + SearchSpecificValue(); + } + else if ( sa_btn->isChecked() ) + { + // Specific Address + } + else if ( nc_btn->isChecked() ) + { + // Number of Changes + } undoButton->setEnabled( deactvFrameStack.size() > 0 ); } @@ -803,6 +950,34 @@ void RamSearchDialog_t::opMdClicked(void) moduloEdit->setEnabled(true); } //---------------------------------------------------------------------------- +void RamSearchDialog_t::pvBtnClicked(void) +{ + specValEdit->setEnabled(false); + specAddrEdit->setEnabled(false); + numChangeEdit->setEnabled(false); +} +//---------------------------------------------------------------------------- +void RamSearchDialog_t::svBtnClicked(void) +{ + specValEdit->setEnabled(true); + specAddrEdit->setEnabled(false); + numChangeEdit->setEnabled(false); +} +//---------------------------------------------------------------------------- +void RamSearchDialog_t::saBtnClicked(void) +{ + specValEdit->setEnabled(false); + specAddrEdit->setEnabled(true); + numChangeEdit->setEnabled(false); +} +//---------------------------------------------------------------------------- +void RamSearchDialog_t::ncBtnClicked(void) +{ + specValEdit->setEnabled(false); + specAddrEdit->setEnabled(false); + numChangeEdit->setEnabled(true); +} +//---------------------------------------------------------------------------- void RamSearchDialog_t::ds1Clicked(void) { dpySize = 'b'; diff --git a/src/drivers/Qt/RamSearch.h b/src/drivers/Qt/RamSearch.h index e495520d..989b4fd4 100644 --- a/src/drivers/Qt/RamSearch.h +++ b/src/drivers/Qt/RamSearch.h @@ -122,6 +122,7 @@ class RamSearchDialog_t : public QDialog void updateRamValues(void); void calcRamList(void); void SearchRelative(void); + void SearchSpecificValue(void); public slots: void closeWindow(void); @@ -149,6 +150,10 @@ class RamSearchDialog_t : public QDialog void opNeClicked(void); void opDfClicked(void); void opMdClicked(void); + void pvBtnClicked(void); + void svBtnClicked(void); + void saBtnClicked(void); + void ncBtnClicked(void); }; From 4215f2d3f73875a68107f64f17bff20f145983eb Mon Sep 17 00:00:00 2001 From: mjbudd77 Date: Fri, 16 Oct 2020 20:47:29 -0400 Subject: [PATCH 11/17] Successful test of all RAM search functions in Qt GUI. --- src/drivers/Qt/RamSearch.cpp | 167 ++++++++++++++++++++++++++++++++++- src/drivers/Qt/RamSearch.h | 2 + 2 files changed, 167 insertions(+), 2 deletions(-) diff --git a/src/drivers/Qt/RamSearch.cpp b/src/drivers/Qt/RamSearch.cpp index 6c67045d..a1c8f456 100644 --- a/src/drivers/Qt/RamSearch.cpp +++ b/src/drivers/Qt/RamSearch.cpp @@ -467,6 +467,10 @@ void RamSearchDialog_t::periodicUpdate(void) //} updateRamValues(); + if ( autoSearchCbox->isChecked() ) + { + runSearch(); + } frameCounterLastPass = currFrameCounter; } @@ -520,7 +524,7 @@ static bool UnequalCmp (int64_t x, int64_t y, int64_t i) { return x != y; } static bool DiffByCmp (int64_t x, int64_t y, int64_t p) { return x - y == p || y - x == p; } static bool ModIsCmp (int64_t x, int64_t y, int64_t p) { return p && x % p == y; } -static int64_t getLineEditValue( QLineEdit *edit ) +static int64_t getLineEditValue( QLineEdit *edit, bool forceHex = false ) { int64_t val=0; std::string s; @@ -529,7 +533,7 @@ static int64_t getLineEditValue( QLineEdit *edit ) if ( s.size() > 0 ) { - val = strtoll( s.c_str(), NULL, 0 ); + val = strtoll( s.c_str(), NULL, forceHex ? 16 : 0 ); } return val; } @@ -770,6 +774,160 @@ void RamSearchDialog_t::SearchSpecificValue(void) vbar->setMaximum( actvSrchList.size() ); } //---------------------------------------------------------------------------- +void RamSearchDialog_t::SearchSpecificAddress(void) +{ + int elimCount = 0; + std::list ::iterator it; + memoryLocation_t *loc = NULL; + int64_t x = 0, y = 0, p = 0; + bool (*cmpFun)(int64_t x, int64_t y, int64_t p) = NULL; + + switch ( cmpOp ) + { + case '<': + cmpFun = LessCmp; + break; + case '>': + cmpFun = MoreCmp; + break; + case '=': + cmpFun = EqualCmp; + break; + case '!': + cmpFun = UnequalCmp; + break; + case 'l': + cmpFun = LessEqualCmp; + break; + case 'm': + cmpFun = MoreEqualCmp; + break; + case 'd': + cmpFun = DiffByCmp; + p = getLineEditValue( diffByEdit ); + break; + case '%': + cmpFun = ModIsCmp; + p = getLineEditValue( moduloEdit ); + break; + default: + cmpFun = NULL; + break; + } + + if ( cmpFun == NULL ) + { + return; + } + y = getLineEditValue( specAddrEdit ); + + printf("Performing Specific Address Search Operation %zi: 'x %c 0x%llx' '%lli' '0x%llx' \n", deactvFrameStack.size()+1, cmpOp, + (unsigned long long int)y, (long long int)p, (unsigned long long int)p ); + + it = actvSrchList.begin(); + + while (it != actvSrchList.end()) + { + loc = *it; + + x = loc->addr; + + if ( cmpFun( x, y, p ) == false ) + { + //printf("Eliminated Address: $%04X\n", loc->addr ); + it = actvSrchList.erase(it); + + deactvSrchList.push_back( loc ); elimCount++; + } + else + { + loc->hist.push_back( loc->val ); + it++; + } + } + + deactvFrameStack.push_back( elimCount ); + + vbar->setMaximum( actvSrchList.size() ); +} +//---------------------------------------------------------------------------- +void RamSearchDialog_t::SearchNumberChanges(void) +{ + int elimCount = 0; + std::list ::iterator it; + memoryLocation_t *loc = NULL; + int64_t x = 0, y = 0, p = 0; + bool (*cmpFun)(int64_t x, int64_t y, int64_t p) = NULL; + + switch ( cmpOp ) + { + case '<': + cmpFun = LessCmp; + break; + case '>': + cmpFun = MoreCmp; + break; + case '=': + cmpFun = EqualCmp; + break; + case '!': + cmpFun = UnequalCmp; + break; + case 'l': + cmpFun = LessEqualCmp; + break; + case 'm': + cmpFun = MoreEqualCmp; + break; + case 'd': + cmpFun = DiffByCmp; + p = getLineEditValue( diffByEdit ); + break; + case '%': + cmpFun = ModIsCmp; + p = getLineEditValue( moduloEdit ); + break; + default: + cmpFun = NULL; + break; + } + + if ( cmpFun == NULL ) + { + return; + } + y = getLineEditValue( numChangeEdit ); + + printf("Performing Number of Changes Search Operation %zi: 'x %c 0x%llx' '%lli' '0x%llx' \n", deactvFrameStack.size()+1, cmpOp, + (unsigned long long int)y, (long long int)p, (unsigned long long int)p ); + + it = actvSrchList.begin(); + + while (it != actvSrchList.end()) + { + loc = *it; + + x = loc->chgCount; + + if ( cmpFun( x, y, p ) == false ) + { + //printf("Eliminated Address: $%04X\n", loc->addr ); + it = actvSrchList.erase(it); + + deactvSrchList.push_back( loc ); elimCount++; + } + else + { + loc->hist.push_back( loc->val ); + it++; + } + } + + deactvFrameStack.push_back( elimCount ); + + vbar->setMaximum( actvSrchList.size() ); +} +//---------------------------------------------------------------------------- static unsigned int ReadValueAtHardwareAddress(int address, unsigned int size) { unsigned int value = 0; @@ -790,6 +948,8 @@ static unsigned int ReadValueAtHardwareAddress(int address, unsigned int size) //---------------------------------------------------------------------------- void RamSearchDialog_t::runSearch(void) { + fceuWrapperLock(); + if ( pv_btn->isChecked() ) { // Relative Value @@ -803,11 +963,14 @@ void RamSearchDialog_t::runSearch(void) else if ( sa_btn->isChecked() ) { // Specific Address + SearchSpecificAddress(); } else if ( nc_btn->isChecked() ) { // Number of Changes + SearchNumberChanges(); } + fceuWrapperUnLock(); undoButton->setEnabled( deactvFrameStack.size() > 0 ); } diff --git a/src/drivers/Qt/RamSearch.h b/src/drivers/Qt/RamSearch.h index 989b4fd4..53c224b8 100644 --- a/src/drivers/Qt/RamSearch.h +++ b/src/drivers/Qt/RamSearch.h @@ -123,6 +123,8 @@ class RamSearchDialog_t : public QDialog void calcRamList(void); void SearchRelative(void); void SearchSpecificValue(void); + void SearchSpecificAddress(void); + void SearchNumberChanges(void); public slots: void closeWindow(void); From 1dc0181e017d9481d8e7431ae6294eaaa41f7e77 Mon Sep 17 00:00:00 2001 From: mjbudd77 Date: Fri, 16 Oct 2020 22:04:45 -0400 Subject: [PATCH 12/17] Added RAM search quick eliminate and hex editor functions for Qt GUI. --- src/drivers/Qt/RamSearch.cpp | 252 +++++++++++++++++++++++++++++++++-- src/drivers/Qt/RamSearch.h | 10 +- 2 files changed, 246 insertions(+), 16 deletions(-) diff --git a/src/drivers/Qt/RamSearch.cpp b/src/drivers/Qt/RamSearch.cpp index a1c8f456..990aa35f 100644 --- a/src/drivers/Qt/RamSearch.cpp +++ b/src/drivers/Qt/RamSearch.cpp @@ -33,14 +33,13 @@ #include "Qt/fceuWrapper.h" #include "Qt/RamWatch.h" #include "Qt/RamSearch.h" +#include "Qt/HexEditor.h" #include "Qt/CheatsConf.h" #include "Qt/ConsoleUtilities.h" static bool ShowROM = false; static RamSearchDialog_t *ramSearchWin = NULL; -static uint64_t iterMask = 0x01; - struct memoryState_t { union { @@ -185,7 +184,7 @@ RamSearchDialog_t::RamSearchDialog_t(QWidget *parent) mainLayout = new QVBoxLayout(); hbox1 = new QHBoxLayout(); - mainLayout->addLayout( hbox1 ); + mainLayout->addLayout( hbox1, 100 ); grid = new QGridLayout(); ramView = new QRamSearchView(this); @@ -233,7 +232,7 @@ RamSearchDialog_t::RamSearchDialog_t(QWidget *parent) elimButton = new QPushButton( tr("Eliminate") ); vbox->addWidget( elimButton ); - //connect( elimButton, SIGNAL(clicked(void)), this, SLOT(newWatchClicked(void))); + connect( elimButton, SIGNAL(clicked(void)), this, SLOT(eliminateSelAddr(void))); elimButton->setEnabled(false); watchButton = new QPushButton( tr("Watch") ); @@ -248,11 +247,11 @@ RamSearchDialog_t::RamSearchDialog_t(QWidget *parent) hexEditButton = new QPushButton( tr("Hex Editor") ); vbox->addWidget( hexEditButton ); - //connect( hexEditButton, SIGNAL(clicked(void)), this, SLOT(sepWatchClicked(void))); + connect( hexEditButton, SIGNAL(clicked(void)), this, SLOT(hexEditSelAddr(void))); hexEditButton->setEnabled(false); hbox2 = new QHBoxLayout(); - mainLayout->addLayout( hbox2 ); + mainLayout->addLayout( hbox2, 1 ); frame = new QGroupBox( tr("Comparison Operator") ); vbox = new QVBoxLayout(); @@ -459,6 +458,9 @@ void RamSearchDialog_t::closeWindow(void) //---------------------------------------------------------------------------- void RamSearchDialog_t::periodicUpdate(void) { + int selAddr = -1; + + fceuWrapperLock(); if ( currFrameCounter != frameCounterLastPass ) { //if ( currFrameCounter != (frameCounterLastPass+1) ) @@ -473,9 +475,27 @@ void RamSearchDialog_t::periodicUpdate(void) } frameCounterLastPass = currFrameCounter; } + fceuWrapperUnLock(); undoButton->setEnabled( deactvFrameStack.size() > 0 ); + selAddr = ramView->getSelAddr(); + + if ( selAddr >= 0 ) + { + elimButton->setEnabled(true); + watchButton->setEnabled(true); + addCheatButton->setEnabled(true); + hexEditButton->setEnabled(true); + } + else + { + elimButton->setEnabled(false); + watchButton->setEnabled(false); + addCheatButton->setEnabled(false); + hexEditButton->setEnabled(false); + } + if ( (cycleCounter % 10) == 0) { ramView->update(); @@ -948,8 +968,6 @@ static unsigned int ReadValueAtHardwareAddress(int address, unsigned int size) //---------------------------------------------------------------------------- void RamSearchDialog_t::runSearch(void) { - fceuWrapperLock(); - if ( pv_btn->isChecked() ) { // Relative Value @@ -970,7 +988,6 @@ void RamSearchDialog_t::runSearch(void) // Number of Changes SearchNumberChanges(); } - fceuWrapperUnLock(); undoButton->setEnabled( deactvFrameStack.size() > 0 ); } @@ -992,7 +1009,6 @@ void RamSearchDialog_t::resetSearch(void) memLoc[addr].chgCount = 0; memLoc[addr].hist.push_back( memLoc[addr].val ); } - iterMask = 0x01; calcRamList(); @@ -1057,6 +1073,99 @@ void RamSearchDialog_t::clearChangeCounts(void) } } //---------------------------------------------------------------------------- +void RamSearchDialog_t::eliminateSelAddr(void) +{ + int elimCount = 0, op = '!'; + std::list ::iterator it; + memoryLocation_t *loc = NULL; + int64_t x = 0, y = 0, p = 0; + bool (*cmpFun)(int64_t x, int64_t y, int64_t p) = NULL; + + switch ( op ) + { + case '<': + cmpFun = LessCmp; + break; + case '>': + cmpFun = MoreCmp; + break; + case '=': + cmpFun = EqualCmp; + break; + case '!': + cmpFun = UnequalCmp; + break; + case 'l': + cmpFun = LessEqualCmp; + break; + case 'm': + cmpFun = MoreEqualCmp; + break; + case 'd': + cmpFun = DiffByCmp; + p = getLineEditValue( diffByEdit ); + break; + case '%': + cmpFun = ModIsCmp; + p = getLineEditValue( moduloEdit ); + break; + default: + cmpFun = NULL; + break; + } + + if ( cmpFun == NULL ) + { + return; + } + y = ramView->getSelAddr(); + + if ( y < 0 ) + { + return; + } + + printf("Performing Eliminate Address Operation %zi: 'x %c 0x%llx' '%lli' '0x%llx' \n", deactvFrameStack.size()+1, cmpOp, + (unsigned long long int)y, (long long int)p, (unsigned long long int)p ); + + it = actvSrchList.begin(); + + while (it != actvSrchList.end()) + { + loc = *it; + + x = loc->addr; + + if ( cmpFun( x, y, p ) == false ) + { + //printf("Eliminated Address: $%04X\n", loc->addr ); + it = actvSrchList.erase(it); + + deactvSrchList.push_back( loc ); elimCount++; + } + else + { + loc->hist.push_back( loc->val ); + it++; + } + } + + deactvFrameStack.push_back( elimCount ); + + vbar->setMaximum( actvSrchList.size() ); +} +//---------------------------------------------------------------------------- +void RamSearchDialog_t::hexEditSelAddr(void) +{ + int addr = ramView->getSelAddr(); + + if ( addr < 0 ) + { + return; + } + hexEditorOpenFromDebugger( QHexEdit::MODE_NES_RAM, addr ); +} +//---------------------------------------------------------------------------- void RamSearchDialog_t::opLtClicked(void) { cmpOp = '<'; @@ -1301,6 +1410,11 @@ QRamSearchView::QRamSearchView(QWidget *parent) lineOffset = 0; maxLineOffset = 0; + selAddr = -1; + selLine = -1; + + setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Expanding ); + setFocusPolicy(Qt::StrongFocus); } //---------------------------------------------------------------------------- QRamSearchView::~QRamSearchView(void) @@ -1359,6 +1473,102 @@ void QRamSearchView::resizeEvent(QResizeEvent *event) } //---------------------------------------------------------------------------- +int QRamSearchView::convPixToLine( QPoint p ) +{ + int lineNum = 0; + float ly = ( (float)pxLineLead / (float)pxLineSpacing ); + float py = ( (float)p.y() - (float)pxLineSpacing) / (float)pxLineSpacing; + float ry = fmod( py, 1.0 ); + + if ( ry < ly ) + { + lineNum = ( ((int)py) - 1 ); + } + else + { + lineNum = ( ((int)py) ); + } + //printf("Pos: %ix%i = %i\n", p.x(), p.y(), lineNum ); + + return lineNum; +} +//---------------------------------------------------------------------------- +void QRamSearchView::keyPressEvent(QKeyEvent *event) +{ + //printf("Ram Search View Key Press: 0x%x \n", event->key() ); + + if (event->matches(QKeySequence::MoveToPreviousLine)) + { + selAddr = -1; + if ( selLine > 0 ) + { + selLine--; + } + if ( selLine < lineOffset ) + { + lineOffset = selLine; + } + if ( lineOffset < 0 ) + { + lineOffset = 0; + } + vbar->setValue( lineOffset ); + } + else if (event->matches(QKeySequence::MoveToNextLine)) + { + selAddr = -1; + selLine++; + + if ( selLine >= actvSrchList.size() ) + { + selLine = actvSrchList.size() - 1; + } + + if ( selLine >= (lineOffset+viewLines) ) + { + lineOffset = selLine - viewLines + 1; + } + + if ( lineOffset >= maxLineOffset ) + { + lineOffset = maxLineOffset; + } + vbar->setValue( lineOffset ); + } + else if (event->matches(QKeySequence::MoveToNextPage)) + { + lineOffset += ( (3 * viewLines) / 4); + + if ( lineOffset >= maxLineOffset ) + { + lineOffset = maxLineOffset; + } + vbar->setValue( lineOffset ); + } + else if (event->matches(QKeySequence::MoveToPreviousPage)) + { + lineOffset -= ( (3 * viewLines) / 4); + + if ( lineOffset < 0 ) + { + lineOffset = 0; + } + vbar->setValue( lineOffset ); + } +} +//---------------------------------------------------------------------------- +void QRamSearchView::mousePressEvent(QMouseEvent * event) +{ + int lineNum = convPixToLine( event->pos() ); + + //printf("c: %ix%i \n", c.x(), c.y() ); + + if ( event->button() == Qt::LeftButton ) + { + selLine = lineOffset + lineNum; + } +} +//---------------------------------------------------------------------------- void QRamSearchView::paintEvent(QPaintEvent *event) { int i,x,y,row,nrow; @@ -1442,10 +1652,6 @@ void QRamSearchView::paintEvent(QPaintEvent *event) painter.drawText( x+fieldStart[i]+fieldPad[i], y, tr(fieldText[i]) ); } - painter.drawLine( 0, y+pxLineLead, viewWidth, y+pxLineLead ); - painter.drawLine( x+fieldStart[1], 0, x+fieldStart[1], viewHeight ); - painter.drawLine( x+fieldStart[2], 0, x+fieldStart[2], viewHeight ); - painter.drawLine( x+fieldStart[3], 0, x+fieldStart[3], viewHeight ); y += pxLineSpacing; @@ -1464,8 +1670,20 @@ void QRamSearchView::paintEvent(QPaintEvent *event) { continue; } + if ( selLine >= 0 ) + { + if ( selLine == (lineOffset+row) ) + { + selAddr = loc->addr; + } + } it++; + if ( selAddr == loc->addr ) + { + painter.fillRect( 0, y - pxLineSpacing + pxLineLead, viewWidth, pxLineSpacing, QColor("light blue") ); + } + sprintf (addrStr, "$%04X", loc->addr); if ( dpySize == 'd' ) @@ -1536,5 +1754,11 @@ void QRamSearchView::paintEvent(QPaintEvent *event) y += pxLineSpacing; } + + painter.drawLine( 0, pxLineSpacing+pxLineLead, viewWidth, pxLineSpacing+pxLineLead ); + painter.drawLine( x+fieldStart[1], 0, x+fieldStart[1], viewHeight ); + painter.drawLine( x+fieldStart[2], 0, x+fieldStart[2], viewHeight ); + painter.drawLine( x+fieldStart[3], 0, x+fieldStart[3], viewHeight ); + } //---------------------------------------------------------------------------- diff --git a/src/drivers/Qt/RamSearch.h b/src/drivers/Qt/RamSearch.h index 53c224b8..9daf0a04 100644 --- a/src/drivers/Qt/RamSearch.h +++ b/src/drivers/Qt/RamSearch.h @@ -29,13 +29,15 @@ class QRamSearchView : public QWidget void setScrollBars( QScrollBar *hbar, QScrollBar *vbar ); + int getSelAddr(void){ return selAddr; } protected: void paintEvent(QPaintEvent *event); - //void keyPressEvent(QKeyEvent *event); + void keyPressEvent(QKeyEvent *event); //void keyReleaseEvent(QKeyEvent *event); - //void mousePressEvent(QMouseEvent * event); + void mousePressEvent(QMouseEvent * event); void resizeEvent(QResizeEvent *event); + int convPixToLine( QPoint p ); void calcFontData(void); QFont font; @@ -55,6 +57,8 @@ class QRamSearchView : public QWidget int viewLines; int viewWidth; int viewHeight; + int selAddr; + int selLine; }; class RamSearchDialog_t : public QDialog @@ -133,6 +137,8 @@ class RamSearchDialog_t : public QDialog void resetSearch(void); void undoSearch(void); void clearChangeCounts(void); + void eliminateSelAddr(void); + void hexEditSelAddr(void); void periodicUpdate(void); void hbarChanged(int val); void vbarChanged(int val); From 65bb5269517cd210e48e74dcbc1a76727094710f Mon Sep 17 00:00:00 2001 From: mjbudd77 Date: Fri, 16 Oct 2020 22:30:04 -0400 Subject: [PATCH 13/17] Added logic to refresh cheat window when adding from RAM search or watch windows for Qt GUI --- src/drivers/Qt/CheatsConf.cpp | 21 +++++++++++++++++++++ src/drivers/Qt/CheatsConf.h | 7 ++++++- src/drivers/Qt/ConsoleWindow.cpp | 6 +----- src/drivers/Qt/RamSearch.cpp | 18 +++++++++++++++++- src/drivers/Qt/RamSearch.h | 1 + src/drivers/Qt/RamWatch.cpp | 3 +++ 6 files changed, 49 insertions(+), 7 deletions(-) diff --git a/src/drivers/Qt/CheatsConf.cpp b/src/drivers/Qt/CheatsConf.cpp index 0dbfd5ee..e274300a 100644 --- a/src/drivers/Qt/CheatsConf.cpp +++ b/src/drivers/Qt/CheatsConf.cpp @@ -27,6 +27,26 @@ static GuiCheatsDialog_t *win = NULL; //---------------------------------------------------------------------------- +void openCheatDialog(QWidget *parent) +{ + if ( win != NULL ) + { + return; + } + win = new GuiCheatsDialog_t(parent); + + win->show(); +} +//---------------------------------------------------------------------------- +void updateCheatDialog(void) +{ + if ( win == NULL ) + { + return; + } + win->showActiveCheatList( true ); +} +//---------------------------------------------------------------------------- GuiCheatsDialog_t::GuiCheatsDialog_t(QWidget *parent) : QDialog( parent ) { @@ -412,6 +432,7 @@ GuiCheatsDialog_t::~GuiCheatsDialog_t(void) } wasPausedByCheats = false; + win = NULL; printf("Destroy Cheat Window Event\n"); } //---------------------------------------------------------------------------- diff --git a/src/drivers/Qt/CheatsConf.h b/src/drivers/Qt/CheatsConf.h index fbc46a24..9b86631b 100644 --- a/src/drivers/Qt/CheatsConf.h +++ b/src/drivers/Qt/CheatsConf.h @@ -32,6 +32,8 @@ class GuiCheatsDialog_t : public QDialog int activeCheatListCB (char *name, uint32 a, uint8 v, int c, int s, int type, void *data); + void showActiveCheatList(bool redraw); + protected: void closeEvent(QCloseEvent *event); @@ -75,7 +77,6 @@ class GuiCheatsDialog_t : public QDialog private: void showCheatSearchResults(void); - void showActiveCheatList(bool redraw); public slots: void closeWindow(void); @@ -97,3 +98,7 @@ class GuiCheatsDialog_t : public QDialog void actvCheatItemClicked( QTreeWidgetItem *item, int column); }; + +void openCheatDialog(QWidget *parent); + +void updateCheatDialog(void); diff --git a/src/drivers/Qt/ConsoleWindow.cpp b/src/drivers/Qt/ConsoleWindow.cpp index bb5bda85..e7a23295 100644 --- a/src/drivers/Qt/ConsoleWindow.cpp +++ b/src/drivers/Qt/ConsoleWindow.cpp @@ -1026,13 +1026,9 @@ void consoleWin_t::openGuiConfWin(void) void consoleWin_t::openCheats(void) { - GuiCheatsDialog_t *cheatWin; - //printf("Open GUI Cheat Window\n"); - cheatWin = new GuiCheatsDialog_t(this); - - cheatWin->show(); + openCheatDialog(this); } void consoleWin_t::openRamWatch(void) diff --git a/src/drivers/Qt/RamSearch.cpp b/src/drivers/Qt/RamSearch.cpp index 990aa35f..3da79f3b 100644 --- a/src/drivers/Qt/RamSearch.cpp +++ b/src/drivers/Qt/RamSearch.cpp @@ -242,7 +242,7 @@ RamSearchDialog_t::RamSearchDialog_t(QWidget *parent) addCheatButton = new QPushButton( tr("Add Cheat") ); vbox->addWidget( addCheatButton ); - //connect( addCheatButton, SIGNAL(clicked(void)), this, SLOT(sepWatchClicked(void))); + connect( addCheatButton, SIGNAL(clicked(void)), this, SLOT(addCheatClicked(void))); addCheatButton->setEnabled(false); hexEditButton = new QPushButton( tr("Hex Editor") ); @@ -1155,6 +1155,22 @@ void RamSearchDialog_t::eliminateSelAddr(void) vbar->setMaximum( actvSrchList.size() ); } //---------------------------------------------------------------------------- +void RamSearchDialog_t::addCheatClicked(void) +{ + int addr = ramView->getSelAddr(); + char desc[128]; + + if ( addr < 0 ) + { + return; + } + strcpy( desc, "Quick Cheat Add"); + + FCEUI_AddCheat( desc, addr, GetMem(addr), -1, 1 ); + + updateCheatDialog(); +} +//---------------------------------------------------------------------------- void RamSearchDialog_t::hexEditSelAddr(void) { int addr = ramView->getSelAddr(); diff --git a/src/drivers/Qt/RamSearch.h b/src/drivers/Qt/RamSearch.h index 9daf0a04..072f7194 100644 --- a/src/drivers/Qt/RamSearch.h +++ b/src/drivers/Qt/RamSearch.h @@ -139,6 +139,7 @@ class RamSearchDialog_t : public QDialog void clearChangeCounts(void); void eliminateSelAddr(void); void hexEditSelAddr(void); + void addCheatClicked(void); void periodicUpdate(void); void hbarChanged(int val); void vbarChanged(int val); diff --git a/src/drivers/Qt/RamWatch.cpp b/src/drivers/Qt/RamWatch.cpp index ea1cf86b..bd1f77ca 100644 --- a/src/drivers/Qt/RamWatch.cpp +++ b/src/drivers/Qt/RamWatch.cpp @@ -28,6 +28,7 @@ #include "Qt/keyscan.h" #include "Qt/fceuWrapper.h" #include "Qt/RamWatch.h" +#include "Qt/CheatsConf.h" #include "Qt/ConsoleUtilities.h" ramWatchList_t ramWatchList; @@ -898,6 +899,8 @@ void RamWatchDialog_t::addCheatClicked(void) if ( rw != NULL ) { FCEUI_AddCheat( rw->name.c_str(), rw->addr, GetMem(rw->addr), -1, 1 ); + + updateCheatDialog(); } } //---------------------------------------------------------------------------- From c98276945ebde8a51e66c67a7c36d36e2264ab5e Mon Sep 17 00:00:00 2001 From: mjbudd77 Date: Fri, 16 Oct 2020 22:44:23 -0400 Subject: [PATCH 14/17] Added RAM Watch quick access from RAM search window for Qt GUI --- src/drivers/Qt/RamSearch.cpp | 19 ++++++++++++++++++- src/drivers/Qt/RamSearch.h | 1 + src/drivers/Qt/RamWatch.cpp | 19 +++++++++++++++++++ src/drivers/Qt/RamWatch.h | 2 ++ 4 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/drivers/Qt/RamSearch.cpp b/src/drivers/Qt/RamSearch.cpp index 3da79f3b..1ce6941f 100644 --- a/src/drivers/Qt/RamSearch.cpp +++ b/src/drivers/Qt/RamSearch.cpp @@ -35,6 +35,7 @@ #include "Qt/RamSearch.h" #include "Qt/HexEditor.h" #include "Qt/CheatsConf.h" +#include "Qt/ConsoleWindow.h" #include "Qt/ConsoleUtilities.h" static bool ShowROM = false; @@ -237,7 +238,7 @@ RamSearchDialog_t::RamSearchDialog_t(QWidget *parent) watchButton = new QPushButton( tr("Watch") ); vbox->addWidget( watchButton ); - //connect( watchButton, SIGNAL(clicked(void)), this, SLOT(dupWatchClicked(void))); + connect( watchButton, SIGNAL(clicked(void)), this, SLOT(addRamWatchClicked(void))); watchButton->setEnabled(false); addCheatButton = new QPushButton( tr("Add Cheat") ); @@ -1171,6 +1172,22 @@ void RamSearchDialog_t::addCheatClicked(void) updateCheatDialog(); } //---------------------------------------------------------------------------- +void RamSearchDialog_t::addRamWatchClicked(void) +{ + int addr = ramView->getSelAddr(); + char desc[128]; + + if ( addr < 0 ) + { + return; + } + strcpy( desc, "Quick Watch Add"); + + ramWatchList.add_entry( desc, addr, dpyType, dpySize, 0 ); + + openRamWatchWindow(consoleWindow); +} +//---------------------------------------------------------------------------- void RamSearchDialog_t::hexEditSelAddr(void) { int addr = ramView->getSelAddr(); diff --git a/src/drivers/Qt/RamSearch.h b/src/drivers/Qt/RamSearch.h index 072f7194..ed2c0ce5 100644 --- a/src/drivers/Qt/RamSearch.h +++ b/src/drivers/Qt/RamSearch.h @@ -140,6 +140,7 @@ class RamSearchDialog_t : public QDialog void eliminateSelAddr(void); void hexEditSelAddr(void); void addCheatClicked(void); + void addRamWatchClicked(void); void periodicUpdate(void); void hbarChanged(int val); void vbarChanged(int val); diff --git a/src/drivers/Qt/RamWatch.cpp b/src/drivers/Qt/RamWatch.cpp index bd1f77ca..85e37a15 100644 --- a/src/drivers/Qt/RamWatch.cpp +++ b/src/drivers/Qt/RamWatch.cpp @@ -32,6 +32,18 @@ #include "Qt/ConsoleUtilities.h" ramWatchList_t ramWatchList; +static RamWatchDialog_t *ramWatchMainWin = NULL; +//---------------------------------------------------------------------------- +void openRamWatchWindow( QWidget *parent, int force ) +{ + if ( !force ) + { + if ( ramWatchMainWin != NULL ) return; + } + ramWatchMainWin = new RamWatchDialog_t(parent); + + ramWatchMainWin->show(); +} //---------------------------------------------------------------------------- RamWatchDialog_t::RamWatchDialog_t(QWidget *parent) : QDialog( parent ) @@ -264,6 +276,8 @@ RamWatchDialog_t::RamWatchDialog_t(QWidget *parent) setLayout( mainLayout ); + ramWatchMainWin = this; + updateTimer = new QTimer( this ); connect( updateTimer, &QTimer::timeout, this, &RamWatchDialog_t::periodicUpdate ); @@ -274,6 +288,11 @@ RamWatchDialog_t::RamWatchDialog_t(QWidget *parent) RamWatchDialog_t::~RamWatchDialog_t(void) { updateTimer->stop(); + + if ( ramWatchMainWin == this ) + { + ramWatchMainWin = NULL; + } printf("Destroy RAM Watch Config Window\n"); } //---------------------------------------------------------------------------- diff --git a/src/drivers/Qt/RamWatch.h b/src/drivers/Qt/RamWatch.h index b15b1b4d..c2a3f91c 100644 --- a/src/drivers/Qt/RamWatch.h +++ b/src/drivers/Qt/RamWatch.h @@ -254,3 +254,5 @@ class RamWatchDialog_t : public QDialog }; extern ramWatchList_t ramWatchList; + +void openRamWatchWindow( QWidget *parent, int force = 0 ); From 3c67d440e8ad1d1e57928776582a8e16a26cad41 Mon Sep 17 00:00:00 2001 From: mjbudd77 Date: Fri, 16 Oct 2020 23:15:23 -0400 Subject: [PATCH 15/17] Added logic to Qt RAM search window to not store search history when auto search is active. This will avoid excessive memory allocation. --- src/drivers/Qt/RamSearch.cpp | 78 +++++++++++++++++++++++++++--------- 1 file changed, 59 insertions(+), 19 deletions(-) diff --git a/src/drivers/Qt/RamSearch.cpp b/src/drivers/Qt/RamSearch.cpp index 1ce6941f..ea178c7e 100644 --- a/src/drivers/Qt/RamSearch.cpp +++ b/src/drivers/Qt/RamSearch.cpp @@ -567,6 +567,7 @@ void RamSearchDialog_t::SearchRelative(void) memoryLocation_t *loc = NULL; int64_t x = 0, y = 0, p = 0; bool (*cmpFun)(int64_t x, int64_t y, int64_t p) = NULL; + bool storeHistory = !autoSearchCbox->isChecked(); switch ( cmpOp ) { @@ -605,7 +606,7 @@ void RamSearchDialog_t::SearchRelative(void) { return; } - printf("Performing Relative Search Operation %zi: '%c' '%lli' '0x%llx' \n", deactvFrameStack.size()+1, cmpOp, (long long int)p, (unsigned long long int)p ); + //printf("Performing Relative Search Operation %zi: '%c' '%lli' '0x%llx' \n", deactvFrameStack.size()+1, cmpOp, (long long int)p, (unsigned long long int)p ); it = actvSrchList.begin(); @@ -665,16 +666,25 @@ void RamSearchDialog_t::SearchRelative(void) //printf("Eliminated Address: $%04X\n", loc->addr ); it = actvSrchList.erase(it); - deactvSrchList.push_back( loc ); elimCount++; + if ( storeHistory ) + { + deactvSrchList.push_back( loc ); elimCount++; + } } else { - loc->hist.push_back( loc->val ); + if ( storeHistory ) + { + loc->hist.push_back( loc->val ); + } it++; } } - deactvFrameStack.push_back( elimCount ); + if ( storeHistory ) + { + deactvFrameStack.push_back( elimCount ); + } vbar->setMaximum( actvSrchList.size() ); } @@ -686,6 +696,7 @@ void RamSearchDialog_t::SearchSpecificValue(void) memoryLocation_t *loc = NULL; int64_t x = 0, y = 0, p = 0; bool (*cmpFun)(int64_t x, int64_t y, int64_t p) = NULL; + bool storeHistory = !autoSearchCbox->isChecked(); switch ( cmpOp ) { @@ -726,8 +737,8 @@ void RamSearchDialog_t::SearchSpecificValue(void) } y = getLineEditValue( specValEdit ); - printf("Performing Specific Value Search Operation %zi: 'x %c %lli' '%lli' '0x%llx' \n", deactvFrameStack.size()+1, cmpOp, - (long long int)y, (long long int)p, (unsigned long long int)p ); + //printf("Performing Specific Value Search Operation %zi: 'x %c %lli' '%lli' '0x%llx' \n", deactvFrameStack.size()+1, cmpOp, + // (long long int)y, (long long int)p, (unsigned long long int)p ); it = actvSrchList.begin(); @@ -781,16 +792,25 @@ void RamSearchDialog_t::SearchSpecificValue(void) //printf("Eliminated Address: $%04X\n", loc->addr ); it = actvSrchList.erase(it); - deactvSrchList.push_back( loc ); elimCount++; + if ( storeHistory ) + { + deactvSrchList.push_back( loc ); elimCount++; + } } else { - loc->hist.push_back( loc->val ); + if ( storeHistory ) + { + loc->hist.push_back( loc->val ); + } it++; } } - deactvFrameStack.push_back( elimCount ); + if ( storeHistory ) + { + deactvFrameStack.push_back( elimCount ); + } vbar->setMaximum( actvSrchList.size() ); } @@ -802,6 +822,7 @@ void RamSearchDialog_t::SearchSpecificAddress(void) memoryLocation_t *loc = NULL; int64_t x = 0, y = 0, p = 0; bool (*cmpFun)(int64_t x, int64_t y, int64_t p) = NULL; + bool storeHistory = !autoSearchCbox->isChecked(); switch ( cmpOp ) { @@ -842,8 +863,8 @@ void RamSearchDialog_t::SearchSpecificAddress(void) } y = getLineEditValue( specAddrEdit ); - printf("Performing Specific Address Search Operation %zi: 'x %c 0x%llx' '%lli' '0x%llx' \n", deactvFrameStack.size()+1, cmpOp, - (unsigned long long int)y, (long long int)p, (unsigned long long int)p ); + //printf("Performing Specific Address Search Operation %zi: 'x %c 0x%llx' '%lli' '0x%llx' \n", deactvFrameStack.size()+1, cmpOp, + // (unsigned long long int)y, (long long int)p, (unsigned long long int)p ); it = actvSrchList.begin(); @@ -858,16 +879,25 @@ void RamSearchDialog_t::SearchSpecificAddress(void) //printf("Eliminated Address: $%04X\n", loc->addr ); it = actvSrchList.erase(it); - deactvSrchList.push_back( loc ); elimCount++; + if ( storeHistory ) + { + deactvSrchList.push_back( loc ); elimCount++; + } } else { - loc->hist.push_back( loc->val ); + if ( storeHistory ) + { + loc->hist.push_back( loc->val ); + } it++; } } - deactvFrameStack.push_back( elimCount ); + if ( storeHistory ) + { + deactvFrameStack.push_back( elimCount ); + } vbar->setMaximum( actvSrchList.size() ); } @@ -879,6 +909,7 @@ void RamSearchDialog_t::SearchNumberChanges(void) memoryLocation_t *loc = NULL; int64_t x = 0, y = 0, p = 0; bool (*cmpFun)(int64_t x, int64_t y, int64_t p) = NULL; + bool storeHistory = !autoSearchCbox->isChecked(); switch ( cmpOp ) { @@ -919,8 +950,8 @@ void RamSearchDialog_t::SearchNumberChanges(void) } y = getLineEditValue( numChangeEdit ); - printf("Performing Number of Changes Search Operation %zi: 'x %c 0x%llx' '%lli' '0x%llx' \n", deactvFrameStack.size()+1, cmpOp, - (unsigned long long int)y, (long long int)p, (unsigned long long int)p ); + //printf("Performing Number of Changes Search Operation %zi: 'x %c 0x%llx' '%lli' '0x%llx' \n", deactvFrameStack.size()+1, cmpOp, + // (unsigned long long int)y, (long long int)p, (unsigned long long int)p ); it = actvSrchList.begin(); @@ -935,16 +966,25 @@ void RamSearchDialog_t::SearchNumberChanges(void) //printf("Eliminated Address: $%04X\n", loc->addr ); it = actvSrchList.erase(it); - deactvSrchList.push_back( loc ); elimCount++; + if ( storeHistory ) + { + deactvSrchList.push_back( loc ); elimCount++; + } } else { - loc->hist.push_back( loc->val ); + if ( storeHistory ) + { + loc->hist.push_back( loc->val ); + } it++; } } - deactvFrameStack.push_back( elimCount ); + if ( storeHistory ) + { + deactvFrameStack.push_back( elimCount ); + } vbar->setMaximum( actvSrchList.size() ); } From e77dd77b7c1f87e44fbea36dd6c10f7ded98c1bf Mon Sep 17 00:00:00 2001 From: mjbudd77 Date: Fri, 16 Oct 2020 23:18:13 -0400 Subject: [PATCH 16/17] Resolved simple cppcheck warning on Qt Ram watch window. --- src/drivers/Qt/RamSearch.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/drivers/Qt/RamSearch.cpp b/src/drivers/Qt/RamSearch.cpp index ea178c7e..f0858020 100644 --- a/src/drivers/Qt/RamSearch.cpp +++ b/src/drivers/Qt/RamSearch.cpp @@ -1813,7 +1813,7 @@ void QRamSearchView::paintEvent(QPaintEvent *event) sprintf( prevStr, "%i", loc->hist.back().v8.i ); } } - sprintf( chgStr, "%i", loc->chgCount ); + sprintf( chgStr, "%u", loc->chgCount ); for (i=0; i<4; i++) From 5715ec235a0f9f49338e49dfbeba01bbe90bbb44 Mon Sep 17 00:00:00 2001 From: mjbudd77 Date: Fri, 16 Oct 2020 23:53:20 -0400 Subject: [PATCH 17/17] Added Qt Hex Editor goto Address Dialog. Added RAM search to Qt GUI capability list. --- TODO-SDL | 2 +- src/drivers/Qt/HexEditor.cpp | 51 ++++++++++++++++++++++++++++++++++-- src/drivers/Qt/HexEditor.h | 3 +++ 3 files changed, 53 insertions(+), 3 deletions(-) diff --git a/TODO-SDL b/TODO-SDL index 2a81dfdc..cdf06c03 100644 --- a/TODO-SDL +++ b/TODO-SDL @@ -38,7 +38,7 @@ Game genie load/enable capability | YES | YES Movie record/save/play functionality | YES | YES | Cheat search window | YES | YES | Active Cheat window | YES | YES | -RAM Search Window | NO | NO | +RAM Search Window | YES | NO | RAM Watch Window | YES | YES | Memory Watch Window | NO | NO | TAS Editor | NO | NO | diff --git a/src/drivers/Qt/HexEditor.cpp b/src/drivers/Qt/HexEditor.cpp index e5dd46a1..f1fdd389 100644 --- a/src/drivers/Qt/HexEditor.cpp +++ b/src/drivers/Qt/HexEditor.cpp @@ -563,7 +563,7 @@ HexEditorDialog_t::HexEditorDialog_t(QWidget *parent) // File -> Save ROM saveROM = new QAction(tr("Save ROM"), this); - //saveROM->setShortcuts(QKeySequence::Open); + //saveROM->setShortcut(QKeySequence::Open); saveROM->setStatusTip(tr("Save ROM File")); connect(saveROM, SIGNAL(triggered()), this, SLOT(saveRomFile(void)) ); @@ -571,12 +571,20 @@ HexEditorDialog_t::HexEditorDialog_t(QWidget *parent) // File -> Save ROM As saveROM = new QAction(tr("Save ROM As"), this); - //saveROM->setShortcuts(QKeySequence::Open); + //saveROM->setShortcut(QKeySequence::Open); saveROM->setStatusTip(tr("Save ROM File As")); connect(saveROM, SIGNAL(triggered()), this, SLOT(saveRomFileAs(void)) ); fileMenu->addAction(saveROM); + // File -> Goto Address + gotoAddrAct = new QAction(tr("Goto Addresss"), this); + gotoAddrAct->setShortcut(QKeySequence(tr("Ctrl+A"))); + gotoAddrAct->setStatusTip(tr("Goto Address")); + connect(gotoAddrAct, SIGNAL(triggered()), this, SLOT(openGotoAddrDialog(void)) ); + + fileMenu->addAction(gotoAddrAct); + fileMenu->addSeparator(); // File -> Close @@ -1132,6 +1140,11 @@ void HexEditorDialog_t::updatePeriodic(void) } } //---------------------------------------------------------------------------- +void HexEditorDialog_t::openGotoAddrDialog(void) +{ + editor->openGotoAddrDialog(); +} +//---------------------------------------------------------------------------- QHexEdit::QHexEdit(QWidget *parent) : QWidget( parent ) { @@ -1361,6 +1374,33 @@ void QHexEdit::resizeEvent(QResizeEvent *event) } //---------------------------------------------------------------------------- +void QHexEdit::openGotoAddrDialog(void) +{ + int ret; + char stmp[128]; + QInputDialog dialog(this); + + sprintf( stmp, "Specify Address [ 0x0 -> 0x%X ]", mb.size()-1 ); + + dialog.setWindowTitle( tr("Goto Address") ); + dialog.setLabelText( tr(stmp) ); + dialog.setOkButtonText( tr("Go") ); + //dialog.setTextValue( tr("0") ); + + dialog.show(); + ret = dialog.exec(); + + if ( QDialog::Accepted == ret ) + { + int addr; + std::string s = dialog.textValue().toStdString(); + + addr = strtol( s.c_str(), NULL, 16 ); + + parent->gotoAddress(addr); + } +} +//---------------------------------------------------------------------------- void QHexEdit::resetCursor(void) { cursorBlink = true; @@ -1599,6 +1639,13 @@ void QHexEdit::keyPressEvent(QKeyEvent *event) vbar->setValue( lineOffset ); resetCursor(); } + else if (Qt::ControlModifier == event->modifiers()) + { + if ( event->key() == Qt::Key_A ) + { + openGotoAddrDialog(); + } + } else if (event->key() == Qt::Key_Tab && (cursorPosX < 32) ) { // switch from hex to ascii edit cursorPosX = 32 + (cursorPosX / 2); diff --git a/src/drivers/Qt/HexEditor.h b/src/drivers/Qt/HexEditor.h index a7f5a8b1..d0fb5b9d 100644 --- a/src/drivers/Qt/HexEditor.h +++ b/src/drivers/Qt/HexEditor.h @@ -113,6 +113,7 @@ class QHexEdit : public QWidget void setForeGroundColor( QColor fg ); void setBackGroundColor( QColor bg ); void memModeUpdate(void); + void openGotoAddrDialog(void); int checkMemActivity(void); int getAddr(void){ return cursorAddr; }; @@ -221,6 +222,7 @@ class HexEditorDialog_t : public QDialog QAction *viewPPU; QAction *viewOAM; QAction *viewROM; + QAction *gotoAddrAct; private: @@ -242,6 +244,7 @@ class HexEditorDialog_t : public QDialog void pickForeGroundColor(void); void pickBackGroundColor(void); void removeAllBookmarks(void); + void openGotoAddrDialog(void); }; int hexEditorNumWindows(void);