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 + +