#include "mainwindow.h" #include "ui_mainwindow.h" #include "MachineController.h" #include "../../include/machine.h" #include "../../include/instructions.h" #include "../../include/opcode.h" #include "../../include/constants.h" #include "../../../include/loader.h" #include #include #include #include #include #include #include #include #include #include class Loader; std::shared_ptr g_loader; 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); connect(m_controller.get(), &MachineController::tick, this, &MainWindow::updateMemoryDisplay); 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); connect(ui->MemoryInc256Btn, &QPushButton::clicked, this, &MainWindow::onMemoryInc256); connect(ui->MemoryInc4096Btn, &QPushButton::clicked, this, &MainWindow::onMemoryInc4096); connect(ui->MemoryInc65536Btn, &QPushButton::clicked, this, &MainWindow::onMemoryInc65536); connect(ui->MemoryDec256Btn, &QPushButton::clicked, this, &MainWindow::onMemoryDec256); connect(ui->MemoryDec4096Btn, &QPushButton::clicked, this, &MainWindow::onMemoryDec4096); connect(ui->MemoryDec65536Btn, &QPushButton::clicked, this, &MainWindow::onMemoryDec65536); connect(ui->MemoryGoToStart_2, &QPushButton::clicked, this, &MainWindow::onMemoryGoToStart); connect(ui->MemoryGoToEnd, &QPushButton::clicked, this, &MainWindow::onMemoryGoToEnd); connect(ui->DisasmInc256Btn, &QPushButton::clicked, this, &MainWindow::onDisassemblyInc); connect(ui->DisasmInc4096Btn, &QPushButton::clicked, this, &MainWindow::onDisassemblyInc16); connect(ui->DisasmInc65536Btn, &QPushButton::clicked, this, &MainWindow::onDisassemblyInc256); connect(ui->DisasmDec256Btn, &QPushButton::clicked, this, &MainWindow::onDisassemblyDec); connect(ui->DisasmDec4096Btn, &QPushButton::clicked, this, &MainWindow::onDisassemblyDec16); connect(ui->DisasmDec65536Btn, &QPushButton::clicked, this, &MainWindow::onDisassemblyDec256); connect(ui->DisasmGoToStart, &QPushButton::clicked, this, &MainWindow::onDisassemblyGoToStart); connect(ui->DisasmGoToEnd, &QPushButton::clicked, this, &MainWindow::onDisassemblyGoToEnd); connect(m_controller.get(), &MachineController::tick, this, &MainWindow::updateDisassemblyDisplay); setupMemoryDisplay(); setupDisassemblyDisplay(); //loadDemoProgram(); g_loader = std::make_shared(machine(), std::string(PATH_RESOURCES) + "demo_program.obj"); g_loader->load(); updateRegisterDisplays(); updateMemoryDisplay(); updateDisassemblyDisplay(); } 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: Array Sum with Indirect Addressing"; // Memory layout const int ARRAY_ADDR = 0x100; // Array of 3 numbers const int PTR_ADDR = 0x200; // Pointer to array const int SUM_ADDR = 0x300; // Result storage const int COUNTER_ADDR = 0x310; // Loop counter // Initialize array with values: 10, 20, 30 m_machine->setWord(ARRAY_ADDR, 10); m_machine->setWord(ARRAY_ADDR + 3, 20); m_machine->setWord(ARRAY_ADDR + 6, 30); // Initialize pointer to point to array m_machine->setWord(PTR_ADDR, ARRAY_ADDR); // Initialize counter to 3 m_machine->setWord(COUNTER_ADDR, 3); // Initialize sum to 0 m_machine->setWord(SUM_ADDR, 0); int addr = 0x00; // Program: Sum array elements using indirect addressing // 0x00: LDA #0 ; Initialize accumulator to 0 m_machine->setByte(addr++, 0x01); // LDA with immediate (n=0,i=1) m_machine->setByte(addr++, 0x00); m_machine->setByte(addr++, 0x00); // 0x03: STA SUM_ADDR ; Store 0 in SUM m_machine->setByte(addr++, 0x0F); // STA m_machine->setByte(addr++, (SUM_ADDR >> 8) & 0xFF); m_machine->setByte(addr++, SUM_ADDR & 0xFF); // 0x06: LDX #0 ; Initialize index to 0 m_machine->setByte(addr++, 0x05); // LDX with immediate m_machine->setByte(addr++, 0x00); m_machine->setByte(addr++, 0x00); // LOOP (0x09): const int LOOP_START = addr; // 0x09: LDA @PTR_ADDR ; Load value indirectly through pointer m_machine->setByte(addr++, 0x02); // LDA with indirect (n=1,i=0) m_machine->setByte(addr++, (PTR_ADDR >> 8) & 0xFF); m_machine->setByte(addr++, PTR_ADDR & 0xFF); // 0x0C: ADD SUM_ADDR ; Add to sum m_machine->setByte(addr++, 0x1B); // ADD m_machine->setByte(addr++, (SUM_ADDR >> 8) & 0xFF); m_machine->setByte(addr++, SUM_ADDR & 0xFF); // 0x0F: STA SUM_ADDR ; Store result back m_machine->setByte(addr++, 0x0F); // STA m_machine->setByte(addr++, (SUM_ADDR >> 8) & 0xFF); m_machine->setByte(addr++, SUM_ADDR & 0xFF); // 0x12: LDA PTR_ADDR ; Load current pointer value m_machine->setByte(addr++, 0x03); // LDA m_machine->setByte(addr++, (PTR_ADDR >> 8) & 0xFF); m_machine->setByte(addr++, PTR_ADDR & 0xFF); // 0x15: ADD #3 ; Add 3 to move to next array element m_machine->setByte(addr++, 0x19); // ADD with immediate m_machine->setByte(addr++, 0x00); m_machine->setByte(addr++, 0x03); // 0x18: STA PTR_ADDR ; Store updated pointer m_machine->setByte(addr++, 0x0F); // STA m_machine->setByte(addr++, (PTR_ADDR >> 8) & 0xFF); m_machine->setByte(addr++, PTR_ADDR & 0xFF); // 0x1B: LDA COUNTER_ADDR ; Load counter m_machine->setByte(addr++, 0x03); // LDA m_machine->setByte(addr++, (COUNTER_ADDR >> 8) & 0xFF); m_machine->setByte(addr++, COUNTER_ADDR & 0xFF); // 0x1E: ADD #-1 ; Decrement counter (add -1) m_machine->setByte(addr++, 0x19); // ADD with immediate m_machine->setByte(addr++, 0x0F); // -1 in 12-bit two's complement m_machine->setByte(addr++, 0xFF); // 0x21: STA COUNTER_ADDR ; Store counter m_machine->setByte(addr++, 0x0F); // STA m_machine->setByte(addr++, (COUNTER_ADDR >> 8) & 0xFF); m_machine->setByte(addr++, COUNTER_ADDR & 0xFF); // 0x24: COMP #0 ; Compare with 0 m_machine->setByte(addr++, 0x29); // COMP with immediate m_machine->setByte(addr++, 0x00); m_machine->setByte(addr++, 0x00); // 0x27: JGT LOOP ; Jump if greater than 0 m_machine->setByte(addr++, 0x37); // JGT m_machine->setByte(addr++, (LOOP_START >> 8) & 0xFF); m_machine->setByte(addr++, LOOP_START & 0xFF); // 0x2A: J 0x2A ; Infinite loop (halt) m_machine->setByte(addr++, 0x3F); // J m_machine->setByte(addr++, 0x00); m_machine->setByte(addr++, 0x2A); // Set PC to start of program m_machine->setPC(0x00); qDebug() << "Program loaded:"; qDebug() << " Array at 0x" << QString::number(ARRAY_ADDR, 16).toUpper() << " = [10, 20, 30]"; qDebug() << " Pointer at 0x" << QString::number(PTR_ADDR, 16).toUpper(); qDebug() << " Sum will be stored at 0x" << QString::number(SUM_ADDR, 16).toUpper(); qDebug() << " Expected result: 60 (0x3C)"; } void MainWindow::setupMemoryDisplay() { // Set the title ui->MemorygroupBox->setTitle("Memory (RAM)"); } void MainWindow::onMemoryInc256() { m_memoryOffset += 256; if (m_memoryOffset > 1048576 - 256) { m_memoryOffset = 1048576 - 256; } updateMemoryDisplay(); } void MainWindow::onMemoryInc4096() { m_memoryOffset += 4096; if (m_memoryOffset > 1048576 - 256) { m_memoryOffset = 1048576 - 256; } updateMemoryDisplay(); } void MainWindow::onMemoryInc65536() { m_memoryOffset += 65536; if (m_memoryOffset > 1048576 - 256) { m_memoryOffset = 1048576 - 256; } updateMemoryDisplay(); } void MainWindow::onMemoryDec256() { m_memoryOffset -= 256; if (m_memoryOffset < 0) { m_memoryOffset = 0; } updateMemoryDisplay(); } void MainWindow::onMemoryDec4096() { m_memoryOffset -= 4096; if (m_memoryOffset < 0) { m_memoryOffset = 0; } updateMemoryDisplay(); } void MainWindow::onMemoryDec65536() { m_memoryOffset -= 65536; if (m_memoryOffset < 0) { m_memoryOffset = 0; } updateMemoryDisplay(); } void MainWindow::onMemoryGoToStart() { m_memoryOffset = 0; updateMemoryDisplay(); } void MainWindow::onMemoryGoToEnd() { m_memoryOffset = 1048576 - 256; updateMemoryDisplay(); } void MainWindow::setupDisassemblyDisplay() { ui->MemorygroupBox_3->setTitle("Disassembly"); } void MainWindow::onDisassemblyInc() { // Move forward by 1 instruction auto instr = disassembleAt(m_disassemblyOffset); m_disassemblyOffset += instr.size; if (m_disassemblyOffset > 1048576 - 16) { m_disassemblyOffset = 1048576 - 16; } updateDisassemblyDisplay(); } void MainWindow::onDisassemblyInc16() { // Move forward by 16 instructions for (int i = 0; i < 16 && m_disassemblyOffset < 1048576 - 16; i++) { auto instr = disassembleAt(m_disassemblyOffset); m_disassemblyOffset += instr.size; } updateDisassemblyDisplay(); } void MainWindow::onDisassemblyInc256() { // Move forward by 256 instructions for (int i = 0; i < 256 && m_disassemblyOffset < 1048576 - 16; i++) { auto instr = disassembleAt(m_disassemblyOffset); m_disassemblyOffset += instr.size; } updateDisassemblyDisplay(); } void MainWindow::onDisassemblyDec() { // Move back by trying to find previous instruction (assume max 4 bytes) m_disassemblyOffset = std::max(0, m_disassemblyOffset - 4); updateDisassemblyDisplay(); } void MainWindow::onDisassemblyDec16() { // Move back by approximately 16 instructions (16*3 = 48 bytes avg) m_disassemblyOffset = std::max(0, m_disassemblyOffset - 48); updateDisassemblyDisplay(); } void MainWindow::onDisassemblyDec256() { // Move back by approximately 256 instructions (256*3 = 768 bytes avg) m_disassemblyOffset = std::max(0, m_disassemblyOffset - 768); updateDisassemblyDisplay(); } void MainWindow::onDisassemblyGoToStart() { m_disassemblyOffset = 0; updateDisassemblyDisplay(); } void MainWindow::onDisassemblyGoToEnd() { m_disassemblyOffset = std::max(0, 1048576 - 1024); updateDisassemblyDisplay(); } MainWindow::DisassembledInstruction MainWindow::disassembleAt(int address) { DisassembledInstruction result; result.address = address; result.size = 1; result.mnemonic = "???"; result.operand = ""; result.effectiveAddr = -1; result.isImmediate = false; result.isIndirect = false; if (address >= 1048576) { return result; } int byte1 = m_machine->getByte(address); int opcode = byte1 & 0xFC; // Mask off lower 2 bits (n, i flags) if (opcode >= 0xff || instructions[opcode].type == InstructionType::INVALID) { result.mnemonic = QString("BYTE 0x%1").arg(byte1, 2, 16, QChar('0')).toUpper(); return result; } result.mnemonic = QString(instructions[opcode].name); switch (instructions[opcode].type) { case InstructionType::TYPE1: result.size = 1; break; case InstructionType::TYPE2: { result.size = 2; if (address + 1 < 1048576) { int byte2 = m_machine->getByte(address + 1); int r1 = (byte2 >> 4) & 0xF; int r2 = byte2 & 0xF; const char* regNames[] = {"A", "X", "L", "B", "S", "T", "F", "?", "PC", "SW"}; QString reg1Str = (r1 < 10) ? regNames[r1] : "?"; QString reg2Str = (r2 < 10) ? regNames[r2] : "?"; result.operand = QString("%1, %2").arg(reg1Str).arg(reg2Str); } break; } case InstructionType::TYPE3_4: { if (address + 2 >= 1048576) { result.size = 3; break; } int byte2 = m_machine->getByte(address + 1); int byte3 = m_machine->getByte(address + 2); int ni = (byte1 >> 0) & 0x3; int x = (byte2 >> 7) & 0x1; int b = (byte2 >> 6) & 0x1; int p = (byte2 >> 5) & 0x1; int e = (byte2 >> 4) & 0x1; if (e) { // Format 4 - add + prefix to mnemonic result.mnemonic = "+" + result.mnemonic; result.size = 4; if (address + 3 < 1048576) { int byte4 = m_machine->getByte(address + 3); int addr = ((byte2 & 0xF) << 16) | (byte3 << 8) | byte4; result.isImmediate = (ni == 0x1); result.isIndirect = (ni == 0x2); if (!result.isImmediate) { result.effectiveAddr = addr; } QString prefix = ""; if (ni == 0x1) prefix = "#"; // Immediate else if (ni == 0x2) prefix = "@"; // Indirect result.operand = QString("%1%2").arg(prefix).arg(addr, 5, 16, QChar('0')).toUpper(); if (x) result.operand += ",X"; } } else { result.size = 3; int disp = ((byte2 & 0xF) << 8) | byte3; if (disp & 0x800) { disp |= 0xFFFFF000; } result.isImmediate = (ni == 0x1); result.isIndirect = (ni == 0x2); QString prefix = ""; if (ni == 0x1) prefix = "#"; // Immediate else if (ni == 0x2) prefix = "@"; // Indirect if (ni == 0x1 && !p && !b) { result.operand = QString("#%1").arg(disp & 0xFFF); } else { // Calculate effective address for display int ea = disp; QString addrMode = ""; if (p) { ea += m_machine->getPC(); addrMode = " (PC)"; } else if (b) { ea += m_machine->getB(); addrMode = " (B)"; } if (!result.isImmediate && !x) { result.effectiveAddr = ea & 0xFFFFF; } result.operand = QString("%1%2%3").arg(prefix).arg(ea & 0xFFFFF, 4, 16, QChar('0')).toUpper().arg(addrMode); if (x) result.operand += ",X"; } } break; } default: break; } return result; } void MainWindow::updateDisassemblyDisplay() { if (!m_machine) return; QWidget* container = new QWidget(); QVBoxLayout* layout = new QVBoxLayout(container); layout->setSpacing(1); layout->setContentsMargins(5, 5, 5, 5); QFont monoFont("Courier New"); monoFont.setPointSize(9); // Header QString headerText = QString("Address Mnemonic Operand *var **var"); QLabel* header = new QLabel(headerText); QFont headerFont = monoFont; headerFont.setBold(true); header->setFont(headerFont); layout->addWidget(header); int pc = m_machine->getPC(); int currentAddr = m_disassemblyOffset; // Disassemble up to 255 instructions for (int i = 0; i < 255 && currentAddr < 1048576; i++) { auto instr = disassembleAt(currentAddr); QString varCol = ""; QString varVar = ""; // *var column - show value at effective address (if not immediate) if (instr.effectiveAddr >= 0 && instr.effectiveAddr < 1048576) { int value = m_machine->getWord(instr.effectiveAddr); varCol = QString("0x%1").arg(value & 0xFFFFFF, 6, 16, QChar('0')).toUpper(); // **var column - if indirect (@), dereference again if (instr.isIndirect && value >= 0 && value < 1048576) { int derefValue = m_machine->getWord(value); varVar = QString("0x%1").arg(derefValue & 0xFFFFFF, 6, 16, QChar('0')).toUpper(); } } QString line = QString("0x%1 %2 %3 %4 %5") .arg(instr.address, 5, 16, QChar('0')).toUpper() .arg(instr.mnemonic, -9) .arg(instr.operand, -14) .arg(varCol, -9) .arg(varVar, -9); QLabel* instrLine = new QLabel(line); instrLine->setFont(monoFont); // Highlight current PC if (pc == instr.address) { instrLine->setStyleSheet("background-color: #FFFF99; font-weight: bold;"); } layout->addWidget(instrLine); currentAddr += instr.size; } layout->addStretch(); container->setLayout(layout); ui->DisasemblyScrollArea->setWidget(container); } void MainWindow::updateMemoryDisplay() { if (!m_machine) return; // Create a widget to hold the memory display QWidget* container = new QWidget(); QVBoxLayout* layout = new QVBoxLayout(container); layout->setSpacing(1); layout->setContentsMargins(5, 5, 5, 5); // Create monospace font for memory display QFont monoFont("Courier New"); monoFont.setPointSize(9); // Header with current offset range QString headerText = QString("Address Hex Value Char [0x%1 - 0x%2]") .arg(m_memoryOffset, 5, 16, QChar('0')).toUpper() .arg(m_memoryOffset + 255, 5, 16, QChar('0')).toUpper(); QLabel* header = new QLabel(headerText); QFont headerFont = monoFont; headerFont.setBold(true); header->setFont(headerFont); layout->addWidget(header); // Get PC for highlighting int pc = m_machine->getPC(); // Display memory byte by byte - ONLY 256 bytes from current offset for (int i = 0; i < 256; i++) { int addr = m_memoryOffset + i; int byte = m_machine->getByte(addr); QString addressStr = QString("0x%1").arg(addr, 5, 16, QChar('0')).toUpper(); // Hex value column QString hexStr = QString("0x%1").arg(byte, 2, 16, QChar('0')).toUpper(); // Char representation QString charStr; if (byte >= 32 && byte <= 126) { charStr = QChar(byte); } else { charStr = '.'; } QString line = QString("%1 %2 %3") .arg(addressStr, -12) .arg(hexStr, -12) .arg(charStr); QLabel* memLine = new QLabel(line); memLine->setFont(monoFont); // Highlight the current PC address if (pc == addr) { memLine->setStyleSheet("background-color: #FFFF99; font-weight: bold;"); } layout->addWidget(memLine); } layout->addStretch(); container->setLayout(layout); ui->MemoryScrollArea->setWidget(container); }