Core: Add more memory search ops (closes #1510)

This commit is contained in:
Vicki Pfau 2019-10-13 15:53:40 -07:00
parent 447c053f7e
commit b9edcd8d93
6 changed files with 183 additions and 51 deletions

View File

@ -84,6 +84,7 @@ Misc:
- Qt: Add copy and QoL improvements to graphic views (closes mgba.io/i/1541) - Qt: Add copy and QoL improvements to graphic views (closes mgba.io/i/1541)
- Qt: Show list of all sprites in sprite view - Qt: Show list of all sprites in sprite view
- Qt: Add option for disabling OSD messages - Qt: Add option for disabling OSD messages
- Core: Add more memory search ops (closes mgba.io/i/1510)
0.7.3: (2019-09-15) 0.7.3: (2019-09-15)
Emulation fixes: Emulation fixes:

View File

@ -22,7 +22,11 @@ enum mCoreMemorySearchOp {
mCORE_MEMORY_SEARCH_EQUAL, mCORE_MEMORY_SEARCH_EQUAL,
mCORE_MEMORY_SEARCH_GREATER, mCORE_MEMORY_SEARCH_GREATER,
mCORE_MEMORY_SEARCH_LESS, mCORE_MEMORY_SEARCH_LESS,
mCORE_MEMORY_SEARCH_ANY,
mCORE_MEMORY_SEARCH_DELTA, mCORE_MEMORY_SEARCH_DELTA,
mCORE_MEMORY_SEARCH_DELTA_POSITIVE,
mCORE_MEMORY_SEARCH_DELTA_NEGATIVE,
mCORE_MEMORY_SEARCH_DELTA_ANY,
}; };
struct mCoreMemorySearchParams { struct mCoreMemorySearchParams {

View File

@ -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_EQUAL:
case mCORE_MEMORY_SEARCH_DELTA: case mCORE_MEMORY_SEARCH_DELTA:
return value == match; 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; return false;
} }
@ -244,20 +252,20 @@ bool _testGuess(struct mCore* core, struct mCoreMemorySearchResult* res, const s
int64_t value; int64_t value;
int32_t offset = 0; int32_t offset = 0;
char* end; char* end;
if (params->op == mCORE_MEMORY_SEARCH_DELTA) { if (params->op >= mCORE_MEMORY_SEARCH_DELTA) {
offset = res->oldValue; offset = res->oldValue;
} }
value = strtoll(params->valueStr, &end, 10); value = strtoll(params->valueStr, &end, 10);
if (end) { if (end) {
res->oldValue += value; 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; 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; 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; return true;
} }
res->oldValue -= value; res->oldValue -= value;
@ -266,13 +274,13 @@ bool _testGuess(struct mCore* core, struct mCoreMemorySearchResult* res, const s
value = strtoll(params->valueStr, &end, 16); value = strtoll(params->valueStr, &end, 16);
if (end) { if (end) {
res->oldValue += value; 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; 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; 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; return true;
} }
res->oldValue -= value; res->oldValue -= value;
@ -293,10 +301,7 @@ void mCoreMemorySearchRepeat(struct mCore* core, const struct mCoreMemorySearchP
--i; --i;
} }
} else if (params->type == mCORE_MEMORY_SEARCH_INT) { } else if (params->type == mCORE_MEMORY_SEARCH_INT) {
int32_t oldValue = params->valueInt; int32_t match = params->valueInt;
if (params->op == mCORE_MEMORY_SEARCH_DELTA) {
oldValue += res->oldValue;
}
int32_t value = 0; int32_t value = 0;
switch (params->width) { switch (params->width) {
case 1: case 1:
@ -311,7 +316,11 @@ void mCoreMemorySearchRepeat(struct mCore* core, const struct mCoreMemorySearchP
default: default:
break; 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); *res = *mCoreMemorySearchResultsGetPointer(inout, mCoreMemorySearchResultsSize(inout) - 1);
mCoreMemorySearchResultsResize(inout, -1); mCoreMemorySearchResultsResize(inout, -1);
--i; --i;
@ -322,7 +331,7 @@ void mCoreMemorySearchRepeat(struct mCore* core, const struct mCoreMemorySearchP
break; break;
case mCORE_MEMORY_SEARCH_STRING: case mCORE_MEMORY_SEARCH_STRING:
case mCORE_MEMORY_SEARCH_GUESS: case mCORE_MEMORY_SEARCH_GUESS:
// TOOD // TODO
break; break;
} }
} }

View File

