Core: Add more memory search ops (closes #1510)
@@ -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:
@@ -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 {
@@ -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; } }
@@ -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(¶ms)) { + if (m_ui.opUnknown->isChecked()) { + params.op = mCORE_MEMORY_SEARCH_DELTA_ANY; + } mCoreMemorySearchRepeat(core, ¶ms, &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);
@@ -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>
@@ -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>