Qt: Memory viewer can now select segments
@@ -104,16 +104,16 @@ uint32_t (*busRead16)(struct mCore*, uint32_t address);
uint32_t (*busRead32)(struct mCore*, uint32_t address); void (*busWrite8)(struct mCore*, uint32_t address, uint8_t); - void (*busWrite16)(struct mCore*, uint32_t address, uint16_t); +void (*busWrite16)(struct mCore*, uint32_t address, uint16_t); void (*busWrite32)(struct mCore*, uint32_t address, uint32_t); - uint32_t (*rawRead8)(struct mCore*, uint32_t address); - uint32_t (*rawRead16)(struct mCore*, uint32_t address); - uint32_t (*rawRead32)(struct mCore*, uint32_t address); + uint32_t (*rawRead8)(struct mCore*, uint32_t address, int segment); + uint32_t (*rawRead16)(struct mCore*, uint32_t address, int segment); + uint32_t (*rawRead32)(struct mCore*, uint32_t address, int segment); - void (*rawWrite8)(struct mCore*, uint32_t address, uint8_t); - void (*rawWrite16)(struct mCore*, uint32_t address, uint16_t); - void (*rawWrite32)(struct mCore*, uint32_t address, uint32_t); + void (*rawWrite8)(struct mCore*, uint32_t address, int segment, uint8_t); + void (*rawWrite16)(struct mCore*, uint32_t address, int segment, uint16_t); + void (*rawWrite32)(struct mCore*, uint32_t address, int segment, uint32_t); bool (*supportsDebuggerType)(struct mCore*, enum mDebuggerType); struct mDebuggerPlatform* (*debuggerPlatform)(struct mCore*);
@@ -317,34 +317,34 @@ cpu->memory.store8(cpu, address + 2, value >> 16);
cpu->memory.store8(cpu, address + 3, value >> 24); } -static uint32_t _GBCoreRawRead8(struct mCore* core, uint32_t address) { +static uint32_t _GBCoreRawRead8(struct mCore* core, uint32_t address, int segment) { struct LR35902Core* cpu = core->cpu; - return GBLoad8(cpu, address); + return GBView8(cpu, address, segment); } -static uint32_t _GBCoreRawRead16(struct mCore* core, uint32_t address) { +static uint32_t _GBCoreRawRead16(struct mCore* core, uint32_t address, int segment) { struct LR35902Core* cpu = core->cpu; - return GBLoad8(cpu, address) | (GBLoad8(cpu, address + 1) << 8); + return GBView8(cpu, address, segment) | (GBView8(cpu, address + 1, segment) << 8); } -static uint32_t _GBCoreRawRead32(struct mCore* core, uint32_t address) { +static uint32_t _GBCoreRawRead32(struct mCore* core, uint32_t address, int segment) { struct LR35902Core* cpu = core->cpu; - return GBLoad8(cpu, address) | (GBLoad8(cpu, address + 1) << 8) | - (GBLoad8(cpu, address + 2) << 16) | (GBLoad8(cpu, address + 3) << 24); + return GBView8(cpu, address, segment) | (GBView8(cpu, address + 1, segment) << 8) | + (GBView8(cpu, address + 2, segment) << 16) | (GBView8(cpu, address + 3, segment) << 24); } -static void _GBCoreRawWrite8(struct mCore* core, uint32_t address, uint8_t value) { +static void _GBCoreRawWrite8(struct mCore* core, uint32_t address, int segment, uint8_t value) { struct LR35902Core* cpu = core->cpu; GBPatch8(cpu, address, value, NULL); } -static void _GBCoreRawWrite16(struct mCore* core, uint32_t address, uint16_t value) { +static void _GBCoreRawWrite16(struct mCore* core, uint32_t address, int segment, uint16_t value) { struct LR35902Core* cpu = core->cpu; GBPatch8(cpu, address, value, NULL); GBPatch8(cpu, address + 1, value >> 8, NULL); } -static void _GBCoreRawWrite32(struct mCore* core, uint32_t address, uint32_t value) { +static void _GBCoreRawWrite32(struct mCore* core, uint32_t address, int segment, uint32_t value) { struct LR35902Core* cpu = core->cpu; GBPatch8(cpu, address, value, NULL); GBPatch8(cpu, address + 1, value >> 8, NULL);
@@ -229,9 +229,9 @@ return gb->video.vramBank[address & (GB_SIZE_VRAM_BANK0 - 1)];
case GB_REGION_EXTERNAL_RAM: case GB_REGION_EXTERNAL_RAM + 1: if (memory->rtcAccess) { - return gb->memory.rtcRegs[memory->activeRtcReg]; + return memory->rtcRegs[memory->activeRtcReg]; } else if (memory->sramAccess) { - return gb->memory.sramBank[address & (GB_SIZE_EXTERNAL_RAM - 1)]; + return memory->sramBank[address & (GB_SIZE_EXTERNAL_RAM - 1)]; } else if (memory->mbcType == GB_MBC7) { return _GBMBC7Read(memory, address); } else if (memory->mbcType == GB_HuC3) {@@ -290,11 +290,11 @@ return;
case GB_REGION_EXTERNAL_RAM: case GB_REGION_EXTERNAL_RAM + 1: if (memory->rtcAccess) { - gb->memory.rtcRegs[memory->activeRtcReg] = value; + memory->rtcRegs[memory->activeRtcReg] = value; } else if (memory->sramAccess) { - gb->memory.sramBank[address & (GB_SIZE_EXTERNAL_RAM - 1)] = value; - } else if (gb->memory.mbcType == GB_MBC7) { - _GBMBC7Write(&gb->memory, address, value); + memory->sramBank[address & (GB_SIZE_EXTERNAL_RAM - 1)] = value; + } else if (memory->mbcType == GB_MBC7) { + _GBMBC7Write(memory, address, value); } return; case GB_REGION_WORKING_RAM_BANK0:@@ -320,6 +320,82 @@ memory->hram[address & GB_SIZE_HRAM] = value;
} else { GBIOWrite(gb, REG_IE, value); } + } +} +uint8_t GBView8(struct LR35902Core* cpu, uint16_t address, int segment) { + struct GB* gb = (struct GB*) cpu->master; + struct GBMemory* memory = &gb->memory; + switch (address >> 12) { + case GB_REGION_CART_BANK0: + case GB_REGION_CART_BANK0 + 1: + case GB_REGION_CART_BANK0 + 2: + case GB_REGION_CART_BANK0 + 3: + return memory->romBase[address & (GB_SIZE_CART_BANK0 - 1)]; + case GB_REGION_CART_BANK1: + case GB_REGION_CART_BANK1 + 1: + case GB_REGION_CART_BANK1 + 2: + case GB_REGION_CART_BANK1 + 3: + if (segment < 0) { + return memory->romBank[address & (GB_SIZE_CART_BANK0 - 1)]; + } else { + if ((size_t) segment * GB_SIZE_CART_BANK0 > memory->romSize) { + return 0xFF; + } + return memory->rom[(address & (GB_SIZE_CART_BANK0 - 1)) + segment * GB_SIZE_CART_BANK0]; + } + case GB_REGION_VRAM: + case GB_REGION_VRAM + 1: + if (segment < 0) { + return gb->video.vramBank[address & (GB_SIZE_VRAM_BANK0 - 1)]; + } else { + return gb->video.vram[(address & (GB_SIZE_VRAM_BANK0 - 1)) + segment *GB_SIZE_VRAM_BANK0]; + } + case GB_REGION_EXTERNAL_RAM: + case GB_REGION_EXTERNAL_RAM + 1: + if (memory->rtcAccess) { + return memory->rtcRegs[memory->activeRtcReg]; + } else if (memory->sramAccess) { + if (segment < 0) { + return memory->sramBank[address & (GB_SIZE_EXTERNAL_RAM - 1)]; + } else { + return memory->sram[(address & (GB_SIZE_EXTERNAL_RAM - 1)) + segment *GB_SIZE_EXTERNAL_RAM]; + } + } else if (memory->mbcType == GB_MBC7) { + return _GBMBC7Read(memory, address); + } else if (memory->mbcType == GB_HuC3) { + return 0x01; // TODO: Is this supposed to be the current SRAM bank? + } + return 0xFF; + case GB_REGION_WORKING_RAM_BANK0: + case GB_REGION_WORKING_RAM_BANK0 + 2: + return memory->wram[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)]; + case GB_REGION_WORKING_RAM_BANK1: + if (segment < 0) { + return memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)]; + } else { + return memory->wram[(address & (GB_SIZE_WORKING_RAM_BANK0 - 1)) + segment *GB_SIZE_WORKING_RAM_BANK0]; + } + default: + if (address < GB_BASE_OAM) { + return memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)]; + } + if (address < GB_BASE_UNUSABLE) { + if (gb->video.mode < 2) { + return gb->video.oam.raw[address & 0xFF]; + } + return 0xFF; + } + if (address < GB_BASE_IO) { + mLOG(GB_MEM, GAME_ERROR, "Attempt to read from unusable memory: %04X", address); + return 0xFF; + } + if (address < GB_BASE_HRAM) { + return GBIORead(gb, address & (GB_SIZE_IO - 1)); + } + if (address < GB_BASE_IE) { + return memory->hram[address & GB_SIZE_HRAM]; + } + return GBIORead(gb, REG_IE); } }
@@ -165,6 +165,8 @@
uint8_t GBLoad8(struct LR35902Core* cpu, uint16_t address); void GBStore8(struct LR35902Core* cpu, uint16_t address, int8_t value); +uint8_t GBView8(struct LR35902Core* cpu, uint16_t address, int segment); + int32_t GBMemoryProcessEvents(struct GB* gb, int32_t cycles); void GBMemoryDMA(struct GB* gb, uint16_t base); void GBMemoryWriteHDMA5(struct GB* gb, uint8_t value);
@@ -371,32 +371,38 @@ struct ARMCore* cpu = core->cpu;
cpu->memory.store32(cpu, address, value, 0); } -static uint32_t _GBACoreRawRead8(struct mCore* core, uint32_t address) { +static uint32_t _GBACoreRawRead8(struct mCore* core, uint32_t address, int segment) { + UNUSED(segment); struct ARMCore* cpu = core->cpu; return GBAView8(cpu, address); } -static uint32_t _GBACoreRawRead16(struct mCore* core, uint32_t address) { +static uint32_t _GBACoreRawRead16(struct mCore* core, uint32_t address, int segment) { + UNUSED(segment); struct ARMCore* cpu = core->cpu; return GBAView16(cpu, address); } -static uint32_t _GBACoreRawRead32(struct mCore* core, uint32_t address) { +static uint32_t _GBACoreRawRead32(struct mCore* core, uint32_t address, int segment) { + UNUSED(segment); struct ARMCore* cpu = core->cpu; return GBAView32(cpu, address); } -static void _GBACoreRawWrite8(struct mCore* core, uint32_t address, uint8_t value) { +static void _GBACoreRawWrite8(struct mCore* core, uint32_t address, int segment, uint8_t value) { + UNUSED(segment); struct ARMCore* cpu = core->cpu; GBAPatch8(cpu, address, value, NULL); } -static void _GBACoreRawWrite16(struct mCore* core, uint32_t address, uint16_t value) { +static void _GBACoreRawWrite16(struct mCore* core, uint32_t address, int segment, uint16_t value) { + UNUSED(segment); struct ARMCore* cpu = core->cpu; GBAPatch16(cpu, address, value, NULL); } -static void _GBACoreRawWrite32(struct mCore* core, uint32_t address, uint32_t value) { +static void _GBACoreRawWrite32(struct mCore* core, uint32_t address, int segment, uint32_t value) { + UNUSED(segment); struct ARMCore* cpu = core->cpu; GBAPatch32(cpu, address, value, NULL); }
@@ -90,14 +90,20 @@ void MemoryModel::setController(GameController* controller) {
m_core = controller->thread()->core; } -void MemoryModel::setRegion(uint32_t base, uint32_t size, const QString& name) { +void MemoryModel::setRegion(uint32_t base, uint32_t size, const QString& name, int segment) { m_top = 0; m_base = base; m_size = size; m_regionName = name; m_regionName.prepare(QTransform(), m_font); + m_currentBank = segment; verticalScrollBar()->setRange(0, (size >> 4) + 1 - viewport()->size().height() / m_cellHeight); verticalScrollBar()->setValue(0); + viewport()->update(); +} + +void MemoryModel::setSegment(int segment) { + m_currentBank = segment; viewport()->update(); }@@ -169,17 +175,17 @@ void MemoryModel::serialize(QDataStream* stream) {
switch (m_align) { case 1: for (uint32_t i = m_selection.first; i < m_selection.second; i += m_align) { - *stream << m_core->rawRead8(m_core, i); + *stream << m_core->rawRead8(m_core, i, m_currentBank); } break; case 2: for (uint32_t i = m_selection.first; i < m_selection.second; i += m_align) { - *stream << m_core->rawRead16(m_core, i); + *stream << m_core->rawRead16(m_core, i, m_currentBank); } break; case 4: for (uint32_t i = m_selection.first; i < m_selection.second; i += m_align) { - *stream << m_core->rawRead32(m_core, i); + *stream << m_core->rawRead32(m_core, i, m_currentBank); } break; }@@ -198,6 +204,7 @@ painter.setFont(m_font);
painter.setPen(palette.color(QPalette::WindowText)); static QChar c0('0'); static QString arg("%0"); + static QString arg2("%0:%1"); QSizeF letterSize = QSizeF(m_letterWidth, m_cellHeight); painter.drawStaticText(QPointF((m_margins.left() - m_regionName.size().width() - 1) / 2.0, 0), m_regionName); painter.drawText(@@ -213,7 +220,12 @@ int yp = m_cellHeight * y + m_margins.top();
if ((y + m_top) * 16 >= m_size) { break; } - QString data = arg.arg((y + m_top) * 16 + m_base, 8, 16, c0).toUpper(); + QString data; + if (m_currentBank >= 0) { + data = arg2.arg(m_currentBank, 2, 16, c0).arg((y + m_top) * 16 + m_base, 4, 16, c0).toUpper(); + } else { + data = arg.arg((y + m_top) * 16 + m_base, 8, 16, c0).toUpper(); + } painter.drawText(QRectF(QPointF(0, yp), QSizeF(m_margins.left(), m_cellHeight)), Qt::AlignHCenter, data); switch (m_align) { case 2:@@ -236,7 +248,7 @@ }
} else { painter.setPen(palette.color(QPalette::WindowText)); } - uint16_t b = m_core->rawRead16(m_core, address); + uint16_t b = m_core->rawRead16(m_core, address, m_currentBank); painter.drawStaticText( QPointF(m_cellSize.width() * (x + 1.0) - 2 * m_letterWidth + m_margins.left(), yp), m_staticNumbers[(b >> 8) & 0xFF]);@@ -264,7 +276,7 @@ }
} else { painter.setPen(palette.color(QPalette::WindowText)); } - uint32_t b = m_core->rawRead32(m_core, address); + uint32_t b = m_core->rawRead32(m_core, address, m_currentBank); painter.drawStaticText( QPointF(m_cellSize.width() * (x + 2.0) - 4 * m_letterWidth + m_margins.left(), yp), m_staticNumbers[(b >> 24) & 0xFF]);@@ -297,7 +309,7 @@ }
} else { painter.setPen(palette.color(QPalette::WindowText)); } - uint8_t b = m_core->rawRead8(m_core, address); + uint8_t b = m_core->rawRead8(m_core, address, m_currentBank); painter.drawStaticText(QPointF(m_cellSize.width() * (x + 0.5) - m_letterWidth + m_margins.left(), yp), m_staticNumbers[b]); }@@ -305,7 +317,7 @@ break;
} painter.setPen(palette.color(QPalette::WindowText)); for (int x = 0; x < 16; ++x) { - uint8_t b =m_core->rawRead8(m_core, (y + m_top) * 16 + x + m_base); + uint8_t b =m_core->rawRead8(m_core, (y + m_top) * 16 + x + m_base, m_currentBank); painter.drawStaticText( QPointF(viewport()->size().width() - (16 - x) * m_margins.right() / 17.0 - m_letterWidth * 0.5, yp), b < 0x80 ? m_staticAscii[b] : m_staticAscii[0]);@@ -422,13 +434,13 @@ ++m_bufferedNybbles;
if (m_bufferedNybbles == m_align * 2) { switch (m_align) { case 1: - m_core->rawWrite8(m_core, m_selection.first, m_buffer); + m_core->rawWrite8(m_core, m_selection.first, m_buffer, m_currentBank); break; case 2: - m_core->rawWrite16(m_core, m_selection.first, m_buffer); + m_core->rawWrite16(m_core, m_selection.first, m_buffer, m_currentBank); break; case 4: - m_core->rawWrite32(m_core, m_selection.first, m_buffer); + m_core->rawWrite32(m_core, m_selection.first, m_buffer, m_currentBank); break; } m_bufferedNybbles = 0;
@@ -26,7 +26,8 @@ MemoryModel(QWidget* parent = nullptr);
void setController(GameController* controller); - void setRegion(uint32_t base, uint32_t size, const QString& name = QString()); + void setRegion(uint32_t base, uint32_t size, const QString& name = QString(), int segment = -1); + void setSegment(int segment); void setAlignment(int); int alignment() const { return m_align; }@@ -77,6 +78,7 @@ QPair<uint32_t, uint32_t> m_selection;
uint32_t m_selectionAnchor; uint32_t m_buffer; int m_bufferedNybbles; + int m_currentBank; }; }
@@ -25,6 +25,7 @@ const char* name;
const char* longName; uint32_t base; uint32_t size; + int maxSegment; }; #ifdef M_CORE_GBA const static struct IndexInfo indexInfoGBA[] = {@@ -40,20 +41,20 @@ { "ROM", "Game Pak (32MiB)", BASE_CART0, SIZE_CART0 },
{ "ROM WS1", "Game Pak (Waitstate 1)", BASE_CART1, SIZE_CART1 }, { "ROM WS2", "Game Pak (Waitstate 2)", BASE_CART2, SIZE_CART2 }, { "SRAM", "Static RAM (64kiB)", BASE_CART_SRAM, SIZE_CART_SRAM }, - { nullptr, nullptr, 0, 0 } + { nullptr, nullptr, 0, 0, 0 } }; #endif #ifdef M_CORE_GB const static struct IndexInfo indexInfoGB[] = { { "All", "All", 0, 0x10000 }, - { "ROM", "Game Pak (32kiB)", GB_BASE_CART_BANK0, GB_SIZE_CART_BANK0 * 2 }, - { "VRAM", "Video RAM (8kiB)", GB_BASE_VRAM, GB_SIZE_VRAM }, - { "SRAM", "External RAM (8kiB)", GB_BASE_EXTERNAL_RAM, GB_SIZE_EXTERNAL_RAM }, - { "WRAM", "Working RAM (8kiB)", GB_BASE_WORKING_RAM_BANK0, GB_SIZE_WORKING_RAM_BANK0 * 2 }, + { "ROM", "Game Pak (32kiB)", GB_BASE_CART_BANK0, GB_SIZE_CART_BANK0 * 2, 511 }, + { "VRAM", "Video RAM (8kiB)", GB_BASE_VRAM, GB_SIZE_VRAM, 1 }, + { "SRAM", "External RAM (8kiB)", GB_BASE_EXTERNAL_RAM, GB_SIZE_EXTERNAL_RAM, 3 }, + { "WRAM", "Working RAM (8kiB)", GB_BASE_WORKING_RAM_BANK0, GB_SIZE_WORKING_RAM_BANK0 * 2, 7 }, { "OAM", "OBJ Attribute Memory", GB_BASE_OAM, GB_SIZE_OAM }, { "IO", "Memory-Mapped I/O", GB_BASE_IO, GB_SIZE_IO }, { "HRAM", "High RAM", GB_BASE_HRAM, GB_SIZE_HRAM }, - { nullptr, nullptr, 0, 0 } + { nullptr, nullptr, 0, 0, 0 } }; #endif@@ -83,6 +84,8 @@ break;
} connect(m_ui.regions, SIGNAL(currentIndexChanged(int)), this, SLOT(setIndex(int))); + connect(m_ui.segments, SIGNAL(valueChanged(int)), this, SLOT(setSegment(int))); + if (info) { for (size_t i = 0; info[i].name; ++i) { m_ui.regions->addItem(tr(info[i].longName));@@ -93,7 +96,6 @@ connect(m_ui.width8, &QAbstractButton::clicked, [this]() { m_ui.hexfield->setAlignment(1); });
connect(m_ui.width16, &QAbstractButton::clicked, [this]() { m_ui.hexfield->setAlignment(2); }); connect(m_ui.width32, &QAbstractButton::clicked, [this]() { m_ui.hexfield->setAlignment(4); }); connect(m_ui.setAddress, SIGNAL(valueChanged(const QString&)), m_ui.hexfield, SLOT(jumpToAddress(const QString&))); - connect(m_ui.hexfield, SIGNAL(selectionChanged(uint32_t, uint32_t)), this, SLOT(updateSelection(uint32_t, uint32_t))); connect(controller, SIGNAL(gameStopped(mCoreThread*)), this, SLOT(close()));@@ -121,9 +123,32 @@ #endif
default: return; } + m_ui.segments->setValue(-1); + m_ui.segments->setVisible(info.maxSegment > 0); + m_ui.segments->setMaximum(info.maxSegment); m_ui.hexfield->setRegion(info.base, info.size, info.name); } +void MemoryView::setSegment(int segment) { + mCore* core = m_controller->thread()->core; + IndexInfo info; + switch (core->platform(core)) { +#ifdef M_CORE_GBA + case PLATFORM_GBA: + info = indexInfoGBA[m_ui.regions->currentIndex()]; + break; +#endif +#ifdef M_CORE_GB + case PLATFORM_GB: + info = indexInfoGB[m_ui.regions->currentIndex()]; + break; +#endif + default: + return; + } + m_ui.hexfield->setSegment(info.maxSegment < segment ? info.maxSegment : segment); +} + void MemoryView::update() { m_ui.hexfield->viewport()->update(); updateStatus();@@ -156,17 +181,17 @@ int8_t i8;
} value; switch (align) { case 1: - value.u8 = core->rawRead8(core, m_selection.first); + value.u8 = core->rawRead8(core, m_selection.first, m_ui.segments->value()); m_ui.sintVal->setText(QString::number(value.i8)); m_ui.uintVal->setText(QString::number(value.u8)); break; case 2: - value.u16 = core->rawRead16(core, m_selection.first); + value.u16 = core->rawRead16(core, m_selection.first, m_ui.segments->value()); m_ui.sintVal->setText(QString::number(value.i16)); m_ui.uintVal->setText(QString::number(value.u16)); break; case 4: - value.u32 = core->rawRead32(core, m_selection.first); + value.u32 = core->rawRead32(core, m_selection.first, m_ui.segments->value()); m_ui.sintVal->setText(QString::number(value.i32)); m_ui.uintVal->setText(QString::number(value.u32)); break;
@@ -25,6 +25,7 @@ void update();
private slots: void setIndex(int); + void setSegment(int); void updateSelection(uint32_t start, uint32_t end); void updateStatus();
@@ -40,7 +40,23 @@ </property>
</widget> </item> <item> + <widget class="QSpinBox" name="segments"> + <property name="minimum"> + <number>-1</number> + </property> + <property name="maximum"> + <number>0</number> + </property> + <property name="displayIntegerBase"> + <number>16</number> + </property> + </widget> + </item> + <item> <widget class="QSpinBox" name="setAddress"> + <property name="accelerated"> + <bool>true</bool> + </property> <property name="prefix"> <string>0x</string> </property>