all repos — mgba @ b9edcd8d93759311eebb54cf4d8be704916d566d

mGBA Game Boy Advance Emulator

Core: Add more memory search ops (closes #1510)
Vicki Pfau vi@endrift.com
Sun, 13 Oct 2019 15:53:40 -0700
commit

b9edcd8d93759311eebb54cf4d8be704916d566d

parent

447c053f7e802941d036da12233080e1a75403f4

M CHANGESCHANGES

@@ -84,6 +84,7 @@ - Qt: Printer quality of life improvements (fixes mgba.io/i/1540)

- 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:
M include/mgba/core/mem-search.hinclude/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 {
M src/core/mem-search.csrc/core/mem-search.c

@@ -19,6 +19,14 @@ return value < match;

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 struct mCoreMemorySearchParams* params) {

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

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 @@ mCoreMemorySearchResultsResize(inout, -1);

--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 @@ break;

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 @@ }

break; case mCORE_MEMORY_SEARCH_STRING: case mCORE_MEMORY_SEARCH_GUESS: - // TOOD + // TODO break; } }
M src/platform/qt/MemorySearch.cppsrc/platform/qt/MemorySearch.cpp

@@ -35,19 +35,28 @@ mCoreMemorySearchResultsDeinit(&m_results);

} 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 @@ }

} 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 @@ CoreController::Interrupter interrupter(m_controller);

mCore* core = m_controller->thread()->core; if (createParams(&params)) { + if (m_ui.opUnknown->isChecked()) { + params.op = mCORE_MEMORY_SEARCH_DELTA_ANY; + } mCoreMemorySearchRepeat(core, &params, &m_results); }

@@ -153,6 +171,9 @@

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,8 +235,17 @@ }

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);
M src/platform/qt/MemorySearch.uisrc/platform/qt/MemorySearch.ui

@@ -6,14 +6,20 @@ <property name="geometry">

<rect> <x>0</x> <y>0</y> - <width>540</width> - <height>491</height> + <width>725</width> + <height>813</height> </rect> </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> <property name="minimumSize"> <size> <width>540</width> - <height>241</height> + <height>400</height> </size> </property> <property name="windowTitle">

@@ -99,21 +105,21 @@ <string notr="true">type</string>

</attribute> </widget> </item> - <item row="3" column="0" colspan="2"> + <item row="4" column="0" colspan="2"> <widget class="Line" name="line"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> </widget> </item> - <item row="4" column="0"> + <item row="5" column="0"> <widget class="QLabel" name="label_3"> <property name="text"> <string>Width</string> </property> </widget> </item> - <item row="4" column="1"> + <item row="5" column="1"> <widget class="QRadioButton" name="bitsGuess"> <property name="text"> <string>Guess</string>

@@ -126,7 +132,7 @@ <string notr="true">width</string>

</attribute> </widget> </item> - <item row="5" column="1"> + <item row="6" column="1"> <widget class="QRadioButton" name="bits8"> <property name="text"> <string>1 Byte (8-bit)</string>

@@ -136,7 +142,7 @@ <string notr="true">width</string>

</attribute> </widget> </item> - <item row="6" column="1"> + <item row="7" column="1"> <widget class="QRadioButton" name="bits16"> <property name="text"> <string>2 Bytes (16-bit)</string>

@@ -146,7 +152,7 @@ <string notr="true">width</string>

</attribute> </widget> </item> - <item row="7" column="1"> + <item row="8" column="1"> <widget class="QRadioButton" name="bits32"> <property name="text"> <string>4 Bytes (32-bit)</string>

@@ -159,21 +165,21 @@ <string notr="true">width</string>

</attribute> </widget> </item> - <item row="8" column="0" colspan="2"> + <item row="9" column="0" colspan="2"> <widget class="Line" name="line_2"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> </widget> </item> - <item row="9" column="0"> + <item row="10" column="0"> <widget class="QLabel" name="label_4"> <property name="text"> <string>Number type</string> </property> </widget> </item> - <item row="9" column="1"> + <item row="10" column="1"> <widget class="QRadioButton" name="numGuess"> <property name="text"> <string>Guess</string>

@@ -183,38 +189,38 @@ <bool>true</bool>

