all repos — mgba @ a3ee07a6cc20512e3db26d84a23adfa5b8d0f52b

mGBA Game Boy Advance Emulator

src/platform/qt/MemoryView.cpp (view raw)

  1/* Copyright (c) 2013-2015 Jeffrey Pfau
  2 *
  3 * This Source Code Form is subject to the terms of the Mozilla Public
  4 * License, v. 2.0. If a copy of the MPL was not distributed with this
  5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  6
  7#include "MemoryView.h"
  8
  9#include "GameController.h"
 10
 11extern "C" {
 12#include "core/core.h"
 13#ifdef M_CORE_GBA
 14#include "gba/memory.h"
 15#endif
 16#ifdef M_CORE_GB
 17#include "gb/memory.h"
 18#endif
 19}
 20
 21using namespace QGBA;
 22
 23struct IndexInfo {
 24	const char* name;
 25	const char* longName;
 26	uint32_t base;
 27	uint32_t size;
 28	int maxSegment;
 29};
 30#ifdef M_CORE_GBA
 31const static struct IndexInfo indexInfoGBA[] = {
 32	{ "All", "All", 0, 0x10000000 },
 33	{ "BIOS", "BIOS (16kiB)", BASE_BIOS, SIZE_BIOS },
 34	{ "EWRAM", "Working RAM (256kiB)", BASE_WORKING_RAM, SIZE_WORKING_RAM },
 35	{ "IWRAM", "Internal Working RAM (32kiB)", BASE_WORKING_IRAM, SIZE_WORKING_IRAM },
 36	{ "MMIO", "Memory-Mapped I/O", BASE_IO, SIZE_IO },
 37	{ "Palette", "Palette RAM (1kiB)", BASE_PALETTE_RAM, SIZE_PALETTE_RAM },
 38	{ "VRAM", "Video RAM (96kiB)", BASE_VRAM, SIZE_VRAM },
 39	{ "OAM", "OBJ Attribute Memory (1kiB)", BASE_OAM, SIZE_OAM },
 40	{ "ROM", "Game Pak (32MiB)", BASE_CART0, SIZE_CART0 },
 41	{ "ROM WS1", "Game Pak (Waitstate 1)", BASE_CART1, SIZE_CART1 },
 42	{ "ROM WS2", "Game Pak (Waitstate 2)", BASE_CART2, SIZE_CART2 },
 43	{ "SRAM", "Static RAM (64kiB)", BASE_CART_SRAM, SIZE_CART_SRAM },
 44	{ nullptr, nullptr, 0, 0, 0 }
 45};
 46#endif
 47#ifdef M_CORE_GB
 48const static struct IndexInfo indexInfoGB[] = {
 49	{ "All", "All", 0, 0x10000 },
 50	{ "ROM", "Game Pak (32kiB)", GB_BASE_CART_BANK0, GB_SIZE_CART_BANK0 * 2, 511 },
 51	{ "VRAM", "Video RAM (8kiB)", GB_BASE_VRAM, GB_SIZE_VRAM, 1 },
 52	{ "SRAM", "External RAM (8kiB)", GB_BASE_EXTERNAL_RAM, GB_SIZE_EXTERNAL_RAM, 3 },
 53	{ "WRAM", "Working RAM (8kiB)", GB_BASE_WORKING_RAM_BANK0, GB_SIZE_WORKING_RAM_BANK0 * 2, 7 },
 54	{ "OAM", "OBJ Attribute Memory", GB_BASE_OAM, GB_SIZE_OAM },
 55	{ "IO", "Memory-Mapped I/O", GB_BASE_IO, GB_SIZE_IO },
 56	{ "HRAM", "High RAM", GB_BASE_HRAM, GB_SIZE_HRAM },
 57	{ nullptr, nullptr, 0, 0, 0 }
 58};
 59#endif
 60
 61MemoryView::MemoryView(GameController* controller, QWidget* parent)
 62	: QWidget(parent)
 63	, m_controller(controller)
 64{
 65	m_ui.setupUi(this);
 66
 67	m_ui.hexfield->setController(controller);
 68
 69	mCore* core = m_controller->thread()->core;
 70	const IndexInfo* info = nullptr;
 71	switch (core->platform(core)) {
 72#ifdef M_CORE_GBA
 73	case PLATFORM_GBA:
 74		info = indexInfoGBA;
 75		break;
 76#endif
 77#ifdef M_CORE_GB
 78	case PLATFORM_GB:
 79		info = indexInfoGB;
 80		break;
 81#endif
 82	default:
 83		break;
 84	}
 85
 86	connect(m_ui.regions, SIGNAL(currentIndexChanged(int)), this, SLOT(setIndex(int)));
 87	connect(m_ui.segments, SIGNAL(valueChanged(int)), this, SLOT(setSegment(int)));
 88
 89	if (info) {
 90		for (size_t i = 0; info[i].name; ++i) {
 91			m_ui.regions->addItem(tr(info[i].longName));
 92		}
 93	}
 94
 95	connect(m_ui.width8, &QAbstractButton::clicked, [this]() { m_ui.hexfield->setAlignment(1); });
 96	connect(m_ui.width16, &QAbstractButton::clicked, [this]() { m_ui.hexfield->setAlignment(2); });
 97	connect(m_ui.width32, &QAbstractButton::clicked, [this]() { m_ui.hexfield->setAlignment(4); });
 98	connect(m_ui.setAddress, SIGNAL(valueChanged(const QString&)), m_ui.hexfield, SLOT(jumpToAddress(const QString&)));
 99	connect(m_ui.hexfield, SIGNAL(selectionChanged(uint32_t, uint32_t)), this, SLOT(updateSelection(uint32_t, uint32_t)));
100
101	connect(controller, SIGNAL(gameStopped(mCoreThread*)), this, SLOT(close()));
102
103	connect(controller, SIGNAL(frameAvailable(const uint32_t*)), this, SLOT(update()));
104	connect(controller, SIGNAL(gamePaused(mCoreThread*)), this, SLOT(update()));
105	connect(controller, SIGNAL(stateLoaded(mCoreThread*)), this, SLOT(update()));
106	connect(controller, SIGNAL(rewound(mCoreThread*)), this, SLOT(update()));
107
108	connect(m_ui.copy, SIGNAL(clicked()), m_ui.hexfield, SLOT(copy()));
109	connect(m_ui.save, SIGNAL(clicked()), m_ui.hexfield, SLOT(save()));
110	connect(m_ui.paste, SIGNAL(clicked()), m_ui.hexfield, SLOT(paste()));
111	connect(m_ui.load, SIGNAL(clicked()), m_ui.hexfield, SLOT(load()));
112
113	connect(m_ui.loadTBL, SIGNAL(clicked()), m_ui.hexfield, SLOT(loadTBL()));
114}
115
116void MemoryView::setIndex(int index) {
117	mCore* core = m_controller->thread()->core;
118	IndexInfo info;
119	switch (core->platform(core)) {
120#ifdef M_CORE_GBA
121	case PLATFORM_GBA:
122		info = indexInfoGBA[index];
123		break;
124#endif
125#ifdef M_CORE_GB
126	case PLATFORM_GB:
127		info = indexInfoGB[index];
128		break;
129#endif
130	default:
131		return;
132	}
133	m_ui.segments->setValue(-1);
134	m_ui.segments->setVisible(info.maxSegment > 0);
135	m_ui.segments->setMaximum(info.maxSegment);
136	m_ui.hexfield->setRegion(info.base, info.size, info.name);
137}
138
139void MemoryView::setSegment(int segment) {
140	mCore* core = m_controller->thread()->core;
141	IndexInfo info;
142	switch (core->platform(core)) {
143#ifdef M_CORE_GBA
144	case PLATFORM_GBA:
145		info = indexInfoGBA[m_ui.regions->currentIndex()];
146		break;
147#endif
148#ifdef M_CORE_GB
149	case PLATFORM_GB:
150		info = indexInfoGB[m_ui.regions->currentIndex()];
151		break;
152#endif
153	default:
154		return;
155	}
156	m_ui.hexfield->setSegment(info.maxSegment < segment ? info.maxSegment : segment);
157}
158
159void MemoryView::update() {
160	m_ui.hexfield->viewport()->update();
161	updateStatus();
162}
163
164void MemoryView::updateSelection(uint32_t start, uint32_t end) {
165	m_selection.first = start;
166	m_selection.second = end;
167	updateStatus();
168}
169
170void MemoryView::updateStatus() {
171	int align = m_ui.hexfield->alignment();
172	if (!m_controller->isLoaded()) {
173		return;
174	}
175	mCore* core = m_controller->thread()->core;
176	QByteArray selection(m_ui.hexfield->serialize());
177	QString text(m_ui.hexfield->decodeText(selection));
178	m_ui.stringVal->setText(text);
179
180	if (m_selection.first & (align - 1) || m_selection.second - m_selection.first != align) {
181		m_ui.sintVal->clear();
182		m_ui.uintVal->clear();
183		return;
184	}
185	union {
186		uint32_t u32;
187		int32_t i32;
188		uint16_t u16;
189		int16_t i16;
190		uint8_t u8;
191		int8_t i8;
192	} value;
193	switch (align) {
194	case 1:
195		value.u8 = core->rawRead8(core, m_selection.first, m_ui.segments->value());
196		m_ui.sintVal->setText(QString::number(value.i8));
197		m_ui.uintVal->setText(QString::number(value.u8));
198		break;
199	case 2:
200		value.u16 = core->rawRead16(core, m_selection.first, m_ui.segments->value());
201		m_ui.sintVal->setText(QString::number(value.i16));
202		m_ui.uintVal->setText(QString::number(value.u16));
203		break;
204	case 4:
205		value.u32 = core->rawRead32(core, m_selection.first, m_ui.segments->value());
206		m_ui.sintVal->setText(QString::number(value.i32));
207		m_ui.uintVal->setText(QString::number(value.u32));
208		break;
209	}
210}