Qt: Start adding I/O register info

This commit is contained in:
Jeffrey Pfau 2015-10-11 19:11:15 -07:00
parent d31326a024
commit d9a60540f7
3 changed files with 194 additions and 89 deletions

View File

@ -8,6 +8,7 @@
#include "GameController.h" #include "GameController.h"
#include <QFontDatabase> #include <QFontDatabase>
#include <QVBoxLayout>
extern "C" { extern "C" {
#include "gba/io.h" #include "gba/io.h"
@ -15,6 +16,119 @@ extern "C" {
using namespace QGBA; using namespace QGBA;
QList<IOViewer::RegisterDescription> IOViewer::s_registers;
const QList<IOViewer::RegisterDescription>& IOViewer::registerDescriptions() {
if (!s_registers.isEmpty()) {
return s_registers;
}
// 0x04000000: DISPCNT
s_registers.append({
{ tr("Background mode"), 0, 3 },
{ tr("CGB Mode"), 3, 1, true },
{ tr("Frame select"), 4 },
{ tr("Unlocked HBlank"), 5 },
{ tr("Linear OBJ tile mapping"), 6 },
{ tr("Force blank screen"), 7 },
{ tr("Enable background 0"), 8 },
{ tr("Enable background 1"), 9 },
{ tr("Enable background 2"), 10 },
{ tr("Enable background 3"), 11 },
{ tr("Enable OBJ"), 12 },
{ tr("Enable Window 0"), 13 },
{ tr("Enable Window 1"), 14 },
{ tr("Enable OBJ Window"), 15 },
});
// 0x04000002: Green swap (undocumented and unimplemented)
s_registers.append(RegisterDescription());
// 0x04000004: DISPSTAT
s_registers.append({
{ tr("Currently in VBlank"), 0, 1, true },
{ tr("Currently in HBlank"), 1, 1, true },
{ tr("Currently in VCounter"), 2, 1, true },
{ tr("Enable VBlank IRQ generation"), 3 },
{ tr("Enable HBlank IRQ generation"), 4 },
{ tr("Enable VCounter IRQ generation"), 5 },
{ tr("VCounter scanline"), 8, 8 },
});
// 0x04000006: VCOUNT
s_registers.append({
{ tr("Current scanline"), 0, 8, true },
});
// 0x04000008: BG0CNT
s_registers.append({
{ tr("Priority"), 0, 2 },
{ tr("Tile data base (* 16kB)"), 2, 2 },
{ tr("Enable mosaic"), 3 },
{ tr("Enable 256-color"), 3 },
{ tr("Tile map base (* 2kB)"), 8, 5 },
{ tr("Background dimensions"), 14, 2 },
});
// 0x0400000A: BG1CNT
s_registers.append({
{ tr("Priority"), 0, 2 },
{ tr("Tile data base (* 16kB)"), 2, 2 },
{ tr("Enable mosaic"), 3 },
{ tr("Enable 256-color"), 3 },
{ tr("Tile map base (* 2kB)"), 8, 5 },
{ tr("Background dimensions"), 14, 2 },
});
// 0x0400000C: BG2CNT
s_registers.append({
{ tr("Priority"), 0, 2 },
{ tr("Tile data base (* 16kB)"), 2, 2 },
{ tr("Enable mosaic"), 3 },
{ tr("Enable 256-color"), 3 },
{ tr("Tile map base (* 2kB)"), 8, 5 },
{ tr("Overflow wraps"), 9 },
{ tr("Background dimensions"), 14, 2 },
});
// 0x0400000E: BG3CNT
s_registers.append({
{ tr("Priority"), 0, 2 },
{ tr("Tile data base (* 16kB)"), 2, 2 },
{ tr("Enable mosaic"), 3 },
{ tr("Enable 256-color"), 3 },
{ tr("Tile map base (* 2kB)"), 8, 5 },
{ tr("Overflow wraps"), 9 },
{ tr("Background dimensions"), 14, 2 },
});
// 0x04000010: BG0HOFS
s_registers.append({
{ tr("Horizontal offset"), 0, 9 },
});
// 0x04000012: BG0VOFS
s_registers.append({
{ tr("Vertical offset"), 0, 9 },
});
// 0x04000014: BG1HOFS
s_registers.append({
{ tr("Horizontal offset"), 0, 9 },
});
// 0x04000016: BG1VOFS
s_registers.append({
{ tr("Vertical offset"), 0, 9 },
});
// 0x04000018: BG2HOFS
s_registers.append({
{ tr("Horizontal offset"), 0, 9 },
});
// 0x0400001A: BG2VOFS
s_registers.append({
{ tr("Vertical offset"), 0, 9 },
});
// 0x0400001C: BG3HOFS
s_registers.append({
{ tr("Horizontal offset"), 0, 9 },
});
// 0x0400001E: BG3VOFS
s_registers.append({
{ tr("Vertical offset"), 0, 9 },
});
return s_registers;
}
IOViewer::IOViewer(GameController* controller, QWidget* parent) IOViewer::IOViewer(GameController* controller, QWidget* parent)
: QDialog(parent) : QDialog(parent)
, m_controller(controller) , m_controller(controller)
@ -36,104 +150,50 @@ IOViewer::IOViewer(GameController* controller, QWidget* parent)
connect(m_ui.buttonBox, SIGNAL(rejected()), this, SLOT(close())); connect(m_ui.buttonBox, SIGNAL(rejected()), this, SLOT(close()));
connect(m_ui.regSelect, SIGNAL(currentIndexChanged(int)), this, SLOT(selectRegister())); connect(m_ui.regSelect, SIGNAL(currentIndexChanged(int)), this, SLOT(selectRegister()));
connect(m_ui.b0, SIGNAL(toggled(bool)), this, SLOT(bitFlipped())); m_b[0] = m_ui.b0;
connect(m_ui.b1, SIGNAL(toggled(bool)), this, SLOT(bitFlipped())); m_b[1] = m_ui.b1;
connect(m_ui.b2, SIGNAL(toggled(bool)), this, SLOT(bitFlipped())); m_b[2] = m_ui.b2;
connect(m_ui.b3, SIGNAL(toggled(bool)), this, SLOT(bitFlipped())); m_b[3] = m_ui.b3;
connect(m_ui.b4, SIGNAL(toggled(bool)), this, SLOT(bitFlipped())); m_b[4] = m_ui.b4;
connect(m_ui.b5, SIGNAL(toggled(bool)), this, SLOT(bitFlipped())); m_b[5] = m_ui.b5;
connect(m_ui.b6, SIGNAL(toggled(bool)), this, SLOT(bitFlipped())); m_b[6] = m_ui.b6;
connect(m_ui.b7, SIGNAL(toggled(bool)), this, SLOT(bitFlipped())); m_b[7] = m_ui.b7;
connect(m_ui.b8, SIGNAL(toggled(bool)), this, SLOT(bitFlipped())); m_b[8] = m_ui.b8;
connect(m_ui.b9, SIGNAL(toggled(bool)), this, SLOT(bitFlipped())); m_b[9] = m_ui.b9;
connect(m_ui.bA, SIGNAL(toggled(bool)), this, SLOT(bitFlipped())); m_b[10] = m_ui.bA;
connect(m_ui.bB, SIGNAL(toggled(bool)), this, SLOT(bitFlipped())); m_b[11] = m_ui.bB;
connect(m_ui.bC, SIGNAL(toggled(bool)), this, SLOT(bitFlipped())); m_b[12] = m_ui.bC;
connect(m_ui.bD, SIGNAL(toggled(bool)), this, SLOT(bitFlipped())); m_b[13] = m_ui.bD;
connect(m_ui.bE, SIGNAL(toggled(bool)), this, SLOT(bitFlipped())); m_b[14] = m_ui.bE;
connect(m_ui.bF, SIGNAL(toggled(bool)), this, SLOT(bitFlipped())); m_b[15] = m_ui.bF;
for (int i = 0; i < 16; ++i) {
connect(m_b[i], SIGNAL(toggled(bool)), this, SLOT(bitFlipped()));
}
selectRegister(0); selectRegister(0);
} }
void IOViewer::update() { void IOViewer::updateRegister() {
m_value = 0; m_value = 0;
uint16_t value = 0;
m_controller->threadInterrupt(); m_controller->threadInterrupt();
if (m_controller->isLoaded()) { if (m_controller->isLoaded()) {
m_value = GBAIORead(m_controller->thread()->gba, m_register); value = GBAIORead(m_controller->thread()->gba, m_register);
} }
m_controller->threadContinue(); m_controller->threadContinue();
m_ui.regValue->setText("0x" + QString("%1").arg(m_value, 4, 16, QChar('0')).toUpper()); for (int i = 0; i < 16; ++i) {
bool signalsBlocked; m_b[i]->setChecked(value & (1 << i) ? Qt::Checked : Qt::Unchecked);
signalsBlocked = m_ui.b0->blockSignals(true); }
m_ui.b0->setChecked(m_value & 0x0001 ? Qt::Checked : Qt::Unchecked); m_value = value;
m_ui.b0->blockSignals(signalsBlocked);
signalsBlocked = m_ui.b1->blockSignals(true);
m_ui.b1->setChecked(m_value & 0x0002 ? Qt::Checked : Qt::Unchecked);
m_ui.b1->blockSignals(signalsBlocked);
signalsBlocked = m_ui.b2->blockSignals(true);
m_ui.b2->setChecked(m_value & 0x0004 ? Qt::Checked : Qt::Unchecked);
m_ui.b2->blockSignals(signalsBlocked);
signalsBlocked = m_ui.b3->blockSignals(true);
m_ui.b3->setChecked(m_value & 0x0008 ? Qt::Checked : Qt::Unchecked);
m_ui.b3->blockSignals(signalsBlocked);
signalsBlocked = m_ui.b4->blockSignals(true);
m_ui.b4->setChecked(m_value & 0x0010 ? Qt::Checked : Qt::Unchecked);
m_ui.b4->blockSignals(signalsBlocked);
signalsBlocked = m_ui.b5->blockSignals(true);
m_ui.b5->setChecked(m_value & 0x0020 ? Qt::Checked : Qt::Unchecked);
m_ui.b5->blockSignals(signalsBlocked);
signalsBlocked = m_ui.b6->blockSignals(true);
m_ui.b6->setChecked(m_value & 0x0040 ? Qt::Checked : Qt::Unchecked);
m_ui.b6->blockSignals(signalsBlocked);
signalsBlocked = m_ui.b7->blockSignals(true);
m_ui.b7->setChecked(m_value & 0x0080 ? Qt::Checked : Qt::Unchecked);
m_ui.b7->blockSignals(signalsBlocked);
signalsBlocked = m_ui.b8->blockSignals(true);
m_ui.b8->setChecked(m_value & 0x0100 ? Qt::Checked : Qt::Unchecked);
m_ui.b8->blockSignals(signalsBlocked);
signalsBlocked = m_ui.b9->blockSignals(true);
m_ui.b9->setChecked(m_value & 0x0200 ? Qt::Checked : Qt::Unchecked);
m_ui.b9->blockSignals(signalsBlocked);
signalsBlocked = m_ui.bA->blockSignals(true);
m_ui.bA->setChecked(m_value & 0x0400 ? Qt::Checked : Qt::Unchecked);
m_ui.bA->blockSignals(signalsBlocked);
signalsBlocked = m_ui.bB->blockSignals(true);
m_ui.bB->setChecked(m_value & 0x0800 ? Qt::Checked : Qt::Unchecked);
m_ui.bB->blockSignals(signalsBlocked);
signalsBlocked = m_ui.bC->blockSignals(true);
m_ui.bC->setChecked(m_value & 0x1000 ? Qt::Checked : Qt::Unchecked);
m_ui.bC->blockSignals(signalsBlocked);
signalsBlocked = m_ui.bD->blockSignals(true);
m_ui.bD->setChecked(m_value & 0x2000 ? Qt::Checked : Qt::Unchecked);
m_ui.bD->blockSignals(signalsBlocked);
signalsBlocked = m_ui.bE->blockSignals(true);
m_ui.bE->setChecked(m_value & 0x4000 ? Qt::Checked : Qt::Unchecked);
m_ui.bE->blockSignals(signalsBlocked);
signalsBlocked = m_ui.bF->blockSignals(true);
m_ui.bF->setChecked(m_value & 0x8000 ? Qt::Checked : Qt::Unchecked);
m_ui.bF->blockSignals(signalsBlocked);
} }
void IOViewer::bitFlipped() { void IOViewer::bitFlipped() {
m_value = 0; m_value = 0;
m_value |= m_ui.b0->isChecked() << 0x0; for (int i = 0; i < 16; ++i) {
m_value |= m_ui.b1->isChecked() << 0x1; m_value |= m_b[i]->isChecked() << i;
m_value |= m_ui.b2->isChecked() << 0x2; }
m_value |= m_ui.b3->isChecked() << 0x3;
m_value |= m_ui.b4->isChecked() << 0x4;
m_value |= m_ui.b5->isChecked() << 0x5;
m_value |= m_ui.b6->isChecked() << 0x6;
m_value |= m_ui.b7->isChecked() << 0x7;
m_value |= m_ui.b8->isChecked() << 0x8;
m_value |= m_ui.b9->isChecked() << 0x9;
m_value |= m_ui.bA->isChecked() << 0xA;
m_value |= m_ui.bB->isChecked() << 0xB;
m_value |= m_ui.bC->isChecked() << 0xC;
m_value |= m_ui.bD->isChecked() << 0xD;
m_value |= m_ui.bE->isChecked() << 0xE;
m_value |= m_ui.bF->isChecked() << 0xF;
m_ui.regValue->setText("0x" + QString("%1").arg(m_value, 4, 16, QChar('0')).toUpper()); m_ui.regValue->setText("0x" + QString("%1").arg(m_value, 4, 16, QChar('0')).toUpper());
} }
@ -143,12 +203,38 @@ void IOViewer::writeback() {
GBAIOWrite(m_controller->thread()->gba, m_register, m_value); GBAIOWrite(m_controller->thread()->gba, m_register, m_value);
} }
m_controller->threadContinue(); m_controller->threadContinue();
update(); updateRegister();
} }
void IOViewer::selectRegister(unsigned address) { void IOViewer::selectRegister(unsigned address) {
m_register = address; m_register = address;
update(); QLayout* box = m_ui.regDescription->layout();
if (box) {
// I can't believe there isn't a real way to do this...
while (!box->isEmpty()) {
QLayoutItem* item = box->takeAt(0);
if (item->widget()) {
delete item->widget();
}
delete item;
}
} else {
box = new QVBoxLayout;
}
if (registerDescriptions().count() > address >> 1) {
// TODO: Remove the check when done filling in register information
const RegisterDescription& description = registerDescriptions().at(address >> 1);
for (const RegisterItem& ri : description) {
QCheckBox* check = new QCheckBox;
check->setText(ri.description);
check->setEnabled(!ri.readonly);
box->addWidget(check);
connect(m_b[ri.start], SIGNAL(toggled(bool)), check, SLOT(setChecked(bool)));
connect(check, SIGNAL(toggled(bool)), m_b[ri.start], SLOT(setChecked(bool)));
}
}
m_ui.regDescription->setLayout(box);
updateRegister();
} }
void IOViewer::selectRegister() { void IOViewer::selectRegister() {
@ -158,7 +244,7 @@ void IOViewer::selectRegister() {
void IOViewer::buttonPressed(QAbstractButton* button) { void IOViewer::buttonPressed(QAbstractButton* button) {
switch (m_ui.buttonBox->standardButton(button)) { switch (m_ui.buttonBox->standardButton(button)) {
case QDialogButtonBox::Reset: case QDialogButtonBox::Reset:
update(); updateRegister();
break; break;
case QDialogButtonBox::Apply: case QDialogButtonBox::Apply:
writeback(); writeback();

View File

@ -7,6 +7,7 @@
#define QGBA_IOVIEWER #define QGBA_IOVIEWER
#include <QDialog> #include <QDialog>
#include <QList>
#include "ui_IOViewer.h" #include "ui_IOViewer.h"
@ -18,10 +19,25 @@ class IOViewer : public QDialog {
Q_OBJECT Q_OBJECT
public: public:
struct RegisterItem {
RegisterItem(const QString& description, uint start, uint size = 1, bool readonly = false)
: description(description)
, start(start)
, size(size)
, readonly(readonly) {}
uint start;
uint size;
bool readonly;
QString description;
};
typedef QList<RegisterItem> RegisterDescription;
IOViewer(GameController* controller, QWidget* parent = nullptr); IOViewer(GameController* controller, QWidget* parent = nullptr);
static const QList<RegisterDescription>& registerDescriptions();
public slots: public slots:
void update(); void updateRegister();
void selectRegister(unsigned address); void selectRegister(unsigned address);
private slots: private slots:
@ -31,11 +47,14 @@ private slots:
void selectRegister(); void selectRegister();
private: private:
static QList<RegisterDescription> s_registers;
Ui::IOViewer m_ui; Ui::IOViewer m_ui;
unsigned m_register; unsigned m_register;
uint16_t m_value; uint16_t m_value;
QCheckBox* m_b[16];
GameController* m_controller; GameController* m_controller;
}; };

View File

@ -372,7 +372,7 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QWidget" name="widget" native="true"> <widget class="QWidget" name="regDescription" native="true">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding"> <sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
<horstretch>0</horstretch> <horstretch>0</horstretch>