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}