mirror of https://github.com/mgba-emu/mgba.git
Qt: Memory viewer can now edit select regions of memory
This commit is contained in:
parent
63071d9bc2
commit
298b7e7a8b
1
CHANGES
1
CHANGES
|
@ -13,6 +13,7 @@ Features:
|
||||||
- Menu items for specific solar sensor brightness levels
|
- Menu items for specific solar sensor brightness levels
|
||||||
- Remappable controls for tilt and gyroscope sensors
|
- Remappable controls for tilt and gyroscope sensors
|
||||||
- Status messages for actions taken while a game is running (e.g. save/load state)
|
- Status messages for actions taken while a game is running (e.g. save/load state)
|
||||||
|
- Memory inspector
|
||||||
Bugfixes:
|
Bugfixes:
|
||||||
- GBA: Fix timers not updating timing when writing to only the reload register
|
- GBA: Fix timers not updating timing when writing to only the reload register
|
||||||
- All: Fix sanitize-deb script not cleaning up after itself
|
- All: Fix sanitize-deb script not cleaning up after itself
|
||||||
|
|
|
@ -941,6 +941,63 @@ void GBAPatch16(struct ARMCore* cpu, uint32_t address, int16_t value, int16_t* o
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GBAPatch8(struct ARMCore* cpu, uint32_t address, int8_t value, int8_t* old) {
|
||||||
|
struct GBA* gba = (struct GBA*) cpu->master;
|
||||||
|
struct GBAMemory* memory = &gba->memory;
|
||||||
|
int8_t oldValue = -1;
|
||||||
|
|
||||||
|
switch (address >> BASE_OFFSET) {
|
||||||
|
case REGION_WORKING_RAM:
|
||||||
|
oldValue = ((int8_t*) memory->wram)[address & (SIZE_WORKING_RAM - 1)];
|
||||||
|
((int8_t*) memory->wram)[address & (SIZE_WORKING_RAM - 1)] = value;
|
||||||
|
break;
|
||||||
|
case REGION_WORKING_IRAM:
|
||||||
|
oldValue = ((int8_t*) memory->iwram)[address & (SIZE_WORKING_IRAM - 1)];
|
||||||
|
((int8_t*) memory->iwram)[address & (SIZE_WORKING_IRAM - 1)] = value;
|
||||||
|
break;
|
||||||
|
case REGION_IO:
|
||||||
|
GBALog(gba, GBA_LOG_STUB, "Unimplemented memory Patch8: 0x%08X", address);
|
||||||
|
break;
|
||||||
|
case REGION_PALETTE_RAM:
|
||||||
|
GBALog(gba, GBA_LOG_STUB, "Unimplemented memory Patch8: 0x%08X", address);
|
||||||
|
break;
|
||||||
|
case REGION_VRAM:
|
||||||
|
GBALog(gba, GBA_LOG_STUB, "Unimplemented memory Patch8: 0x%08X", address);
|
||||||
|
break;
|
||||||
|
case REGION_OAM:
|
||||||
|
GBALog(gba, GBA_LOG_STUB, "Unimplemented memory Patch8: 0x%08X", address);
|
||||||
|
break;
|
||||||
|
case REGION_CART0:
|
||||||
|
case REGION_CART0_EX:
|
||||||
|
case REGION_CART1:
|
||||||
|
case REGION_CART1_EX:
|
||||||
|
case REGION_CART2:
|
||||||
|
case REGION_CART2_EX:
|
||||||
|
_pristineCow(gba);
|
||||||
|
if ((address & (SIZE_CART0 - 1)) < gba->memory.romSize) {
|
||||||
|
gba->memory.romSize = (address & (SIZE_CART0 - 2)) + 2;
|
||||||
|
}
|
||||||
|
oldValue = ((int8_t*) memory->rom)[address & (SIZE_CART0 - 1)];
|
||||||
|
((int8_t*) memory->rom)[address & (SIZE_CART0 - 1)] = value;
|
||||||
|
break;
|
||||||
|
case REGION_CART_SRAM:
|
||||||
|
case REGION_CART_SRAM_MIRROR:
|
||||||
|
if (memory->savedata.type == SAVEDATA_SRAM) {
|
||||||
|
oldValue = ((int8_t*) memory->savedata.data)[address & (SIZE_CART_SRAM - 1)];
|
||||||
|
((int8_t*) memory->savedata.data)[address & (SIZE_CART_SRAM - 1)] = value;
|
||||||
|
} else {
|
||||||
|
GBALog(gba, GBA_LOG_GAME_ERROR, "Writing to non-existent SRAM: 0x%08X", address);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
GBALog(gba, GBA_LOG_WARN, "Bad memory Patch8: 0x%08X", address);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (old) {
|
||||||
|
*old = oldValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#define LDM_LOOP(LDM) \
|
#define LDM_LOOP(LDM) \
|
||||||
for (i = 0; i < 16; i += 4) { \
|
for (i = 0; i < 16; i += 4) { \
|
||||||
if (UNLIKELY(mask & (1 << i))) { \
|
if (UNLIKELY(mask & (1 << i))) { \
|
||||||
|
|
|
@ -154,6 +154,7 @@ void GBAStore8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCo
|
||||||
|
|
||||||
void GBAPatch32(struct ARMCore* cpu, uint32_t address, int32_t value, int32_t* old);
|
void GBAPatch32(struct ARMCore* cpu, uint32_t address, int32_t value, int32_t* old);
|
||||||
void GBAPatch16(struct ARMCore* cpu, uint32_t address, int16_t value, int16_t* old);
|
void GBAPatch16(struct ARMCore* cpu, uint32_t address, int16_t value, int16_t* old);
|
||||||
|
void GBAPatch8(struct ARMCore* cpu, uint32_t address, int8_t value, int8_t* old);
|
||||||
|
|
||||||
uint32_t GBALoadMultiple(struct ARMCore*, uint32_t baseAddress, int mask, enum LSMDirection direction, int* cycleCounter);
|
uint32_t GBALoadMultiple(struct ARMCore*, uint32_t baseAddress, int mask, enum LSMDirection direction, int* cycleCounter);
|
||||||
uint32_t GBAStoreMultiple(struct ARMCore*, uint32_t baseAddress, int mask, enum LSMDirection direction, int* cycleCounter);
|
uint32_t GBAStoreMultiple(struct ARMCore*, uint32_t baseAddress, int mask, enum LSMDirection direction, int* cycleCounter);
|
||||||
|
|
|
@ -34,6 +34,8 @@ MemoryModel::MemoryModel(QWidget* parent)
|
||||||
m_cellHeight = metrics.height();
|
m_cellHeight = metrics.height();
|
||||||
m_letterWidth = metrics.averageCharWidth();
|
m_letterWidth = metrics.averageCharWidth();
|
||||||
|
|
||||||
|
setFocusPolicy(Qt::StrongFocus);
|
||||||
|
|
||||||
for (int i = 0; i < 256; ++i) {
|
for (int i = 0; i < 256; ++i) {
|
||||||
QStaticText str(QString("%0").arg(i, 2, 16, QChar('0')).toUpper());
|
QStaticText str(QString("%0").arg(i, 2, 16, QChar('0')).toUpper());
|
||||||
str.prepare(QTransform(), m_font);
|
str.prepare(QTransform(), m_font);
|
||||||
|
@ -83,6 +85,8 @@ void MemoryModel::setAlignment(int width) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_align = width;
|
m_align = width;
|
||||||
|
m_buffer = 0;
|
||||||
|
m_bufferedNybbles = 0;
|
||||||
viewport()->update();
|
viewport()->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,6 +108,8 @@ void MemoryModel::jumpToAddress(uint32_t address) {
|
||||||
m_top = (address - m_base) / 16;
|
m_top = (address - m_base) / 16;
|
||||||
boundsCheck();
|
boundsCheck();
|
||||||
verticalScrollBar()->setValue(m_top);
|
verticalScrollBar()->setValue(m_top);
|
||||||
|
m_buffer = 0;
|
||||||
|
m_bufferedNybbles = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MemoryModel::resizeEvent(QResizeEvent*) {
|
void MemoryModel::resizeEvent(QResizeEvent*) {
|
||||||
|
@ -204,6 +210,8 @@ void MemoryModel::mousePressEvent(QMouseEvent* event) {
|
||||||
uint32_t address = int(position.x() / m_cellSize.width()) + (int(position.y() / m_cellSize.height()) + m_top) * 16 + m_base;
|
uint32_t address = int(position.x() / m_cellSize.width()) + (int(position.y() / m_cellSize.height()) + m_top) * 16 + m_base;
|
||||||
m_selectionAnchor = address & ~(m_align - 1);
|
m_selectionAnchor = address & ~(m_align - 1);
|
||||||
m_selection = qMakePair(m_selectionAnchor, m_selectionAnchor + m_align);
|
m_selection = qMakePair(m_selectionAnchor, m_selectionAnchor + m_align);
|
||||||
|
m_buffer = 0;
|
||||||
|
m_bufferedNybbles = 0;
|
||||||
emit selectionChanged(m_selection.first, m_selection.second);
|
emit selectionChanged(m_selection.first, m_selection.second);
|
||||||
viewport()->update();
|
viewport()->update();
|
||||||
}
|
}
|
||||||
|
@ -220,10 +228,68 @@ void MemoryModel::mouseMoveEvent(QMouseEvent* event) {
|
||||||
} else {
|
} else {
|
||||||
m_selection = qMakePair(m_selectionAnchor, (address & ~(m_align - 1)) + m_align);
|
m_selection = qMakePair(m_selectionAnchor, (address & ~(m_align - 1)) + m_align);
|
||||||
}
|
}
|
||||||
|
m_buffer = 0;
|
||||||
|
m_bufferedNybbles = 0;
|
||||||
emit selectionChanged(m_selection.first, m_selection.second);
|
emit selectionChanged(m_selection.first, m_selection.second);
|
||||||
viewport()->update();
|
viewport()->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MemoryModel::keyPressEvent(QKeyEvent* event) {
|
||||||
|
if (m_selection.first >= m_selection.second) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int key = event->key();
|
||||||
|
uint8_t nybble = 0;
|
||||||
|
switch (key) {
|
||||||
|
case Qt::Key_0:
|
||||||
|
case Qt::Key_1:
|
||||||
|
case Qt::Key_2:
|
||||||
|
case Qt::Key_3:
|
||||||
|
case Qt::Key_4:
|
||||||
|
case Qt::Key_5:
|
||||||
|
case Qt::Key_6:
|
||||||
|
case Qt::Key_7:
|
||||||
|
case Qt::Key_8:
|
||||||
|
case Qt::Key_9:
|
||||||
|
nybble = key - Qt::Key_0;
|
||||||
|
break;
|
||||||
|
case Qt::Key_A:
|
||||||
|
case Qt::Key_B:
|
||||||
|
case Qt::Key_C:
|
||||||
|
case Qt::Key_D:
|
||||||
|
case Qt::Key_E:
|
||||||
|
case Qt::Key_F:
|
||||||
|
nybble = key - Qt::Key_A + 10;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_buffer <<= 4;
|
||||||
|
m_buffer |= nybble;
|
||||||
|
++m_bufferedNybbles;
|
||||||
|
if (m_bufferedNybbles == m_align * 2) {
|
||||||
|
switch (m_align) {
|
||||||
|
case 1:
|
||||||
|
GBAPatch8(m_cpu, m_selection.first, m_buffer, nullptr);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
GBAPatch16(m_cpu, m_selection.first, m_buffer, nullptr);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
GBAPatch32(m_cpu, m_selection.first, m_buffer, nullptr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
m_bufferedNybbles = 0;
|
||||||
|
m_buffer = 0;
|
||||||
|
m_selection.first += m_align;
|
||||||
|
if (m_selection.second <= m_selection.first) {
|
||||||
|
m_selection.second = m_selection.first + m_align;
|
||||||
|
}
|
||||||
|
emit selectionChanged(m_selection.first, m_selection.second);
|
||||||
|
viewport()->update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void MemoryModel::boundsCheck() {
|
void MemoryModel::boundsCheck() {
|
||||||
if (m_top < 0) {
|
if (m_top < 0) {
|
||||||
m_top = 0;
|
m_top = 0;
|
||||||
|
|
|
@ -44,6 +44,7 @@ protected:
|
||||||
void wheelEvent(QWheelEvent*) override;
|
void wheelEvent(QWheelEvent*) override;
|
||||||
void mousePressEvent(QMouseEvent*) override;
|
void mousePressEvent(QMouseEvent*) override;
|
||||||
void mouseMoveEvent(QMouseEvent*) override;
|
void mouseMoveEvent(QMouseEvent*) override;
|
||||||
|
void keyPressEvent(QKeyEvent*) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void boundsCheck();
|
void boundsCheck();
|
||||||
|
@ -65,6 +66,8 @@ private:
|
||||||
QSizeF m_cellSize;
|
QSizeF m_cellSize;
|
||||||
QPair<uint32_t, uint32_t> m_selection;
|
QPair<uint32_t, uint32_t> m_selection;
|
||||||
uint32_t m_selectionAnchor;
|
uint32_t m_selectionAnchor;
|
||||||
|
uint32_t m_buffer;
|
||||||
|
int m_bufferedNybbles;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue