first gui
This commit is contained in:
parent
42737c0a66
commit
c918993060
6 changed files with 1027 additions and 33 deletions
|
|
@ -1,14 +1,414 @@
|
|||
#include "mainwindow.h"
|
||||
#include "ui_mainwindow.h"
|
||||
#include "MachineController.h"
|
||||
#include "../../include/machine.h"
|
||||
#include "../../include/instructions.h"
|
||||
|
||||
#include <QIntValidator>
|
||||
#include <QLineEdit>
|
||||
#include <QDebug>
|
||||
#include <QRegularExpressionValidator>
|
||||
#include <QDoubleValidator>
|
||||
#include <QPushButton>
|
||||
#include <cstdint>
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent) :
|
||||
QMainWindow(parent),
|
||||
ui(new Ui::MainWindow)
|
||||
ui(new Ui::MainWindow),
|
||||
m_machine(std::make_shared<Machine>()),
|
||||
m_controller(std::make_unique<MachineController>(m_machine, this))
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
ui->regA_dec_field->setValidator(new QIntValidator(-8388608, 8388607, this));
|
||||
ui->regB_dec_field->setValidator(new QIntValidator(-8388608, 8388607, this));
|
||||
ui->regS_dec_field->setValidator(new QIntValidator(-8388608, 8388607, this));
|
||||
ui->regT_dec_field->setValidator(new QIntValidator(-8388608, 8388607, this));
|
||||
ui->regX_dec_field->setValidator(new QIntValidator(-8388608, 8388607, this));
|
||||
// unsigned 24 bit
|
||||
ui->regL_dec_field->setValidator(new QIntValidator(0, 16777215, this));
|
||||
ui->regPC_dec_field->setValidator(new QIntValidator(0, 16777215, this));
|
||||
ui->regSW_dec_field->setValidator(new QIntValidator(0, 16777215, this));
|
||||
// float
|
||||
ui->regF_dec_field->setValidator(new QDoubleValidator(-3.402823e38, 3.402823e38, 6, this));
|
||||
|
||||
QRegularExpressionValidator* hexValidator = new QRegularExpressionValidator(QRegularExpression("^(0x)?[0-9A-Fa-f]{1,6}$"), this);
|
||||
ui->regA_hex_field->setValidator(hexValidator);
|
||||
ui->regB_hex_field->setValidator(hexValidator);
|
||||
ui->regX_hex_field->setValidator(hexValidator);
|
||||
ui->regS_hex_field->setValidator(hexValidator);
|
||||
ui->regT_hex_field->setValidator(hexValidator);
|
||||
ui->regL_hex_field->setValidator(hexValidator);
|
||||
ui->regPC_hex_field->setValidator(hexValidator);
|
||||
ui->regSW_hex_field->setValidator(hexValidator);
|
||||
|
||||
QRegularExpressionValidator* binValidator = new QRegularExpressionValidator(QRegularExpression("^[01]{1,24}$"), this);
|
||||
ui->regA_bin_field->setValidator(binValidator);
|
||||
ui->regB_bin_field->setValidator(binValidator);
|
||||
ui->regX_bin_field->setValidator(binValidator);
|
||||
ui->regS_bin_field->setValidator(binValidator);
|
||||
ui->regT_bin_field->setValidator(binValidator);
|
||||
ui->regL_bin_field->setValidator(binValidator);
|
||||
ui->regPC_bin_field->setValidator(binValidator);
|
||||
ui->regSW_bin_field->setValidator(binValidator);
|
||||
|
||||
QRegularExpressionValidator* floatHexValidator = new QRegularExpressionValidator(QRegularExpression("^(0x)?[0-9A-Fa-f]{1,12}$"), this);
|
||||
ui->regF_hex_field->setValidator(floatHexValidator);
|
||||
|
||||
QRegularExpressionValidator* floatBinValidator = new QRegularExpressionValidator(QRegularExpression("^[01]{1,48}$"), this);
|
||||
ui->regF_bin_field->setValidator(floatBinValidator);
|
||||
|
||||
|
||||
connect(m_controller.get(), &MachineController::tick, this, &MainWindow::updateRegisterDisplays);
|
||||
|
||||
connectRegisterFields();
|
||||
|
||||
connect(ui->StartBtn, &QPushButton::clicked, this, &MainWindow::startExecution);
|
||||
connect(ui->StopBtn, &QPushButton::clicked, this, &MainWindow::stopExecution);
|
||||
connect(ui->StepBtn, &QPushButton::clicked, this, &MainWindow::stepExecution);
|
||||
|
||||
loadDemoProgram();
|
||||
|
||||
updateRegisterDisplays();
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void MainWindow::updateRegisterDisplays()
|
||||
{
|
||||
if (!m_machine) return;
|
||||
|
||||
// Update all register display formats (decimal, hex, binary)
|
||||
updateAllFormatsForRegister("regA", m_machine->getA());
|
||||
updateAllFormatsForRegister("regB", m_machine->getB());
|
||||
updateAllFormatsForRegister("regX", m_machine->getX());
|
||||
updateAllFormatsForRegister("regS", m_machine->getS());
|
||||
updateAllFormatsForRegister("regT", m_machine->getT());
|
||||
updateAllFormatsForRegister("regL", m_machine->getL());
|
||||
updateAllFormatsForRegister("regPC", m_machine->getPC());
|
||||
updateAllFormatsForRegister("regSW", m_machine->getSW());
|
||||
updateFloatRegisterFormats("regF", m_machine->getF());
|
||||
}
|
||||
|
||||
void MainWindow::updateSingleRegisterDisplay(const QString& fieldName, int value)
|
||||
{
|
||||
QLineEdit* field = findChild<QLineEdit*>(fieldName);
|
||||
if (field) {
|
||||
// Only update if the field doesn't have focus (to avoid interfering with user input)
|
||||
if (!field->hasFocus()) {
|
||||
field->setText(QString::number(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::updateAllFormatsForRegister(const QString& regPrefix, int value)
|
||||
{
|
||||
// Update decimal field
|
||||
QLineEdit* decField = findChild<QLineEdit*>(regPrefix + "_dec_field");
|
||||
if (decField && !decField->hasFocus()) {
|
||||
decField->setText(QString::number(value));
|
||||
}
|
||||
|
||||
// Update hex field
|
||||
QLineEdit* hexField = findChild<QLineEdit*>(regPrefix + "_hex_field");
|
||||
if (hexField && !hexField->hasFocus()) {
|
||||
// Convert to 24-bit representation, handle negative numbers
|
||||
unsigned int unsignedValue = static_cast<unsigned int>(value) & 0xFFFFFF;
|
||||
hexField->setText(QString("0x%1").arg(unsignedValue, 6, 16, QChar('0')).toUpper());
|
||||
}
|
||||
|
||||
// Update binary field
|
||||
QLineEdit* binField = findChild<QLineEdit*>(regPrefix + "_bin_field");
|
||||
if (binField && !binField->hasFocus()) {
|
||||
// Convert to 24-bit binary representation
|
||||
unsigned int unsignedValue = static_cast<unsigned int>(value) & 0xFFFFFF;
|
||||
QString binaryStr = QString::number(unsignedValue, 2);
|
||||
// Pad to 24 bits
|
||||
binaryStr = binaryStr.rightJustified(24, '0');
|
||||
binField->setText(binaryStr);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::updateFloatRegisterFormats(const QString& regPrefix, double value)
|
||||
{
|
||||
// Update decimal field
|
||||
QLineEdit* decField = findChild<QLineEdit*>(regPrefix + "_dec_field");
|
||||
if (decField && !decField->hasFocus()) {
|
||||
decField->setText(QString::number(value, 'g', 10));
|
||||
}
|
||||
|
||||
// Update hex field (48-bit float representation)
|
||||
QLineEdit* hexField = findChild<QLineEdit*>(regPrefix + "_hex_field");
|
||||
if (hexField && !hexField->hasFocus()) {
|
||||
// Convert double to 48-bit hex representation
|
||||
// For SIC/XE, we need to convert to the 48-bit float format
|
||||
uint64_t* intPtr = reinterpret_cast<uint64_t*>(&value);
|
||||
uint64_t bits48 = (*intPtr) & 0xFFFFFFFFFFFFULL; // Mask to 48 bits
|
||||
hexField->setText(QString("0x%1").arg(bits48, 12, 16, QChar('0')).toUpper());
|
||||
}
|
||||
|
||||
// Update binary field (48-bit float representation)
|
||||
QLineEdit* binField = findChild<QLineEdit*>(regPrefix + "_bin_field");
|
||||
if (binField && !binField->hasFocus()) {
|
||||
// Convert double to 48-bit binary representation
|
||||
uint64_t* intPtr = reinterpret_cast<uint64_t*>(&value);
|
||||
uint64_t bits48 = (*intPtr) & 0xFFFFFFFFFFFFULL; // Mask to 48 bits
|
||||
QString binaryStr = QString::number(bits48, 2);
|
||||
// Pad to 48 bits
|
||||
binaryStr = binaryStr.rightJustified(48, '0');
|
||||
binField->setText(binaryStr);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::connectRegisterFields()
|
||||
{
|
||||
// Connect decimal register fields to update machine registers when changed
|
||||
connect(ui->regA_dec_field, &QLineEdit::editingFinished, this, &MainWindow::onRegisterFieldChanged);
|
||||
connect(ui->regB_dec_field, &QLineEdit::editingFinished, this, &MainWindow::onRegisterFieldChanged);
|
||||
connect(ui->regX_dec_field, &QLineEdit::editingFinished, this, &MainWindow::onRegisterFieldChanged);
|
||||
connect(ui->regS_dec_field, &QLineEdit::editingFinished, this, &MainWindow::onRegisterFieldChanged);
|
||||
connect(ui->regT_dec_field, &QLineEdit::editingFinished, this, &MainWindow::onRegisterFieldChanged);
|
||||
connect(ui->regL_dec_field, &QLineEdit::editingFinished, this, &MainWindow::onRegisterFieldChanged);
|
||||
connect(ui->regPC_dec_field, &QLineEdit::editingFinished, this, &MainWindow::onRegisterFieldChanged);
|
||||
connect(ui->regSW_dec_field, &QLineEdit::editingFinished, this, &MainWindow::onRegisterFieldChanged);
|
||||
connect(ui->regF_dec_field, &QLineEdit::editingFinished, this, &MainWindow::onRegisterFieldChanged);
|
||||
|
||||
// Connect hex register fields
|
||||
QLineEdit* hexFields[] = {
|
||||
ui->regA_hex_field, ui->regB_hex_field, ui->regX_hex_field,
|
||||
ui->regS_hex_field, ui->regT_hex_field, ui->regL_hex_field,
|
||||
ui->regPC_hex_field, ui->regSW_hex_field, ui->regF_hex_field
|
||||
};
|
||||
for (auto* field : hexFields) {
|
||||
if (field) {
|
||||
connect(field, &QLineEdit::editingFinished, this, &MainWindow::onRegisterFieldChanged);
|
||||
}
|
||||
}
|
||||
|
||||
// Connect binary register fields
|
||||
QLineEdit* binFields[] = {
|
||||
ui->regA_bin_field, ui->regB_bin_field, ui->regX_bin_field,
|
||||
ui->regS_bin_field, ui->regT_bin_field, ui->regL_bin_field,
|
||||
ui->regPC_bin_field, ui->regSW_bin_field, ui->regF_bin_field
|
||||
};
|
||||
for (auto* field : binFields) {
|
||||
if (field) {
|
||||
connect(field, &QLineEdit::editingFinished, this, &MainWindow::onRegisterFieldChanged);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::onRegisterFieldChanged()
|
||||
{
|
||||
if (!m_machine) return;
|
||||
|
||||
QLineEdit* field = qobject_cast<QLineEdit*>(sender());
|
||||
if (!field) return;
|
||||
|
||||
QString objectName = field->objectName();
|
||||
QString regName = objectName.split('_')[0];
|
||||
|
||||
|
||||
if (regName == "regF") {
|
||||
handleFloatRegisterFieldChanged(field, objectName);
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle integer registers
|
||||
int value = 0;
|
||||
bool ok = false;
|
||||
|
||||
// Parse value based on field type
|
||||
if (objectName.contains("_dec_field")) {
|
||||
value = field->text().toInt(&ok);
|
||||
} else if (objectName.contains("_hex_field")) {
|
||||
QString hexText = field->text();
|
||||
// Remove 0x prefix if present
|
||||
if (hexText.startsWith("0x", Qt::CaseInsensitive)) {
|
||||
hexText = hexText.mid(2);
|
||||
}
|
||||
value = hexText.toInt(&ok, 16);
|
||||
|
||||
if (ok && (regName == "regA" || regName == "regB" || regName == "regX" ||
|
||||
regName == "regS" || regName == "regT")) {
|
||||
if (value > 0x7FFFFF) {
|
||||
value = value - 0x1000000;
|
||||
}
|
||||
}
|
||||
} else if (objectName.contains("_bin_field")) {
|
||||
value = field->text().toInt(&ok, 2);
|
||||
|
||||
if (ok && (regName == "regA" || regName == "regB" || regName == "regX" ||
|
||||
regName == "regS" || regName == "regT")) {
|
||||
if (value > 0x7FFFFF) {
|
||||
value = value - 0x1000000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
|
||||
updateRegisterDisplays();
|
||||
return;
|
||||
}
|
||||
|
||||
if (regName == "regA") {
|
||||
m_machine->setA(value);
|
||||
updateAllFormatsForRegister("regA", m_machine->getA());
|
||||
} else if (regName == "regB") {
|
||||
m_machine->setB(value);
|
||||
updateAllFormatsForRegister("regB", m_machine->getB());
|
||||
} else if (regName == "regX") {
|
||||
m_machine->setX(value);
|
||||
updateAllFormatsForRegister("regX", m_machine->getX());
|
||||
} else if (regName == "regS") {
|
||||
m_machine->setS(value);
|
||||
updateAllFormatsForRegister("regS", m_machine->getS());
|
||||
} else if (regName == "regT") {
|
||||
m_machine->setT(value);
|
||||
updateAllFormatsForRegister("regT", m_machine->getT());
|
||||
} else if (regName == "regL") {
|
||||
m_machine->setL(value);
|
||||
updateAllFormatsForRegister("regL", m_machine->getL());
|
||||
} else if (regName == "regPC") {
|
||||
m_machine->setPC(value);
|
||||
updateAllFormatsForRegister("regPC", m_machine->getPC());
|
||||
} else if (regName == "regSW") {
|
||||
m_machine->setSW(value);
|
||||
updateAllFormatsForRegister("regSW", m_machine->getSW());
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::handleFloatRegisterFieldChanged(QLineEdit* field, const QString& objectName)
|
||||
{
|
||||
double value = 0.0;
|
||||
bool ok = false;
|
||||
|
||||
if (objectName.contains("_dec_field")) {
|
||||
value = field->text().toDouble(&ok);
|
||||
} else if (objectName.contains("_hex_field")) {
|
||||
QString hexText = field->text();
|
||||
if (hexText.startsWith("0x", Qt::CaseInsensitive)) {
|
||||
hexText = hexText.mid(2);
|
||||
}
|
||||
|
||||
uint64_t intValue = hexText.toULongLong(&ok, 16);
|
||||
if (ok) {
|
||||
intValue &= 0xFFFFFFFFFFFFULL;
|
||||
double* floatPtr = reinterpret_cast<double*>(&intValue);
|
||||
value = *floatPtr;
|
||||
}
|
||||
} else if (objectName.contains("_bin_field")) {
|
||||
uint64_t intValue = field->text().toULongLong(&ok, 2);
|
||||
if (ok) {
|
||||
intValue &= 0xFFFFFFFFFFFFULL;
|
||||
double* floatPtr = reinterpret_cast<double*>(&intValue);
|
||||
value = *floatPtr;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
updateRegisterDisplays();
|
||||
return;
|
||||
}
|
||||
|
||||
m_machine->setF(value);
|
||||
updateFloatRegisterFormats("regF", m_machine->getF());
|
||||
}
|
||||
|
||||
void MainWindow::setTestRegisterValues()
|
||||
{
|
||||
if (!m_machine) return;
|
||||
|
||||
// Set some test values to demonstrate the register updating
|
||||
m_machine->setA(12345); // Decimal: 12345, Hex: 0x003039, Binary: 000000011000000111001
|
||||
m_machine->setB(-1000); // Negative value to test signed representation
|
||||
m_machine->setX(0xABCDEF); // Hex value to test various formats
|
||||
m_machine->setS(255); // Simple power of 2 minus 1
|
||||
m_machine->setT(0x7FFFFF); // Maximum positive 24-bit value
|
||||
|
||||
// Update all displays
|
||||
updateRegisterDisplays();
|
||||
}
|
||||
|
||||
void MainWindow::startExecution()
|
||||
{
|
||||
if (m_controller) {
|
||||
m_controller->start();
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::stopExecution()
|
||||
{
|
||||
if (m_controller) {
|
||||
m_controller->stop();
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::stepExecution()
|
||||
{
|
||||
if (m_controller) {
|
||||
m_controller->step();
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::loadDemoProgram()
|
||||
{
|
||||
if (!m_machine) return;
|
||||
|
||||
// Load the instruction set first
|
||||
loadInstructionSet();
|
||||
|
||||
qDebug() << "Loading SIC/XE Demo Program: Accumulator Loop";
|
||||
|
||||
const int TEMP_ADDR = 0x50;
|
||||
const int LOOP_ADDR = 0x03;
|
||||
|
||||
// clear TEMP
|
||||
m_machine->setByte(TEMP_ADDR, 0);
|
||||
|
||||
// Program (addresses):
|
||||
// 0x00 LDA #1
|
||||
// 0x03 LDB TEMP
|
||||
// 0x06 ADDR A,B
|
||||
// 0x08 RMO B,A
|
||||
// 0x0A STA TEMP
|
||||
// 0x0D J LOOP
|
||||
|
||||
// LDA #1
|
||||
m_machine->setByte(0x00, 0x01);
|
||||
m_machine->setByte(0x01, 0x00);
|
||||
m_machine->setByte(0x02, 0x01);
|
||||
|
||||
// LDB TEMP
|
||||
m_machine->setByte(0x03, 0x6B);
|
||||
m_machine->setByte(0x04, 0x00);
|
||||
m_machine->setByte(0x05, TEMP_ADDR);
|
||||
|
||||
// ADDR A,B
|
||||
m_machine->setByte(0x06, 0x90);
|
||||
m_machine->setByte(0x07, 0x03);
|
||||
|
||||
// RMO B,A
|
||||
m_machine->setByte(0x08, 0xAC);
|
||||
m_machine->setByte(0x09, 0x30);
|
||||
|
||||
// STA TEMP
|
||||
m_machine->setByte(0x0A, 0x0F);
|
||||
m_machine->setByte(0x0B, 0x00);
|
||||
m_machine->setByte(0x0C, TEMP_ADDR);
|
||||
|
||||
// J LOOP
|
||||
m_machine->setByte(0x0D, 0x3F);
|
||||
m_machine->setByte(0x0E, 0x00);
|
||||
m_machine->setByte(0x0F, LOOP_ADDR);
|
||||
|
||||
// Set PC to start of program
|
||||
m_machine->setPC(0x00);
|
||||
|
||||
qDebug() << "Program loaded. TEMP at 0x" << QString::number(TEMP_ADDR, 16).toUpper();
|
||||
qDebug() << "PC set to 0x00. Ready to execute.";
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue