From ad3078ba481c656be39c882b78699db4f9acf680 Mon Sep 17 00:00:00 2001 From: zanostro Date: Sat, 15 Nov 2025 17:00:57 +0100 Subject: [PATCH] added disasembly and better demo program --- simulator_SIC_XE/gui/qt/mainwindow.cpp | 448 ++++++++++++++++++++++--- simulator_SIC_XE/gui/qt/mainwindow.h | 24 ++ simulator_SIC_XE/gui/qt/mainwindow.ui | 284 ++++++++++++---- 3 files changed, 651 insertions(+), 105 deletions(-) diff --git a/simulator_SIC_XE/gui/qt/mainwindow.cpp b/simulator_SIC_XE/gui/qt/mainwindow.cpp index f49990a..aba288f 100644 --- a/simulator_SIC_XE/gui/qt/mainwindow.cpp +++ b/simulator_SIC_XE/gui/qt/mainwindow.cpp @@ -3,6 +3,7 @@ #include "MachineController.h" #include "../../include/machine.h" #include "../../include/instructions.h" +#include "../../include/opcode.h" #include #include @@ -77,12 +78,26 @@ MainWindow::MainWindow(QWidget *parent) : 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(); updateRegisterDisplays(); updateMemoryDisplay(); + updateDisassemblyDisplay(); } MainWindow::~MainWindow() @@ -375,55 +390,117 @@ void MainWindow::loadDemoProgram() // 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); + 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. TEMP at 0x" << QString::number(TEMP_ADDR, 16).toUpper(); - qDebug() << "PC set to 0x00. Ready to execute."; + 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() @@ -486,6 +563,285 @@ void MainWindow::onMemoryDec65536() 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; @@ -501,7 +857,7 @@ void MainWindow::updateMemoryDisplay() monoFont.setPointSize(9); // Header with current offset range - QString headerText = QString("Address Hex Value Char [0x%1 - 0x%2]") + 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); diff --git a/simulator_SIC_XE/gui/qt/mainwindow.h b/simulator_SIC_XE/gui/qt/mainwindow.h index 0507803..1e39a7d 100644 --- a/simulator_SIC_XE/gui/qt/mainwindow.h +++ b/simulator_SIC_XE/gui/qt/mainwindow.h @@ -32,6 +32,7 @@ public: private slots: void updateRegisterDisplays(); void updateMemoryDisplay(); + void updateDisassemblyDisplay(); void onRegisterFieldChanged(); void onMemoryInc256(); void onMemoryInc4096(); @@ -39,12 +40,23 @@ private slots: void onMemoryDec256(); void onMemoryDec4096(); void onMemoryDec65536(); + void onMemoryGoToStart(); + void onMemoryGoToEnd(); + void onDisassemblyInc(); + void onDisassemblyInc16(); + void onDisassemblyInc256(); + void onDisassemblyDec(); + void onDisassemblyDec16(); + void onDisassemblyDec256(); + void onDisassemblyGoToStart(); + void onDisassemblyGoToEnd(); private: Ui::MainWindow *ui; std::shared_ptr m_machine; std::unique_ptr m_controller; int m_memoryOffset = 0; + int m_disassemblyOffset = 0; void connectRegisterFields(); void updateSingleRegisterDisplay(const QString& fieldName, int value); @@ -53,6 +65,18 @@ private: void handleFloatRegisterFieldChanged(QLineEdit* field, const QString& objectName); void loadDemoProgram(); void setupMemoryDisplay(); + void setupDisassemblyDisplay(); + + struct DisassembledInstruction { + int address; + int size; + QString mnemonic; + QString operand; + int effectiveAddr; + bool isImmediate; + bool isIndirect; + }; + DisassembledInstruction disassembleAt(int address); }; #endif // MAINWINDOW_H diff --git a/simulator_SIC_XE/gui/qt/mainwindow.ui b/simulator_SIC_XE/gui/qt/mainwindow.ui index 7722091..2fad622 100644 --- a/simulator_SIC_XE/gui/qt/mainwindow.ui +++ b/simulator_SIC_XE/gui/qt/mainwindow.ui @@ -6,7 +6,7 @@ 0 0 - 1137 + 1172 649 @@ -17,7 +17,7 @@ - 0 + 10 0 431 601 @@ -27,7 +27,7 @@ 0 - 280 + 80 431 321 @@ -48,8 +48,8 @@ - 20 - 41 + 10 + 40 57 20 @@ -150,8 +150,8 @@ - 20 - 71 + 10 + 70 57 20 @@ -198,8 +198,8 @@ - 20 - 101 + 10 + 100 57 20 @@ -246,8 +246,8 @@ - 20 - 131 + 10 + 130 57 20 @@ -294,8 +294,8 @@ - 20 - 161 + 10 + 160 57 20 @@ -352,8 +352,8 @@ - 20 - 191 + 10 + 190 57 20 @@ -380,8 +380,8 @@ - 20 - 221 + 10 + 220 57 20 @@ -428,8 +428,8 @@ - 20 - 250 + 10 + 249 57 20 @@ -476,8 +476,8 @@ - 20 - 281 + 10 + 280 57 20 @@ -528,7 +528,7 @@ 0 0 431 - 161 + 81 @@ -537,8 +537,8 @@ - 40 - 70 + 30 + 40 80 23 @@ -550,8 +550,8 @@ - 180 - 70 + 170 + 40 80 23 @@ -563,8 +563,8 @@ - 320 - 70 + 310 + 40 80 23 @@ -578,9 +578,9 @@ - 430 + 450 0 - 711 + 721 601 @@ -590,11 +590,11 @@ 0 0 711 - 251 + 291 - GroupBox + Memory @@ -602,7 +602,7 @@ 0 20 711 - 171 + 221 @@ -614,7 +614,7 @@ 0 0 709 - 169 + 219 @@ -622,79 +622,245 @@ - 460 - 200 - 121 + 450 + 250 + 71 23 - >> M[+0x01000] + >> - 360 - 200 - 101 + 370 + 250 + 71 23 - > M[+0x00100] + > - 580 - 200 - 121 + 530 + 250 + 71 23 - >>> M[+0x10000] + >>> - 250 - 200 - 101 + 290 + 250 + 71 23 - < M[-0x00100] + < - 130 - 200 - 121 + 210 + 250 + 71 23 - << M[-0x01000] + << - 10 - 200 - 121 + 130 + 250 + 71 21 - <<< M[-0x10000] + <<< + + + + + + 50 + 250 + 71 + 21 + + + + O + + + + + + 610 + 250 + 71 + 21 + + + + | + + + + + + + 0 + 300 + 711 + 301 + + + + Disasembly + + + + + 0 + 20 + 711 + 221 + + + + true + + + + + 0 + 0 + 709 + 219 + + + + + + + + 440 + 250 + 71 + 23 + + + + >> + + + + + + 360 + 250 + 71 + 23 + + + + > + + + + + + 520 + 250 + 71 + 23 + + + + >>> + + + + + + 280 + 250 + 71 + 23 + + + + < + + + + + + 200 + 250 + 71 + 23 + + + + << + + + + + + 120 + 250 + 71 + 21 + + + + <<< + + + + + + 40 + 250 + 71 + 21 + + + + O + + + + + + 600 + 250 + 71 + 21 + + + + | @@ -705,7 +871,7 @@ 0 0 - 1137 + 1172 20