</property> </widget> </item> - <item row="10" column="1"> + <item row="11" column="1"> <widget class="QRadioButton" name="numDec"> <property name="text"> <string>Decimal</string> </property> </widget> </item> - <item row="11" column="1"> + <item row="12" column="1"> <widget class="QRadioButton" name="numHex"> <property name="text"> <string>Hexadecimal</string> </property> </widget> </item> - <item row="12" column="0" colspan="2"> + <item row="13" column="0" colspan="2"> <widget class="Line" name="line_3"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> </widget> </item> - <item row="13" column="0"> + <item row="14" column="0"> <widget class="QLabel" name="label_5"> <property name="text"> - <string>Compare</string> + <string>Search type</string> </property> </widget> </item> - <item row="13" column="1"> + <item row="14" column="1"> <widget class="QRadioButton" name="opEqual"> <property name="text"> - <string>Equal</string> + <string>Equal to value</string> </property> <property name="checked"> <bool>true</bool>

@@ -224,39 +230,95 @@ <string notr="true">op</string>

</attribute> </widget> </item> - <item row="14" column="1"> + <item row="15" column="1"> <widget class="QRadioButton" name="opGreater"> <property name="text"> - <string>Greater</string> + <string>Greater than value</string> </property> <attribute name="buttonGroup"> <string notr="true">op</string> </attribute> </widget> </item> - <item row="15" column="1"> + <item row="16" column="1"> <widget class="QRadioButton" name="opLess"> <property name="text"> - <string>Less</string> + <string>Less than value</string> </property> <attribute name="buttonGroup"> <string notr="true">op</string> </attribute> </widget> </item> - <item row="16" column="1"> + <item row="17" column="1"> + <widget class="QRadioButton" name="opUnknown"> + <property name="text"> + <string>Unknown/changed</string> + </property> + <attribute name="buttonGroup"> + <string notr="true">op</string> + </attribute> + </widget> + </item> + <item row="18" column="1"> <widget class="QRadioButton" name="opDelta"> <property name="enabled"> <bool>false</bool> </property> <property name="text"> - <string>Delta</string> + <string>Changed by value</string> </property> <attribute name="buttonGroup"> <string notr="true">op</string> </attribute> </widget> </item> + <item row="21" column="1"> + <widget class="QRadioButton" name="opDelta0"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Unchanged</string> + </property> + <attribute name="buttonGroup"> + <string notr="true">op</string> + </attribute> + </widget> + </item> + <item row="19" column="1"> + <widget class="QRadioButton" name="opDeltaPositive"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Increased</string> + </property> + <attribute name="buttonGroup"> + <string notr="true">op</string> + </attribute> + </widget> + </item> + <item row="20" column="1"> + <widget class="QRadioButton" name="opDeltaNegative"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Decreased</string> + </property> + <attribute name="buttonGroup"> + <string notr="true">op</string> + </attribute> + </widget> + </item> + <item row="3" column="1"> + <widget class="QCheckBox" name="searchROM"> + <property name="text"> + <string>Search ROM</string> + </property> + </widget> + </item> </layout> </item> <item row="2" column="0" colspan="2">

@@ -271,7 +333,7 @@ <layout class="QHBoxLayout" name="horizontalLayout_2">

<item> <widget class="QPushButton" name="search"> <property name="text"> - <string>Search</string> + <string>New Search</string> </property> </widget> </item>

@@ -318,10 +380,26 @@ <y>188</y>

</hint> </hints> </connection> + <connection> + <sender>opDelta0</sender> + <signal>toggled(bool)</signal> + <receiver>value</receiver> + <slot>setDisabled(bool)</slot> + <hints> + <hint type="sourcelabel"> + <x>231</x> + <y>768</y> + </hint> + <hint type="destinationlabel"> + <x>272</x> + <y>26</y> + </hint> + </hints> + </connection> </connections> <buttongroups> - <buttongroup name="width"/> <buttongroup name="type"/> <buttongroup name="op"/> + <buttongroup name="width"/> </buttongroups> </ui>
M src/platform/qt/SettingsView.uisrc/platform/qt/SettingsView.ui

@@ -6,7 +6,7 @@ <property name="geometry">

<rect> <x>0</x> <y>0</y> - <width>849</width> + <width>885</width> <height>797</height> </rect> </property>

@@ -2043,6 +2043,16 @@ <sender>fastForwardHeldUnbounded</sender>

<signal>toggled(bool)</signal> <receiver>fastForwardHeldRatio</receiver> <slot>setDisabled(bool)</slot> + <hints> + <hint type="sourcelabel"> + <x>20</x> + <y>20</y> + </hint> + <hint type="destinationlabel"> + <x>20</x> + <y>20</y> + </hint> + </hints> </connection> </connections> </ui>