From cfa752a69312b4099998db3db76d44d80154aa84 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Sun, 11 Oct 2020 21:36:26 -0400 Subject: [PATCH] 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);