#include "mainwindow.h" #include "ui_mainwindow.h" #include "MachineController.h" #include "../../include/machine.h" #include "../../include/instructions.h" #include #include #include #include #include #include #include MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow), m_machine(std::make_shared()), m_controller(std::make_unique(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(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(regPrefix + "_dec_field"); if (decField && !decField->hasFocus()) { decField->setText(QString::number(value)); } // Update hex field QLineEdit* hexField = findChild(regPrefix + "_hex_field"); if (hexField && !hexField->hasFocus()) { // Convert to 24-bit representation, handle negative numbers unsigned int unsignedValue = static_cast(value) & 0xFFFFFF; hexField->setText(QString("0x%1").arg(unsignedValue, 6, 16, QChar('0')).toUpper()); } // Update binary field QLineEdit* binField = findChild(regPrefix + "_bin_field"); if (binField && !binField->hasFocus()) { // Convert to 24-bit binary representation unsigned int unsignedValue = static_cast(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(regPrefix + "_dec_field"); if (decField && !decField->hasFocus()) { decField->setText(QString::number(value, 'g', 10)); } // Update hex field (48-bit float representation) QLineEdit* hexField = findChild(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(&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(regPrefix + "_bin_field"); if (binField && !binField->hasFocus()) { // Convert double to 48-bit binary representation uint64_t* intPtr = reinterpret_cast(&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(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(&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(&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."; }