diff --git a/CHANGES b/CHANGES
index 2aff452c5..430717069 100644
--- a/CHANGES
+++ b/CHANGES
@@ -84,6 +84,7 @@ Misc:
- Qt: Add copy and QoL improvements to graphic views (closes mgba.io/i/1541)
- Qt: Show list of all sprites in sprite view
- Qt: Add option for disabling OSD messages
+ - Core: Add more memory search ops (closes mgba.io/i/1510)
0.7.3: (2019-09-15)
Emulation fixes:
diff --git a/include/mgba/core/mem-search.h b/include/mgba/core/mem-search.h
index c18c20922..d45601556 100644
--- a/include/mgba/core/mem-search.h
+++ b/include/mgba/core/mem-search.h
@@ -22,7 +22,11 @@ enum mCoreMemorySearchOp {
mCORE_MEMORY_SEARCH_EQUAL,
mCORE_MEMORY_SEARCH_GREATER,
mCORE_MEMORY_SEARCH_LESS,
+ mCORE_MEMORY_SEARCH_ANY,
mCORE_MEMORY_SEARCH_DELTA,
+ mCORE_MEMORY_SEARCH_DELTA_POSITIVE,
+ mCORE_MEMORY_SEARCH_DELTA_NEGATIVE,
+ mCORE_MEMORY_SEARCH_DELTA_ANY,
};
struct mCoreMemorySearchParams {
diff --git a/src/core/mem-search.c b/src/core/mem-search.c
index c6404638f..7f0c215a1 100644
--- a/src/core/mem-search.c
+++ b/src/core/mem-search.c
@@ -19,6 +19,14 @@ static bool _op(int32_t value, int32_t match, enum mCoreMemorySearchOp op) {
case mCORE_MEMORY_SEARCH_EQUAL:
case mCORE_MEMORY_SEARCH_DELTA:
return value == match;
+ case mCORE_MEMORY_SEARCH_DELTA_POSITIVE:
+ return value > 0;
+ case mCORE_MEMORY_SEARCH_DELTA_NEGATIVE:
+ return value < 0;
+ case mCORE_MEMORY_SEARCH_DELTA_ANY:
+ return value != 0;
+ case mCORE_MEMORY_SEARCH_ANY:
+ return true;
}
return false;
}
@@ -244,20 +252,20 @@ bool _testGuess(struct mCore* core, struct mCoreMemorySearchResult* res, const s
int64_t value;
int32_t offset = 0;
char* end;
- if (params->op == mCORE_MEMORY_SEARCH_DELTA) {
+ if (params->op >= mCORE_MEMORY_SEARCH_DELTA) {
offset = res->oldValue;
}
value = strtoll(params->valueStr, &end, 10);
if (end) {
res->oldValue += value;
- if (_op(core->rawRead8(core, res->address, res->segment) * res->guessDivisor / res->guessMultiplier, value + offset, params->op)) {
+ if (_op(core->rawRead8(core, res->address, res->segment) * res->guessDivisor / res->guessMultiplier - offset, value, params->op)) {
return true;
}
- if (!(res->address & 1) && (res->width >= 2 || res->width == -1) && _op(core->rawRead16(core, res->address, res->segment) * res->guessDivisor / res->guessMultiplier, value + offset, params->op)) {
+ if (!(res->address & 1) && (res->width >= 2 || res->width == -1) && _op(core->rawRead16(core, res->address, res->segment) * res->guessDivisor / res->guessMultiplier - offset, value, params->op)) {
return true;
}
- if (!(res->address & 3) && (res->width >= 4 || res->width == -1) && _op(core->rawRead32(core, res->address, res->segment) * res->guessDivisor / res->guessMultiplier, value + offset, params->op)) {
+ if (!(res->address & 3) && (res->width >= 4 || res->width == -1) && _op(core->rawRead32(core, res->address, res->segment) * res->guessDivisor / res->guessMultiplier - offset, value, params->op)) {
return true;
}
res->oldValue -= value;
@@ -266,13 +274,13 @@ bool _testGuess(struct mCore* core, struct mCoreMemorySearchResult* res, const s
value = strtoll(params->valueStr, &end, 16);
if (end) {
res->oldValue += value;
- if (_op(core->rawRead8(core, res->address, res->segment) * res->guessDivisor / res->guessMultiplier, value + offset, params->op)) {
+ if (_op(core->rawRead8(core, res->address, res->segment) * res->guessDivisor / res->guessMultiplier - offset, value, params->op)) {
return true;
}
- if (!(res->address & 1) && (res->width >= 2 || res->width == -1) && _op(core->rawRead16(core, res->address, res->segment) * res->guessDivisor / res->guessMultiplier, value + offset, params->op)) {
+ if (!(res->address & 1) && (res->width >= 2 || res->width == -1) && _op(core->rawRead16(core, res->address, res->segment) * res->guessDivisor / res->guessMultiplier - offset, value, params->op)) {
return true;
}
- if (!(res->address & 3) && (res->width >= 4 || res->width == -1) && _op(core->rawRead32(core, res->address, res->segment) * res->guessDivisor / res->guessMultiplier, value + offset, params->op)) {
+ if (!(res->address & 3) && (res->width >= 4 || res->width == -1) && _op(core->rawRead32(core, res->address, res->segment) * res->guessDivisor / res->guessMultiplier - offset, value, params->op)) {
return true;
}
res->oldValue -= value;
@@ -293,10 +301,7 @@ void mCoreMemorySearchRepeat(struct mCore* core, const struct mCoreMemorySearchP
--i;
}
} 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 match = params->valueInt;
int32_t value = 0;
switch (params->width) {
case 1:
@@ -311,7 +316,11 @@ void mCoreMemorySearchRepeat(struct mCore* core, const struct mCoreMemorySearchP
default:
break;
}
- if (!_op(value, oldValue, params->op)) {
+ int32_t opValue = value;
+ if (params->op >= mCORE_MEMORY_SEARCH_DELTA) {
+ opValue -= res->oldValue;
+ }
+ if (!_op(opValue, match, params->op)) {
*res = *mCoreMemorySearchResultsGetPointer(inout, mCoreMemorySearchResultsSize(inout) - 1);
mCoreMemorySearchResultsResize(inout, -1);
--i;
@@ -322,7 +331,7 @@ void mCoreMemorySearchRepeat(struct mCore* core, const struct mCoreMemorySearchP
break;
case mCORE_MEMORY_SEARCH_STRING:
case mCORE_MEMORY_SEARCH_GUESS:
- // TOOD
+ // TODO
break;
}
}
diff --git a/src/platform/qt/MemorySearch.cpp b/src/platform/qt/MemorySearch.cpp
index 4ff967da5..f3f82c9ed 100644
--- a/src/platform/qt/MemorySearch.cpp
+++ b/src/platform/qt/MemorySearch.cpp
@@ -35,19 +35,28 @@ MemorySearch::~MemorySearch() {
}
bool MemorySearch::createParams(mCoreMemorySearchParams* params) {
- params->memoryFlags = mCORE_MEMORY_RW;
+ params->memoryFlags = mCORE_MEMORY_WRITE;
+ if (m_ui.searchROM->isChecked()) {
+ params->memoryFlags |= mCORE_MEMORY_READ;
+ }
mCore* core = m_controller->thread()->core;
QByteArray string;
bool ok = false;
if (m_ui.typeNum->isChecked()) {
params->type = mCORE_MEMORY_SEARCH_INT;
- if (m_ui.opDelta->isChecked()) {
+ if (m_ui.opDelta->isChecked() || m_ui.opDelta0->isChecked()) {
params->op = mCORE_MEMORY_SEARCH_DELTA;
} else if (m_ui.opGreater->isChecked()) {
params->op = mCORE_MEMORY_SEARCH_GREATER;
} else if (m_ui.opLess->isChecked()) {
params->op = mCORE_MEMORY_SEARCH_LESS;
+ } else if (m_ui.opUnknown->isChecked()) {
+ params->op = mCORE_MEMORY_SEARCH_ANY;
+ } else if (m_ui.opDeltaPositive->isChecked()) {
+ params->op = mCORE_MEMORY_SEARCH_DELTA_POSITIVE;
+ } else if (m_ui.opDeltaNegative->isChecked()) {
+ params->op = mCORE_MEMORY_SEARCH_DELTA_NEGATIVE;
} else {
params->op = mCORE_MEMORY_SEARCH_EQUAL;
}
@@ -103,9 +112,15 @@ bool MemorySearch::createParams(mCoreMemorySearchParams* params) {
}
if (m_ui.numGuess->isChecked()) {
params->type = mCORE_MEMORY_SEARCH_GUESS;
- m_string = m_ui.value->text().toLocal8Bit();
+ if (m_ui.opDelta0->isChecked()) {
+ m_string = QString("0").toLocal8Bit();
+ } else {
+ m_string = m_ui.value->text().toLocal8Bit();
+ }
params->valueStr = m_string.constData();
ok = true;
+ } else if (m_ui.opDelta0->isChecked()) {
+ params->valueInt = 0;
}
}
if (m_ui.typeStr->isChecked()) {
@@ -140,6 +155,9 @@ void MemorySearch::searchWithin() {
mCore* core = m_controller->thread()->core;
if (createParams(¶ms)) {
+ if (m_ui.opUnknown->isChecked()) {
+ params.op = mCORE_MEMORY_SEARCH_DELTA_ANY;
+ }
mCoreMemorySearchRepeat(core, ¶ms, &m_results);
}
@@ -153,6 +171,9 @@ void MemorySearch::refresh() {
m_ui.results->clearContents();
m_ui.results->setRowCount(mCoreMemorySearchResultsSize(&m_results));
m_ui.opDelta->setEnabled(false);
+ m_ui.opDelta0->setEnabled(false);
+ m_ui.opDeltaPositive->setEnabled(false);
+ m_ui.opDeltaNegative->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')));
@@ -214,9 +235,18 @@ void MemorySearch::refresh() {
m_ui.results->setItem(i, 1, item);
m_ui.results->setItem(i, 2, type);
m_ui.opDelta->setEnabled(true);
+ m_ui.opDelta0->setEnabled(true);
+ m_ui.opDeltaPositive->setEnabled(true);
+ m_ui.opDeltaNegative->setEnabled(true);
}
if (m_ui.opDelta->isChecked() && !m_ui.opDelta->isEnabled()) {
m_ui.opEqual->setChecked(true);
+ } else if (m_ui.opDelta0->isChecked() && !m_ui.opDelta0->isEnabled()) {
+ m_ui.opEqual->setChecked(true);
+ } else if (m_ui.opDeltaPositive->isChecked() && !m_ui.opDeltaPositive->isEnabled()) {
+ m_ui.opEqual->setChecked(true);
+ } else if (m_ui.opDeltaNegative->isChecked() && !m_ui.opDeltaNegative->isEnabled()) {
+ m_ui.opEqual->setChecked(true);
}
m_ui.results->sortItems(0);
}
diff --git a/src/platform/qt/MemorySearch.ui b/src/platform/qt/MemorySearch.ui
index 4e8649e42..7811c14a3 100644
--- a/src/platform/qt/MemorySearch.ui
+++ b/src/platform/qt/MemorySearch.ui
@@ -6,14 +6,20 @@
0
0
- 540
- 491
+ 725
+ 813
+
+
+ 0
+ 0
+
+
540
- 241
+ 400
@@ -99,21 +105,21 @@
- -
+
-
Qt::Horizontal
- -
+
-
Width
- -
+
-
Guess
@@ -126,7 +132,7 @@
- -
+
-
1 Byte (8-bit)
@@ -136,7 +142,7 @@
- -
+
-
2 Bytes (16-bit)
@@ -146,7 +152,7 @@
- -
+
-
4 Bytes (32-bit)
@@ -159,21 +165,21 @@
- -
+
-
Qt::Horizontal
- -
+
-
Number type
- -
+
-
Guess
@@ -183,38 +189,38 @@
- -
+
-
Decimal
- -
+
-
Hexadecimal
- -
+
-
Qt::Horizontal
- -
+
-
- Compare
+ Search type
- -
+
-
- Equal
+ Equal to value
true
@@ -224,20 +230,10 @@
- -
+
-
- Greater
-
-
- op
-
-
-
- -
-
-
- Less
+ Greater than value
op
@@ -245,18 +241,84 @@
-
+
+
+ Less than value
+
+
+ op
+
+
+
+ -
+
+
+ Unknown/changed
+
+
+ op
+
+
+
+ -
false
- Delta
+ Changed by value
op
+ -
+
+
+ false
+
+
+ Unchanged
+
+
+ op
+
+
+
+ -
+
+
+ false
+
+
+ Increased
+
+
+ op
+
+
+
+ -
+
+
+ false
+
+
+ Decreased
+
+
+ op
+
+
+
+ -
+
+
+ Search ROM
+
+
+
-
@@ -271,7 +333,7 @@
-
- Search
+ New Search
@@ -318,10 +380,26 @@
+
+ opDelta0
+ toggled(bool)
+ value
+ setDisabled(bool)
+
+
+ 231
+ 768
+
+
+ 272
+ 26
+
+
+
-
+
diff --git a/src/platform/qt/SettingsView.ui b/src/platform/qt/SettingsView.ui
index 2dbb2fca7..0847639a7 100644
--- a/src/platform/qt/SettingsView.ui
+++ b/src/platform/qt/SettingsView.ui
@@ -6,7 +6,7 @@
0
0
- 849
+ 885
797
@@ -2043,6 +2043,16 @@
toggled(bool)
fastForwardHeldRatio
setDisabled(bool)
+
+
+ 20
+ 20
+
+
+ 20
+ 20
+
+