all repos — mgba @ 7020e45841797e9091e4ee0cf81d5447a496b656

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