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};
29#ifdef M_CORE_GBA
30const static struct IndexInfo indexInfoGBA[] = {
31 { "All", "All", 0, 0x10000000 },
32 { "BIOS", "BIOS (16kiB)", BASE_BIOS, SIZE_BIOS },
33 { "EWRAM", "Working RAM (256kiB)", BASE_WORKING_RAM, SIZE_WORKING_RAM },
34 { "IWRAM", "Internal Working RAM (32kiB)", BASE_WORKING_IRAM, SIZE_WORKING_IRAM },
35 { "MMIO", "Memory-Mapped I/O", BASE_IO, SIZE_IO },
36 { "Palette", "Palette RAM (1kiB)", BASE_PALETTE_RAM, SIZE_PALETTE_RAM },
37 { "VRAM", "Video RAM (96kiB)", BASE_VRAM, SIZE_VRAM },
38 { "OAM", "OBJ Attribute Memory (1kiB)", BASE_OAM, SIZE_OAM },
39 { "ROM", "Game Pak (32MiB)", BASE_CART0, SIZE_CART0 },
40 { "ROM WS1", "Game Pak (Waitstate 1)", BASE_CART1, SIZE_CART1 },
41 { "ROM WS2", "Game Pak (Waitstate 2)", BASE_CART2, SIZE_CART2 },
42 { "SRAM", "Static RAM (64kiB)", BASE_CART_SRAM, SIZE_CART_SRAM },
43 { nullptr, nullptr, 0, 0 }
44};
45#endif
46#ifdef M_CORE_GB
47const static struct IndexInfo indexInfoGB[] = {
48 { "All", "All", 0, 0x10000 },
49 { "ROM", "Game Pak (32kiB)", GB_BASE_CART_BANK0, GB_SIZE_CART_BANK0 * 2 },
50 { "VRAM", "Video RAM (8kiB)", GB_BASE_VRAM, GB_SIZE_VRAM },
51 { "SRAM", "External RAM (8kiB)", GB_BASE_EXTERNAL_RAM, GB_SIZE_EXTERNAL_RAM },
52 { "WRAM", "Working RAM (8kiB)", GB_BASE_WORKING_RAM_BANK0, GB_SIZE_WORKING_RAM_BANK0 * 2 },
53 { "OAM", "OBJ Attribute Memory", GB_BASE_OAM, GB_SIZE_OAM },
54 { "IO", "Memory-Mapped I/O", GB_BASE_IO, GB_SIZE_IO },
55 { "HRAM", "High RAM", GB_BASE_HRAM, GB_SIZE_HRAM },
56 { nullptr, nullptr, 0, 0 }
57};
58#endif
59
60MemoryView::MemoryView(GameController* controller, QWidget* parent)
61 : QWidget(parent)
62 , m_controller(controller)
63{
64 m_ui.setupUi(this);
65
66 m_ui.hexfield->setController(controller);
67
68 mCore* core = m_controller->thread()->core;
69 const IndexInfo* info = nullptr;
70 switch (core->platform(core)) {
71#ifdef M_CORE_GBA
72 case PLATFORM_GBA:
73 info = indexInfoGBA;
74 break;
75#endif
76#ifdef M_CORE_GB
77 case PLATFORM_GB:
78 info = indexInfoGB;
79 break;
80#endif
81 default:
82 break;
83 }
84
85 connect(m_ui.regions, SIGNAL(currentIndexChanged(int)), this, SLOT(setIndex(int)));
86 if (info) {
87 for (size_t i = 0; info[i].name; ++i) {
88 m_ui.regions->addItem(tr(info[i].longName));
89 }
90 }
91
92 connect(m_ui.width8, &QAbstractButton::clicked, [this]() { m_ui.hexfield->setAlignment(1); });
93 connect(m_ui.width16, &QAbstractButton::clicked, [this]() { m_ui.hexfield->setAlignment(2); });
94 connect(m_ui.width32, &QAbstractButton::clicked, [this]() { m_ui.hexfield->setAlignment(4); });
95 connect(m_ui.setAddress, SIGNAL(valueChanged(const QString&)), m_ui.hexfield, SLOT(jumpToAddress(const QString&)));
96
97 connect(m_ui.hexfield, SIGNAL(selectionChanged(uint32_t, uint32_t)), this, SLOT(updateSelection(uint32_t, uint32_t)));
98
99 connect(controller, SIGNAL(gameStopped(mCoreThread*)), this, SLOT(close()));
100
101 connect(controller, SIGNAL(frameAvailable(const uint32_t*)), this, SLOT(update()));
102 connect(controller, SIGNAL(gamePaused(mCoreThread*)), this, SLOT(update()));
103 connect(controller, SIGNAL(stateLoaded(mCoreThread*)), this, SLOT(update()));
104 connect(controller, SIGNAL(rewound(mCoreThread*)), this, SLOT(update()));
105}
106
107void MemoryView::setIndex(int index) {
108 mCore* core = m_controller->thread()->core;
109 IndexInfo info;
110 switch (core->platform(core)) {
111#ifdef M_CORE_GBA
112 case PLATFORM_GBA:
113 info = indexInfoGBA[index];
114 break;
115#endif
116#ifdef M_CORE_GB
117 case PLATFORM_GB:
118 info = indexInfoGB[index];
119 break;
120#endif
121 default:
122 return;
123 }
124 m_ui.hexfield->setRegion(info.base, info.size, info.name);
125}
126
127void MemoryView::update() {
128 m_ui.hexfield->viewport()->update();
129 updateStatus();
130}
131
132void MemoryView::updateSelection(uint32_t start, uint32_t end) {
133 m_selection.first = start;
134 m_selection.second = end;
135 updateStatus();
136}
137
138void MemoryView::updateStatus() {
139 int align = m_ui.hexfield->alignment();
140 if (m_selection.first & (align - 1) || m_selection.second - m_selection.first != align) {
141 m_ui.sintVal->clear();
142 m_ui.uintVal->clear();
143 return;
144 }
145 if (!m_controller->isLoaded()) {
146 return;
147 }
148 mCore* core = m_controller->thread()->core;
149 union {
150 uint32_t u32;
151 int32_t i32;
152 uint16_t u16;
153 int16_t i16;
154 uint8_t u8;
155 int8_t i8;
156 } value;
157 switch (align) {
158 case 1:
159 value.u8 = core->rawRead8(core, m_selection.first);
160 m_ui.sintVal->setText(QString::number(value.i8));
161 m_ui.uintVal->setText(QString::number(value.u8));
162 break;
163 case 2:
164 value.u16 = core->rawRead16(core, m_selection.first);
165 m_ui.sintVal->setText(QString::number(value.i16));
166 m_ui.uintVal->setText(QString::number(value.u16));
167 break;
168 case 4:
169 value.u32 = core->rawRead32(core, m_selection.first);
170 m_ui.sintVal->setText(QString::number(value.i32));
171 m_ui.uintVal->setText(QString::number(value.u32));
172 break;
173 }
174}