mirror of
https://github.com/libretro/mgba.git
synced 2024-11-23 16:10:01 +00:00
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
|
||||
- Remappable controls for tilt and gyroscope sensors
|
||||
- Status messages for actions taken while a game is running (e.g. save/load state)
|
||||
- Memory inspector
|
||||
Bugfixes:
|
||||
- GBA: Fix timers not updating timing when writing to only the reload register
|
||||
- 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) \
|
||||
for (i = 0; i < 16; i += 4) { \
|
||||
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 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 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_letterWidth = metrics.averageCharWidth();
|
||||
|
||||
setFocusPolicy(Qt::StrongFocus);
|
||||
|
||||
for (int i = 0; i < 256; ++i) {
|
||||
QStaticText str(QString("%0").arg(i, 2, 16, QChar('0')).toUpper());
|
||||
str.prepare(QTransform(), m_font);
|
||||
@ -83,6 +85,8 @@ void MemoryModel::setAlignment(int width) {
|
||||
return;
|
||||
}
|
||||
m_align = width;
|
||||
m_buffer = 0;
|
||||
m_bufferedNybbles = 0;
|
||||
viewport()->update();
|
||||
}
|
||||
|
||||
@ -104,6 +108,8 @@ void MemoryModel::jumpToAddress(uint32_t address) {
|
||||
m_top = (address - m_base) / 16;
|
||||
boundsCheck();
|
||||
verticalScrollBar()->setValue(m_top);
|
||||
m_buffer = 0;
|
||||
m_bufferedNybbles = 0;
|
||||
}
|
||||
|
||||
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;
|
||||
m_selectionAnchor = address & ~(m_align - 1);
|
||||
m_selection = qMakePair(m_selectionAnchor, m_selectionAnchor + m_align);
|
||||
m_buffer = 0;
|
||||
m_bufferedNybbles = 0;
|
||||
emit selectionChanged(m_selection.first, m_selection.second);
|
||||
viewport()->update();
|
||||
}
|
||||
@ -220,10 +228,68 @@ void MemoryModel::mouseMoveEvent(QMouseEvent* event) {
|
||||
} else {
|
||||
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);
|
||||
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() {
|
||||
if (m_top < 0) {
|
||||
m_top = 0;
|
||||
|
@ -44,6 +44,7 @@ protected:
|
||||
void wheelEvent(QWheelEvent*) override;
|
||||
void mousePressEvent(QMouseEvent*) override;
|
||||
void mouseMoveEvent(QMouseEvent*) override;
|
||||
void keyPressEvent(QKeyEvent*) override;
|
||||
|
||||
private:
|
||||
void boundsCheck();
|
||||
@ -65,6 +66,8 @@ private:
|
||||
QSizeF m_cellSize;
|
||||
QPair<uint32_t, uint32_t> m_selection;
|
||||
uint32_t m_selectionAnchor;
|
||||
uint32_t m_buffer;
|
||||
int m_bufferedNybbles;
|
||||
};
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user