From d3ab78e76cc51b702fe87f215044ec00a05920a5 Mon Sep 17 00:00:00 2001 From: zanostro Date: Fri, 5 Dec 2025 19:00:11 +0100 Subject: [PATCH 1/2] ui changes --- simulator_SIC_XE/gui/qt/MachineController.cpp | 7 ++- simulator_SIC_XE/gui/qt/mainwindow.cpp | 52 ++++++++++++++++--- simulator_SIC_XE/gui/qt/mainwindow.h | 1 + simulator_SIC_XE/gui/qt/mainwindow.ui | 49 ++++++++++++++++- simulator_SIC_XE/include/machine.h | 8 +-- simulator_SIC_XE/src/machine.cpp | 31 +++++++++-- 6 files changed, 131 insertions(+), 17 deletions(-) diff --git a/simulator_SIC_XE/gui/qt/MachineController.cpp b/simulator_SIC_XE/gui/qt/MachineController.cpp index 0ea4178..9861e0c 100644 --- a/simulator_SIC_XE/gui/qt/MachineController.cpp +++ b/simulator_SIC_XE/gui/qt/MachineController.cpp @@ -42,8 +42,13 @@ void MachineController::runLoop() { try { if (m_machine) { m_machine->execute(); - m_machine->tick(); + m_machine->tick(); emit tick(); + + if (m_machine->isStopped()) { + m_running.store(false); + break; + } } } catch (const std::exception &e) { emit error(QString::fromStdString(e.what())); diff --git a/simulator_SIC_XE/gui/qt/mainwindow.cpp b/simulator_SIC_XE/gui/qt/mainwindow.cpp index de0ca3c..e2d4c61 100644 --- a/simulator_SIC_XE/gui/qt/mainwindow.cpp +++ b/simulator_SIC_XE/gui/qt/mainwindow.cpp @@ -17,6 +17,8 @@ #include #include #include +#include +#include class Loader; @@ -69,8 +71,8 @@ MainWindow::MainWindow(QWidget *parent) : ui->regF_bin_field->setValidator(floatBinValidator); - connect(m_controller.get(), &MachineController::tick, this, &MainWindow::updateRegisterDisplays); - connect(m_controller.get(), &MachineController::tick, this, &MainWindow::updateMemoryDisplay); + connect(m_controller.get(), &MachineController::tick, this, &MainWindow::updateRegisterDisplays, Qt::QueuedConnection); + connect(m_controller.get(), &MachineController::tick, this, &MainWindow::updateMemoryDisplay, Qt::QueuedConnection); connectRegisterFields(); @@ -95,15 +97,16 @@ MainWindow::MainWindow(QWidget *parent) : 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); + connect(m_controller.get(), &MachineController::tick, this, &MainWindow::updateDisassemblyDisplay, Qt::QueuedConnection); + + // Connect menu actions + connect(ui->actionLoad_Object_File, &QAction::triggered, this, &MainWindow::loadObjectFile); setupMemoryDisplay(); setupDisassemblyDisplay(); loadInstructionSet(); - //loadDemoProgram(); - Loader loader(m_machine, std::string(PATH_RESOURCES) + "print.obj"); - loader.load(); + // Don't load any program by default - user will load via File menu updateRegisterDisplays(); updateMemoryDisplay(); @@ -760,7 +763,7 @@ MainWindow::DisassembledInstruction MainWindow::disassembleAt(int address) QString addrMode = ""; if (p) { - ea += m_machine->getPC(); + ea += (address + 3); addrMode = " (PC)"; } else if (b) { ea += m_machine->getB(); @@ -918,3 +921,38 @@ void MainWindow::updateMemoryDisplay() ui->MemoryScrollArea->setWidget(container); } + +void MainWindow::loadObjectFile() +{ + QString fileName = QFileDialog::getOpenFileName(this, + tr("Load Object File"), + QString(), + tr("Object Files (*.obj);;All Files (*)")); + + if (fileName.isEmpty()) { + return; + } + + try { + // Stop execution if running + m_controller->stop(); + + // Reset machine state + m_machine->reset(); + + // Load the object file + Loader loader(m_machine, fileName.toStdString()); + loader.load(); + + // Update displays + updateRegisterDisplays(); + updateMemoryDisplay(); + updateDisassemblyDisplay(); + + QMessageBox::information(this, tr("Success"), + tr("Object file loaded successfully")); + } catch (const std::exception &e) { + QMessageBox::critical(this, tr("Error"), + tr("Failed to load object file: %1").arg(e.what())); + } +} diff --git a/simulator_SIC_XE/gui/qt/mainwindow.h b/simulator_SIC_XE/gui/qt/mainwindow.h index 1e39a7d..caa9550 100644 --- a/simulator_SIC_XE/gui/qt/mainwindow.h +++ b/simulator_SIC_XE/gui/qt/mainwindow.h @@ -50,6 +50,7 @@ private slots: void onDisassemblyDec256(); void onDisassemblyGoToStart(); void onDisassemblyGoToEnd(); + void loadObjectFile(); private: Ui::MainWindow *ui; diff --git a/simulator_SIC_XE/gui/qt/mainwindow.ui b/simulator_SIC_XE/gui/qt/mainwindow.ui index 2fad622..e9084bd 100644 --- a/simulator_SIC_XE/gui/qt/mainwindow.ui +++ b/simulator_SIC_XE/gui/qt/mainwindow.ui @@ -866,6 +866,18 @@ + + + + toolBar + + + TopToolBarArea + + + false + + @@ -875,8 +887,43 @@ 20 + + + File + + + + + + Machine + + + + + + Help + + + + + + - + + + Load Object File + + + + + Frequency + + + + + About + + diff --git a/simulator_SIC_XE/include/machine.h b/simulator_SIC_XE/include/machine.h index 8e80669..cd14f74 100644 --- a/simulator_SIC_XE/include/machine.h +++ b/simulator_SIC_XE/include/machine.h @@ -26,7 +26,7 @@ using std::cout; class Machine { public: Machine(); - Machine(int speedkHz) : Machine() { this->speedkHz = speedkHz; _instructionsTable = instructions; } + Machine(int speedHz) : Machine() { this->speedHz = speedHz; _instructionsTable = instructions; } ~Machine(); int getA() const { return A; } @@ -84,11 +84,13 @@ public: // Execution and speed control int getSpeed() const; - void setSpeed(int kHz); + void setSpeed(int Hz); void start(); void stop(); void tick(); void halt(); + bool isStopped() const { return _stopped; } + void reset(); // error handling methods void notImplemented(string mnemonic); @@ -128,7 +130,7 @@ private: // Execution control std::atomic running{false}; - std::atomic speedkHz{1}; // Default 1 kHz + std::atomic speedHz{10}; // Default 10 Hz bool execF1(int opcode); bool execF2(int opcode, int operand); diff --git a/simulator_SIC_XE/src/machine.cpp b/simulator_SIC_XE/src/machine.cpp index e15e6c1..f71814d 100644 --- a/simulator_SIC_XE/src/machine.cpp +++ b/simulator_SIC_XE/src/machine.cpp @@ -45,12 +45,12 @@ Machine::~Machine() int Machine::getSpeed() const { - return speedkHz.load(); + return speedHz.load(); } -void Machine::setSpeed(int kHz) +void Machine::setSpeed(int Hz) { - speedkHz.store(kHz); + speedHz.store(Hz); } // TODO: implement errors @@ -138,10 +138,10 @@ void Machine::setVT(const int *values) void Machine::tick() { - const int speed = speedkHz.load(); + const int speed = speedHz.load(); if (speed <= 0) throw std::runtime_error("Invalid speed setting in Machine::tick"); - const auto delay = std::chrono::microseconds(1000 / speed); + const auto delay = std::chrono::milliseconds(1000 / speed); std::this_thread::sleep_for(delay); } @@ -150,6 +150,27 @@ void Machine::halt() _stopped = true; } +void Machine::reset() +{ + // Reset all registers + A = B = X = L = S = T = PC = SW = 0; + F = 0.0; + + // Clear memory + for (int i = 0; i < MEMORY_SIZE; i++) { + memory[i] = 0; + } + + // Reset execution state + _stopped = false; + running.store(false); + + // Reset vector registers + for (int i = 0; i < VECTOR_REG_SIZE; i++) { + VA[i] = VS[i] = VT[i] = 0; + } +} + int Machine::getReg(int regNum) const { switch (regNum) { From 098766bb6545b1d97a4222f943456a45acbdd0ca Mon Sep 17 00:00:00 2001 From: zanostro Date: Sat, 6 Dec 2025 22:55:01 +0100 Subject: [PATCH 2/2] fixed bugs --- simulator_SIC_XE/gui/qt/mainwindow.cpp | 24 +++++++++++++++++++++++- simulator_SIC_XE/include/file_device.h | 1 + simulator_SIC_XE/src/file_device.cpp | 17 +++++++++++++---- simulator_SIC_XE/src/loader.cpp | 26 ++++++++++++++++---------- simulator_SIC_XE/src/machine.cpp | 11 +++++++++++ 5 files changed, 64 insertions(+), 15 deletions(-) diff --git a/simulator_SIC_XE/gui/qt/mainwindow.cpp b/simulator_SIC_XE/gui/qt/mainwindow.cpp index e2d4c61..dcdb9bc 100644 --- a/simulator_SIC_XE/gui/qt/mainwindow.cpp +++ b/simulator_SIC_XE/gui/qt/mainwindow.cpp @@ -19,6 +19,7 @@ #include #include #include +#include class Loader; @@ -698,7 +699,18 @@ MainWindow::DisassembledInstruction MainWindow::disassembleAt(int address) QString reg1Str = (r1 < 10) ? regNames[r1] : "?"; QString reg2Str = (r2 < 10) ? regNames[r2] : "?"; - result.operand = QString("%1, %2").arg(reg1Str).arg(reg2Str); + // Check if this is a single-operand Format 2 instruction + QString mnem = result.mnemonic.toUpper(); + if (mnem == "CLEAR" || mnem == "TIXR") { + result.operand = reg1Str; + } else if (mnem == "SVC") { + result.operand = QString::number(r1); + } else if (mnem == "SHIFTL" || mnem == "SHIFTR") { + result.operand = QString("%1, %2").arg(reg1Str).arg(r2); + } else { + // Two register operands (ADDR, SUBR, COMPR, etc.) + result.operand = QString("%1, %2").arg(reg1Str).arg(reg2Str); + } } break; } @@ -852,7 +864,13 @@ void MainWindow::updateDisassemblyDisplay() layout->addStretch(); container->setLayout(layout); + // Save scroll position before updating + int scrollPos = ui->DisasemblyScrollArea->verticalScrollBar()->value(); + ui->DisasemblyScrollArea->setWidget(container); + + // Restore scroll position after updating + ui->DisasemblyScrollArea->verticalScrollBar()->setValue(scrollPos); } void MainWindow::updateMemoryDisplay() @@ -919,7 +937,11 @@ void MainWindow::updateMemoryDisplay() layout->addStretch(); container->setLayout(layout); + int scrollPos = ui->MemoryScrollArea->verticalScrollBar()->value(); + ui->MemoryScrollArea->setWidget(container); + + ui->MemoryScrollArea->verticalScrollBar()->setValue(scrollPos); } void MainWindow::loadObjectFile() diff --git a/simulator_SIC_XE/include/file_device.h b/simulator_SIC_XE/include/file_device.h index a08e2ac..01b433c 100644 --- a/simulator_SIC_XE/include/file_device.h +++ b/simulator_SIC_XE/include/file_device.h @@ -17,6 +17,7 @@ private: std::fstream fileStream; std::string filename; bool fileCreated; + std::streampos readPosition; }; #endif // FILE_DEVICE_H \ No newline at end of file diff --git a/simulator_SIC_XE/src/file_device.cpp b/simulator_SIC_XE/src/file_device.cpp index 8ca554f..781a9b6 100644 --- a/simulator_SIC_XE/src/file_device.cpp +++ b/simulator_SIC_XE/src/file_device.cpp @@ -3,9 +3,8 @@ #include FileDevice::FileDevice(const std::string &filename) - : filename(filename), fileCreated(false) + : filename(filename), fileCreated(false), readPosition(0) { - // Don't create the file yet - wait until first write } FileDevice::~FileDevice() @@ -18,9 +17,16 @@ FileDevice::~FileDevice() void FileDevice::ensureFileOpen() { if (!fileStream.is_open()) { - if (fileCreated) { - fileStream.open(filename, std::ios::in | std::ios::out); + // Check if file exists + std::ifstream checkFile(filename); + bool fileExists = checkFile.good(); + checkFile.close(); + + if (fileExists) { + fileStream.open(filename, std::ios::in | std::ios::out | std::ios::ate); + fileCreated = true; } else { + // Create new file std::ofstream create(filename); if (!create) { throw std::runtime_error("Failed to create file: " + filename); @@ -41,9 +47,11 @@ unsigned char FileDevice::read() unsigned char value = 0; ensureFileOpen(); if (fileStream.is_open()) { + fileStream.seekg(readPosition); char ch; if (fileStream.get(ch)) { value = static_cast(ch); + readPosition = fileStream.tellg(); } } return value; @@ -53,6 +61,7 @@ void FileDevice::write(unsigned char value) { ensureFileOpen(); if (fileStream.is_open()) { + fileStream.seekp(0, std::ios::end); fileStream.put(static_cast(value)); fileStream.flush(); } diff --git a/simulator_SIC_XE/src/loader.cpp b/simulator_SIC_XE/src/loader.cpp index 9b3d293..8d3aa17 100644 --- a/simulator_SIC_XE/src/loader.cpp +++ b/simulator_SIC_XE/src/loader.cpp @@ -1,8 +1,10 @@ #include "loader.h" #include "file_reader.h" +#include "string_reader.h" #include "machine.h" #include "constants.h" #include +#include Loader::~Loader() { @@ -82,20 +84,24 @@ Loader::TextRecord Loader::readTextRecord() if(FILE_CONTAINS_WHITE_SPACES) _file_reader->readByte(); // Read length (1 byte, 2 hex digits) - int length = std::stoi(_file_reader->readString(2), nullptr, 16); - if(FILE_CONTAINS_WHITE_SPACES) _file_reader->readByte(); - + std::string lengthStr = _file_reader->readString(2); + int length = std::stoi(lengthStr, nullptr, 16); + + // Read the rest of the line (data bytes with spaces) + std::string dataLine = _file_reader->readLine(); + + // Remove all whitespace from the data line + dataLine.erase(std::remove_if(dataLine.begin(), dataLine.end(), ::isspace), dataLine.end()); + + // Now use StringReader to parse the hex bytes + StringReader stringReader(dataLine); record.data.resize(length); - - int index = 0; - string byteStr = _file_reader->readLine(); - // Remove spaces, newlines, and other whitespace characters - byteStr.erase(std::remove_if(byteStr.begin(), byteStr.end(), ::isspace), byteStr.end()); - + for (int i = 0; i < length; ++i) { - std::string byteHex = byteStr.substr(i * 2, 2); + std::string byteHex = stringReader.readString(2); record.data[i] = static_cast(std::stoi(byteHex, nullptr, 16)); } + return record; } diff --git a/simulator_SIC_XE/src/machine.cpp b/simulator_SIC_XE/src/machine.cpp index f71814d..d8d0356 100644 --- a/simulator_SIC_XE/src/machine.cpp +++ b/simulator_SIC_XE/src/machine.cpp @@ -14,6 +14,17 @@ string prefix = "Machine error: "; Machine::Machine() { + // Initialize registers and memory to zero + A = B = X = L = S = T = PC = SW = 0; + F = 0.0; + for (int i = 0; i < MEMORY_SIZE; i++) { + memory[i] = 0; + } + for (int i = 0; i < VECTOR_REG_SIZE; i++) { + VA[i] = VS[i] = VT[i] = 0; + } + _stopped = false; + devices.resize(NUM_DEVICES); // device 0: standard input devices[0] = make_shared(std::cin);