diff --git a/include/mgba/core/mem-search.h b/include/mgba/core/mem-search.h
index a9a3a8223..b879d6f09 100644
--- a/include/mgba/core/mem-search.h
+++ b/include/mgba/core/mem-search.h
@@ -18,24 +18,31 @@ enum mCoreMemorySearchType {
mCORE_MEMORY_SEARCH_GUESS,
};
+enum mCoreMemorySearchOp {
+ mCORE_MEMORY_SEARCH_FIXED,
+ mCORE_MEMORY_SEARCH_DELTA,
+};
+
struct mCoreMemorySearchParams {
int memoryFlags;
enum mCoreMemorySearchType type;
+ enum mCoreMemorySearchOp op;
int align;
int width;
union {
const char* valueStr;
- uint32_t valueInt;
+ int32_t valueInt;
};
};
struct mCoreMemorySearchResult {
uint32_t address;
int segment;
- uint64_t guessDivisor;
- uint64_t guessMultiplier;
+ uint32_t guessDivisor;
+ uint32_t guessMultiplier;
enum mCoreMemorySearchType type;
int width;
+ int32_t oldValue;
};
DECLARE_VECTOR(mCoreMemorySearchResults, struct mCoreMemorySearchResult);
diff --git a/src/core/mem-search.c b/src/core/mem-search.c
index 1c47b633c..1b0ce9ae9 100644
--- a/src/core/mem-search.c
+++ b/src/core/mem-search.c
@@ -34,6 +34,7 @@ static size_t _search32(const void* mem, size_t size, const struct mCoreMemoryBl
res->segment = -1; // TODO
res->guessDivisor = 1;
res->guessMultiplier = 1;
+ res->oldValue = value32;
++found;
}
if ((mask & 2) && (!limit || found < limit)) {
@@ -44,6 +45,7 @@ static size_t _search32(const void* mem, size_t size, const struct mCoreMemoryBl
res->segment = -1; // TODO
res->guessDivisor = 1;
res->guessMultiplier = 1;
+ res->oldValue = value32;
++found;
}
if ((mask & 4) && (!limit || found < limit)) {
@@ -54,6 +56,7 @@ static size_t _search32(const void* mem, size_t size, const struct mCoreMemoryBl
res->segment = -1; // TODO
res->guessDivisor = 1;
res->guessMultiplier = 1;
+ res->oldValue = value32;
++found;
}
if ((mask & 8) && (!limit || found < limit)) {
@@ -64,6 +67,7 @@ static size_t _search32(const void* mem, size_t size, const struct mCoreMemoryBl
res->segment = -1; // TODO
res->guessDivisor = 1;
res->guessMultiplier = 1;
+ res->oldValue = value32;
++found;
}
}
@@ -99,6 +103,7 @@ static size_t _search16(const void* mem, size_t size, const struct mCoreMemoryBl
res->segment = -1; // TODO
res->guessDivisor = 1;
res->guessMultiplier = 1;
+ res->oldValue = value16;
++found;
}
if ((mask & 2) && (!limit || found < limit)) {
@@ -109,6 +114,7 @@ static size_t _search16(const void* mem, size_t size, const struct mCoreMemoryBl
res->segment = -1; // TODO
res->guessDivisor = 1;
res->guessMultiplier = 1;
+ res->oldValue = value16;
++found;
}
if ((mask & 4) && (!limit || found < limit)) {
@@ -119,6 +125,7 @@ static size_t _search16(const void* mem, size_t size, const struct mCoreMemoryBl
res->segment = -1; // TODO
res->guessDivisor = 1;
res->guessMultiplier = 1;
+ res->oldValue = value16;
++found;
}
if ((mask & 8) && (!limit || found < limit)) {
@@ -129,6 +136,7 @@ static size_t _search16(const void* mem, size_t size, const struct mCoreMemoryBl
res->segment = -1; // TODO
res->guessDivisor = 1;
res->guessMultiplier = 1;
+ res->oldValue = value16;
++found;
}
if ((mask & 16) && (!limit || found < limit)) {
@@ -139,6 +147,7 @@ static size_t _search16(const void* mem, size_t size, const struct mCoreMemoryBl
res->segment = -1; // TODO
res->guessDivisor = 1;
res->guessMultiplier = 1;
+ res->oldValue = value16;
++found;
}
if ((mask & 32) && (!limit || found < limit)) {
@@ -149,6 +158,7 @@ static size_t _search16(const void* mem, size_t size, const struct mCoreMemoryBl
res->segment = -1; // TODO
res->guessDivisor = 1;
res->guessMultiplier = 1;
+ res->oldValue = value16;
++found;
}
if ((mask & 64) && (!limit || found < limit)) {
@@ -159,6 +169,7 @@ static size_t _search16(const void* mem, size_t size, const struct mCoreMemoryBl
res->segment = -1; // TODO
res->guessDivisor = 1;
res->guessMultiplier = 1;
+ res->oldValue = value16;
++found;
}
if ((mask & 128) && (!limit || found < limit)) {
@@ -169,6 +180,7 @@ static size_t _search16(const void* mem, size_t size, const struct mCoreMemoryBl
res->segment = -1; // TODO
res->guessDivisor = 1;
res->guessMultiplier = 1;
+ res->oldValue = value16;
++found;
}
}
@@ -203,6 +215,7 @@ static size_t _search8(const void* mem, size_t size, const struct mCoreMemoryBlo
res->segment = -1; // TODO
res->guessDivisor = 1;
res->guessMultiplier = 1;
+ res->oldValue = value8;
++found;
}
if ((mask & 2) && (!limit || found < limit)) {
@@ -213,6 +226,7 @@ static size_t _search8(const void* mem, size_t size, const struct mCoreMemoryBlo
res->segment = -1; // TODO
res->guessDivisor = 1;
res->guessMultiplier = 1;
+ res->oldValue = value8;
++found;
}
if ((mask & 4) && (!limit || found < limit)) {
@@ -223,6 +237,7 @@ static size_t _search8(const void* mem, size_t size, const struct mCoreMemoryBlo
res->segment = -1; // TODO
res->guessDivisor = 1;
res->guessMultiplier = 1;
+ res->oldValue = value8;
++found;
}
if ((mask & 8) && (!limit || found < limit)) {
@@ -233,6 +248,7 @@ static size_t _search8(const void* mem, size_t size, const struct mCoreMemoryBlo
res->segment = -1; // TODO
res->guessDivisor = 1;
res->guessMultiplier = 1;
+ res->oldValue = value8;
++found;
}
if ((mask & 16) && (!limit || found < limit)) {
@@ -243,6 +259,7 @@ static size_t _search8(const void* mem, size_t size, const struct mCoreMemoryBlo
res->segment = -1; // TODO
res->guessDivisor = 1;
res->guessMultiplier = 1;
+ res->oldValue = value8;
++found;
}
if ((mask & 32) && (!limit || found < limit)) {
@@ -253,6 +270,7 @@ static size_t _search8(const void* mem, size_t size, const struct mCoreMemoryBlo
res->segment = -1; // TODO
res->guessDivisor = 1;
res->guessMultiplier = 1;
+ res->oldValue = value8;
++found;
}
if ((mask & 64) && (!limit || found < limit)) {
@@ -263,6 +281,7 @@ static size_t _search8(const void* mem, size_t size, const struct mCoreMemoryBlo
res->segment = -1; // TODO
res->guessDivisor = 1;
res->guessMultiplier = 1;
+ res->oldValue = value8;
++found;
}
if ((mask & 128) && (!limit || found < limit)) {
@@ -273,6 +292,7 @@ static size_t _search8(const void* mem, size_t size, const struct mCoreMemoryBlo
res->segment = -1; // TODO
res->guessDivisor = 1;
res->guessMultiplier = 1;
+ res->oldValue = value8;
++found;
}
}
@@ -317,7 +337,7 @@ static size_t _searchGuess(const void* mem, size_t size, const struct mCoreMemor
// TODO: As str
char* end;
- uint64_t value;
+ int64_t value;
size_t found = 0;
@@ -325,7 +345,7 @@ static size_t _searchGuess(const void* mem, size_t size, const struct mCoreMemor
mCoreMemorySearchResultsInit(&tmp, 0);
// Decimal:
- value = strtoull(valueStr, &end, 10);
+ value = strtoll(valueStr, &end, 10);
if (end && !end[0]) {
if (value > 0x10000) {
found += _search32(mem, size, block, value, out, limit ? limit - found : 0);
@@ -358,7 +378,7 @@ static size_t _searchGuess(const void* mem, size_t size, const struct mCoreMemor
}
// Hex:
- value = strtoull(valueStr, &end, 16);
+ value = strtoll(valueStr, &end, 16);
if (end && !end[0]) {
if (value > 0x10000) {
found += _search32(mem, size, block, value, out, limit ? limit - found : 0);
@@ -428,34 +448,42 @@ void mCoreMemorySearch(struct mCore* core, const struct mCoreMemorySearchParams*
}
}
-bool _testGuess(struct mCore* core, const struct mCoreMemorySearchResult* res, const struct mCoreMemorySearchParams* params) {
- uint64_t value;
+bool _testGuess(struct mCore* core, struct mCoreMemorySearchResult* res, const struct mCoreMemorySearchParams* params) {
+ int64_t value;
+ int32_t offset = 0;
char* end;
-
- value = strtoull(params->valueStr, &end, 10);
- if (end) {
- if (core->rawRead8(core, res->address, res->segment) * res->guessDivisor / res->guessMultiplier == value) {
- return true;
- }
- if (!(res->address & 1) && core->rawRead16(core, res->address, res->segment) * res->guessDivisor / res->guessMultiplier == value) {
- return true;
- }
- if (!(res->address & 3) && core->rawRead32(core, res->address, res->segment) * res->guessDivisor / res->guessMultiplier == value) {
- return true;
- }
+ if (params->op == mCORE_MEMORY_SEARCH_DELTA) {
+ offset = res->oldValue;
}
- value = strtoull(params->valueStr, &end, 16);
+ value = strtoll(params->valueStr, &end, 10);
if (end) {
- if (core->rawRead8(core, res->address, res->segment) * res->guessDivisor / res->guessMultiplier == value) {
+ res->oldValue += value;
+ if (core->rawRead8(core, res->address, res->segment) * res->guessDivisor / res->guessMultiplier == value + offset) {
return true;
}
- if (!(res->address & 1) && core->rawRead16(core, res->address, res->segment) * res->guessDivisor / res->guessMultiplier == value) {
+ if (!(res->address & 1) && core->rawRead16(core, res->address, res->segment) * res->guessDivisor / res->guessMultiplier == value + offset) {
return true;
}
- if (!(res->address & 3) && core->rawRead32(core, res->address, res->segment) * res->guessDivisor / res->guessMultiplier == value) {
+ if (!(res->address & 3) && core->rawRead32(core, res->address, res->segment) * res->guessDivisor / res->guessMultiplier == value + offset) {
return true;
}
+ res->oldValue -= value;
+ }
+
+ value = strtoll(params->valueStr, &end, 16);
+ if (end) {
+ res->oldValue += value;
+ if (core->rawRead8(core, res->address, res->segment) * res->guessDivisor / res->guessMultiplier == value + offset) {
+ return true;
+ }
+ if (!(res->address & 1) && core->rawRead16(core, res->address, res->segment) * res->guessDivisor / res->guessMultiplier == value + offset) {
+ return true;
+ }
+ if (!(res->address & 3) && core->rawRead32(core, res->address, res->segment) * res->guessDivisor / res->guessMultiplier == value + offset) {
+ return true;
+ }
+ res->oldValue -= value;
}
return false;
}
@@ -466,33 +494,36 @@ void mCoreMemorySearchRepeat(struct mCore* core, const struct mCoreMemorySearchP
struct mCoreMemorySearchResult* res = mCoreMemorySearchResultsGetPointer(inout, i);
switch (res->type) {
case mCORE_MEMORY_SEARCH_INT:
- switch (params->width) {
- case 1:
- if (core->rawRead8(core, res->address, res->segment) != params->valueInt) {
- mCoreMemorySearchResultsShift(inout, i, 1);
- --i;
- }
- break;
- case 2:
- if (core->rawRead8(core, res->address, res->segment) != params->valueInt) {
- mCoreMemorySearchResultsShift(inout, i, 1);
- --i;
- }
- break;
- case 4:
- if (core->rawRead32(core, res->address, res->segment) != params->valueInt) {
- mCoreMemorySearchResultsShift(inout, i, 1);
- --i;
- }
- break;
- case -1:
+ if (params->type == mCORE_MEMORY_SEARCH_GUESS) {
if (!_testGuess(core, res, params)) {
mCoreMemorySearchResultsShift(inout, i, 1);
--i;
}
- break;
- default:
- break;
+ } else if (params->type == mCORE_MEMORY_SEARCH_INT) {
+ int32_t oldValue = params->valueInt;
+ if (params->op == mCORE_MEMORY_SEARCH_DELTA) {
+ oldValue += res->oldValue;
+ }
+ int32_t value = 0;
+ switch (params->width) {
+ case 1:
+ value = core->rawRead8(core, res->address, res->segment);
+ break;
+ case 2:
+ value = core->rawRead16(core, res->address, res->segment);
+ break;
+ case 4:
+ value = core->rawRead32(core, res->address, res->segment);
+ break;
+ default:
+ break;
+ }
+ if (value != oldValue) {
+ mCoreMemorySearchResultsShift(inout, i, 1);
+ --i;
+ } else {
+ res->oldValue = value;
+ }
}
break;
case mCORE_MEMORY_SEARCH_STRING:
diff --git a/src/platform/qt/MemorySearch.cpp b/src/platform/qt/MemorySearch.cpp
index c7c1d9373..7c06791dd 100644
--- a/src/platform/qt/MemorySearch.cpp
+++ b/src/platform/qt/MemorySearch.cpp
@@ -40,8 +40,9 @@ bool MemorySearch::createParams(mCoreMemorySearchParams* params) {
QByteArray string;
bool ok = false;
- if (m_ui.typeNum->isChecked()) {
+ if (m_ui.typeNum->isChecked() || m_ui.typeDelta->isChecked()) {
params->type = mCORE_MEMORY_SEARCH_INT;
+ params->op = m_ui.typeDelta->isChecked() ? mCORE_MEMORY_SEARCH_DELTA : mCORE_MEMORY_SEARCH_FIXED;
params->align = -1;
if (m_ui.bits8->isChecked()) {
params->width = 1;
@@ -140,6 +141,7 @@ void MemorySearch::refresh() {
m_ui.results->clearContents();
m_ui.results->setRowCount(mCoreMemorySearchResultsSize(&m_results));
+ m_ui.typeDelta->setEnabled(false);
for (size_t i = 0; i < mCoreMemorySearchResultsSize(&m_results); ++i) {
mCoreMemorySearchResult* result = mCoreMemorySearchResultsGetPointer(&m_results, i);
QTableWidgetItem* item = new QTableWidgetItem(QString("%1").arg(result->address, 8, 16, QChar('0')));
@@ -200,6 +202,10 @@ void MemorySearch::refresh() {
}
m_ui.results->setItem(i, 1, item);
m_ui.results->setItem(i, 2, type);
+ m_ui.typeDelta->setEnabled(true);
+ }
+ if (m_ui.typeDelta->isChecked() && !m_ui.typeDelta->isEnabled()) {
+ m_ui.typeNum->setChecked(true);
}
m_ui.results->sortItems(0);
}
diff --git a/src/platform/qt/MemorySearch.ui b/src/platform/qt/MemorySearch.ui
index ccbe07076..678405867 100644
--- a/src/platform/qt/MemorySearch.ui
+++ b/src/platform/qt/MemorySearch.ui
@@ -6,8 +6,8 @@
0
0
- 631
- 378
+ 639
+ 397
@@ -89,7 +89,7 @@
- -
+
-
Text
@@ -99,14 +99,14 @@
- -
+
-
Width
- -
+
-
1 Byte (8-bit)
@@ -116,7 +116,7 @@
- -
+
-
2 Bytes (16-bit)
@@ -126,7 +126,7 @@
- -
+
-
4 Bytes (32-bit)
@@ -139,14 +139,14 @@
- -
+
-
Number type
- -
+
-
Hexadecimal
@@ -156,20 +156,47 @@
- -
+
-
Decimal
- -
+
-
Guess
+ -
+
+
+ Qt::Horizontal
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ -
+
+
+ false
+
+
+ Delta
+
+
+ type
+
+
+
-