@ -35,19 +35,28 @@ MemorySearch::~MemorySearch() {
} }
bool MemorySearch::createParams(mCoreMemorySearchParams* params) { 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; mCore* core = m_controller->thread()->core;
QByteArray string; QByteArray string;
bool ok = false; bool ok = false;
if (m_ui.typeNum->isChecked()) { if (m_ui.typeNum->isChecked()) {
params->type = mCORE_MEMORY_SEARCH_INT; 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; params->op = mCORE_MEMORY_SEARCH_DELTA;
} else if (m_ui.opGreater->isChecked()) { } else if (m_ui.opGreater->isChecked()) {
params->op = mCORE_MEMORY_SEARCH_GREATER; params->op = mCORE_MEMORY_SEARCH_GREATER;
} else if (m_ui.opLess->isChecked()) { } else if (m_ui.opLess->isChecked()) {
params->op = mCORE_MEMORY_SEARCH_LESS; 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 { } else {
params->op = mCORE_MEMORY_SEARCH_EQUAL; params->op = mCORE_MEMORY_SEARCH_EQUAL;
} }
@ -103,9 +112,15 @@ bool MemorySearch::createParams(mCoreMemorySearchParams* params) {
} }
if (m_ui.numGuess->isChecked()) { if (m_ui.numGuess->isChecked()) {
params->type = mCORE_MEMORY_SEARCH_GUESS; 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(); params->valueStr = m_string.constData();
ok = true; ok = true;
} else if (m_ui.opDelta0->isChecked()) {
params->valueInt = 0;
} }
} }
if (m_ui.typeStr->isChecked()) { if (m_ui.typeStr->isChecked()) {
@ -140,6 +155,9 @@ void MemorySearch::searchWithin() {
mCore* core = m_controller->thread()->core; mCore* core = m_controller->thread()->core;
if (createParams(&params)) { if (createParams(&params)) {
if (m_ui.opUnknown->isChecked()) {
params.op = mCORE_MEMORY_SEARCH_DELTA_ANY;
}
mCoreMemorySearchRepeat(core, &params, &m_results); mCoreMemorySearchRepeat(core, &params, &m_results);
} }
@ -153,6 +171,9 @@ void MemorySearch::refresh() {
m_ui.results->clearContents(); m_ui.results->clearContents();
m_ui.results->setRowCount(mCoreMemorySearchResultsSize(&m_results)); m_ui.results->setRowCount(mCoreMemorySearchResultsSize(&m_results));
m_ui.opDelta->setEnabled(false); 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) { for (size_t i = 0; i < mCoreMemorySearchResultsSize(&m_results); ++i) {
mCoreMemorySearchResult* result = mCoreMemorySearchResultsGetPointer(&m_results, i); mCoreMemorySearchResult* result = mCoreMemorySearchResultsGetPointer(&m_results, i);
QTableWidgetItem* item = new QTableWidgetItem(QString("%1").arg(result->address, 8, 16, QChar('0'))); 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, 1, item);
m_ui.results->setItem(i, 2, type); m_ui.results->setItem(i, 2, type);
m_ui.opDelta->setEnabled(true); 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()) { if (m_ui.opDelta->isChecked() && !m_ui.opDelta->isEnabled()) {
m_ui.opEqual->setChecked(true); 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_ui.results->sortItems(0);
} }

View File

@ -6,14 +6,20 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>540</width> <width>725</width>
<height>491</height> <height>813</height>
</rect> </rect>
</property> </property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
<width>540</width> <width>540</width>
<height>241</height> <height>400</height>
</size> </size>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@ -99,21 +105,21 @@
</attribute> </attribute>
</widget> </widget>
</item> </item>
<item row="3" column="0" colspan="2"> <item row="4" column="0" colspan="2">
<widget class="Line" name="line"> <widget class="Line" name="line">
<property name="orientation"> <property name="orientation">
<enum>Qt::Horizontal</enum> <enum>Qt::Horizontal</enum>
</property> </property>
</widget> </widget>
</item> </item>
<item row="4" column="0"> <item row="5" column="0">
<widget class="QLabel" name="label_3"> <widget class="QLabel" name="label_3">
<property name="text"> <property name="text">
<string>Width</string> <string>Width</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="4" column="1"> <item row="5" column="1">
<widget class="QRadioButton" name="bitsGuess"> <widget class="QRadioButton" name="bitsGuess">
<property name="text"> <property name="text">
<string>Guess</string> <string>Guess</string>
@ -126,7 +132,7 @@
</attribute> </attribute>
</widget> </widget>
</item> </item>
<item row="5" column="1"> <item row="6" column="1">
<widget class="QRadioButton" name="bits8"> <widget class="QRadioButton" name="bits8">
<property name="text"> <property name="text">
<string>1 Byte (8-bit)</string> <string>1 Byte (8-bit)</string>
@ -136,7 +142,7 @@
</attribute> </attribute>
</widget> </widget>
</item> </item>
<item row="6" column="1"> <item row="7" column="1">
<widget class="QRadioButton" name="bits16"> <widget class="QRadioButton" name="bits16">
<property name="text"> <property name="text">
<string>2 Bytes (16-bit)</string> <string>2 Bytes (16-bit)</string>
@ -146,7 +152,7 @@
</attribute> </attribute>
</widget> </widget>
</item> </item>
<item row="7" column="1"> <item row="8" column="1">
<widget class="QRadioButton" name="bits32"> <widget class="QRadioButton" name="bits32">
<property name="text"> <property name="text">
<string>4 Bytes (32-bit)</string> <string>4 Bytes (32-bit)</string>
@ -159,21 +165,21 @@
</attribute> </attribute>
</widget> </widget>
</item> </item>
<item row="8" column="0" colspan="2"> <item row="9" column="0" colspan="2">
<widget class="Line" name="line_2"> <widget class="Line" name="line_2">
<property name="orientation"> <property name="orientation">
<enum>Qt::Horizontal</enum> <enum>Qt::Horizontal</enum>
</property> </property>
</widget> </widget>
</item> </item>
<item row="9" column="0"> <item row="10" column="0">
<widget class="QLabel" name="label_4"> <widget class="QLabel" name="label_4">
<property name="text"> <property name="text">
<string>Number type</string> <string>Number type</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="9" column="1"> <item row="10" column="1">
<widget class="QRadioButton" name="numGuess"> <widget class="QRadioButton" name="numGuess">
<property name="text"> <property name="text">
<string>Guess</string> <string>Guess</string>
@ -183,38 +189,38 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="10" column="1"> <item row="11" column="1">
<widget class="QRadioButton" name="numDec"> <widget class="QRadioButton" name="numDec">
<property name="text"> <property name="text">
<string>Decimal</string> <string>Decimal</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="11" column="1"> <item row="12" column="1">
<widget class="QRadioButton" name="numHex"> <widget class="QRadioButton" name="numHex">
<property name="text"> <property name="text">
<string>Hexadecimal</string> <string>Hexadecimal</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="12" column="0" colspan="2"> <item row="13" column="0" colspan="2">
<widget class="Line" name="line_3"> <widget class="Line" name="line_3">
<property name="orientation"> <property name="orientation">
<enum>Qt::Horizontal</enum> <enum>Qt::Horizontal</enum>
</property> </property>
</widget> </widget>
</item> </item>
<item row="13" column="0"> <item row="14" column="0">
<widget class="QLabel" name="label_5"> <widget class="QLabel" name="label_5">
<property name="text"> <property name="text">
<string>Compare</string> <string>Search type</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="13" column="1"> <item row="14" column="1">
<widget class="QRadioButton" name="opEqual"> <widget class="QRadioButton" name="opEqual">
<property name="text"> <property name="text">
<string>Equal</string> <string>Equal to value</string>
</property> </property>
<property name="checked"> <property name="checked">
<bool>true</bool> <bool>true</bool>
@ -224,20 +230,10 @@
</attribute> </attribute>
</widget> </widget>
</item> </item>
<item row="14" column="1"> <item row="15" column="1">
<widget class="QRadioButton" name="opGreater"> <widget class="QRadioButton" name="opGreater">
<property name="text"> <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">
<widget class="QRadioButton" name="opLess">
<property name="text">
<string>Less</string>
</property> </property>
<attribute name="buttonGroup"> <attribute name="buttonGroup">
<string notr="true">op</string> <string notr="true">op</string>
@ -245,18 +241,84 @@
</widget> </widget>
</item> </item>
<item row="16" column="1"> <item row="16" column="1">
<widget class="QRadioButton" name="opLess">
<property name="text">
<string>Less than value</string>
</property>
<attribute name="buttonGroup">
<string notr="true">op</string>
</attribute>
</widget>
</item>
<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"> <widget class="QRadioButton" name="opDelta">
<property name="enabled"> <property name="enabled">
<bool>false</bool> <bool>false</bool>
</property> </property>
<property name="text"> <property name="text">
<string>Delta</string> <string>Changed by value</string>
</property> </property>
<attribute name="buttonGroup"> <attribute name="buttonGroup">
<string notr="true">op</string> <string notr="true">op</string>
</attribute> </attribute>
</widget> </widget>
</item> </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> </layout>
</item> </item>
<item row="2" column="0" colspan="2"> <item row="2" column="0" colspan="2">
@ -271,7 +333,7 @@
<item> <item>
<widget class="QPushButton" name="search"> <widget class="QPushButton" name="search">
<property name="text"> <property name="text">
<string>Search</string> <string>New Search</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -318,10 +380,26 @@
</hint> </hint>
</hints> </hints>
</connection> </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> </connections>
<buttongroups> <buttongroups>
<buttongroup name="width"/>
<buttongroup name="type"/> <buttongroup name="type"/>
<buttongroup name="op"/> <buttongroup name="op"/>
<buttongroup name="width"/>
</buttongroups> </buttongroups>
</ui> </ui>

View File

@ -6,7 +6,7 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>849</width> <width>885</width>
<height>797</height> <height>797</height>
</rect> </rect>
</property> </property>
@ -2043,6 +2043,16 @@
<signal>toggled(bool)</signal> <signal>toggled(bool)</signal>
<receiver>fastForwardHeldRatio</receiver> <receiver>fastForwardHeldRatio</receiver>
<slot>setDisabled(bool)</slot> <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> </connection>
</connections> </connections>
</ui> </ui>