all repos — mgba @ 4f671290989321fc98ec15e0ec307eaafc07d031

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 "CoreController.h"
 10#include "MemoryDump.h"
 11
 12#include <mgba/core/core.h>
 13
 14using namespace QGBA;
 15
 16MemoryView::MemoryView(std::shared_ptr<CoreController> controller, QWidget* parent)
 17	: QWidget(parent)
 18	, m_controller(controller)
 19{
 20	m_ui.setupUi(this);
 21
 22	m_ui.hexfield->setController(controller);
 23
 24	mCore* core = m_controller->thread()->core;
 25	const mCoreMemoryBlock* info;
 26	size_t nBlocks = core->listMemoryBlocks(core, &info);
 27
 28	connect(m_ui.regions, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
 29	        this, &MemoryView::setIndex);
 30	connect(m_ui.segments, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
 31	        this, &MemoryView::setSegment);
 32
 33	if (info) {
 34		for (size_t i = 0; i < nBlocks; ++i) {
 35			if (!(info[i].flags & (mCORE_MEMORY_MAPPED | mCORE_MEMORY_VIRTUAL))) {
 36				continue;
 37			}
 38			m_ui.regions->addItem(tr(info[i].longName));
 39		}
 40	}
 41
 42	connect(m_ui.width8, &QAbstractButton::clicked, [this]() { m_ui.hexfield->setAlignment(1); });
 43	connect(m_ui.width16, &QAbstractButton::clicked, [this]() { m_ui.hexfield->setAlignment(2); });
 44	connect(m_ui.width32, &QAbstractButton::clicked, [this]() { m_ui.hexfield->setAlignment(4); });
 45	connect(m_ui.setAddress, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
 46	        this, static_cast<void (MemoryView::*)(uint32_t)>(&MemoryView::jumpToAddress));
 47	connect(m_ui.hexfield, &MemoryModel::selectionChanged, this, &MemoryView::updateSelection);
 48	connect(m_ui.saveRange, &QAbstractButton::clicked, this, &MemoryView::saveRange);
 49
 50	connect(controller.get(), &CoreController::stopping, this, &QWidget::close);
 51
 52	connect(controller.get(), &CoreController::frameAvailable, this, &MemoryView::update);
 53	connect(controller.get(), &CoreController::paused, this, &MemoryView::update);
 54	connect(controller.get(), &CoreController::stateLoaded, this, &MemoryView::update);
 55	connect(controller.get(), &CoreController::rewound, this, &MemoryView::update);
 56
 57	connect(m_ui.copy, &QAbstractButton::clicked, m_ui.hexfield, &MemoryModel::copy);
 58	connect(m_ui.save, &QAbstractButton::clicked, m_ui.hexfield, &MemoryModel::save);
 59	connect(m_ui.paste, &QAbstractButton::clicked, m_ui.hexfield, &MemoryModel::paste);
 60	connect(m_ui.load, &QAbstractButton::clicked, m_ui.hexfield, &MemoryModel::load);
 61
 62	connect(m_ui.loadTBL, &QAbstractButton::clicked, m_ui.hexfield, &MemoryModel::loadTBL);
 63}
 64
 65void MemoryView::setIndex(int index) {
 66	mCore* core = m_controller->thread()->core;
 67	const mCoreMemoryBlock* blocks;
 68	size_t nBlocks = core->listMemoryBlocks(core, &blocks);
 69	const mCoreMemoryBlock& info = blocks[index];
 70
 71	m_region = qMakePair(info.start, info.end);
 72	m_ui.segments->setValue(-1);
 73	m_ui.segments->setVisible(info.maxSegment > 0);
 74	m_ui.segmentColon->setVisible(info.maxSegment > 0);
 75	m_ui.segments->setMaximum(info.maxSegment);
 76	m_ui.hexfield->setRegion(info.start, info.end - info.start, info.shortName);
 77}
 78
 79void MemoryView::setSegment(int segment) {
 80	mCore* core = m_controller->thread()->core;
 81	const mCoreMemoryBlock* blocks;
 82	size_t nBlocks = core->listMemoryBlocks(core, &blocks);
 83	const mCoreMemoryBlock& info = blocks[m_ui.regions->currentIndex()];
 84
 85	m_ui.hexfield->setSegment(info.maxSegment < segment ? info.maxSegment : segment);
 86}
 87
 88void MemoryView::update() {
 89	m_ui.hexfield->viewport()->update();
 90	updateStatus();
 91}
 92
 93void MemoryView::jumpToAddress(uint32_t address) {
 94	if (address < m_region.first || address >= m_region.second) {
 95		m_ui.regions->setCurrentIndex(0);
 96		setIndex(0);
 97	}
 98	if (address < m_region.first || address >= m_region.second) {
 99		return;
100	}
101	m_ui.hexfield->jumpToAddress(address);
102}
103
104void MemoryView::updateSelection(uint32_t start, uint32_t end) {
105	m_selection.first = start;
106	m_selection.second = end;
107	updateStatus();
108}
109
110void MemoryView::updateStatus() {
111	int align = m_ui.hexfield->alignment();
112	mCore* core = m_controller->thread()->core;
113	QByteArray selection(m_ui.hexfield->serialize());
114	QString text(m_ui.hexfield->decodeText(selection));
115	m_ui.stringVal->setText(text);
116
117	if (m_selection.first & (align - 1) || m_selection.second - m_selection.first != align) {
118		m_ui.sintVal->clear();
119		m_ui.uintVal->clear();
120		return;
121	}
122	union {
123		uint32_t u32;
124		int32_t i32;
125		uint16_t u16;
126		int16_t i16;
127		uint8_t u8;
128		int8_t i8;
129	} value;
130	switch (align) {
131	case 1:
132		value.u8 = core->rawRead8(core, m_selection.first, m_ui.segments->value());
133		m_ui.sintVal->setText(QString::number(value.i8));
134		m_ui.uintVal->setText(QString::number(value.u8));
135		break;
136	case 2:
137		value.u16 = core->rawRead16(core, m_selection.first, m_ui.segments->value());
138		m_ui.sintVal->setText(QString::number(value.i16));
139		m_ui.uintVal->setText(QString::number(value.u16));
140		break;
141	case 4:
142		value.u32 = core->rawRead32(core, m_selection.first, m_ui.segments->value());
143		m_ui.sintVal->setText(QString::number(value.i32));
144		m_ui.uintVal->setText(QString::number(value.u32));
145		break;
146	}
147}
148
149void MemoryView::saveRange() {
150	MemoryDump* memdump = new MemoryDump(m_controller);
151	memdump->setAttribute(Qt::WA_DeleteOnClose);
152	memdump->setAddress(m_selection.first);
153	memdump->setSegment(m_ui.segments->value());
154	memdump->setByteCount(m_selection.second - m_selection.first);
155	memdump->show();
156}