mirror of https://github.com/Treeki/WindEmu.git
add a very basic debugger UI
This commit is contained in:
parent
1d6e77ced8
commit
6a41ed1d76
|
@ -6,7 +6,6 @@
|
||||||
|
|
||||||
|
|
||||||
Emu::Emu() {
|
Emu::Emu() {
|
||||||
configure();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -464,7 +463,10 @@ void Emu::loadROM(const char *path) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Emu::executeUntil(int64_t cycles) {
|
void Emu::executeUntil(int64_t cycles) {
|
||||||
while (!asleep && cpu.cycles <= cycles) {
|
if (!configured)
|
||||||
|
configure();
|
||||||
|
|
||||||
|
while (!asleep && cpu.cycles < cycles) {
|
||||||
if (cpu.cycles >= nextTickAt) {
|
if (cpu.cycles >= nextTickAt) {
|
||||||
// increment RTCDIV
|
// increment RTCDIV
|
||||||
if ((pwrsr & 0x3F) == 0x3F) {
|
if ((pwrsr & 0x3F) == 0x3F) {
|
||||||
|
|
|
@ -82,4 +82,5 @@ public:
|
||||||
void dumpRAM(const char *path);
|
void dumpRAM(const char *path);
|
||||||
void executeUntil(int64_t cycles);
|
void executeUntil(int64_t cycles);
|
||||||
int64_t currentCycles() const { return cpu.cycles; }
|
int64_t currentCycles() const { return cpu.cycles; }
|
||||||
|
uint32_t getGPR(int index) const { return cpu.gprs[index]; }
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include "../WindCore/wind.h"
|
#include "../WindCore/wind.h"
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QKeyEvent>
|
#include <QKeyEvent>
|
||||||
|
#include "../WindCore/decoder.h"
|
||||||
|
|
||||||
MainWindow::MainWindow(QWidget *parent) :
|
MainWindow::MainWindow(QWidget *parent) :
|
||||||
QMainWindow(parent),
|
QMainWindow(parent),
|
||||||
|
@ -14,8 +15,10 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||||
emu->loadROM("/Users/ash/src/psion/Sys$rom.bin");
|
emu->loadROM("/Users/ash/src/psion/Sys$rom.bin");
|
||||||
|
|
||||||
timer = new QTimer(this);
|
timer = new QTimer(this);
|
||||||
timer->start(1000/64);
|
timer->setInterval(1000/64);
|
||||||
connect(timer, SIGNAL(timeout()), SLOT(execTimer()));
|
connect(timer, SIGNAL(timeout()), SLOT(execTimer()));
|
||||||
|
|
||||||
|
updateScreen();
|
||||||
}
|
}
|
||||||
|
|
||||||
MainWindow::~MainWindow()
|
MainWindow::~MainWindow()
|
||||||
|
@ -23,22 +26,54 @@ MainWindow::~MainWindow()
|
||||||
delete ui;
|
delete ui;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::execTimer()
|
|
||||||
{
|
|
||||||
emu->executeUntil(emu->currentCycles() + (CLOCK_SPEED / 64));
|
|
||||||
ui->cycleCounter->setText(QString("Cycles: %1").arg(emu->currentCycles()));
|
|
||||||
updateScreen();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::on_stepButton_clicked()
|
|
||||||
{
|
|
||||||
emu->executeUntil(emu->currentCycles() + (CLOCK_SPEED * 2));
|
|
||||||
ui->cycleCounter->setText(QString("Cycles: %1").arg(emu->currentCycles()));
|
|
||||||
updateScreen();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::updateScreen()
|
void MainWindow::updateScreen()
|
||||||
{
|
{
|
||||||
|
ui->cycleCounter->setText(QString("Cycles: %1").arg(emu->currentCycles()));
|
||||||
|
|
||||||
|
ui->regsLabel->setText(
|
||||||
|
QString("R0: %1 / R1: %2 / R2: %3 / R3: %4 / R4: %5 / R5: %6 / R6: %7 / R7: %8 / R8: %9\nR9: %10 / R10:%11 / R11:%12 / R12:%13 / SP: %14 / LR: %15 / PC: %16")
|
||||||
|
.arg(emu->getGPR(0), 8, 16)
|
||||||
|
.arg(emu->getGPR(1), 8, 16)
|
||||||
|
.arg(emu->getGPR(2), 8, 16)
|
||||||
|
.arg(emu->getGPR(3), 8, 16)
|
||||||
|
.arg(emu->getGPR(4), 8, 16)
|
||||||
|
.arg(emu->getGPR(5), 8, 16)
|
||||||
|
.arg(emu->getGPR(6), 8, 16)
|
||||||
|
.arg(emu->getGPR(7), 8, 16)
|
||||||
|
.arg(emu->getGPR(8), 8, 16)
|
||||||
|
.arg(emu->getGPR(9), 8, 16)
|
||||||
|
.arg(emu->getGPR(10), 8, 16)
|
||||||
|
.arg(emu->getGPR(11), 8, 16)
|
||||||
|
.arg(emu->getGPR(12), 8, 16)
|
||||||
|
.arg(emu->getGPR(13), 8, 16)
|
||||||
|
.arg(emu->getGPR(14), 8, 16)
|
||||||
|
.arg(emu->getGPR(15), 8, 16)
|
||||||
|
);
|
||||||
|
|
||||||
|
// show a crude disassembly
|
||||||
|
const int context = 8 * 4;
|
||||||
|
uint32_t pc = emu->getGPR(15) - 4;
|
||||||
|
uint32_t minCode = pc - context;
|
||||||
|
if (minCode >= (UINT32_MAX - context))
|
||||||
|
minCode = 0;
|
||||||
|
uint32_t maxCode = pc + context;
|
||||||
|
if (maxCode < context)
|
||||||
|
maxCode = UINT32_MAX;
|
||||||
|
|
||||||
|
QStringList codeLines;
|
||||||
|
for (uint32_t addr = minCode; addr >= minCode && addr <= maxCode; addr += 4) {
|
||||||
|
const char *prefix = (addr == pc) ? "==>" : " ";
|
||||||
|
struct ARMInstructionInfo info;
|
||||||
|
char buffer[512];
|
||||||
|
|
||||||
|
uint32_t opcode = emu->readVirt32(addr);
|
||||||
|
ARMDecodeARM(opcode, &info);
|
||||||
|
ARMDisassemble(&info, addr, buffer, sizeof(buffer));
|
||||||
|
codeLines.append(QString("%1 %2 | %3 | %4").arg(prefix).arg(addr, 8, 16).arg(opcode, 8, 16).arg(buffer));
|
||||||
|
}
|
||||||
|
ui->codeLabel->setText(codeLines.join('\n'));
|
||||||
|
|
||||||
|
// now, the actual screen
|
||||||
const uint8_t *lcdBuf = emu->getLCDBuffer();
|
const uint8_t *lcdBuf = emu->getLCDBuffer();
|
||||||
if (lcdBuf) {
|
if (lcdBuf) {
|
||||||
QImage img(640, 240, QImage::Format_Grayscale8);
|
QImage img(640, 240, QImage::Format_Grayscale8);
|
||||||
|
@ -169,3 +204,42 @@ void MainWindow::keyReleaseEvent(QKeyEvent *event)
|
||||||
if (k >= 0)
|
if (k >= 0)
|
||||||
emu->keyboardKeys[k] = false;
|
emu->keyboardKeys[k] = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void MainWindow::on_startButton_clicked()
|
||||||
|
{
|
||||||
|
timer->start();
|
||||||
|
ui->startButton->setEnabled(false);
|
||||||
|
ui->stopButton->setEnabled(true);
|
||||||
|
ui->stepInsnButton->setEnabled(false);
|
||||||
|
ui->stepTickButton->setEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_stopButton_clicked()
|
||||||
|
{
|
||||||
|
timer->stop();
|
||||||
|
ui->startButton->setEnabled(true);
|
||||||
|
ui->stopButton->setEnabled(false);
|
||||||
|
ui->stepInsnButton->setEnabled(true);
|
||||||
|
ui->stepTickButton->setEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_stepTickButton_clicked()
|
||||||
|
{
|
||||||
|
emu->executeUntil(emu->currentCycles() + (CLOCK_SPEED * 2));
|
||||||
|
updateScreen();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_stepInsnButton_clicked()
|
||||||
|
{
|
||||||
|
emu->executeUntil(emu->currentCycles() + 1);
|
||||||
|
updateScreen();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::execTimer()
|
||||||
|
{
|
||||||
|
emu->executeUntil(emu->currentCycles() + (CLOCK_SPEED / 64));
|
||||||
|
updateScreen();
|
||||||
|
}
|
||||||
|
|
|
@ -17,9 +17,13 @@ public:
|
||||||
~MainWindow() override;
|
~MainWindow() override;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void on_stepButton_clicked();
|
|
||||||
void execTimer();
|
void execTimer();
|
||||||
|
|
||||||
|
void on_startButton_clicked();
|
||||||
|
void on_stopButton_clicked();
|
||||||
|
void on_stepInsnButton_clicked();
|
||||||
|
void on_stepTickButton_clicked();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::MainWindow *ui;
|
Ui::MainWindow *ui;
|
||||||
Emu *emu;
|
Emu *emu;
|
||||||
|
|
|
@ -15,6 +15,75 @@
|
||||||
</property>
|
</property>
|
||||||
<widget class="QWidget" name="centralWidget">
|
<widget class="QWidget" name="centralWidget">
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="1" column="4">
|
||||||
|
<widget class="QPushButton" name="stopButton">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Stop</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="3">
|
||||||
|
<widget class="QPushButton" name="stepInsnButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Step (Insn)</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="0" colspan="5">
|
||||||
|
<widget class="QTabWidget" name="tabWidget">
|
||||||
|
<property name="currentIndex">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="tab">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Memory</string>
|
||||||
|
</attribute>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="tab_2">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Code</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="codeLabel">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Courier New</family>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>TextLabel</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0" colspan="6">
|
||||||
|
<widget class="QLabel" name="screen">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="3">
|
||||||
|
<widget class="QPushButton" name="startButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Start</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="cycleCounter">
|
||||||
|
<property name="text">
|
||||||
|
<string>Cycles</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item row="1" column="2">
|
<item row="1" column="2">
|
||||||
<spacer name="horizontalSpacer">
|
<spacer name="horizontalSpacer">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
|
@ -28,22 +97,20 @@
|
||||||
</property>
|
</property>
|
||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="3">
|
<item row="2" column="4">
|
||||||
<widget class="QPushButton" name="stepButton">
|
<widget class="QPushButton" name="stepTickButton">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Step</string>
|
<string>Step (Tick)</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="0">
|
<item row="3" column="0" colspan="5">
|
||||||
<widget class="QLabel" name="cycleCounter">
|
<widget class="QLabel" name="regsLabel">
|
||||||
<property name="text">
|
<property name="font">
|
||||||
<string>Cycles</string>
|
<font>
|
||||||
|
<family>Courier New</family>
|
||||||
|
</font>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="0" colspan="4">
|
|
||||||
<widget class="QLabel" name="screen">
|
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string/>
|
<string/>
|
||||||
</property>
|
</property>
|
||||||
|
|
Loading…
Reference in New Issue