diff --git a/.gitignore b/.gitignore index 6f03a8e..7be8ac1 100644 --- a/.gitignore +++ b/.gitignore @@ -23,4 +23,3 @@ __pycache__/ *.dev autotester sictools.jar -simulator_SIC_XE/CMakeLists.txt.user diff --git a/ass2/simulator_SIC_XE/.gitignore b/ass2/simulator_SIC_XE/.gitignore deleted file mode 100644 index 4cbe372..0000000 --- a/ass2/simulator_SIC_XE/.gitignore +++ /dev/null @@ -1,95 +0,0 @@ -# Build directories -build/ -target/ - -# CMake generated files -CMakeCache.txt -CMakeFiles/ -CMakeScripts/ -cmake_install.cmake -*.cmake -!CMakeLists.txt - -# Compiled Object files -*.o -*.obj - -# Precompiled Headers -*.gch -*.pch - -# Compiled Dynamic libraries -*.so -*.dylib -*.dll - -# Fortran module files -*.mod -*.smod - -# Compiled Static libraries -*.lai -*.la -*.a -*.lib - -# Executables -*.exe -*.out -*.app - -# Debug files -*.dSYM/ -*.su -*.idb -*.pdb - -# VS Code -.vscode/ -*.code-workspace - -# CLion -.idea/ -cmake-build-*/ - -# Xcode -*.pbxuser -*.mode1v3 -*.mode2v3 -*.perspectivev3 -*.xcuserstate -project.xcworkspace/ -xcuserdata/ - -# Qt Creator -*.pro.user -*.pro.user.* -*.qbs.user -*.qbs.user.* -*.moc -*.moc.cpp -*.qm -*.prl -CMakeLists.txt.user - -# OS generated files -.DS_Store -.DS_Store? -._* -.Spotlight-V100 -.Trashes -ehthumbs.db -Thumbs.db - -# Temporary files -*~ -*.swp -*.swo -*.tmp -*.bak - -# Log files -*.log - -# Core dumps -core \ No newline at end of file diff --git a/ass2/simulator_SIC_XE/CMakeLists.txt b/ass2/simulator_SIC_XE/CMakeLists.txt deleted file mode 100644 index c6c37e1..0000000 --- a/ass2/simulator_SIC_XE/CMakeLists.txt +++ /dev/null @@ -1,60 +0,0 @@ -cmake_minimum_required(VERSION 3.10) -project(simulator_SIC_XE VERSION 1.0 LANGUAGES CXX) - -set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_STANDARD_REQUIRED ON) - -# Put all build outputs under target/bin -set(OUTPUT_DIR ${CMAKE_SOURCE_DIR}/target/bin) -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${OUTPUT_DIR}) -set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${OUTPUT_DIR}) -set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${OUTPUT_DIR}) - -# Collect all .cpp sources under src/ -file(GLOB_RECURSE SOURCES "${PROJECT_SOURCE_DIR}/src/*.cpp") - -if(NOT SOURCES) - message(WARNING "No source files found in ${PROJECT_SOURCE_DIR}/src — the build will create an empty library") -endif() - -# Build a static library from all sources -add_library(simulator_lib STATIC ${SOURCES}) -target_include_directories(simulator_lib PUBLIC ${PROJECT_SOURCE_DIR}/include) -set_target_properties(simulator_lib PROPERTIES OUTPUT_NAME "simulator") - -# If a main.cpp exists, create an executable that links the library. -if(EXISTS "${PROJECT_SOURCE_DIR}/src/main.cpp") - add_executable(simulator_exec "${PROJECT_SOURCE_DIR}/src/main.cpp") - target_link_libraries(simulator_exec PRIVATE simulator_lib) -endif() - - -if(TARGET simulator_exec) - add_custom_target(run - DEPENDS simulator_exec - COMMAND ${CMAKE_COMMAND} -E echo "Running simulator_exec..." - COMMAND $ - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - COMMENT "Builds and runs simulator_exec" - ) -endif() - -message(STATUS "Project: ${PROJECT_NAME}") -message(STATUS "Sources found: ${SOURCES}") -message(STATUS "Output directory: ${OUTPUT_DIR}") - -if(EXISTS "${CMAKE_SOURCE_DIR}/gui/qt/CMakeLists.txt") - add_subdirectory(gui/qt) -endif() - -# Copy resources directory (if present) to target/res so build output includes them -if(EXISTS "${CMAKE_SOURCE_DIR}/res") - add_custom_target(copy_resources - COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_SOURCE_DIR}/target/res - COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/res ${CMAKE_SOURCE_DIR}/target/res - COMMENT "Copying resources from res/ to target/res/" - ) - if(TARGET simulator_exec) - add_dependencies(simulator_exec copy_resources) - endif() -endif() diff --git a/ass2/simulator_SIC_XE/Makefile b/ass2/simulator_SIC_XE/Makefile deleted file mode 100644 index 93bc1f6..0000000 --- a/ass2/simulator_SIC_XE/Makefile +++ /dev/null @@ -1,68 +0,0 @@ -# Simple Makefile wrapper to configure, build and run the CMake project. -# Usage: -# make # configure + build with all cores -# make build # configure + build with all cores -# make all # clean + configure + build + run -# make run # just run the executable (no build) -# make clean # run CMake clean (or remove build files) -# make distclean # remove build dir and generated targets - -CMAKE ?= cmake -BUILD_DIR := build -CMAKE_BUILD_TYPE ?= Release -TARGET := target/bin/simulator_exec -GUI_TARGET := target/bin/simulator_qt -NPROC := $(shell nproc) - -.PHONY: all configure build run clean distclean - -# Default target: just build -default: build - -# make all: clean, build, then run -all: clean build run - -configure: - @echo "Configuring (build dir: $(BUILD_DIR), type: $(CMAKE_BUILD_TYPE))" - $(CMAKE) -S . -B $(BUILD_DIR) -DCMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE) - -build: configure - @echo "Building with $(NPROC) cores..." - $(CMAKE) --build $(BUILD_DIR) -j$(NPROC) - -# make run: just launch the executable (no build) -run: - @echo "Running primary target..." - # Prefer GUI if available, otherwise fall back to console executable - @if [ -x "$(GUI_TARGET)" ]; then \ - echo "Launching GUI: $(GUI_TARGET)"; \ - ./$(GUI_TARGET); \ - elif [ -x "$(TARGET)" ]; then \ - ./$(TARGET); \ - else \ - echo "No runnable target found (tried $(GUI_TARGET) and $(TARGET))."; exit 1; \ - fi - -.PHONY: run-gui -run-gui: build - @echo "Running GUI target ($(GUI_TARGET))" - @if [ -x "$(GUI_TARGET)" ]; then \ - echo "Starting GUI..."; ./$(GUI_TARGET) -platform xcb; \ - else \ - echo "GUI executable not found: $(GUI_TARGET)"; exit 1; \ - fi - -.PHONY: build-gui -build-gui: configure - @echo "Building GUI (and core)..." - $(CMAKE) --build $(BUILD_DIR) -j$(shell nproc) --target simulator_qt || true - -clean: - @echo "Cleaning build (CMake clean)..." - -$(CMAKE) --build $(BUILD_DIR) --target clean || true - @echo "Removing target directory..." - -rm -rf target/ - -distclean: - @echo "Removing build artifacts and generated files..." - -rm -rf $(BUILD_DIR) CMakeFiles CMakeCache.txt cmake_install.cmake target/ diff --git a/ass2/simulator_SIC_XE/README.md b/ass2/simulator_SIC_XE/README.md deleted file mode 100644 index aac6331..0000000 --- a/ass2/simulator_SIC_XE/README.md +++ /dev/null @@ -1,55 +0,0 @@ -# SIC/XE Simulator - -A complete SIC/XE architecture simulator with instruction execution, device I/O, and memory management. - -## Quick Start - -The easiest way to build and run the simulator: - -```bash -make run -``` - -This single command will: -- Configure the build system (if needed) -- Compile all source files -- Link the executable -- Run the simulator - -## Build Commands - -| Command | Description | -|--------------|----------------------------------------------------| -| `make` | Build the project | -| `make build` | Build the project | -| `make run` | Build run the simulator | -| `make clean` | Clean build artifacts | -| `make run` | Clean build artifacts, build and run the simulator | - - -## Project Structure - -``` -simulator_SIC_XE/ -├── include/ # Header files (.h) -├── src/ # Source files (.cpp) -├── target/bin/ # Build output (executables, libraries) -└── build/ # CMake build directory -``` - -## Features - -- **SIC/XE Architecture**: Complete register set (A, X, L, B, S, T, F, PC, SW) -- **Instruction Execution**: Format 1, 2, and 3/4 instruction support -- **Device I/O**: Input, output, and file device management -- **Memory Management**: 24-bit address space with proper bounds checking - -## Development - -The project uses CMake with a convenient Makefile wrapper. All build artifacts are placed in `target/bin/` for easy access. - -For manual CMake usage: -```bash -cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -cmake --build build -j -``` diff --git a/ass2/simulator_SIC_XE/gui/qt/CMakeLists.txt b/ass2/simulator_SIC_XE/gui/qt/CMakeLists.txt deleted file mode 100644 index cf8072a..0000000 --- a/ass2/simulator_SIC_XE/gui/qt/CMakeLists.txt +++ /dev/null @@ -1,54 +0,0 @@ -cmake_minimum_required(VERSION 3.16) -project(simulator_qt LANGUAGES CXX) - -set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_STANDARD_REQUIRED ON) - -set(CMAKE_AUTOMOC ON) -set(CMAKE_AUTOUIC ON) -set(CMAKE_AUTORCC ON) - -# Prefer Qt6, fall back to Qt5 -find_package(Qt6 COMPONENTS Widgets QUIET) -if(NOT Qt6_FOUND) - # Try explicitly the system Qt6 cmake prefix on Debian/Ubuntu - find_package(Qt6 COMPONENTS Widgets QUIET PATHS /usr/lib/x86_64-linux-gnu) -endif() - -if(NOT Qt6_FOUND) - # Fallback: try Qt5 if Qt6 is unavailable - find_package(Qt5 COMPONENTS Widgets QUIET) -endif() - -if(Qt6_FOUND) - set(QT_LIB Qt6::Widgets) -elseif(Qt5_FOUND) - set(QT_LIB Qt5::Widgets) -else() - message(FATAL_ERROR "Qt6 or Qt5 not found. Install Qt development packages or set CMAKE_PREFIX_PATH to your Qt installation.") -endif() - -set(GUI_SRCS - main.cpp - mainwindow.cpp - MachineController.cpp -) - -set(GUI_HDRS - mainwindow.h - MachineController.h -) - -add_executable(simulator_qt ${GUI_SRCS} ${GUI_HDRS}) - -# Allow the generated UI headers (from AUTOUIC) to be found in the build dir -# and also include the top-level include folder (works when added with add_subdirectory) -target_include_directories(simulator_qt PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_SOURCE_DIR}/include) - -# Link to core library target (must be defined by top-level CMake) -target_link_libraries(simulator_qt PRIVATE simulator_lib ${QT_LIB}) - -# Place runtime binary under repo/target/bin to match project layout -set_target_properties(simulator_qt PROPERTIES - RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/target/bin -) \ No newline at end of file diff --git a/ass2/simulator_SIC_XE/gui/qt/MachineController.cpp b/ass2/simulator_SIC_XE/gui/qt/MachineController.cpp deleted file mode 100644 index 881e97d..0000000 --- a/ass2/simulator_SIC_XE/gui/qt/MachineController.cpp +++ /dev/null @@ -1,76 +0,0 @@ -#include "MachineController.h" -#include "../../include/machine.h" -#include -#include - -using namespace std::chrono; - -MachineController::MachineController(std::shared_ptr machine, QObject *parent) - : QObject(parent), m_machine(std::move(machine)) -{ - if (!m_machine) { - m_machine = std::make_shared(); - } - m_lastUpdateTime = steady_clock::now(); -} - -MachineController::~MachineController() { - stop(); -} - -void MachineController::start() { - if (m_running.exchange(true)) return; - m_thread = std::thread([this]{ runLoop(); }); -} - -void MachineController::stop() { - if (!m_running.exchange(false)) return; - if (m_thread.joinable()) m_thread.join(); -} - -void MachineController::step() { - try { - if (m_machine) { - m_machine->execute(); - m_machine->tick(); - emit tick(); - } - } catch (const std::exception &e) { - emit error(QString::fromStdString(e.what())); - } -} - -void MachineController::runLoop() { - const auto minUpdateInterval = milliseconds(16); - - while (m_running.load()) { - try { - if (m_machine) { - m_machine->execute(); - m_machine->tick(); - m_ticksSinceLastUpdate++; - - // Throttle GUI updates to 60 Hz - auto now = steady_clock::now(); - auto elapsed = duration_cast(now - m_lastUpdateTime); - - if (elapsed >= minUpdateInterval) { - emit tick(); - m_lastUpdateTime = now; - m_ticksSinceLastUpdate = 0; - } - - if (m_machine->isStopped()) { - emit tick(); - m_running.store(false); - break; - } - } - } catch (const std::exception &e) { - emit error(QString::fromStdString(e.what())); - // Stop on fatal error - m_running.store(false); - break; - } - } -} diff --git a/ass2/simulator_SIC_XE/gui/qt/MachineController.h b/ass2/simulator_SIC_XE/gui/qt/MachineController.h deleted file mode 100644 index 801b5f4..0000000 --- a/ass2/simulator_SIC_XE/gui/qt/MachineController.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef MACHINECONTROLLER_H -#define MACHINECONTROLLER_H - -#include -#include -#include -#include - -class Machine; - -class MachineController : public QObject { - Q_OBJECT -public: - explicit MachineController(std::shared_ptr machine = nullptr, QObject *parent = nullptr); - ~MachineController() override; - - void start(); - void stop(); - void step(); - -signals: - void tick(); - void error(const QString &msg); - -private: - void runLoop(); - std::atomic m_running{false}; - std::thread m_thread; - std::shared_ptr m_machine; - std::atomic m_ticksSinceLastUpdate{0}; - std::chrono::steady_clock::time_point m_lastUpdateTime; -}; - -#endif // MACHINECONTROLLER_H diff --git a/ass2/simulator_SIC_XE/gui/qt/main.cpp b/ass2/simulator_SIC_XE/gui/qt/main.cpp deleted file mode 100644 index 707d916..0000000 --- a/ass2/simulator_SIC_XE/gui/qt/main.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include -#include "mainwindow.h" -#include "../../include/opcode.h" - -int main(int argc, char **argv) { - loadInstructionSet(); - - qputenv("QT_QPA_PLATFORM", "xcb"); - - QApplication app(argc, argv); - MainWindow w; - w.show(); - return app.exec(); -} \ No newline at end of file diff --git a/ass2/simulator_SIC_XE/gui/qt/mainwindow.cpp b/ass2/simulator_SIC_XE/gui/qt/mainwindow.cpp deleted file mode 100644 index b53aa72..0000000 --- a/ass2/simulator_SIC_XE/gui/qt/mainwindow.cpp +++ /dev/null @@ -1,1030 +0,0 @@ -#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 -#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, Qt::QueuedConnection); - connect(m_controller.get(), &MachineController::tick, this, &MainWindow::updateMemoryDisplay, Qt::QueuedConnection); - - 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, Qt::QueuedConnection); - - // Connect menu actions - connect(ui->actionLoad_Object_File, &QAction::triggered, this, &MainWindow::loadObjectFile); - connect(ui->actionAbout, &QAction::triggered, this, &MainWindow::showAboutDialog); - connect(ui->actionFrequency, &QAction::triggered, this, &MainWindow::showFrequencyDialog); - - setupMemoryDisplay(); - setupDisassemblyDisplay(); - - loadInstructionSet(); - // Don't load any program by default - user will load via File menu - - 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] : "?"; - - // 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; - } - - 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 += (address + 3); - 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); - - // 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() -{ - 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); - - int scrollPos = ui->MemoryScrollArea->verticalScrollBar()->value(); - - ui->MemoryScrollArea->setWidget(container); - - ui->MemoryScrollArea->verticalScrollBar()->setValue(scrollPos); -} - -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())); - } -} - -void MainWindow::showAboutDialog() -{ - QMessageBox::about(this, tr("About SIC/XE Simulator"), - tr("SIC/XE Simulator\nby Zan Skvarca\n2025")); -} - -void MainWindow::showFrequencyDialog() -{ - if (!m_machine) return; - - QDialog dialog(this); - dialog.setWindowTitle(tr("Set Frequency")); - dialog.setModal(true); - - QVBoxLayout *layout = new QVBoxLayout(&dialog); - - QLabel *currentLabel = new QLabel(tr("Current frequency: %1 Hz").arg(m_machine->getSpeed()), &dialog); - layout->addWidget(currentLabel); - - QLabel *newLabel = new QLabel(tr("New frequency (Hz):"), &dialog); - layout->addWidget(newLabel); - - QLineEdit *freqInput = new QLineEdit(&dialog); - freqInput->setValidator(new QIntValidator(1, 1000000000, &dialog)); - freqInput->setText(QString::number(m_machine->getSpeed())); - layout->addWidget(freqInput); - - QHBoxLayout *buttonLayout = new QHBoxLayout(); - QPushButton *submitBtn = new QPushButton(tr("Submit"), &dialog); - QPushButton *cancelBtn = new QPushButton(tr("Cancel"), &dialog); - buttonLayout->addWidget(submitBtn); - buttonLayout->addWidget(cancelBtn); - layout->addLayout(buttonLayout); - - connect(submitBtn, &QPushButton::clicked, &dialog, &QDialog::accept); - connect(cancelBtn, &QPushButton::clicked, &dialog, &QDialog::reject); - - if (dialog.exec() == QDialog::Accepted) { - bool ok; - int newFreq = freqInput->text().toInt(&ok); - if (ok && newFreq > 0) { - m_machine->setSpeed(newFreq); - QMessageBox::information(this, tr("Success"), - tr("Frequency set to %1 Hz").arg(newFreq)); - } - } -} diff --git a/ass2/simulator_SIC_XE/gui/qt/mainwindow.h b/ass2/simulator_SIC_XE/gui/qt/mainwindow.h deleted file mode 100644 index 2dba671..0000000 --- a/ass2/simulator_SIC_XE/gui/qt/mainwindow.h +++ /dev/null @@ -1,85 +0,0 @@ -#ifndef MAINWINDOW_H -#define MAINWINDOW_H - -#include -#include - -class MachineController; -class Machine; -class QLineEdit; - -namespace Ui { -class MainWindow; -} - -class MainWindow : public QMainWindow -{ - Q_OBJECT - -public: - explicit MainWindow(QWidget *parent = nullptr); - ~MainWindow(); - - std::shared_ptr machine() const { return m_machine; } - MachineController* controller() const { return m_controller.get(); } - - void startExecution(); - void stopExecution(); - void stepExecution(); - - void setTestRegisterValues(); - -private slots: - void updateRegisterDisplays(); - void updateMemoryDisplay(); - void updateDisassemblyDisplay(); - void onRegisterFieldChanged(); - void onMemoryInc256(); - void onMemoryInc4096(); - void onMemoryInc65536(); - 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(); - void loadObjectFile(); - void showAboutDialog(); - void showFrequencyDialog(); - -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); - void updateAllFormatsForRegister(const QString& regPrefix, int value); - void updateFloatRegisterFormats(const QString& regPrefix, double value); - 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/ass2/simulator_SIC_XE/gui/qt/mainwindow.ui b/ass2/simulator_SIC_XE/gui/qt/mainwindow.ui deleted file mode 100644 index e9084bd..0000000 --- a/ass2/simulator_SIC_XE/gui/qt/mainwindow.ui +++ /dev/null @@ -1,930 +0,0 @@ - - - MainWindow - - - - 0 - 0 - 1172 - 649 - - - - MainWindow - - - - - - 10 - 0 - 431 - 601 - - - - - - 0 - 80 - 431 - 321 - - - - Register values - - - - - 70 - 40 - 113 - 23 - - - - - - - 10 - 40 - 57 - 20 - - - - - 10 - - - - Reg A - - - - - - 190 - 40 - 113 - 23 - - - - - - - 310 - 40 - 113 - 23 - - - - - - - 110 - 20 - 57 - 20 - - - - - 10 - - - - Bin - - - - - - 230 - 20 - 57 - 20 - - - - - 10 - - - - Hex - - - - - - 350 - 20 - 57 - 20 - - - - - 10 - - - - Dec - - - - - - 310 - 70 - 113 - 23 - - - - - - - 10 - 70 - 57 - 20 - - - - - 10 - - - - Reg B - - - - - - 190 - 70 - 113 - 23 - - - - - - - 70 - 70 - 113 - 23 - - - - - - - 310 - 100 - 113 - 23 - - - - - - - 10 - 100 - 57 - 20 - - - - - 10 - - - - Reg X - - - - - - 190 - 100 - 113 - 23 - - - - - - - 70 - 100 - 113 - 23 - - - - - - - 310 - 130 - 113 - 23 - - - - - - - 10 - 130 - 57 - 20 - - - - - 10 - - - - Reg S - - - - - - 190 - 130 - 113 - 23 - - - - - - - 70 - 130 - 113 - 23 - - - - - - - 310 - 160 - 113 - 23 - - - - - - - 10 - 160 - 57 - 20 - - - - - 10 - - - - Reg T - - - - - - 190 - 160 - 113 - 23 - - - - - - - 70 - 160 - 113 - 23 - - - - - - - 190 - 190 - 113 - 23 - - - - - - - 70 - 190 - 113 - 23 - - - - - - - 10 - 190 - 57 - 20 - - - - - 10 - - - - Reg L - - - - - - 310 - 190 - 113 - 23 - - - - - - - 10 - 220 - 57 - 20 - - - - - 10 - - - - Reg PC - - - - - - 310 - 220 - 113 - 23 - - - - - - - 70 - 220 - 113 - 23 - - - - - - - 190 - 220 - 113 - 23 - - - - - - - 10 - 249 - 57 - 20 - - - - - 10 - - - - Reg SW - - - - - - 310 - 249 - 113 - 23 - - - - - - - 70 - 249 - 113 - 23 - - - - - - - 190 - 249 - 113 - 23 - - - - - - - 10 - 280 - 57 - 20 - - - - - 10 - - - - Reg L - - - - - - 310 - 280 - 113 - 23 - - - - - - - 70 - 280 - 113 - 23 - - - - - - - 190 - 280 - 113 - 23 - - - - - - - - 0 - 0 - 431 - 81 - - - - Control - - - - - 30 - 40 - 80 - 23 - - - - Start - - - - - - 170 - 40 - 80 - 23 - - - - Stop - - - - - - 310 - 40 - 80 - 23 - - - - Step - - - - - - - - 450 - 0 - 721 - 601 - - - - - - 0 - 0 - 711 - 291 - - - - Memory - - - - - 0 - 20 - 711 - 221 - - - - true - - - - - 0 - 0 - 709 - 219 - - - - - - - - 450 - 250 - 71 - 23 - - - - >> - - - - - - 370 - 250 - 71 - 23 - - - - > - - - - - - 530 - 250 - 71 - 23 - - - - >>> - - - - - - 290 - 250 - 71 - 23 - - - - < - - - - - - 210 - 250 - 71 - 23 - - - - << - - - - - - 130 - 250 - 71 - 21 - - - - <<< - - - - - - 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 - - - - | - - - - - - - - - toolBar - - - TopToolBarArea - - - false - - - - - - 0 - 0 - 1172 - 20 - - - - - File - - - - - - Machine - - - - - - Help - - - - - - - - - - Load Object File - - - - - Frequency - - - - - About - - - - - - diff --git a/ass2/simulator_SIC_XE/include/constants.h b/ass2/simulator_SIC_XE/include/constants.h deleted file mode 100644 index 6f2195a..0000000 --- a/ass2/simulator_SIC_XE/include/constants.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef CONSTANTS_H -#define CONSTANTS_H - -#include -// ============================== -// SIC/XE Architecture Constants -// ============================== - -// Memory and system constants -constexpr int MEMORY_SIZE = 1 << 20; // 1 MB memory -constexpr int NUM_DEVICES = 256; -constexpr int WORD_SIZE = 24; -constexpr int WORD_MASK = 0xFFFFFF; - -// SIC/XE floating point constants -constexpr int SICF_BITS = 48; -constexpr int SICF_FRAC_BITS = 40; -constexpr int SICF_EXP_BITS = 7; -constexpr int SICF_EXP_BIAS = 64; -constexpr unsigned long long SICF_FRAC_MASK = (1ULL << SICF_FRAC_BITS) - 1; - -// SW register condition codes -constexpr int CC_LT = 0x0; // 00 -constexpr int CC_EQ = 0x1; // 01 -constexpr int CC_GT = 0x2; // 10 -constexpr int CC_MASK = 0x3; // mask for 2 bits - -// Instruction format bit masks -constexpr int TYPE3_4_SIC_MASK = 0xFC; -constexpr int NI_MASK = 0x03; // mask for n and i bits -constexpr int NI_SIC = 0x0; - -constexpr int BP_BASE_REL_MASK = 0b10; -constexpr int BP_PC_REL_MASK = 0b01; -constexpr int BP_DIRECT_MASK = 0b00; - -constexpr int BIT_E_MASK = 0x10; // mask for e bit in F4 and F3 instructions - -//SIC/XE/XE -constexpr bool USE_EXTENDED_MODE = true; -constexpr int VECTOR_REG_SIZE = 4; - -/* if structure is -/target/ - |-> bin/simulator_exec - |-> res/ -*/ -// When running from project root (./target/bin/simulator_exec), resources are in ./target/res/ -constexpr char PATH_RESOURCES[] = "./target/res/"; -constexpr bool FILE_CONTAINS_WHITE_SPACES = true; - -#endif // CONSTANTS_H \ No newline at end of file diff --git a/ass2/simulator_SIC_XE/include/device.h b/ass2/simulator_SIC_XE/include/device.h deleted file mode 100644 index 6b5acb7..0000000 --- a/ass2/simulator_SIC_XE/include/device.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef DEVICE_H -#define DEVICE_H - - -class Device { -public: - Device(); - - bool test(); - virtual unsigned char read(); - virtual void write(unsigned char value); -}; - - - -#endif // DEVICE_H \ No newline at end of file diff --git a/ass2/simulator_SIC_XE/include/file_device.h b/ass2/simulator_SIC_XE/include/file_device.h deleted file mode 100644 index 01b433c..0000000 --- a/ass2/simulator_SIC_XE/include/file_device.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef FILE_DEVICE_H -#define FILE_DEVICE_H - -#include "device.h" -#include -#include - -class FileDevice : public Device { -public: - explicit FileDevice(const std::string &filename); - ~FileDevice(); - unsigned char read() override; - void write(unsigned char value) override; - -private: - void ensureFileOpen(); - std::fstream fileStream; - std::string filename; - bool fileCreated; - std::streampos readPosition; -}; - -#endif // FILE_DEVICE_H \ No newline at end of file diff --git a/ass2/simulator_SIC_XE/include/file_reader.h b/ass2/simulator_SIC_XE/include/file_reader.h deleted file mode 100644 index 87b8a17..0000000 --- a/ass2/simulator_SIC_XE/include/file_reader.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef FILE_READER_H -#define FILE_READER_H - -#include "reader.h" -#include -#include - -class FileReader : public Reader { -public: - explicit FileReader(const std::string &path, std::ios::openmode m = std::ios::binary); - ~FileReader() override; - - int readByte() override; - - bool readBytes(uint8_t* buf, size_t len) override; - std::string readString(size_t len) override; - std::string readLine() override; - - bool good() const; - -private: - std::ifstream in; -}; - -#endif // FILE_READER_H \ No newline at end of file diff --git a/ass2/simulator_SIC_XE/include/input_device.h b/ass2/simulator_SIC_XE/include/input_device.h deleted file mode 100644 index 40b01d3..0000000 --- a/ass2/simulator_SIC_XE/include/input_device.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef INPUT_DEVICE_H -#define INPUT_DEVICE_H - -#include "device.h" -#include - -class InputDevice : public Device { -public: - explicit InputDevice(std::istream &in); - ~InputDevice(); - - unsigned char read(); - -private: - std::istream &inStream; -}; - -#endif // INPUT_DEVICE_H \ No newline at end of file diff --git a/ass2/simulator_SIC_XE/include/instructions.h b/ass2/simulator_SIC_XE/include/instructions.h deleted file mode 100644 index 5bef303..0000000 --- a/ass2/simulator_SIC_XE/include/instructions.h +++ /dev/null @@ -1,101 +0,0 @@ -#ifndef INSTRUCTIONS_H -#define INSTRUCTIONS_H - -#include "utils.h" - -class Machine; // forward declaration - -// Type 1 instruction handlers -void fix_handler(Machine& m); -void float_handler(Machine& m); -void hio_handler(Machine& m); -void norm_handler(Machine& m); -void sio_handler(Machine& m); -void tio_handler(Machine& m); -void nop_handler(Machine& m); - -/* IDEJE ZA SIC_XE_XE :)*/ -// void nop(Machine& m); - -// Type 2 instruction handlers -void addr_handler(Machine& m, int r1, int r2); -void clear_handler(Machine& m, int r, int unused); -void compr_handler(Machine& m, int r1, int r2); -void divr_handler(Machine& m, int r1, int r2); -void mulr_handler(Machine& m, int r1, int r2); -void rmo_handler(Machine& m, int r1, int r2); -void shiftl_handler(Machine& m, int r1, int n); -void shiftr_handler(Machine& m, int r1, int n); -void subr_handler(Machine& m, int r1, int r2); -void svc_handler(Machine& m, int n, int unused); -void tixr_handler(Machine& m, int r1, int unused); - - -// Type 3/4 instruction handlers -void add_handler(Machine& m, int ea, AddressingMode mode); -void addf_handler(Machine& m, int ea, AddressingMode mode); -void and_handler(Machine& m, int ea, AddressingMode mode); -void comp_handler(Machine& m, int ea, AddressingMode mode); -void compf_handler(Machine& m, int ea, AddressingMode mode); -void div_handler(Machine& m, int ea, AddressingMode mode); -void divf_handler(Machine& m, int ea, AddressingMode mode); -void j_handler(Machine& m, int ea, AddressingMode mode); -void jeq_handler(Machine& m, int ea, AddressingMode mode); -void jgt_handler(Machine& m, int ea, AddressingMode mode); -void jlt_handler(Machine& m, int ea, AddressingMode mode); -void jsub_handler(Machine& m, int ea, AddressingMode mode); -void lda_handler(Machine& m, int ea, AddressingMode mode); -void ldb_handler(Machine& m, int ea, AddressingMode mode); -void ldch_handler(Machine& m, int ea, AddressingMode mode); -void ldf_handler(Machine& m, int ea, AddressingMode mode); -void ldl_handler(Machine& m, int ea, AddressingMode mode); -void lds_handler(Machine& m, int ea, AddressingMode mode); -void ldt_handler(Machine& m, int ea, AddressingMode mode); -void ldx_handler(Machine& m, int ea, AddressingMode mode); -void lps_handler(Machine& m, int ea, AddressingMode mode); -void mul_handler(Machine& m, int ea, AddressingMode mode); -void mulf_handler(Machine& m, int ea, AddressingMode mode); -void or_handler(Machine& m, int ea, AddressingMode mode); -void rd_handler(Machine& m, int ea, AddressingMode mode); -void rsub_handler(Machine& m, int ea, AddressingMode mode); -void ssk_handler(Machine& m, int ea, AddressingMode mode); -void sta_handler(Machine& m, int ea, AddressingMode mode); -void stb_handler(Machine& m, int ea, AddressingMode mode); -void stch_handler(Machine& m, int ea, AddressingMode mode); -void stf_handler(Machine& m, int ea, AddressingMode mode); -void sti_handler(Machine& m, int ea, AddressingMode mode); -void stl_handler(Machine& m, int ea, AddressingMode mode); -void sts_handler(Machine& m, int ea, AddressingMode mode); -void stsw_handler(Machine& m, int ea, AddressingMode mode); -void stt_handler(Machine& m, int ea, AddressingMode mode); -void stx_handler(Machine& m, int ea, AddressingMode mode); -void sub_handler(Machine& m, int ea, AddressingMode mode); -void subf_handler(Machine& m, int ea, AddressingMode mode); -void td_handler(Machine& m, int ea, AddressingMode mode); -void tix_handler(Machine& m, int ea, AddressingMode mode); -void wd_handler(Machine& m, int ea, AddressingMode mode); - - -// SIC/XE/XE Extended instruction handlers -void xexe_handler(Machine& m); -void halt_handler(Machine& m); -void nop_handler(Machine& m); - -void vaddr_handler(Machine& m, int r1, int r2); -void vsubr_handler(Machine& m, int r1, int r2); -void vmulr_handler(Machine& m, int r1, int r2); -void vdivr_handler(Machine& m, int r1, int r2); - -void vadd_handler(Machine& m, int ea, AddressingMode mode); -void vsub_handler(Machine& m, int ea, AddressingMode mode); -void vmul_handler(Machine& m, int ea, AddressingMode mode); -void vdiv_handler(Machine& m, int ea, AddressingMode mode); -void stva_handler(Machine& m, int ea, AddressingMode mode); -void stvs_handler(Machine& m, int ea, AddressingMode mode); -void stvt_handler(Machine& m, int ea, AddressingMode mode); -void ldva_handler(Machine& m, int ea, AddressingMode mode); -void ldvs_handler(Machine& m, int ea, AddressingMode mode); -void ldvt_handler(Machine& m, int ea, AddressingMode mode); - - -#endif // INSTRUCTIONS_H \ No newline at end of file diff --git a/ass2/simulator_SIC_XE/include/loader.h b/ass2/simulator_SIC_XE/include/loader.h deleted file mode 100644 index 41899c2..0000000 --- a/ass2/simulator_SIC_XE/include/loader.h +++ /dev/null @@ -1,68 +0,0 @@ -#ifndef LOADER_H -#define LOADER_H - -#include -#include -#include -#include "file_reader.h" -#include - -class Machine; - -using std::shared_ptr; -using std::string; - - -class Loader { -public: - Loader( shared_ptr machine, string filename) : _machine(machine), _filename(filename) { - _file_reader = std::make_shared(filename, std::ios::in); - if (!_file_reader->good()) { - throw std::runtime_error("Loader: failed to open file: " + filename); - } - } - ~Loader(); - - - enum class RecordType { - HEADER, - TEXT, - END, - UNKNOWN - }; - - struct HeaderMetadata { - string program_name; - int start_address; - int length; - }; - struct TextRecord { - int start_address; - std::vector data; - }; - struct EndRecord { - int execution_start_address; - }; - - void load(); - -private : - - static RecordType parseRecordType(char c); - - - shared_ptr _machine; - string _filename; - shared_ptr _file_reader; - HeaderMetadata readHeader(); - TextRecord readTextRecord(); - EndRecord readEndRecord(); - bool load_into_memory(int start_address, const std::vector& data); - -}; - - - - - -#endif // LOADER_H \ No newline at end of file diff --git a/ass2/simulator_SIC_XE/include/machine.h b/ass2/simulator_SIC_XE/include/machine.h deleted file mode 100644 index cd14f74..0000000 --- a/ass2/simulator_SIC_XE/include/machine.h +++ /dev/null @@ -1,149 +0,0 @@ -#ifndef MACHINE_H -#define MACHINE_H - -#include -#include -#include -#include -#include -#include - - -#include "constants.h" -#include "device.h" -#include "input_device.h" -#include "output_device.h" -#include "file_device.h" -#include "opcode.h" -#include "utils.h" - -using std::string; -using std::cerr; -using std::endl; -using std::cout; - - -class Machine { -public: - Machine(); - Machine(int speedHz) : Machine() { this->speedHz = speedHz; _instructionsTable = instructions; } - ~Machine(); - - int getA() const { return A; } - void setA(int value) { A = toSIC24(value); } - - int getB() const { return B; } - void setB(int value) { B = toSIC24(value); } - - int getX() const { return X; } - void setX(int value) { X = toSIC24(value); } - - int getL() const { return L; } - void setL(int value) { L = toSIC24(value); } - - int getS() const { return S; } - void setS(int value) { S = toSIC24(value); } - - int getT() const { return T; } - void setT(int value) { T = toSIC24(value); } - - // PC is an address → don't mask to 24 unless you want 24-bit addressing - int getPC() const { return PC; } - void setPC(int value) { PC = value; } - - // status word: keep as-is - int getSW() const { return SW; } - void setSW(int value) { SW = value; } - - double getF() const { return F; } - void setF(double value) { F = value; } - - int getReg(int regNum) const; - void setReg(int regNum, int value); - - // Memory access methods - int getByte(int address); - void setByte(int address, int value); - - int getWord(int address); - void setWord(int address, int value); - - double getFloat(int address); - void setFloat(int address, double value); - - - // Device access methods - Device& getDevice(int num); - void setDevice(int num, std::shared_ptr device); - // Set a file device at index `num` using the provided filename. - void setFileDevice(int num, const std::string &filename); - - // Fetch and execute instructions - int fetch(); - void execute(); - - // Execution and speed control - int getSpeed() const; - 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); - void invalidOpcode(int opcode); - void invalidAddressing(); - void divisionByZero(int opcode); - void undefinedHandler(int opcode); - - bool getExtendedMode() const { return _exex_mode; } - void enableExtendedMode(); - void disableExtendedMode(); - - - int* getVectorRegister(int regNum); - void setVectorRegister(int regNum, const int* values); - - const int* getVA() const { return VA; } - const int* getVS() const { return VS; } - const int* getVT() const { return VT; } - void setVA(const int* values); - void setVS(const int* values); - void setVT(const int* values); - - -private: - // registers - int A, B, X, L, S, T, PC, SW; - double F; - - // memory - unsigned char memory[MEMORY_SIZE]; - - // devices - std::vector> devices; - // fallback device returned when device slot is empty/invalid - Device fallbackDevice; - - // Execution control - std::atomic running{false}; - std::atomic speedHz{10}; // Default 10 Hz - - bool execF1(int opcode); - bool execF2(int opcode, int operand); - bool execSICF3F4(int opcode, int ni, int x, int b, int p, int e, int operand); - - - // Extended mode - bool _stopped{false}; - bool _exex_mode{false}; - InstructionInfo* _instructionsTable; - int VA[VECTOR_REG_SIZE], VS[VECTOR_REG_SIZE], VT[VECTOR_REG_SIZE]; // vector operation registers -}; - - - -#endif // MACHINE_H \ No newline at end of file diff --git a/ass2/simulator_SIC_XE/include/opcode.h b/ass2/simulator_SIC_XE/include/opcode.h deleted file mode 100644 index a467488..0000000 --- a/ass2/simulator_SIC_XE/include/opcode.h +++ /dev/null @@ -1,116 +0,0 @@ -#ifndef OPCODE_H -#define OPCODE_H - -#include "utils.h" - -// ============================== -// Opcode definitions (SIC/XE) -// ============================== -#define ADD 0x18 -#define ADDF 0x58 -#define ADDR 0x90 -#define AND 0x40 -#define CLEAR 0xB4 -#define COMP 0x28 -#define COMPF 0x88 -#define COMPR 0xA0 -#define DIV 0x24 -#define DIVF 0x64 -#define DIVR 0x9C -#define FIX 0xC4 -#define FLOAT 0xC0 -#define HIO 0xF4 -#define J 0x3C -#define JEQ 0x30 -#define JGT 0x34 -#define JLT 0x38 -#define JSUB 0x48 -#define LDA 0x00 -#define LDB 0x68 -#define LDCH 0x50 -#define LDF 0x70 -#define LDL 0x08 -#define LDS 0x6C -#define LDT 0x74 -#define LDX 0x04 -#define LPS 0xD0 -#define MUL 0x20 -#define MULF 0x60 -#define MULR 0x98 -#define NORM 0xC8 -#define OR 0x44 -#define RD 0xD8 -#define RMO 0xAC -#define RSUB 0x4C -#define SHIFTL 0xA4 -#define SHIFTR 0xA8 -#define SIO 0xF0 -#define SSK 0xEC -#define STA 0x0C -#define STB 0x78 -#define STCH 0x54 -#define STF 0x80 -#define STI 0xD4 -#define STL 0x14 -#define STS 0x7C -#define STSW 0xE8 -#define STT 0x84 -#define STX 0x10 -#define SUB 0x1C -#define SUBF 0x5C -#define SUBR 0x94 -#define SVC 0xB0 -#define TD 0xE0 -#define TIO 0xF8 -#define TIX 0x2C -#define TIXR 0xB8 -#define WD 0xDC - -// ============================== -// Extended opcodes (SIC/XE/XE) -// ============================== -#define NOP 0xF1 -#define HALT 0xF2 -#define XEXE 0xEE // Enable extended mode -#define VADD 0x18 -#define VADDR 0x90 -#define VSUB 0x1C -#define VSUBR 0x94 -#define VMUL 0x20 -#define VMULR 0x98 -#define VDIV 0x24 -#define VDIVR 0x9C -#define STVA 0x0C -#define STVS 0x7C -#define STVT 0x84 -#define LDVA 0x00 -#define LDVS 0x68 -#define LDVT 0x04 - - - -enum class InstructionType { - TYPE1, - TYPE2, - TYPE3_4, - INVALID -}; - -class Machine; // forward - -// Store raw function pointer (void*) to allow different handler signatures -using RawHandler = void*; - -struct InstructionInfo { - const char* name; - InstructionType type; - RawHandler handler; -}; - -extern InstructionInfo instructions[]; -extern InstructionInfo instructionsEXEX[]; - -// Initialize the instruction table -void loadInstructionSet(); - -#endif // OPCODE_H diff --git a/ass2/simulator_SIC_XE/include/output_device.h b/ass2/simulator_SIC_XE/include/output_device.h deleted file mode 100644 index 94ba8b8..0000000 --- a/ass2/simulator_SIC_XE/include/output_device.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef OUTPUT_DEVICE_H -#define OUTPUT_DEVICE_H - -#include "device.h" -#include - -class OutputDevice : public Device { -public: - explicit OutputDevice(std::ostream &out); - ~OutputDevice(); - - void write(unsigned char value) override; - -private: - std::ostream &outStream; -}; - -#endif // OUTPUT_DEVICE_H \ No newline at end of file diff --git a/ass2/simulator_SIC_XE/include/reader.h b/ass2/simulator_SIC_XE/include/reader.h deleted file mode 100644 index e582161..0000000 --- a/ass2/simulator_SIC_XE/include/reader.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef READER_H -#define READER_H - -#include -#include - -// Abstract Reader class: read bytes/strings from a source (file, string, etc.) -class Reader { -public: - virtual ~Reader() = default; - // return 0..255 on success, -1 on EOF/error - virtual int readByte() = 0; - // read exactly len bytes into buf; return true on success - virtual bool readBytes(uint8_t* buf, size_t len) = 0; - // read up to len bytes into a std::string; may return shorter string on EOF - virtual std::string readString(size_t len) = 0; - // read a line (up to newline), return empty string on EOF - virtual std::string readLine() = 0; -}; - -#endif // READER_H \ No newline at end of file diff --git a/ass2/simulator_SIC_XE/include/string_reader.h b/ass2/simulator_SIC_XE/include/string_reader.h deleted file mode 100644 index 71c3da9..0000000 --- a/ass2/simulator_SIC_XE/include/string_reader.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef STRING_READER_H -#define STRING_READER_H - -#include "reader.h" -#include -#include - -class StringReader : public Reader { -public: - explicit StringReader(const std::string &s); - ~StringReader() override; - - int readByte() override; - bool readBytes(uint8_t* buf, size_t len) override; - std::string readString(size_t len) override; - std::string readLine() override; - -private: - std::istringstream in; -}; - -#endif // STRING_READER_H \ No newline at end of file diff --git a/ass2/simulator_SIC_XE/include/utils.h b/ass2/simulator_SIC_XE/include/utils.h deleted file mode 100644 index 3197a95..0000000 --- a/ass2/simulator_SIC_XE/include/utils.h +++ /dev/null @@ -1,95 +0,0 @@ -#ifndef UTILS_H -#define UTILS_H - -#include "constants.h" - -#include - -// ============================== -// SIC/XE Utility Functions -// ============================== - -// Instruction bit extraction utilities -inline int getXBit(int b2) { - return (b2 & 0x80) ? 1 : 0; -} - -inline int getBPBits(int b2) { - return (b2 >> 5) & 0x03; -} - -enum class AddressingMode { - IMMEDIATE, - INDIRECT, - SIMPLE, - SIC_DIRECT, - INVALID -}; - -// Get addressing mode from ni bits -AddressingMode getAddressingMode(int ni); - - -// convert to signed 24-bit integer -inline int toSIC24(int value) { - value &= 0xFFFFFF; - if (value & 0x800000) { - value -= 0x1000000; - } - return value; -} - -inline int setCC(int sw, int cc) { - sw &= ~CC_MASK; - sw |= (cc & CC_MASK); - return sw; -} - -inline int sic_comp(int a, int b, int sw) { - int sa = toSIC24(a); - int sb = toSIC24(b); - - int cc; - if (sa < sb) { - cc = CC_LT; - } else if (sa == sb) { - cc = CC_EQ; - } else { - cc = CC_GT; - } - - return setCC(sw, cc); -} - -inline int sic_comp(double a, double b, int sw) { - int cc; - if (a < b) { - cc = CC_LT; - } else if (a == b) { - cc = CC_EQ; - } else { - cc = CC_GT; - } - - return setCC(sw, cc); -} - - -inline int getCC(int sw) { - return sw & CC_MASK; -} - -inline double normaliseFloat(double value) -{ - if (value == 0.0 )return 0.0; - if (!std::isfinite(value)) return value; - double mantissa = value; - while (std::fabs(mantissa) >= 10.0) mantissa /= 10.0; - while (std::fabs(mantissa) < 1.0) mantissa *= 10.0; - return mantissa; -} - - - - -#endif // UTILS_H \ No newline at end of file diff --git a/ass2/simulator_SIC_XE/src/device.cpp b/ass2/simulator_SIC_XE/src/device.cpp deleted file mode 100644 index 87ab0d7..0000000 --- a/ass2/simulator_SIC_XE/src/device.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "device.h" - -Device::Device() -{ -} - -bool Device::test() -{ - return true; -} - -unsigned char Device::read() -{ - return 0; -} - -void Device::write(unsigned char value) -{ -} diff --git a/ass2/simulator_SIC_XE/src/file_device.cpp b/ass2/simulator_SIC_XE/src/file_device.cpp deleted file mode 100644 index 781a9b6..0000000 --- a/ass2/simulator_SIC_XE/src/file_device.cpp +++ /dev/null @@ -1,68 +0,0 @@ -#include "file_device.h" -#include -#include - -FileDevice::FileDevice(const std::string &filename) - : filename(filename), fileCreated(false), readPosition(0) -{ -} - -FileDevice::~FileDevice() -{ - if (fileStream.is_open()) { - fileStream.close(); - } -} - -void FileDevice::ensureFileOpen() -{ - if (!fileStream.is_open()) { - // 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); - } - create.close(); - fileCreated = true; - - fileStream.open(filename, std::ios::in | std::ios::out); - if (!fileStream.is_open()) { - throw std::runtime_error("Failed to open file after creating: " + filename); - } - } - } -} - -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; -} - -void FileDevice::write(unsigned char value) -{ - ensureFileOpen(); - if (fileStream.is_open()) { - fileStream.seekp(0, std::ios::end); - fileStream.put(static_cast(value)); - fileStream.flush(); - } -} \ No newline at end of file diff --git a/ass2/simulator_SIC_XE/src/file_reader.cpp b/ass2/simulator_SIC_XE/src/file_reader.cpp deleted file mode 100644 index 2a800cc..0000000 --- a/ass2/simulator_SIC_XE/src/file_reader.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include "file_reader.h" - -FileReader::FileReader(const std::string &path, std::ios::openmode m) - : in(path, m) -{} - -FileReader::~FileReader() = default; - -int FileReader::readByte() { - char c; - if (!in.get(c)) return -1; - return static_cast(c); -} - - -bool FileReader::readBytes(uint8_t* buf, size_t len) { - in.read(reinterpret_cast(buf), static_cast(len)); - return static_cast(in.gcount()) == len; -} - -std::string FileReader::readString(size_t len) { - std::string s; - s.resize(len); - in.read(reinterpret_cast(&s[0]), static_cast(len)); - std::streamsize got = in.gcount(); - if (static_cast(got) < len) s.resize(static_cast(got)); - return s; -} - -bool FileReader::good() const { return static_cast(in); } - -std::string FileReader::readLine() { - std::string s; - if (!std::getline(in, s)) return std::string(); - return s; -} diff --git a/ass2/simulator_SIC_XE/src/input_device.cpp b/ass2/simulator_SIC_XE/src/input_device.cpp deleted file mode 100644 index 340c721..0000000 --- a/ass2/simulator_SIC_XE/src/input_device.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "input_device.h" - -InputDevice::InputDevice(std::istream &in) - : inStream(in) -{ -} - -InputDevice::~InputDevice() -{ -} - -unsigned char InputDevice::read() -{ - char c; - if (!inStream.get(c)) { - // If stream is at EOF or error, return 0 - return 0; - } - return static_cast(c); -} \ No newline at end of file diff --git a/ass2/simulator_SIC_XE/src/instructions.cpp b/ass2/simulator_SIC_XE/src/instructions.cpp deleted file mode 100644 index a1c4e55..0000000 --- a/ass2/simulator_SIC_XE/src/instructions.cpp +++ /dev/null @@ -1,603 +0,0 @@ -#include "instructions.h" -#include "machine.h" -#include "utils.h" - -inline int resolveWordOperand(Machine& m, int ea, AddressingMode mode) -{ - switch (mode) - { - case AddressingMode::IMMEDIATE: return ea; - case AddressingMode::SIMPLE: - case AddressingMode::SIC_DIRECT: return m.getWord(ea); - case AddressingMode::INDIRECT: return m.getWord(m.getWord(ea)); - default: m.invalidAddressing(); return 0; - } -} - -inline double resolveFloatOperand(Machine& m, int ea, AddressingMode mode) -{ - switch (mode) - { - case AddressingMode::IMMEDIATE: return static_cast(ea); - case AddressingMode::SIMPLE: - case AddressingMode::SIC_DIRECT: return m.getFloat(ea); - case AddressingMode::INDIRECT: return m.getFloat(m.getWord(ea)); - default: m.invalidAddressing(); return 0.0; - } -} - - -inline void writeWordOperand(Machine& m, int ea, AddressingMode mode, int value) -{ - switch (mode) - { - case AddressingMode::SIMPLE: - case AddressingMode::SIC_DIRECT: m.setWord(ea, value); break; // direct store - case AddressingMode::INDIRECT: m.setWord(m.getWord(ea), value); break; // store via pointer - default: m.invalidAddressing(); break; - } -} - -inline void writeFloatOperand(Machine& m, int ea, AddressingMode mode, double value) -{ - switch (mode) - { - case AddressingMode::SIMPLE: - case AddressingMode::SIC_DIRECT: m.setFloat(ea, value); break; - case AddressingMode::INDIRECT: m.setFloat(m.getWord(ea), value); break; - default: m.invalidAddressing(); break; - } -} - - -// For jump-like ops: what PC should become? -inline int resolveJumpTarget(Machine& m, int ea, AddressingMode mode) -{ - switch (mode) - { - case AddressingMode::IMMEDIATE: - case AddressingMode::SIMPLE: - case AddressingMode::SIC_DIRECT: return ea; // jump to EA (normal case) - case AddressingMode::INDIRECT: return m.getWord(ea); // jump via pointer - default: m.invalidAddressing(); return m.getPC(); - } -} - -void fix_handler(Machine &m) -{ - m.setA(static_cast(m.getF())); -} - -void float_handler(Machine &m) -{ - m.setF(static_cast(m.getA())); -} - -void norm_handler(Machine &m) -{ - m.setF(normaliseFloat(m.getF())); -} - -void addr_handler(Machine &m, int r1, int r2) -{ - m.setReg(r2, m.getReg(r1) + m.getReg(r2)); -} - -void clear_handler(Machine& m, int r, int unused) { - m.setReg(r, 0); -} - -void compr_handler(Machine &m, int r1, int r2) -{ - m.setSW(sic_comp(m.getReg(r1), m.getReg(r2), m.getSW())); -} - -void divr_handler(Machine& m, int r1, int r2) { - - if (m.getReg(r2) == 0) { - m.invalidOpcode(DIVR); - return; - } - m.setReg(r2, m.getReg(r2) / m.getReg(r1)); -} - -void mulr_handler(Machine &m, int r1, int r2) -{ - m.setReg(r2, m.getReg(r1) * m.getReg(r2)); -} - -void rmo_handler(Machine &m, int r1, int r2) -{ - m.setReg(r2, m.getReg(r1)); -} - - -// SHIFTL r1, n → left *circular* shift n bits -void shiftl_handler(Machine &m, int r1, int n) -{ - unsigned int v = m.getReg(r1) & WORD_MASK; - n %= WORD_SIZE; - unsigned int res = ((v << n) | (v >> (WORD_SIZE - n))) & WORD_MASK; - m.setReg(r1, res); -} - -// SHIFTR r1, n → right shift n bits, fill with original leftmost bit -void shiftr_handler(Machine &m, int r1, int n) -{ - unsigned int v = m.getReg(r1) & WORD_MASK; - n %= WORD_SIZE; - unsigned int msb = (v & 0x800000) ? 1u : 0u; - unsigned int shifted = v >> n; - unsigned int fill = 0; - if (msb) { - fill = (~0u) << (WORD_SIZE - n); - fill &= WORD_MASK; - } - - unsigned int res = (shifted | fill) & WORD_MASK; - m.setReg(r1, res); -} - -void subr_handler(Machine &m, int r1, int r2) -{ - m.setReg(r2, m.getReg(r2) - m.getReg(r1)); -} - -// TODO: implement SVC functionality -void svc_handler(Machine &m, int n, int unused) -{ - m.notImplemented("SVC"); -} - -void tixr_handler(Machine &m, int r1, int unused) -{ - m.setX(m.getX() + 1); - int valX = m.getX(); - int valR1 = m.getReg(r1); - m.setSW(sic_comp(valX, valR1, m.getSW())); -} - -void add_handler(Machine &m, int ea, AddressingMode mode) -{ - int val = resolveWordOperand(m, ea, mode); - m.setA(m.getA() + val); -} - -void addf_handler(Machine &m, int ea, AddressingMode mode) -{ - double val = resolveFloatOperand(m, ea, mode); - m.setA(m.getA() + val); -} - -void and_handler(Machine &m, int ea, AddressingMode mode) -{ - int val = resolveWordOperand(m, ea, mode); - m.setA(m.getA() & val); -} - -void comp_handler(Machine &m, int ea, AddressingMode mode) -{ - int operand = resolveWordOperand(m, ea, mode); - m.setSW(sic_comp(m.getA(), operand, m.getSW())); -} - -void compf_handler(Machine &m, int ea, AddressingMode mode) -{ - double operand = resolveFloatOperand(m, ea, mode); - m.setSW(sic_comp(m.getF(), operand, m.getSW())); -} - -void div_handler(Machine &m, int ea, AddressingMode mode) -{ - int divisor = resolveWordOperand(m, ea, mode); - if (divisor == 0) { - m.divisionByZero(DIV); - return; - } - m.setA(m.getA() / divisor); -} - -void divf_handler(Machine &m, int ea, AddressingMode mode) -{ - double divisor = resolveFloatOperand(m, ea, mode); - if (divisor == 0.0) { - m.divisionByZero(DIVF); - return; - } - m.setF(m.getF() / divisor); -} - -void j_handler(Machine &m, int ea, AddressingMode mode) -{ - int target = resolveJumpTarget(m, ea, mode); - - int instrSize = 3; - int instrAddr = m.getPC() - instrSize; - // Check if jumping to itself (halt pattern) - if (target == instrAddr) { - m.halt(); - } - - m.setPC(target); -} - -void jeq_handler(Machine &m, int ea, AddressingMode mode) -{ - int sw = m.getSW(); - int cc = getCC(sw); - if (cc == CC_EQ) { - int target = resolveJumpTarget(m, ea, mode); - m.setPC(target); - } -} - -void jgt_handler(Machine &m, int ea, AddressingMode mode) -{ - int sw = m.getSW(); - int cc = getCC(sw); - if (cc == CC_GT) { - int target = resolveJumpTarget(m, ea, mode); - m.setPC(target); - } -} - -void jlt_handler(Machine &m, int ea, AddressingMode mode) -{ - int sw = m.getSW(); - int cc = getCC(sw); - if (cc == CC_LT) { - int target = resolveJumpTarget(m, ea, mode); - m.setPC(target); - } -} - -void jsub_handler(Machine &m, int ea, AddressingMode mode) -{ - int target = resolveJumpTarget(m, ea, mode); - m.setL(m.getPC()); - m.setPC(target); -} - -void lda_handler(Machine& m, int ea, AddressingMode mode) -{ - m.setA(resolveWordOperand(m, ea, mode)); -} - -void ldb_handler(Machine &m, int ea, AddressingMode mode) -{ - m.setB(resolveWordOperand(m, ea, mode)); -} - -void ldch_handler(Machine &m, int ea, AddressingMode mode) -{ - int val; - if (mode == AddressingMode::IMMEDIATE) { - val = ea & 0xFF; - } else if (mode == AddressingMode::INDIRECT) { - val = m.getByte(m.getWord(ea)); - } else { - val = m.getByte(ea); - } - m.setA((m.getA() & 0xFFFF00) | (val & 0xFF)); -} - -void ldf_handler(Machine &m, int ea, AddressingMode mode) -{ - m.setF(resolveFloatOperand(m, ea, mode)); -} - -void ldl_handler(Machine &m, int ea, AddressingMode mode) -{ - m.setL(resolveWordOperand(m, ea, mode)); -} - -void lds_handler(Machine &m, int ea, AddressingMode mode) -{ - m.setS(resolveWordOperand(m, ea, mode)); -} - -void ldt_handler(Machine &m, int ea, AddressingMode mode) -{ - m.setT(resolveWordOperand(m, ea, mode)); -} - -void ldx_handler(Machine &m, int ea, AddressingMode mode) -{ - m.setX(resolveWordOperand(m, ea, mode)); -} - -void mul_handler(Machine &m, int ea, AddressingMode mode) -{ - int val = resolveWordOperand(m, ea, mode); - m.setA(m.getA() * val); -} - -void mulf_handler(Machine &m, int ea, AddressingMode mode) -{ - m.setF(m.getF() * resolveFloatOperand(m, ea, mode)); -} - -void or_handler(Machine &m, int ea, AddressingMode mode) -{ - int val = resolveWordOperand(m, ea, mode); - m.setA(m.getA() | val); -} - -void rd_handler(Machine &m, int ea, AddressingMode mode) -{ - int deviceNum = resolveWordOperand(m, ea, mode); - Device& device = m.getDevice(deviceNum); - // Load byte into rightmost byte of A register - m.setA((m.getA() & 0xFFFF00) | device.read()); -} - -void rsub_handler(Machine &m, int ea, AddressingMode mode) -{ - m.setPC(m.getL()); -} - -void sta_handler(Machine &m, int ea, AddressingMode mode) -{ - writeWordOperand(m, ea, mode, m.getA()); -} - -void stb_handler(Machine &m, int ea, AddressingMode mode) -{ - writeWordOperand(m, ea, mode, m.getB()); -} -// Rightmost byte of A register is stored -void stch_handler(Machine &m, int ea, AddressingMode mode) -{ - int val = m.getA() & 0xFF; - switch (mode) - { - case AddressingMode::SIMPLE: - case AddressingMode::SIC_DIRECT: m.setByte(ea, val); break; // direct store - case AddressingMode::INDIRECT: m.setByte(m.getWord(ea), val); break; // store via pointer - default: m.invalidAddressing(); break; - } -} - -void stf_handler(Machine &m, int ea, AddressingMode mode) -{ - writeFloatOperand(m, ea, mode, m.getF()); -} - -void stl_handler(Machine &m, int ea, AddressingMode mode) -{ - writeWordOperand(m, ea, mode, m.getL()); -} - -void sts_handler(Machine &m, int ea, AddressingMode mode) -{ - writeWordOperand(m, ea, mode, m.getS()); -} - -void stsw_handler(Machine &m, int ea, AddressingMode mode) -{ - writeWordOperand(m, ea, mode, m.getSW()); -} - -void stt_handler(Machine &m, int ea, AddressingMode mode) -{ - writeWordOperand(m, ea, mode, m.getT()); -} - -void stx_handler(Machine &m, int ea, AddressingMode mode) -{ - writeWordOperand(m, ea, mode, m.getX()); -} - -void sub_handler(Machine &m, int ea, AddressingMode mode) -{ - int val = resolveWordOperand(m, ea, mode); - m.setA(m.getA() - val); -} - -void subf_handler(Machine &m, int ea, AddressingMode mode) -{ - double val = resolveFloatOperand(m, ea, mode); - m.setF(m.getF() - val); -} - -void td_handler(Machine &m, int ea, AddressingMode mode) -{ - int deviceNum = resolveWordOperand(m, ea, mode); - Device& device = m.getDevice(deviceNum); - // Test device and set SW accordingly - if (device.test()) { - m.setSW(setCC(m.getSW(), CC_EQ)); - } else { - m.setSW(setCC(m.getSW(), CC_LT)); - } -} - -void tix_handler(Machine &m, int ea, AddressingMode mode) -{ - m.setX(m.getX() + 1); - int valX = m.getX(); - int memVal = resolveWordOperand(m, ea, mode); - m.setSW(sic_comp(valX, memVal, m.getSW())); -} - -void wd_handler(Machine &m, int ea, AddressingMode mode) -{ - int deviceNum = resolveWordOperand(m, ea, mode); - Device& device = m.getDevice(deviceNum); - // Write rightmost byte of A register to device - device.write(static_cast(m.getA() & 0xFF)); -} - -void xexe_handler(Machine &m) -{ - m.enableExtendedMode(); - m.execute(); - m.disableExtendedMode(); -} - -void halt_handler(Machine &m) -{ - m.halt(); -} - -void nop_handler(Machine &m) -{ - // Do nothing -} - -void vaddr_handler(Machine &m, int r1, int r2) -{ - int result[VECTOR_REG_SIZE]; - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - result[i] = m.getVectorRegister(r1)[i] + m.getVectorRegister(r2)[i]; - } - m.setVectorRegister(r2, result); -} - -void vsubr_handler(Machine &m, int r1, int r2) -{ - int result[VECTOR_REG_SIZE]; - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - result[i] = m.getVectorRegister(r2)[i] - m.getVectorRegister(r1)[i]; - } - m.setVectorRegister(r2, result); -} - -void vmulr_handler(Machine &m, int r1, int r2) -{ - int result[VECTOR_REG_SIZE]; - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - result[i] = m.getVectorRegister(r1)[i] * m.getVectorRegister(r2)[i]; - } - m.setVectorRegister(r2, result); -} - -void vdivr_handler(Machine &m, int r1, int r2) -{ - int result[VECTOR_REG_SIZE]; - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - if (m.getVectorRegister(r1)[i] == 0) { - m.divisionByZero(VDIVR); - return; - } - result[i] = m.getVectorRegister(r2)[i] / m.getVectorRegister(r1)[i]; - } - m.setVT(result); -} - -void vadd_handler(Machine &m, int ea, AddressingMode mode) -{ - int baseAddr = resolveWordOperand(m, ea, mode); - int vec[VECTOR_REG_SIZE]; - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - vec[i] = m.getWord(baseAddr + i * 3); - } - int result[VECTOR_REG_SIZE]; - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - result[i] = m.getVA()[i] + vec[i]; - } - m.setVA(result); -} - -void vsub_handler(Machine &m, int ea, AddressingMode mode) -{ - int baseAddr = resolveWordOperand(m, ea, mode); - int vec[VECTOR_REG_SIZE]; - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - vec[i] = m.getWord(baseAddr + i * 3); - } - int result[VECTOR_REG_SIZE]; - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - result[i] = m.getVA()[i] - vec[i]; - } - m.setVA(result); -} - -void vmul_handler(Machine &m, int ea, AddressingMode mode) -{ - int baseAddr = resolveWordOperand(m, ea, mode); - int vec[VECTOR_REG_SIZE]; - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - vec[i] = m.getWord(baseAddr + i * 3); - } - int result[VECTOR_REG_SIZE]; - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - result[i] = m.getVA()[i] * vec[i]; - } - m.setVA(result); -} - -void vdiv_handler(Machine &m, int ea, AddressingMode mode) -{ - int baseAddr = resolveWordOperand(m, ea, mode); - int vec[VECTOR_REG_SIZE]; - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - vec[i] = m.getWord(baseAddr + i * 3); - } - int result[VECTOR_REG_SIZE]; - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - if (vec[i] == 0) { - m.divisionByZero(VDIV); - return; - } - result[i] = m.getVA()[i] / vec[i]; - } - m.setVA(result); -} - -void stva_handler(Machine &m, int ea, AddressingMode mode) -{ - int baseAddr = resolveWordOperand(m, ea, mode); - const int* vec = m.getVA(); - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - m.setWord(baseAddr + i * 3, vec[i]); - } -} - -void stvs_handler(Machine &m, int ea, AddressingMode mode) -{ - int baseAddr = resolveWordOperand(m, ea, mode); - const int* vec = m.getVS(); - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - m.setWord(baseAddr + i * 3, vec[i]); - } -} - -void stvt_handler(Machine &m, int ea, AddressingMode mode) -{ - int baseAddr = resolveWordOperand(m, ea, mode); - const int* vec = m.getVT(); - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - m.setWord(baseAddr + i * 3, vec[i]); - } -} - -void ldva_handler(Machine &m, int ea, AddressingMode mode) -{ - int baseAddr = resolveWordOperand(m, ea, mode); - int vec[VECTOR_REG_SIZE]; - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - vec[i] = m.getWord(baseAddr + i * 3); - } - m.setVA(vec); -} - -void ldvs_handler(Machine &m, int ea, AddressingMode mode) -{ - int baseAddr = resolveWordOperand(m, ea, mode); - int vec[VECTOR_REG_SIZE]; - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - vec[i] = m.getWord(baseAddr + i * 3); - } - m.setVS(vec); -} - -void ldvt_handler(Machine &m, int ea, AddressingMode mode) -{ - int baseAddr = resolveWordOperand(m, ea, mode); - int vec[VECTOR_REG_SIZE]; - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - vec[i] = m.getWord(baseAddr + i * 3); - } - m.setVT(vec); -} diff --git a/ass2/simulator_SIC_XE/src/loader.cpp b/ass2/simulator_SIC_XE/src/loader.cpp deleted file mode 100644 index 8d3aa17..0000000 --- a/ass2/simulator_SIC_XE/src/loader.cpp +++ /dev/null @@ -1,134 +0,0 @@ -#include "loader.h" -#include "file_reader.h" -#include "string_reader.h" -#include "machine.h" -#include "constants.h" -#include -#include - -Loader::~Loader() -{ - _machine.reset(); -} - - - - -void Loader::load() -{ - HeaderMetadata header = readHeader(); - - while(true) { - RecordType type = parseRecordType(static_cast(_file_reader->readByte())); - switch (type) { - case RecordType::TEXT: { - TextRecord textRecord = readTextRecord(); - if (!load_into_memory(textRecord.start_address, textRecord.data)) { - throw std::runtime_error("Failed to load text record into memory"); - } - break; - } - case RecordType::END: { - EndRecord endRecord = readEndRecord(); - _machine->setPC(endRecord.execution_start_address); - return; // Loading complete - } - case RecordType::UNKNOWN: - default: - throw std::runtime_error("Unknown record type encountered"); - } - } -} - -Loader::RecordType Loader::parseRecordType(char c) -{ - switch (c) { - case 'H': return RecordType::HEADER; - case 'T': return RecordType::TEXT; - case 'E': return RecordType::END; - default: return RecordType::UNKNOWN; // fallback; adjust as needed - } -} - -Loader::HeaderMetadata Loader::readHeader() -{ - - RecordType type = parseRecordType(static_cast(_file_reader->readByte())); - if (type != RecordType::HEADER) { - throw std::runtime_error("Expected HEADER record"); - } - if(FILE_CONTAINS_WHITE_SPACES) _file_reader->readByte(); - - HeaderMetadata header; - // Read program name (6 bytes) - header.program_name = _file_reader->readString(6); - if(FILE_CONTAINS_WHITE_SPACES) _file_reader->readByte(); - - // Read start address (6 hex digits) - header.start_address = std::stoi(_file_reader->readString(6), nullptr, 16); - if(FILE_CONTAINS_WHITE_SPACES) _file_reader->readByte(); - - // Read length (6 hex digits) - header.length = std::stoi(_file_reader->readString(6), nullptr, 16); - // consume newline - _file_reader->readLine(); - return header; -} - -Loader::TextRecord Loader::readTextRecord() -{ - if(FILE_CONTAINS_WHITE_SPACES) _file_reader->readByte(); - TextRecord record; - // Assume 'T' has already been read - record.start_address = std::stoi(_file_reader->readString(6), nullptr, 16); - if(FILE_CONTAINS_WHITE_SPACES) _file_reader->readByte(); - - // Read length (1 byte, 2 hex digits) - 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); - - for (int i = 0; i < length; ++i) { - std::string byteHex = stringReader.readString(2); - record.data[i] = static_cast(std::stoi(byteHex, nullptr, 16)); - } - - return record; -} - -Loader::EndRecord Loader::readEndRecord() -{ - EndRecord record; - if(FILE_CONTAINS_WHITE_SPACES) _file_reader->readByte(); - // Assume 'E' has already been read - std::string addrStr = _file_reader->readString(6); - if (!addrStr.empty()) { - record.execution_start_address = std::stoi(addrStr, nullptr, 16); - } else { - record.execution_start_address = 0; - } - // consume newline - _file_reader->readLine(); - return record; -} - -bool Loader::load_into_memory(int start_address, const std::vector &data) -{ - for(size_t i = 0; i < data.size(); ++i) { - int addr = start_address + static_cast(i); - if (addr < 0 || addr >= MEMORY_SIZE) { - return false; - } - _machine->setByte(addr, data[i]); - } - return true; -} diff --git a/ass2/simulator_SIC_XE/src/machine.cpp b/ass2/simulator_SIC_XE/src/machine.cpp deleted file mode 100644 index d8d0356..0000000 --- a/ass2/simulator_SIC_XE/src/machine.cpp +++ /dev/null @@ -1,525 +0,0 @@ -#include "machine.h" - -#include - -#include "opcode.h" -#include "instructions.h" -#include -#include - -using std::make_shared; - -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); - // device 1: standard output - devices[1] = make_shared(std::cout); - - // Initialize devices >= 2 as FileDevice with hex names in devices directory - for (int i = 2; i < NUM_DEVICES; i++) { - char hex[3]; - snprintf(hex, sizeof(hex), "%02X", i); - std::string filename = "devices/" + std::string(hex) + ".dev"; - try { - devices[i] = std::make_shared(filename); - } catch (const std::exception &e) { - cerr << prefix << "Warning: Failed to initialize FileDevice for device " << i << ": " << e.what() << endl; - } - } - - _exex_mode = false; - _instructionsTable = instructions; -} - -Machine::~Machine() -{ - for (auto& device : devices) { - device.reset(); - } -} - -int Machine::getSpeed() const -{ - return speedHz.load(); -} - -void Machine::setSpeed(int Hz) -{ - speedHz.store(Hz); -} - -// TODO: implement errors -void Machine::notImplemented(string mnemonic) -{ - cout << prefix << "Not implemented: " << mnemonic << endl; -} - -void Machine::invalidOpcode(int opcode) -{ - cout << prefix << "Invalid opcode: " << opcode << endl; -} - - -void Machine::invalidAddressing() -{ - cout << prefix << "Invalid addressing mode" << endl; -} - -void Machine::divisionByZero(int opcode) -{ - cout << prefix << "Division by zero error in opcode: " << opcode << endl; -} - -void Machine::undefinedHandler(int opcode) -{ - cout << prefix << "Undefined handler for opcode: " << opcode << endl; -} - -void Machine::enableExtendedMode() -{ - if(!USE_EXTENDED_MODE) return; - _exex_mode = true; - _instructionsTable = instructionsEXEX; -} - -void Machine::disableExtendedMode() -{ - if(!USE_EXTENDED_MODE) return; - _exex_mode = false; - _instructionsTable = instructions; -} - -int *Machine::getVectorRegister(int regNum) -{ - switch (regNum) { - case 0: return VA; - case 4: return VS; - case 5: return VT; - default: - cerr << prefix << "Invalid register number: " << regNum << endl; - return nullptr; - } -} - -void Machine::setVectorRegister(int regNum, const int *values) -{ - int* targetReg = getVectorRegister(regNum); - if (targetReg == nullptr) return; - for (int i = 0; i < VECTOR_REG_SIZE; i++) { - targetReg[i] = toSIC24(values[i]); - } -} - -void Machine::setVA(const int *values) -{ - for (int i = 0; i < VECTOR_REG_SIZE; i++) { - VA[i] = toSIC24(values[i]); - } -} - -void Machine::setVS(const int *values) -{ - for (int i = 0; i < VECTOR_REG_SIZE; i++) { - VS[i] = toSIC24(values[i]); - } -} - -void Machine::setVT(const int *values) -{ - for (int i = 0; i < VECTOR_REG_SIZE; i++) { - VT[i] = toSIC24(values[i]); - } -} - -void Machine::tick() -{ - const int speed = speedHz.load(); - if (speed <= 0) throw std::runtime_error("Invalid speed setting in Machine::tick"); - - const auto delay = std::chrono::milliseconds(1000 / speed); - std::this_thread::sleep_for(delay); -} - -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) { - case 0: return A; - case 1: return X; - case 2: return L; - case 3: return B; - case 4: return S; - case 5: return T; - case 6: return F; - case 8: return PC; - case 9: return SW; - default: - cerr << prefix << "Invalid register number: " << regNum << endl; - return -1; - } -} - -// TODO: handle double for F register -void Machine::setReg(int regNum, int value) -{ - value = toSIC24(value); - switch (regNum) { - case 0: A = value; break; - case 1: X = value; break; - case 2: L = value; break; - case 3: B = value; break; - case 4: S = value; break; - case 5: T = value; break; - case 6: F = value; break; - case 8: PC = value; break; - case 9: SW = value; break; - default: - cerr << prefix << "Invalid register number: " << regNum << endl; - break; - } -} - -int Machine::getByte(int address) -{ - if (address < 0 || address >= MEMORY_SIZE) { - cerr << prefix << "Invalid memory address: " << address << endl; - return -1; - } - return static_cast(memory[address]); -} - -void Machine::setByte(int address, int value) -{ - if(address < 0 || address >= MEMORY_SIZE) { - cerr << prefix << "Invalid memory address: " << address << endl; - return; - } - - memory[address] = static_cast(value); -} - -// Assuming word is 3 bytes - -int Machine::getWord(int address) -{ - if (address < 0 || address + 2 >= MEMORY_SIZE) { - cerr << prefix << "Invalid memory address: " << address << endl; - return -1; - } - // Big-endian: high byte first - return (static_cast(memory[address]) << 16) | (static_cast(memory[address + 1]) << 8) | static_cast(memory[address + 2]); -} - -// Assuming word is 3 bytes -void Machine::setWord(int address, int value) -{ - if(address < 0 || address + 2 >= MEMORY_SIZE) { - cerr << prefix << "Invalid memory address: " << address << endl; - return; - } - value &= 0xFFFFFF; - - // Big-endian: high byte first - memory[address] = static_cast((value >> 16) & 0xFF); - memory[address + 1] = static_cast((value >> 8) & 0xFF); - memory[address + 2] = static_cast(value & 0xFF); -} - -double Machine::getFloat(int address) -{ - if (address < 0 || address + 5 >= MEMORY_SIZE) { - cerr << prefix << "Invalid float address: " << address << endl; - return 0.0; - } - - // load 6 bytes, big-endian → 48-bit word - unsigned long long raw = - ((unsigned long long)memory[address] << 40) | - ((unsigned long long)memory[address+1] << 32) | - ((unsigned long long)memory[address+2] << 24) | - ((unsigned long long)memory[address+3] << 16) | - ((unsigned long long)memory[address+4] << 8) | - (unsigned long long)memory[address+5]; - - int sign = (raw >> 47) & 0x1; - int exponent = (raw >> 40) & 0x7F; - unsigned long long frac = raw & SICF_FRAC_MASK; // 40 bits - - if (raw == 0) return 0.0; - - // value = (1 + frac/2^40) * 2^(exp - 64) - double mant = 1.0 + (double)frac / (double)(1ULL << SICF_FRAC_BITS); - int e = exponent - SICF_EXP_BIAS; - double val = std::ldexp(mant, e); // ldexp is fast enough here - return sign ? -val : val; -} - -void Machine::setFloat(int address, double value) -{ - if (address < 0 || address + 5 >= MEMORY_SIZE) { - cerr << prefix << "Invalid float address: " << address << endl; - return; - } - - if (value == 0.0) { - memory[address] = 0; - memory[address+1] = 0; - memory[address+2] = 0; - memory[address+3] = 0; - memory[address+4] = 0; - memory[address+5] = 0; - return; - } - - int sign = value < 0; - double x = sign ? -value : value; - - // normalize x to [1, 2) - int exp2 = 0; - x = std::frexp(x, &exp2); - x *= 2.0; - exp2 -= 1; - - int exp_field = exp2 + SICF_EXP_BIAS; - if (exp_field < 0) exp_field = 0; - if (exp_field > 127) exp_field = 127; - - // mantissa = (x - 1) * 2^40 - double frac_d = (x - 1.0) * (double)(1ULL << SICF_FRAC_BITS); - unsigned long long frac = (unsigned long long)(frac_d + 0.5); // round - frac &= SICF_FRAC_MASK; - - unsigned long long raw = - ((unsigned long long)sign << 47) | - ((unsigned long long)exp_field << 40) | - frac; - - // store 6 bytes big-endian - memory[address] = (unsigned char)((raw >> 40) & 0xFF); - memory[address+1] = (unsigned char)((raw >> 32) & 0xFF); - memory[address+2] = (unsigned char)((raw >> 24) & 0xFF); - memory[address+3] = (unsigned char)((raw >> 16) & 0xFF); - memory[address+4] = (unsigned char)((raw >> 8) & 0xFF); - memory[address+5] = (unsigned char)( raw & 0xFF); -} - - - -Device &Machine::getDevice(int num) -{ - if(num < 0 || num >= static_cast(devices.size()) || !devices[num]) { - cerr << prefix << "Invalid device number: " << num << endl; - return fallbackDevice; - } - return *devices[num]; -} - -void Machine::setDevice(int num, std::shared_ptr device) -{ - if(num < 0 || num >= NUM_DEVICES) { - cerr << prefix << "Invalid device number: " << num << endl; - return; - } - if(static_cast(devices.size()) != NUM_DEVICES) { - devices.resize(NUM_DEVICES); - } - // Enforce: devices with index >= 2 must be FileDevice instances - if (num >= 2) { - // try dynamic cast - if (std::dynamic_pointer_cast(device) == nullptr) { - cerr << prefix << "Device at index " << num << " must be a FileDevice." << endl; - return; - } - } - devices[num] = device; -} - -void Machine::setFileDevice(int num, const std::string &filename) -{ - if(num < 0 || num >= NUM_DEVICES) { - cerr << prefix << "Invalid device number: " << num << endl; - return; - } - if(static_cast(devices.size()) != NUM_DEVICES) { - devices.resize(NUM_DEVICES); - } - try { - devices[num] = std::make_shared(filename); - } catch (const std::exception &e) { - cerr << prefix << "Failed to create FileDevice for index " << num << ": " << e.what() << endl; - } -} - -int Machine::fetch() -{ - return getByte(PC++); -} - -void Machine::execute() { - if (_stopped) return; - - int b1 = fetch(); - - InstructionInfo &info = _instructionsTable[b1]; - - if (info.type == InstructionType::TYPE1) { execF1(b1); return; } - if (info.type == InstructionType::TYPE2) { execF2(b1, fetch()); return; } - - int opcode = b1 & TYPE3_4_SIC_MASK; - InstructionInfo &info34 = _instructionsTable[opcode]; - int ni = b1 & NI_MASK; - - if (info34.type == InstructionType::TYPE3_4) { - int b2 = fetch(), b3 = fetch(); - int x = (b2 & 0x80) ? 1 : 0; - int b = (b2 & 0x40) ? 1 : 0; - int p = (b2 & 0x20) ? 1 : 0; - int e = (b2 & 0x10) ? 1 : 0; - - int operand; - if (ni == NI_SIC) { - // PURE SIC - operand = ((b2 & 0x7F) << 8) | b3; - } else { - // SIC/XE - operand = e - ? (((b2 & 0x0F) << 16) | (b3 << 8) | fetch()) // F4: 20-bit - : (((b2 & 0x0F) << 8) | b3); // F3: 12-bit - } - - execSICF3F4(opcode, ni, x, b, p, e, operand); - return; - } - - invalidOpcode(b1); -} - - - - -bool Machine::execF1(int opcode) -{ - if (_instructionsTable[opcode].handler) { - auto handler = reinterpret_cast(_instructionsTable[opcode].handler); - handler(*this); - return true; - } - undefinedHandler(opcode); - return false; -} - -bool Machine::execF2(int opcode, int operand) -{ - int r1 = (operand >> 4) & 0xF; - int r2 = operand & 0xF; - - if (_instructionsTable[opcode].handler) { - auto handler = reinterpret_cast(_instructionsTable[opcode].handler); - handler(*this, r1, r2); - return true; - } - undefinedHandler(opcode); - return false; -} - - -bool Machine::execSICF3F4(int opcode, int ni, int x, int b, int p, int e, int operand) -{ - int ea_part = operand; - int base = 0; - AddressingMode mode = getAddressingMode(ni); - - // --- PURE SIC --- - if (mode == AddressingMode::SIC_DIRECT) { - int ea = ea_part + (x ? getX() : 0); - if (_instructionsTable[opcode].handler) { - auto h = reinterpret_cast(_instructionsTable[opcode].handler); - h(*this, ea, mode); - return true; - } - undefinedHandler(opcode); - return false; - } - - // --- SIC/XE EA calc --- - - if (!e) { // format 3 - if (b && !p) { - base = getB(); // base-relative, unsigned 12-bit - } else if (p && !b) { - // PC-relative, signed 12-bit - if (ea_part & 0x800) // bit 11 set? - ea_part |= 0xFFFFF000; // sign-extend - base = getPC(); - } - } - // format 4 (e=1): b/p ignored, ea_part is 20-bit absolute - int ea = base + ea_part + (x ? getX() : 0); - - if (_instructionsTable[opcode].handler) { - auto h = reinterpret_cast(_instructionsTable[opcode].handler); - h(*this, ea, mode); - return true; - } - - undefinedHandler(opcode); - return false; -} - -void Machine::start() -{ - running.store(true); - - // Main execution loop - // TODO: consider running in separate thread - while (running.load()) { - execute(); - tick(); - } -} - -void Machine::stop() -{ - running.store(false); -} diff --git a/ass2/simulator_SIC_XE/src/main.cpp b/ass2/simulator_SIC_XE/src/main.cpp deleted file mode 100644 index 433a3f1..0000000 --- a/ass2/simulator_SIC_XE/src/main.cpp +++ /dev/null @@ -1,140 +0,0 @@ -#include -#include -#include -#include "machine.h" -#include "file_device.h" -#include "opcode.h" -#include "instructions.h" -#include "constants.h" -#include "loader.h" - -using std::cout; -using std::endl; - -struct VectorAddProgram { - int x, y; -}; - - - -int main() -{ - /* - loadInstructionSet(); - Machine machine; - cout << "SIC/XE Program: Accumulator Loop" << endl; - - const int TEMP_ADDR = 0x50; - const int LOOP_ADDR = 0x03; - - // clear TEMP - machine.setByte(TEMP_ADDR, 0); - loadInstructionSet(); - - cout << "SIC/XE Program: Vector add test" << endl; - - const int VA_ADDR = 0x100; // source vector A - const int VB_ADDR = 0x200; // source vector B - const int VR_ADDR = 0x300; // result store (STVA) - - // Prepare two 4-element vectors (WORD = 3 bytes) for VA and VB - int a_vals[VECTOR_REG_SIZE] = {1,2,3,4}; - int b_vals[VECTOR_REG_SIZE] = {5,6,7,8}; - - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - machine.setWord(VA_ADDR + i * 3, a_vals[i]); - machine.setWord(VB_ADDR + i * 3, b_vals[i]); - } - - // Assemble program at address 0x000 (we use XEXE before each extended op) - // Offsets and bytes (hex): - // 0x00: XEXE -> 0xEE - // 0x01: LDVA (format 4) -> b1=0x03 (LDVA|ni=0x00|0x03), b2=0x10 (e=1), b3=0x01, b4=0x00 (addr 0x100) - // 0x05: XEXE -> 0xEE - // 0x06: LDVS (format 4) -> b1=0x6B (0x68|0x03), b2=0x10, b3=0x02, b4=0x00 (addr 0x200) - // 0x0A: XEXE -> 0xEE - // 0x0B: VADDR B->A (type 2) -> opcode 0x90, operand r1=4 (VS), r2=0 (VA) => operand=(4<<4)|0=0x40 - // 0x0D: XEXE -> 0xEE - // 0x0E: STVA (format4) -> b1=0x0F (0x0C|0x03), b2=0x10, b3=0x03, b4=0x00 (addr 0x300) - // 0x12: J (format4) to self -> b1=0x3F (0x3C|0x03), b2=0x10, b3=0x00, b4=0x12 - - unsigned char prog[] = { - 0xEE, - 0x01, 0x10, 0x01, 0x00, // LDVA (format 4) with ni=IMMEDIATE -> b1=0x01 - 0xEE, - 0x69, 0x10, 0x02, 0x00, // LDVS (format 4) with ni=IMMEDIATE -> b1=0x69 (0x68|0x01) - 0xEE, - 0x90, 0x40, // VADDR VS->VA (type2) - 0xEE, - 0x0D, 0x10, 0x03, 0x00, // STVA (format4) with ni=IMMEDIATE -> b1=0x0D - 0x3F, 0x10, 0x00, 0x12 // J (format4) loop to 0x12 - }; - - const int PROG_START = 0x00; - for (size_t i = 0; i < sizeof(prog); ++i) { - machine.setByte(PROG_START + static_cast(i), prog[i]); - } - - machine.setPC(PROG_START); - - cout << "Program loaded. VA@0x" << std::hex << VA_ADDR << " VB@0x" << VB_ADDR << " -> store@0x" << VR_ADDR << std::dec << endl; - - - const int MAX_STEPS = 100; - for (int i = 0; i < MAX_STEPS; ++i) { - machine.execute(); - } - - // Read back result vector stored at VR_ADDR - cout << "Result vector at 0x" << std::hex << VR_ADDR << std::dec << ": "; - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - int val = machine.getWord(VR_ADDR + i * 3); - cout << val << (i + 1 < VECTOR_REG_SIZE ? ", " : "\n"); - } - */ - - loadInstructionSet(); - std::shared_ptr machine = std::make_shared(); - Loader loader(machine, std::string(PATH_RESOURCES) + "rec.obj"); - loader.load(); - - cout << "=== Starting execution of rec.obj ===" << endl; - cout << "Initial PC: 0x" << std::hex << machine->getPC() << std::dec << endl; - - int maxSteps = 10000; - for (int step = 0; step < maxSteps; step++) { - int pc = machine->getPC(); - int opcode = machine->getByte(pc) & 0xFC; - const char* instName = (opcode < 256 && instructions[opcode].type != InstructionType::INVALID) - ? instructions[opcode].name : "???"; - - int regA = machine->getA(); - int regB = machine->getB(); - int regX = machine->getX(); - int regL = machine->getL(); - int sw = machine->getSW(); - - printf("Step %4d: PC=0x%05X %-6s A=0x%06X B=0x%06X X=0x%06X L=0x%06X SW=0x%06X\n", - step, pc, instName, regA, regB, regX, regL, sw); - - machine->execute(); - - if (machine->isStopped()) { - cout << "Machine halted at step " << step << endl; - break; - } - - if (step > 100 && machine->getPC() == pc) { - cout << "ERROR: Infinite loop detected at PC=0x" << std::hex << pc << std::dec << endl; - break; - } - } - - cout << "\n=== Final state ===" << endl; - cout << "A: " << machine->getA() << endl; - cout << "B: " << machine->getB() << endl; - cout << "X: " << machine->getX() << endl; - - - return 0; -} \ No newline at end of file diff --git a/ass2/simulator_SIC_XE/src/opcode.cpp b/ass2/simulator_SIC_XE/src/opcode.cpp deleted file mode 100644 index 0b63ce8..0000000 --- a/ass2/simulator_SIC_XE/src/opcode.cpp +++ /dev/null @@ -1,109 +0,0 @@ -#include "opcode.h" -#include "instructions.h" -#include "utils.h" -#include - -InstructionInfo instructions[0xff]; -InstructionInfo instructionsEXEX[0xff]; - -void loadInstructionSet() -{ - instructions[ADD] = {"ADD", InstructionType::TYPE3_4, reinterpret_cast(add_handler)}; - instructions[ADDF] = {"ADDF", InstructionType::TYPE3_4, reinterpret_cast(addf_handler)}; - instructions[ADDR] = {"ADDR", InstructionType::TYPE2, reinterpret_cast(addr_handler)}; - instructions[AND] = {"AND", InstructionType::TYPE3_4, reinterpret_cast(and_handler)}; - instructions[CLEAR] = {"CLEAR", InstructionType::TYPE2, reinterpret_cast(clear_handler)}; - instructions[COMP] = {"COMP", InstructionType::TYPE3_4, reinterpret_cast(comp_handler)}; - instructions[COMPF] = {"COMPF", InstructionType::TYPE3_4, reinterpret_cast(compf_handler)}; - instructions[COMPR] = {"COMPR", InstructionType::TYPE2, reinterpret_cast(compr_handler)}; - instructions[DIV] = {"DIV", InstructionType::TYPE3_4, reinterpret_cast(div_handler)}; - instructions[DIVF] = {"DIVF", InstructionType::TYPE3_4, reinterpret_cast(divf_handler)}; - instructions[DIVR] = {"DIVR", InstructionType::TYPE2, reinterpret_cast(divr_handler)}; - instructions[FIX] = {"FIX", InstructionType::TYPE1, reinterpret_cast(fix_handler)}; - instructions[FLOAT] = {"FLOAT", InstructionType::TYPE1, reinterpret_cast(float_handler)}; - instructions[HIO] = {"HIO", InstructionType::TYPE1, nullptr}; - instructions[J] = {"J", InstructionType::TYPE3_4, reinterpret_cast(j_handler)}; - instructions[JEQ] = {"JEQ", InstructionType::TYPE3_4, reinterpret_cast(jeq_handler)}; - instructions[JGT] = {"JGT", InstructionType::TYPE3_4, reinterpret_cast(jgt_handler)}; - instructions[JLT] = {"JLT", InstructionType::TYPE3_4, reinterpret_cast(jlt_handler)}; - instructions[JSUB] = {"JSUB", InstructionType::TYPE3_4, reinterpret_cast(jsub_handler)}; - instructions[LDA] = {"LDA", InstructionType::TYPE3_4, reinterpret_cast(lda_handler)}; - instructions[LDB] = {"LDB", InstructionType::TYPE3_4, reinterpret_cast(ldb_handler)}; - instructions[LDCH] = {"LDCH", InstructionType::TYPE3_4, reinterpret_cast(ldch_handler)}; - instructions[LDF] = {"LDF", InstructionType::TYPE3_4, reinterpret_cast(ldf_handler)}; - instructions[LDL] = {"LDL", InstructionType::TYPE3_4, reinterpret_cast(ldl_handler)}; - instructions[LDS] = {"LDS", InstructionType::TYPE3_4, reinterpret_cast(lds_handler)}; - instructions[LDT] = {"LDT", InstructionType::TYPE3_4, reinterpret_cast(ldt_handler)}; - instructions[LDX] = {"LDX", InstructionType::TYPE3_4, reinterpret_cast(ldx_handler)}; - instructions[LPS] = {"LPS", InstructionType::TYPE3_4, nullptr}; - instructions[MUL] = {"MUL", InstructionType::TYPE3_4, reinterpret_cast(mul_handler)}; - instructions[MULF] = {"MULF", InstructionType::TYPE3_4, reinterpret_cast(mulf_handler)}; - instructions[MULR] = {"MULR", InstructionType::TYPE2, reinterpret_cast(mulr_handler)}; - instructions[NORM] = {"NORM", InstructionType::TYPE1, reinterpret_cast(norm_handler)}; - instructions[OR] = {"OR", InstructionType::TYPE3_4, reinterpret_cast(or_handler)}; - instructions[RD] = {"RD", InstructionType::TYPE3_4, reinterpret_cast(rd_handler)}; - instructions[RMO] = {"RMO", InstructionType::TYPE2, reinterpret_cast(rmo_handler)}; - instructions[RSUB] = {"RSUB", InstructionType::TYPE3_4, reinterpret_cast(rsub_handler)}; - instructions[SHIFTL] = {"SHIFTL", InstructionType::TYPE2, reinterpret_cast(shiftl_handler)}; - instructions[SHIFTR] = {"SHIFTR", InstructionType::TYPE2, reinterpret_cast(shiftr_handler)}; - instructions[SIO] = {"SIO", InstructionType::TYPE1, nullptr}; - instructions[SSK] = {"SSK", InstructionType::TYPE3_4, nullptr}; - instructions[STA] = {"STA", InstructionType::TYPE3_4, reinterpret_cast(sta_handler)}; - instructions[STB] = {"STB", InstructionType::TYPE3_4, reinterpret_cast(stb_handler)}; - instructions[STCH] = {"STCH", InstructionType::TYPE3_4, reinterpret_cast(stch_handler)}; - instructions[STF] = {"STF", InstructionType::TYPE3_4, reinterpret_cast(stf_handler)}; - instructions[STI] = {"STI", InstructionType::TYPE3_4, nullptr}; - instructions[STL] = {"STL", InstructionType::TYPE3_4, reinterpret_cast(stl_handler)}; - instructions[STS] = {"STS", InstructionType::TYPE3_4, reinterpret_cast(sts_handler)}; - instructions[STSW] = {"STSW", InstructionType::TYPE3_4, reinterpret_cast(stsw_handler)}; - instructions[STT] = {"STT", InstructionType::TYPE3_4, reinterpret_cast(stt_handler)}; - instructions[STX] = {"STX", InstructionType::TYPE3_4, reinterpret_cast(stx_handler)}; - instructions[SUB] = {"SUB", InstructionType::TYPE3_4, reinterpret_cast(sub_handler)}; - instructions[SUBF] = {"SUBF", InstructionType::TYPE3_4, reinterpret_cast(subf_handler)}; - instructions[SUBR] = {"SUBR", InstructionType::TYPE2, reinterpret_cast(subr_handler)}; - instructions[SVC] = {"SVC", InstructionType::TYPE2, reinterpret_cast(svc_handler)}; - instructions[TIXR] = {"TIXR", InstructionType::TYPE2, reinterpret_cast(tixr_handler)}; - instructions[TD] = {"TD", InstructionType::TYPE3_4, reinterpret_cast(td_handler)}; - instructions[TIX] = {"TIX", InstructionType::TYPE3_4, reinterpret_cast(tix_handler)}; - instructions[TIO] = {"TIO", InstructionType::TYPE1, nullptr}; - instructions[WD] = {"WD", InstructionType::TYPE3_4, reinterpret_cast(wd_handler)}; - - // Load SIC/XE/XE extended instructions - if (USE_EXTENDED_MODE) { - // Still in main table - instructions[NOP] = {"NOP", InstructionType::TYPE1, reinterpret_cast(nop_handler)}; - instructions[HALT] = {"HALT", InstructionType::TYPE1, reinterpret_cast(halt_handler)}; - instructions[XEXE] = {"XEXE", InstructionType::TYPE1, reinterpret_cast(xexe_handler)}; - - instructionsEXEX[VADD] = {"VADD", InstructionType::TYPE3_4, reinterpret_cast(vadd_handler)}; - instructionsEXEX[VADDR] = {"VADDR", InstructionType::TYPE2, reinterpret_cast(vaddr_handler)}; - instructionsEXEX[VSUB] = {"VSUB", InstructionType::TYPE3_4, reinterpret_cast(vsub_handler)}; - instructionsEXEX[VSUBR] = {"VSUBR", InstructionType::TYPE2, reinterpret_cast(vsubr_handler)}; - instructionsEXEX[VMUL] = {"VMUL", InstructionType::TYPE3_4, reinterpret_cast(vmul_handler)}; - instructionsEXEX[VMULR] = {"VMULR", InstructionType::TYPE2, reinterpret_cast(vmulr_handler)}; - instructionsEXEX[VDIV] = {"VDIV", InstructionType::TYPE3_4, reinterpret_cast(vdiv_handler)}; - instructionsEXEX[VDIVR] = {"VDIVR", InstructionType::TYPE2, reinterpret_cast(vdivr_handler)}; - instructionsEXEX[STVA] = {"STVA", InstructionType::TYPE3_4, reinterpret_cast(stva_handler)}; - instructionsEXEX[STVS] = {"STVS", InstructionType::TYPE3_4, reinterpret_cast(stvs_handler)}; - instructionsEXEX[STVT] = {"STVT", InstructionType::TYPE3_4, reinterpret_cast(stvt_handler)}; - instructionsEXEX[LDVA] = {"LDVA", InstructionType::TYPE3_4, reinterpret_cast(ldva_handler)}; - instructionsEXEX[LDVS] = {"LDVS", InstructionType::TYPE3_4, reinterpret_cast(ldvs_handler)}; - instructionsEXEX[LDVT] = {"LDVT", InstructionType::TYPE3_4, reinterpret_cast(ldvt_handler)}; - } - // Mark uninitialized opcodes as INVALID - for (int i = 0; i < 0xff; ++i) { - if (instructions[i].name == nullptr) instructions[i] = {"INVALID", InstructionType::INVALID, nullptr}; - if (instructionsEXEX[i].name == nullptr) instructionsEXEX[i] = {"INVALID", InstructionType::INVALID, nullptr}; - } -} - -AddressingMode getAddressingMode(int ni) -{ - switch (ni) { - case 0x0: return AddressingMode::SIC_DIRECT; - case 0x1: return AddressingMode::IMMEDIATE; - case 0x2: return AddressingMode::INDIRECT; - case 0x3: return AddressingMode::SIMPLE; - default: return AddressingMode::INVALID; // Should not happen - } -} diff --git a/ass2/simulator_SIC_XE/src/output_device.cpp b/ass2/simulator_SIC_XE/src/output_device.cpp deleted file mode 100644 index ce7b4ec..0000000 --- a/ass2/simulator_SIC_XE/src/output_device.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "output_device.h" - -OutputDevice::OutputDevice(std::ostream &out) - : outStream(out) -{ -} - -OutputDevice::~OutputDevice() -{ -} - -void OutputDevice::write(unsigned char value) -{ - outStream.put(static_cast(value)); - outStream.flush(); -} diff --git a/ass2/simulator_SIC_XE/src/string_reader.cpp b/ass2/simulator_SIC_XE/src/string_reader.cpp deleted file mode 100644 index b87cc02..0000000 --- a/ass2/simulator_SIC_XE/src/string_reader.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "string_reader.h" - -StringReader::StringReader(const std::string &s) - : in(s) -{} - -StringReader::~StringReader() = default; - -int StringReader::readByte() { - char c; - if (!in.get(c)) return -1; - return static_cast(c); -} - -bool StringReader::readBytes(uint8_t* buf, size_t len) { - in.read(reinterpret_cast(buf), static_cast(len)); - return static_cast(in.gcount()) == len; -} - -std::string StringReader::readString(size_t len) { - std::string s; - s.resize(len); - in.read(reinterpret_cast(&s[0]), static_cast(len)); - std::streamsize got = in.gcount(); - if (static_cast(got) < len) s.resize(static_cast(got)); - return s; -} - -std::string StringReader::readLine() { - std::string s; - if (!std::getline(in, s)) return std::string(); - return s; -} diff --git a/simulator_SIC_XE/.gitignore b/simulator_SIC_XE/.gitignore index 4cbe372..6b70294 100644 --- a/simulator_SIC_XE/.gitignore +++ b/simulator_SIC_XE/.gitignore @@ -7,6 +7,7 @@ CMakeCache.txt CMakeFiles/ CMakeScripts/ cmake_install.cmake +Makefile *.cmake !CMakeLists.txt @@ -70,7 +71,6 @@ xcuserdata/ *.moc.cpp *.qm *.prl -CMakeLists.txt.user # OS generated files .DS_Store diff --git a/simulator_SIC_XE/CMakeLists.txt b/simulator_SIC_XE/CMakeLists.txt index c6c37e1..242ebd3 100644 --- a/simulator_SIC_XE/CMakeLists.txt +++ b/simulator_SIC_XE/CMakeLists.txt @@ -4,7 +4,7 @@ project(simulator_SIC_XE VERSION 1.0 LANGUAGES CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) -# Put all build outputs under target/bin +# Put all build outputs under target/bin as requested set(OUTPUT_DIR ${CMAKE_SOURCE_DIR}/target/bin) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${OUTPUT_DIR}) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${OUTPUT_DIR}) @@ -28,7 +28,8 @@ if(EXISTS "${PROJECT_SOURCE_DIR}/src/main.cpp") target_link_libraries(simulator_exec PRIVATE simulator_lib) endif() - +# Convenience target: `cmake --build build --target run` +# This target will build `simulator_exec` (if present) and then execute it. if(TARGET simulator_exec) add_custom_target(run DEPENDS simulator_exec @@ -42,19 +43,3 @@ endif() message(STATUS "Project: ${PROJECT_NAME}") message(STATUS "Sources found: ${SOURCES}") message(STATUS "Output directory: ${OUTPUT_DIR}") - -if(EXISTS "${CMAKE_SOURCE_DIR}/gui/qt/CMakeLists.txt") - add_subdirectory(gui/qt) -endif() - -# Copy resources directory (if present) to target/res so build output includes them -if(EXISTS "${CMAKE_SOURCE_DIR}/res") - add_custom_target(copy_resources - COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_SOURCE_DIR}/target/res - COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/res ${CMAKE_SOURCE_DIR}/target/res - COMMENT "Copying resources from res/ to target/res/" - ) - if(TARGET simulator_exec) - add_dependencies(simulator_exec copy_resources) - endif() -endif() diff --git a/simulator_SIC_XE/Makefile b/simulator_SIC_XE/Makefile deleted file mode 100644 index 93bc1f6..0000000 --- a/simulator_SIC_XE/Makefile +++ /dev/null @@ -1,68 +0,0 @@ -# Simple Makefile wrapper to configure, build and run the CMake project. -# Usage: -# make # configure + build with all cores -# make build # configure + build with all cores -# make all # clean + configure + build + run -# make run # just run the executable (no build) -# make clean # run CMake clean (or remove build files) -# make distclean # remove build dir and generated targets - -CMAKE ?= cmake -BUILD_DIR := build -CMAKE_BUILD_TYPE ?= Release -TARGET := target/bin/simulator_exec -GUI_TARGET := target/bin/simulator_qt -NPROC := $(shell nproc) - -.PHONY: all configure build run clean distclean - -# Default target: just build -default: build - -# make all: clean, build, then run -all: clean build run - -configure: - @echo "Configuring (build dir: $(BUILD_DIR), type: $(CMAKE_BUILD_TYPE))" - $(CMAKE) -S . -B $(BUILD_DIR) -DCMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE) - -build: configure - @echo "Building with $(NPROC) cores..." - $(CMAKE) --build $(BUILD_DIR) -j$(NPROC) - -# make run: just launch the executable (no build) -run: - @echo "Running primary target..." - # Prefer GUI if available, otherwise fall back to console executable - @if [ -x "$(GUI_TARGET)" ]; then \ - echo "Launching GUI: $(GUI_TARGET)"; \ - ./$(GUI_TARGET); \ - elif [ -x "$(TARGET)" ]; then \ - ./$(TARGET); \ - else \ - echo "No runnable target found (tried $(GUI_TARGET) and $(TARGET))."; exit 1; \ - fi - -.PHONY: run-gui -run-gui: build - @echo "Running GUI target ($(GUI_TARGET))" - @if [ -x "$(GUI_TARGET)" ]; then \ - echo "Starting GUI..."; ./$(GUI_TARGET) -platform xcb; \ - else \ - echo "GUI executable not found: $(GUI_TARGET)"; exit 1; \ - fi - -.PHONY: build-gui -build-gui: configure - @echo "Building GUI (and core)..." - $(CMAKE) --build $(BUILD_DIR) -j$(shell nproc) --target simulator_qt || true - -clean: - @echo "Cleaning build (CMake clean)..." - -$(CMAKE) --build $(BUILD_DIR) --target clean || true - @echo "Removing target directory..." - -rm -rf target/ - -distclean: - @echo "Removing build artifacts and generated files..." - -rm -rf $(BUILD_DIR) CMakeFiles CMakeCache.txt cmake_install.cmake target/ diff --git a/simulator_SIC_XE/README.md b/simulator_SIC_XE/README.md index aac6331..9842788 100644 --- a/simulator_SIC_XE/README.md +++ b/simulator_SIC_XE/README.md @@ -18,14 +18,11 @@ This single command will: ## Build Commands -| Command | Description | -|--------------|----------------------------------------------------| -| `make` | Build the project | -| `make build` | Build the project | -| `make run` | Build run the simulator | -| `make clean` | Clean build artifacts | -| `make run` | Clean build artifacts, build and run the simulator | - +| Command | Description | +|---------|-------------| +| `make` | Build the project | +| `make run` | Build and run the simulator | +| `make clean` | Clean build artifacts | ## Project Structure diff --git a/simulator_SIC_XE/gui/qt/CMakeLists.txt b/simulator_SIC_XE/gui/qt/CMakeLists.txt deleted file mode 100644 index cf8072a..0000000 --- a/simulator_SIC_XE/gui/qt/CMakeLists.txt +++ /dev/null @@ -1,54 +0,0 @@ -cmake_minimum_required(VERSION 3.16) -project(simulator_qt LANGUAGES CXX) - -set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_STANDARD_REQUIRED ON) - -set(CMAKE_AUTOMOC ON) -set(CMAKE_AUTOUIC ON) -set(CMAKE_AUTORCC ON) - -# Prefer Qt6, fall back to Qt5 -find_package(Qt6 COMPONENTS Widgets QUIET) -if(NOT Qt6_FOUND) - # Try explicitly the system Qt6 cmake prefix on Debian/Ubuntu - find_package(Qt6 COMPONENTS Widgets QUIET PATHS /usr/lib/x86_64-linux-gnu) -endif() - -if(NOT Qt6_FOUND) - # Fallback: try Qt5 if Qt6 is unavailable - find_package(Qt5 COMPONENTS Widgets QUIET) -endif() - -if(Qt6_FOUND) - set(QT_LIB Qt6::Widgets) -elseif(Qt5_FOUND) - set(QT_LIB Qt5::Widgets) -else() - message(FATAL_ERROR "Qt6 or Qt5 not found. Install Qt development packages or set CMAKE_PREFIX_PATH to your Qt installation.") -endif() - -set(GUI_SRCS - main.cpp - mainwindow.cpp - MachineController.cpp -) - -set(GUI_HDRS - mainwindow.h - MachineController.h -) - -add_executable(simulator_qt ${GUI_SRCS} ${GUI_HDRS}) - -# Allow the generated UI headers (from AUTOUIC) to be found in the build dir -# and also include the top-level include folder (works when added with add_subdirectory) -target_include_directories(simulator_qt PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_SOURCE_DIR}/include) - -# Link to core library target (must be defined by top-level CMake) -target_link_libraries(simulator_qt PRIVATE simulator_lib ${QT_LIB}) - -# Place runtime binary under repo/target/bin to match project layout -set_target_properties(simulator_qt PROPERTIES - RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/target/bin -) \ No newline at end of file diff --git a/simulator_SIC_XE/gui/qt/MachineController.cpp b/simulator_SIC_XE/gui/qt/MachineController.cpp deleted file mode 100644 index 881e97d..0000000 --- a/simulator_SIC_XE/gui/qt/MachineController.cpp +++ /dev/null @@ -1,76 +0,0 @@ -#include "MachineController.h" -#include "../../include/machine.h" -#include -#include - -using namespace std::chrono; - -MachineController::MachineController(std::shared_ptr machine, QObject *parent) - : QObject(parent), m_machine(std::move(machine)) -{ - if (!m_machine) { - m_machine = std::make_shared(); - } - m_lastUpdateTime = steady_clock::now(); -} - -MachineController::~MachineController() { - stop(); -} - -void MachineController::start() { - if (m_running.exchange(true)) return; - m_thread = std::thread([this]{ runLoop(); }); -} - -void MachineController::stop() { - if (!m_running.exchange(false)) return; - if (m_thread.joinable()) m_thread.join(); -} - -void MachineController::step() { - try { - if (m_machine) { - m_machine->execute(); - m_machine->tick(); - emit tick(); - } - } catch (const std::exception &e) { - emit error(QString::fromStdString(e.what())); - } -} - -void MachineController::runLoop() { - const auto minUpdateInterval = milliseconds(16); - - while (m_running.load()) { - try { - if (m_machine) { - m_machine->execute(); - m_machine->tick(); - m_ticksSinceLastUpdate++; - - // Throttle GUI updates to 60 Hz - auto now = steady_clock::now(); - auto elapsed = duration_cast(now - m_lastUpdateTime); - - if (elapsed >= minUpdateInterval) { - emit tick(); - m_lastUpdateTime = now; - m_ticksSinceLastUpdate = 0; - } - - if (m_machine->isStopped()) { - emit tick(); - m_running.store(false); - break; - } - } - } catch (const std::exception &e) { - emit error(QString::fromStdString(e.what())); - // Stop on fatal error - m_running.store(false); - break; - } - } -} diff --git a/simulator_SIC_XE/gui/qt/MachineController.h b/simulator_SIC_XE/gui/qt/MachineController.h deleted file mode 100644 index 801b5f4..0000000 --- a/simulator_SIC_XE/gui/qt/MachineController.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef MACHINECONTROLLER_H -#define MACHINECONTROLLER_H - -#include -#include -#include -#include - -class Machine; - -class MachineController : public QObject { - Q_OBJECT -public: - explicit MachineController(std::shared_ptr machine = nullptr, QObject *parent = nullptr); - ~MachineController() override; - - void start(); - void stop(); - void step(); - -signals: - void tick(); - void error(const QString &msg); - -private: - void runLoop(); - std::atomic m_running{false}; - std::thread m_thread; - std::shared_ptr m_machine; - std::atomic m_ticksSinceLastUpdate{0}; - std::chrono::steady_clock::time_point m_lastUpdateTime; -}; - -#endif // MACHINECONTROLLER_H diff --git a/simulator_SIC_XE/gui/qt/main.cpp b/simulator_SIC_XE/gui/qt/main.cpp deleted file mode 100644 index 707d916..0000000 --- a/simulator_SIC_XE/gui/qt/main.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include -#include "mainwindow.h" -#include "../../include/opcode.h" - -int main(int argc, char **argv) { - loadInstructionSet(); - - qputenv("QT_QPA_PLATFORM", "xcb"); - - QApplication app(argc, argv); - MainWindow w; - w.show(); - return app.exec(); -} \ No newline at end of file diff --git a/simulator_SIC_XE/gui/qt/mainwindow.cpp b/simulator_SIC_XE/gui/qt/mainwindow.cpp deleted file mode 100644 index b53aa72..0000000 --- a/simulator_SIC_XE/gui/qt/mainwindow.cpp +++ /dev/null @@ -1,1030 +0,0 @@ -#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 -#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, Qt::QueuedConnection); - connect(m_controller.get(), &MachineController::tick, this, &MainWindow::updateMemoryDisplay, Qt::QueuedConnection); - - 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, Qt::QueuedConnection); - - // Connect menu actions - connect(ui->actionLoad_Object_File, &QAction::triggered, this, &MainWindow::loadObjectFile); - connect(ui->actionAbout, &QAction::triggered, this, &MainWindow::showAboutDialog); - connect(ui->actionFrequency, &QAction::triggered, this, &MainWindow::showFrequencyDialog); - - setupMemoryDisplay(); - setupDisassemblyDisplay(); - - loadInstructionSet(); - // Don't load any program by default - user will load via File menu - - 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] : "?"; - - // 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; - } - - 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 += (address + 3); - 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); - - // 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() -{ - 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); - - int scrollPos = ui->MemoryScrollArea->verticalScrollBar()->value(); - - ui->MemoryScrollArea->setWidget(container); - - ui->MemoryScrollArea->verticalScrollBar()->setValue(scrollPos); -} - -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())); - } -} - -void MainWindow::showAboutDialog() -{ - QMessageBox::about(this, tr("About SIC/XE Simulator"), - tr("SIC/XE Simulator\nby Zan Skvarca\n2025")); -} - -void MainWindow::showFrequencyDialog() -{ - if (!m_machine) return; - - QDialog dialog(this); - dialog.setWindowTitle(tr("Set Frequency")); - dialog.setModal(true); - - QVBoxLayout *layout = new QVBoxLayout(&dialog); - - QLabel *currentLabel = new QLabel(tr("Current frequency: %1 Hz").arg(m_machine->getSpeed()), &dialog); - layout->addWidget(currentLabel); - - QLabel *newLabel = new QLabel(tr("New frequency (Hz):"), &dialog); - layout->addWidget(newLabel); - - QLineEdit *freqInput = new QLineEdit(&dialog); - freqInput->setValidator(new QIntValidator(1, 1000000000, &dialog)); - freqInput->setText(QString::number(m_machine->getSpeed())); - layout->addWidget(freqInput); - - QHBoxLayout *buttonLayout = new QHBoxLayout(); - QPushButton *submitBtn = new QPushButton(tr("Submit"), &dialog); - QPushButton *cancelBtn = new QPushButton(tr("Cancel"), &dialog); - buttonLayout->addWidget(submitBtn); - buttonLayout->addWidget(cancelBtn); - layout->addLayout(buttonLayout); - - connect(submitBtn, &QPushButton::clicked, &dialog, &QDialog::accept); - connect(cancelBtn, &QPushButton::clicked, &dialog, &QDialog::reject); - - if (dialog.exec() == QDialog::Accepted) { - bool ok; - int newFreq = freqInput->text().toInt(&ok); - if (ok && newFreq > 0) { - m_machine->setSpeed(newFreq); - QMessageBox::information(this, tr("Success"), - tr("Frequency set to %1 Hz").arg(newFreq)); - } - } -} diff --git a/simulator_SIC_XE/gui/qt/mainwindow.h b/simulator_SIC_XE/gui/qt/mainwindow.h deleted file mode 100644 index 2dba671..0000000 --- a/simulator_SIC_XE/gui/qt/mainwindow.h +++ /dev/null @@ -1,85 +0,0 @@ -#ifndef MAINWINDOW_H -#define MAINWINDOW_H - -#include -#include - -class MachineController; -class Machine; -class QLineEdit; - -namespace Ui { -class MainWindow; -} - -class MainWindow : public QMainWindow -{ - Q_OBJECT - -public: - explicit MainWindow(QWidget *parent = nullptr); - ~MainWindow(); - - std::shared_ptr machine() const { return m_machine; } - MachineController* controller() const { return m_controller.get(); } - - void startExecution(); - void stopExecution(); - void stepExecution(); - - void setTestRegisterValues(); - -private slots: - void updateRegisterDisplays(); - void updateMemoryDisplay(); - void updateDisassemblyDisplay(); - void onRegisterFieldChanged(); - void onMemoryInc256(); - void onMemoryInc4096(); - void onMemoryInc65536(); - 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(); - void loadObjectFile(); - void showAboutDialog(); - void showFrequencyDialog(); - -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); - void updateAllFormatsForRegister(const QString& regPrefix, int value); - void updateFloatRegisterFormats(const QString& regPrefix, double value); - 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 deleted file mode 100644 index e9084bd..0000000 --- a/simulator_SIC_XE/gui/qt/mainwindow.ui +++ /dev/null @@ -1,930 +0,0 @@ - - - MainWindow - - - - 0 - 0 - 1172 - 649 - - - - MainWindow - - - - - - 10 - 0 - 431 - 601 - - - - - - 0 - 80 - 431 - 321 - - - - Register values - - - - - 70 - 40 - 113 - 23 - - - - - - - 10 - 40 - 57 - 20 - - - - - 10 - - - - Reg A - - - - - - 190 - 40 - 113 - 23 - - - - - - - 310 - 40 - 113 - 23 - - - - - - - 110 - 20 - 57 - 20 - - - - - 10 - - - - Bin - - - - - - 230 - 20 - 57 - 20 - - - - - 10 - - - - Hex - - - - - - 350 - 20 - 57 - 20 - - - - - 10 - - - - Dec - - - - - - 310 - 70 - 113 - 23 - - - - - - - 10 - 70 - 57 - 20 - - - - - 10 - - - - Reg B - - - - - - 190 - 70 - 113 - 23 - - - - - - - 70 - 70 - 113 - 23 - - - - - - - 310 - 100 - 113 - 23 - - - - - - - 10 - 100 - 57 - 20 - - - - - 10 - - - - Reg X - - - - - - 190 - 100 - 113 - 23 - - - - - - - 70 - 100 - 113 - 23 - - - - - - - 310 - 130 - 113 - 23 - - - - - - - 10 - 130 - 57 - 20 - - - - - 10 - - - - Reg S - - - - - - 190 - 130 - 113 - 23 - - - - - - - 70 - 130 - 113 - 23 - - - - - - - 310 - 160 - 113 - 23 - - - - - - - 10 - 160 - 57 - 20 - - - - - 10 - - - - Reg T - - - - - - 190 - 160 - 113 - 23 - - - - - - - 70 - 160 - 113 - 23 - - - - - - - 190 - 190 - 113 - 23 - - - - - - - 70 - 190 - 113 - 23 - - - - - - - 10 - 190 - 57 - 20 - - - - - 10 - - - - Reg L - - - - - - 310 - 190 - 113 - 23 - - - - - - - 10 - 220 - 57 - 20 - - - - - 10 - - - - Reg PC - - - - - - 310 - 220 - 113 - 23 - - - - - - - 70 - 220 - 113 - 23 - - - - - - - 190 - 220 - 113 - 23 - - - - - - - 10 - 249 - 57 - 20 - - - - - 10 - - - - Reg SW - - - - - - 310 - 249 - 113 - 23 - - - - - - - 70 - 249 - 113 - 23 - - - - - - - 190 - 249 - 113 - 23 - - - - - - - 10 - 280 - 57 - 20 - - - - - 10 - - - - Reg L - - - - - - 310 - 280 - 113 - 23 - - - - - - - 70 - 280 - 113 - 23 - - - - - - - 190 - 280 - 113 - 23 - - - - - - - - 0 - 0 - 431 - 81 - - - - Control - - - - - 30 - 40 - 80 - 23 - - - - Start - - - - - - 170 - 40 - 80 - 23 - - - - Stop - - - - - - 310 - 40 - 80 - 23 - - - - Step - - - - - - - - 450 - 0 - 721 - 601 - - - - - - 0 - 0 - 711 - 291 - - - - Memory - - - - - 0 - 20 - 711 - 221 - - - - true - - - - - 0 - 0 - 709 - 219 - - - - - - - - 450 - 250 - 71 - 23 - - - - >> - - - - - - 370 - 250 - 71 - 23 - - - - > - - - - - - 530 - 250 - 71 - 23 - - - - >>> - - - - - - 290 - 250 - 71 - 23 - - - - < - - - - - - 210 - 250 - 71 - 23 - - - - << - - - - - - 130 - 250 - 71 - 21 - - - - <<< - - - - - - 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 - - - - | - - - - - - - - - toolBar - - - TopToolBarArea - - - false - - - - - - 0 - 0 - 1172 - 20 - - - - - File - - - - - - Machine - - - - - - Help - - - - - - - - - - Load Object File - - - - - Frequency - - - - - About - - - - - - diff --git a/simulator_SIC_XE/include/constants.h b/simulator_SIC_XE/include/constants.h deleted file mode 100644 index 6f2195a..0000000 --- a/simulator_SIC_XE/include/constants.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef CONSTANTS_H -#define CONSTANTS_H - -#include -// ============================== -// SIC/XE Architecture Constants -// ============================== - -// Memory and system constants -constexpr int MEMORY_SIZE = 1 << 20; // 1 MB memory -constexpr int NUM_DEVICES = 256; -constexpr int WORD_SIZE = 24; -constexpr int WORD_MASK = 0xFFFFFF; - -// SIC/XE floating point constants -constexpr int SICF_BITS = 48; -constexpr int SICF_FRAC_BITS = 40; -constexpr int SICF_EXP_BITS = 7; -constexpr int SICF_EXP_BIAS = 64; -constexpr unsigned long long SICF_FRAC_MASK = (1ULL << SICF_FRAC_BITS) - 1; - -// SW register condition codes -constexpr int CC_LT = 0x0; // 00 -constexpr int CC_EQ = 0x1; // 01 -constexpr int CC_GT = 0x2; // 10 -constexpr int CC_MASK = 0x3; // mask for 2 bits - -// Instruction format bit masks -constexpr int TYPE3_4_SIC_MASK = 0xFC; -constexpr int NI_MASK = 0x03; // mask for n and i bits -constexpr int NI_SIC = 0x0; - -constexpr int BP_BASE_REL_MASK = 0b10; -constexpr int BP_PC_REL_MASK = 0b01; -constexpr int BP_DIRECT_MASK = 0b00; - -constexpr int BIT_E_MASK = 0x10; // mask for e bit in F4 and F3 instructions - -//SIC/XE/XE -constexpr bool USE_EXTENDED_MODE = true; -constexpr int VECTOR_REG_SIZE = 4; - -/* if structure is -/target/ - |-> bin/simulator_exec - |-> res/ -*/ -// When running from project root (./target/bin/simulator_exec), resources are in ./target/res/ -constexpr char PATH_RESOURCES[] = "./target/res/"; -constexpr bool FILE_CONTAINS_WHITE_SPACES = true; - -#endif // CONSTANTS_H \ No newline at end of file diff --git a/simulator_SIC_XE/include/file_device.h b/simulator_SIC_XE/include/file_device.h index 01b433c..e98bfc6 100644 --- a/simulator_SIC_XE/include/file_device.h +++ b/simulator_SIC_XE/include/file_device.h @@ -13,11 +13,7 @@ public: void write(unsigned char value) override; private: - void ensureFileOpen(); 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/include/file_reader.h b/simulator_SIC_XE/include/file_reader.h deleted file mode 100644 index 87b8a17..0000000 --- a/simulator_SIC_XE/include/file_reader.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef FILE_READER_H -#define FILE_READER_H - -#include "reader.h" -#include -#include - -class FileReader : public Reader { -public: - explicit FileReader(const std::string &path, std::ios::openmode m = std::ios::binary); - ~FileReader() override; - - int readByte() override; - - bool readBytes(uint8_t* buf, size_t len) override; - std::string readString(size_t len) override; - std::string readLine() override; - - bool good() const; - -private: - std::ifstream in; -}; - -#endif // FILE_READER_H \ No newline at end of file diff --git a/simulator_SIC_XE/include/instructions.h b/simulator_SIC_XE/include/instructions.h index 5bef303..ff2e532 100644 --- a/simulator_SIC_XE/include/instructions.h +++ b/simulator_SIC_XE/include/instructions.h @@ -1,26 +1,11 @@ #ifndef INSTRUCTIONS_H #define INSTRUCTIONS_H -#include "utils.h" - -class Machine; // forward declaration - -// Type 1 instruction handlers -void fix_handler(Machine& m); -void float_handler(Machine& m); -void hio_handler(Machine& m); -void norm_handler(Machine& m); -void sio_handler(Machine& m); -void tio_handler(Machine& m); -void nop_handler(Machine& m); - -/* IDEJE ZA SIC_XE_XE :)*/ -// void nop(Machine& m); +#include "opcode.h" // Type 2 instruction handlers void addr_handler(Machine& m, int r1, int r2); void clear_handler(Machine& m, int r, int unused); -void compr_handler(Machine& m, int r1, int r2); void divr_handler(Machine& m, int r1, int r2); void mulr_handler(Machine& m, int r1, int r2); void rmo_handler(Machine& m, int r1, int r2); @@ -31,71 +16,5 @@ void svc_handler(Machine& m, int n, int unused); void tixr_handler(Machine& m, int r1, int unused); -// Type 3/4 instruction handlers -void add_handler(Machine& m, int ea, AddressingMode mode); -void addf_handler(Machine& m, int ea, AddressingMode mode); -void and_handler(Machine& m, int ea, AddressingMode mode); -void comp_handler(Machine& m, int ea, AddressingMode mode); -void compf_handler(Machine& m, int ea, AddressingMode mode); -void div_handler(Machine& m, int ea, AddressingMode mode); -void divf_handler(Machine& m, int ea, AddressingMode mode); -void j_handler(Machine& m, int ea, AddressingMode mode); -void jeq_handler(Machine& m, int ea, AddressingMode mode); -void jgt_handler(Machine& m, int ea, AddressingMode mode); -void jlt_handler(Machine& m, int ea, AddressingMode mode); -void jsub_handler(Machine& m, int ea, AddressingMode mode); -void lda_handler(Machine& m, int ea, AddressingMode mode); -void ldb_handler(Machine& m, int ea, AddressingMode mode); -void ldch_handler(Machine& m, int ea, AddressingMode mode); -void ldf_handler(Machine& m, int ea, AddressingMode mode); -void ldl_handler(Machine& m, int ea, AddressingMode mode); -void lds_handler(Machine& m, int ea, AddressingMode mode); -void ldt_handler(Machine& m, int ea, AddressingMode mode); -void ldx_handler(Machine& m, int ea, AddressingMode mode); -void lps_handler(Machine& m, int ea, AddressingMode mode); -void mul_handler(Machine& m, int ea, AddressingMode mode); -void mulf_handler(Machine& m, int ea, AddressingMode mode); -void or_handler(Machine& m, int ea, AddressingMode mode); -void rd_handler(Machine& m, int ea, AddressingMode mode); -void rsub_handler(Machine& m, int ea, AddressingMode mode); -void ssk_handler(Machine& m, int ea, AddressingMode mode); -void sta_handler(Machine& m, int ea, AddressingMode mode); -void stb_handler(Machine& m, int ea, AddressingMode mode); -void stch_handler(Machine& m, int ea, AddressingMode mode); -void stf_handler(Machine& m, int ea, AddressingMode mode); -void sti_handler(Machine& m, int ea, AddressingMode mode); -void stl_handler(Machine& m, int ea, AddressingMode mode); -void sts_handler(Machine& m, int ea, AddressingMode mode); -void stsw_handler(Machine& m, int ea, AddressingMode mode); -void stt_handler(Machine& m, int ea, AddressingMode mode); -void stx_handler(Machine& m, int ea, AddressingMode mode); -void sub_handler(Machine& m, int ea, AddressingMode mode); -void subf_handler(Machine& m, int ea, AddressingMode mode); -void td_handler(Machine& m, int ea, AddressingMode mode); -void tix_handler(Machine& m, int ea, AddressingMode mode); -void wd_handler(Machine& m, int ea, AddressingMode mode); - - -// SIC/XE/XE Extended instruction handlers -void xexe_handler(Machine& m); -void halt_handler(Machine& m); -void nop_handler(Machine& m); - -void vaddr_handler(Machine& m, int r1, int r2); -void vsubr_handler(Machine& m, int r1, int r2); -void vmulr_handler(Machine& m, int r1, int r2); -void vdivr_handler(Machine& m, int r1, int r2); - -void vadd_handler(Machine& m, int ea, AddressingMode mode); -void vsub_handler(Machine& m, int ea, AddressingMode mode); -void vmul_handler(Machine& m, int ea, AddressingMode mode); -void vdiv_handler(Machine& m, int ea, AddressingMode mode); -void stva_handler(Machine& m, int ea, AddressingMode mode); -void stvs_handler(Machine& m, int ea, AddressingMode mode); -void stvt_handler(Machine& m, int ea, AddressingMode mode); -void ldva_handler(Machine& m, int ea, AddressingMode mode); -void ldvs_handler(Machine& m, int ea, AddressingMode mode); -void ldvt_handler(Machine& m, int ea, AddressingMode mode); - #endif // INSTRUCTIONS_H \ No newline at end of file diff --git a/simulator_SIC_XE/include/loader.h b/simulator_SIC_XE/include/loader.h deleted file mode 100644 index 41899c2..0000000 --- a/simulator_SIC_XE/include/loader.h +++ /dev/null @@ -1,68 +0,0 @@ -#ifndef LOADER_H -#define LOADER_H - -#include -#include -#include -#include "file_reader.h" -#include - -class Machine; - -using std::shared_ptr; -using std::string; - - -class Loader { -public: - Loader( shared_ptr machine, string filename) : _machine(machine), _filename(filename) { - _file_reader = std::make_shared(filename, std::ios::in); - if (!_file_reader->good()) { - throw std::runtime_error("Loader: failed to open file: " + filename); - } - } - ~Loader(); - - - enum class RecordType { - HEADER, - TEXT, - END, - UNKNOWN - }; - - struct HeaderMetadata { - string program_name; - int start_address; - int length; - }; - struct TextRecord { - int start_address; - std::vector data; - }; - struct EndRecord { - int execution_start_address; - }; - - void load(); - -private : - - static RecordType parseRecordType(char c); - - - shared_ptr _machine; - string _filename; - shared_ptr _file_reader; - HeaderMetadata readHeader(); - TextRecord readTextRecord(); - EndRecord readEndRecord(); - bool load_into_memory(int start_address, const std::vector& data); - -}; - - - - - -#endif // LOADER_H \ No newline at end of file diff --git a/simulator_SIC_XE/include/machine.h b/simulator_SIC_XE/include/machine.h index cd14f74..e0920da 100644 --- a/simulator_SIC_XE/include/machine.h +++ b/simulator_SIC_XE/include/machine.h @@ -4,18 +4,18 @@ #include #include #include -#include -#include -#include - -#include "constants.h" #include "device.h" #include "input_device.h" #include "output_device.h" #include "file_device.h" #include "opcode.h" -#include "utils.h" + +#include + +#define MEMORY_SIZE 65536 +#define NUM_DEVICES 256 + using std::string; using std::cerr; @@ -26,32 +26,30 @@ using std::cout; class Machine { public: Machine(); - Machine(int speedHz) : Machine() { this->speedHz = speedHz; _instructionsTable = instructions; } ~Machine(); + // Accessor methods for registers int getA() const { return A; } - void setA(int value) { A = toSIC24(value); } + void setA(int value) { A = value; } int getB() const { return B; } - void setB(int value) { B = toSIC24(value); } + void setB(int value) { B = value; } int getX() const { return X; } - void setX(int value) { X = toSIC24(value); } + void setX(int value) { X = value; } int getL() const { return L; } - void setL(int value) { L = toSIC24(value); } + void setL(int value) { L = value; } int getS() const { return S; } - void setS(int value) { S = toSIC24(value); } + void setS(int value) { S = value; } int getT() const { return T; } - void setT(int value) { T = toSIC24(value); } + void setT(int value) { T = value; } - // PC is an address → don't mask to 24 unless you want 24-bit addressing int getPC() const { return PC; } void setPC(int value) { PC = value; } - // status word: keep as-is int getSW() const { return SW; } void setSW(int value) { SW = value; } @@ -78,19 +76,14 @@ public: // Set a file device at index `num` using the provided filename. void setFileDevice(int num, const std::string &filename); + // Fetch and execute instructions int fetch(); void execute(); - // Execution and speed control - int getSpeed() const; - void setSpeed(int Hz); - void start(); - void stop(); - void tick(); - void halt(); - bool isStopped() const { return _stopped; } - void reset(); + bool execF1(int opcode); + bool execF2(int opcode, int operand); + bool execSICF3F4(int opcode, int ni, int operand); // error handling methods void notImplemented(string mnemonic); @@ -99,22 +92,6 @@ public: void divisionByZero(int opcode); void undefinedHandler(int opcode); - bool getExtendedMode() const { return _exex_mode; } - void enableExtendedMode(); - void disableExtendedMode(); - - - int* getVectorRegister(int regNum); - void setVectorRegister(int regNum, const int* values); - - const int* getVA() const { return VA; } - const int* getVS() const { return VS; } - const int* getVT() const { return VT; } - void setVA(const int* values); - void setVS(const int* values); - void setVT(const int* values); - - private: // registers int A, B, X, L, S, T, PC, SW; @@ -127,23 +104,42 @@ private: std::vector> devices; // fallback device returned when device slot is empty/invalid Device fallbackDevice; - - // Execution control - std::atomic running{false}; - std::atomic speedHz{10}; // Default 10 Hz - - bool execF1(int opcode); - bool execF2(int opcode, int operand); - bool execSICF3F4(int opcode, int ni, int x, int b, int p, int e, int operand); - - - // Extended mode - bool _stopped{false}; - bool _exex_mode{false}; - InstructionInfo* _instructionsTable; - int VA[VECTOR_REG_SIZE], VS[VECTOR_REG_SIZE], VT[VECTOR_REG_SIZE]; // vector operation registers }; + // Convert integer to 24-bit signed SIC representation +inline int toSIC24(int value) { + value &= 0xFFFFFF; + if (value & 0x800000) { + value -= 0x1000000; + } + return value; +} + +inline int setCC(int sw, int cc) { + sw &= ~CC_MASK; + sw |= (cc & CC_MASK); + return sw; +} + +inline int sic_comp(int a, int b, int sw) { + int sa = toSIC24(a); + int sb = toSIC24(b); + + int cc; + if (sa < sb) { + cc = CC_LT; + } else if (sa == sb) { + cc = CC_EQ; + } else { + cc = CC_GT; + } + + return setCC(sw, cc); +} + +inline int getCC(int sw) { + return sw & CC_MASK; +} #endif // MACHINE_H \ No newline at end of file diff --git a/simulator_SIC_XE/include/opcode.h b/simulator_SIC_XE/include/opcode.h index a467488..93df629 100644 --- a/simulator_SIC_XE/include/opcode.h +++ b/simulator_SIC_XE/include/opcode.h @@ -1,8 +1,6 @@ #ifndef OPCODE_H #define OPCODE_H -#include "utils.h" - // ============================== // Opcode definitions (SIC/XE) // ============================== @@ -66,26 +64,13 @@ #define TIXR 0xB8 #define WD 0xDC -// ============================== -// Extended opcodes (SIC/XE/XE) -// ============================== -#define NOP 0xF1 -#define HALT 0xF2 -#define XEXE 0xEE // Enable extended mode -#define VADD 0x18 -#define VADDR 0x90 -#define VSUB 0x1C -#define VSUBR 0x94 -#define VMUL 0x20 -#define VMULR 0x98 -#define VDIV 0x24 -#define VDIVR 0x9C -#define STVA 0x0C -#define STVS 0x7C -#define STVT 0x84 -#define LDVA 0x00 -#define LDVS 0x68 -#define LDVT 0x04 + + +// SW register condition codes +constexpr int CC_LT = 0x0; // 00 +constexpr int CC_EQ = 0x1; // 01 +constexpr int CC_GT = 0x2; // 10 +constexpr int CC_MASK = 0x3; // mask for 2 bits @@ -108,7 +93,6 @@ struct InstructionInfo { }; extern InstructionInfo instructions[]; -extern InstructionInfo instructionsEXEX[]; // Initialize the instruction table void loadInstructionSet(); diff --git a/simulator_SIC_XE/include/reader.h b/simulator_SIC_XE/include/reader.h deleted file mode 100644 index e582161..0000000 --- a/simulator_SIC_XE/include/reader.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef READER_H -#define READER_H - -#include -#include - -// Abstract Reader class: read bytes/strings from a source (file, string, etc.) -class Reader { -public: - virtual ~Reader() = default; - // return 0..255 on success, -1 on EOF/error - virtual int readByte() = 0; - // read exactly len bytes into buf; return true on success - virtual bool readBytes(uint8_t* buf, size_t len) = 0; - // read up to len bytes into a std::string; may return shorter string on EOF - virtual std::string readString(size_t len) = 0; - // read a line (up to newline), return empty string on EOF - virtual std::string readLine() = 0; -}; - -#endif // READER_H \ No newline at end of file diff --git a/simulator_SIC_XE/include/string_reader.h b/simulator_SIC_XE/include/string_reader.h deleted file mode 100644 index 71c3da9..0000000 --- a/simulator_SIC_XE/include/string_reader.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef STRING_READER_H -#define STRING_READER_H - -#include "reader.h" -#include -#include - -class StringReader : public Reader { -public: - explicit StringReader(const std::string &s); - ~StringReader() override; - - int readByte() override; - bool readBytes(uint8_t* buf, size_t len) override; - std::string readString(size_t len) override; - std::string readLine() override; - -private: - std::istringstream in; -}; - -#endif // STRING_READER_H \ No newline at end of file diff --git a/simulator_SIC_XE/include/utils.h b/simulator_SIC_XE/include/utils.h deleted file mode 100644 index 3197a95..0000000 --- a/simulator_SIC_XE/include/utils.h +++ /dev/null @@ -1,95 +0,0 @@ -#ifndef UTILS_H -#define UTILS_H - -#include "constants.h" - -#include - -// ============================== -// SIC/XE Utility Functions -// ============================== - -// Instruction bit extraction utilities -inline int getXBit(int b2) { - return (b2 & 0x80) ? 1 : 0; -} - -inline int getBPBits(int b2) { - return (b2 >> 5) & 0x03; -} - -enum class AddressingMode { - IMMEDIATE, - INDIRECT, - SIMPLE, - SIC_DIRECT, - INVALID -}; - -// Get addressing mode from ni bits -AddressingMode getAddressingMode(int ni); - - -// convert to signed 24-bit integer -inline int toSIC24(int value) { - value &= 0xFFFFFF; - if (value & 0x800000) { - value -= 0x1000000; - } - return value; -} - -inline int setCC(int sw, int cc) { - sw &= ~CC_MASK; - sw |= (cc & CC_MASK); - return sw; -} - -inline int sic_comp(int a, int b, int sw) { - int sa = toSIC24(a); - int sb = toSIC24(b); - - int cc; - if (sa < sb) { - cc = CC_LT; - } else if (sa == sb) { - cc = CC_EQ; - } else { - cc = CC_GT; - } - - return setCC(sw, cc); -} - -inline int sic_comp(double a, double b, int sw) { - int cc; - if (a < b) { - cc = CC_LT; - } else if (a == b) { - cc = CC_EQ; - } else { - cc = CC_GT; - } - - return setCC(sw, cc); -} - - -inline int getCC(int sw) { - return sw & CC_MASK; -} - -inline double normaliseFloat(double value) -{ - if (value == 0.0 )return 0.0; - if (!std::isfinite(value)) return value; - double mantissa = value; - while (std::fabs(mantissa) >= 10.0) mantissa /= 10.0; - while (std::fabs(mantissa) < 1.0) mantissa *= 10.0; - return mantissa; -} - - - - -#endif // UTILS_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 781a9b6..3dd404f 100644 --- a/simulator_SIC_XE/src/file_device.cpp +++ b/simulator_SIC_XE/src/file_device.cpp @@ -3,8 +3,21 @@ #include FileDevice::FileDevice(const std::string &filename) - : filename(filename), fileCreated(false), readPosition(0) { + fileStream.open(filename, std::ios::in | std::ios::out | std::ios::binary); + if (!fileStream.is_open()) { + std::ofstream create(filename, std::ios::binary); + if (!create) { + throw std::runtime_error("Failed to create file: " + filename); + } + create.close(); + + fileStream.clear(); + fileStream.open(filename, std::ios::in | std::ios::out | std::ios::binary); + if (!fileStream.is_open()) { + throw std::runtime_error("Failed to open file after creating: " + filename); + } + } } FileDevice::~FileDevice() @@ -14,55 +27,19 @@ FileDevice::~FileDevice() } } -void FileDevice::ensureFileOpen() -{ - if (!fileStream.is_open()) { - // 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); - } - create.close(); - fileCreated = true; - - fileStream.open(filename, std::ios::in | std::ios::out); - if (!fileStream.is_open()) { - throw std::runtime_error("Failed to open file after creating: " + filename); - } - } - } -} - 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(); - } + fileStream.read(reinterpret_cast(&value), sizeof(value)); } return value; } void FileDevice::write(unsigned char value) { - ensureFileOpen(); if (fileStream.is_open()) { - fileStream.seekp(0, std::ios::end); - fileStream.put(static_cast(value)); + fileStream.write(reinterpret_cast(&value), sizeof(value)); fileStream.flush(); } } \ No newline at end of file diff --git a/simulator_SIC_XE/src/file_reader.cpp b/simulator_SIC_XE/src/file_reader.cpp deleted file mode 100644 index 2a800cc..0000000 --- a/simulator_SIC_XE/src/file_reader.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include "file_reader.h" - -FileReader::FileReader(const std::string &path, std::ios::openmode m) - : in(path, m) -{} - -FileReader::~FileReader() = default; - -int FileReader::readByte() { - char c; - if (!in.get(c)) return -1; - return static_cast(c); -} - - -bool FileReader::readBytes(uint8_t* buf, size_t len) { - in.read(reinterpret_cast(buf), static_cast(len)); - return static_cast(in.gcount()) == len; -} - -std::string FileReader::readString(size_t len) { - std::string s; - s.resize(len); - in.read(reinterpret_cast(&s[0]), static_cast(len)); - std::streamsize got = in.gcount(); - if (static_cast(got) < len) s.resize(static_cast(got)); - return s; -} - -bool FileReader::good() const { return static_cast(in); } - -std::string FileReader::readLine() { - std::string s; - if (!std::getline(in, s)) return std::string(); - return s; -} diff --git a/simulator_SIC_XE/src/instructions.cpp b/simulator_SIC_XE/src/instructions.cpp index a1c4e55..364fed1 100644 --- a/simulator_SIC_XE/src/instructions.cpp +++ b/simulator_SIC_XE/src/instructions.cpp @@ -1,96 +1,16 @@ #include "instructions.h" #include "machine.h" -#include "utils.h" - -inline int resolveWordOperand(Machine& m, int ea, AddressingMode mode) -{ - switch (mode) - { - case AddressingMode::IMMEDIATE: return ea; - case AddressingMode::SIMPLE: - case AddressingMode::SIC_DIRECT: return m.getWord(ea); - case AddressingMode::INDIRECT: return m.getWord(m.getWord(ea)); - default: m.invalidAddressing(); return 0; - } -} - -inline double resolveFloatOperand(Machine& m, int ea, AddressingMode mode) -{ - switch (mode) - { - case AddressingMode::IMMEDIATE: return static_cast(ea); - case AddressingMode::SIMPLE: - case AddressingMode::SIC_DIRECT: return m.getFloat(ea); - case AddressingMode::INDIRECT: return m.getFloat(m.getWord(ea)); - default: m.invalidAddressing(); return 0.0; - } -} -inline void writeWordOperand(Machine& m, int ea, AddressingMode mode, int value) -{ - switch (mode) - { - case AddressingMode::SIMPLE: - case AddressingMode::SIC_DIRECT: m.setWord(ea, value); break; // direct store - case AddressingMode::INDIRECT: m.setWord(m.getWord(ea), value); break; // store via pointer - default: m.invalidAddressing(); break; - } -} - -inline void writeFloatOperand(Machine& m, int ea, AddressingMode mode, double value) -{ - switch (mode) - { - case AddressingMode::SIMPLE: - case AddressingMode::SIC_DIRECT: m.setFloat(ea, value); break; - case AddressingMode::INDIRECT: m.setFloat(m.getWord(ea), value); break; - default: m.invalidAddressing(); break; - } -} - - -// For jump-like ops: what PC should become? -inline int resolveJumpTarget(Machine& m, int ea, AddressingMode mode) -{ - switch (mode) - { - case AddressingMode::IMMEDIATE: - case AddressingMode::SIMPLE: - case AddressingMode::SIC_DIRECT: return ea; // jump to EA (normal case) - case AddressingMode::INDIRECT: return m.getWord(ea); // jump via pointer - default: m.invalidAddressing(); return m.getPC(); - } -} - -void fix_handler(Machine &m) -{ - m.setA(static_cast(m.getF())); -} - -void float_handler(Machine &m) -{ - m.setF(static_cast(m.getA())); -} - -void norm_handler(Machine &m) -{ - m.setF(normaliseFloat(m.getF())); -} - -void addr_handler(Machine &m, int r1, int r2) -{ +void addr_handler(Machine& m, int r1, int r2) { m.setReg(r2, m.getReg(r1) + m.getReg(r2)); } +// CLEAR instruction: clears register r (first nibble), second nibble unused void clear_handler(Machine& m, int r, int unused) { m.setReg(r, 0); } -void compr_handler(Machine &m, int r1, int r2) -{ - m.setSW(sic_comp(m.getReg(r1), m.getReg(r2), m.getSW())); -} void divr_handler(Machine& m, int r1, int r2) { @@ -111,33 +31,15 @@ void rmo_handler(Machine &m, int r1, int r2) m.setReg(r2, m.getReg(r1)); } - -// SHIFTL r1, n → left *circular* shift n bits void shiftl_handler(Machine &m, int r1, int n) { - unsigned int v = m.getReg(r1) & WORD_MASK; - n %= WORD_SIZE; - unsigned int res = ((v << n) | (v >> (WORD_SIZE - n))) & WORD_MASK; - m.setReg(r1, res); + m.setReg(r1, m.getReg(r1) << n); } -// SHIFTR r1, n → right shift n bits, fill with original leftmost bit void shiftr_handler(Machine &m, int r1, int n) { - unsigned int v = m.getReg(r1) & WORD_MASK; - n %= WORD_SIZE; - unsigned int msb = (v & 0x800000) ? 1u : 0u; - unsigned int shifted = v >> n; - unsigned int fill = 0; - if (msb) { - fill = (~0u) << (WORD_SIZE - n); - fill &= WORD_MASK; - } - - unsigned int res = (shifted | fill) & WORD_MASK; - m.setReg(r1, res); + m.setReg(r1, m.getReg(r1) >> n); } - void subr_handler(Machine &m, int r1, int r2) { m.setReg(r2, m.getReg(r2) - m.getReg(r1)); @@ -156,448 +58,3 @@ void tixr_handler(Machine &m, int r1, int unused) int valR1 = m.getReg(r1); m.setSW(sic_comp(valX, valR1, m.getSW())); } - -void add_handler(Machine &m, int ea, AddressingMode mode) -{ - int val = resolveWordOperand(m, ea, mode); - m.setA(m.getA() + val); -} - -void addf_handler(Machine &m, int ea, AddressingMode mode) -{ - double val = resolveFloatOperand(m, ea, mode); - m.setA(m.getA() + val); -} - -void and_handler(Machine &m, int ea, AddressingMode mode) -{ - int val = resolveWordOperand(m, ea, mode); - m.setA(m.getA() & val); -} - -void comp_handler(Machine &m, int ea, AddressingMode mode) -{ - int operand = resolveWordOperand(m, ea, mode); - m.setSW(sic_comp(m.getA(), operand, m.getSW())); -} - -void compf_handler(Machine &m, int ea, AddressingMode mode) -{ - double operand = resolveFloatOperand(m, ea, mode); - m.setSW(sic_comp(m.getF(), operand, m.getSW())); -} - -void div_handler(Machine &m, int ea, AddressingMode mode) -{ - int divisor = resolveWordOperand(m, ea, mode); - if (divisor == 0) { - m.divisionByZero(DIV); - return; - } - m.setA(m.getA() / divisor); -} - -void divf_handler(Machine &m, int ea, AddressingMode mode) -{ - double divisor = resolveFloatOperand(m, ea, mode); - if (divisor == 0.0) { - m.divisionByZero(DIVF); - return; - } - m.setF(m.getF() / divisor); -} - -void j_handler(Machine &m, int ea, AddressingMode mode) -{ - int target = resolveJumpTarget(m, ea, mode); - - int instrSize = 3; - int instrAddr = m.getPC() - instrSize; - // Check if jumping to itself (halt pattern) - if (target == instrAddr) { - m.halt(); - } - - m.setPC(target); -} - -void jeq_handler(Machine &m, int ea, AddressingMode mode) -{ - int sw = m.getSW(); - int cc = getCC(sw); - if (cc == CC_EQ) { - int target = resolveJumpTarget(m, ea, mode); - m.setPC(target); - } -} - -void jgt_handler(Machine &m, int ea, AddressingMode mode) -{ - int sw = m.getSW(); - int cc = getCC(sw); - if (cc == CC_GT) { - int target = resolveJumpTarget(m, ea, mode); - m.setPC(target); - } -} - -void jlt_handler(Machine &m, int ea, AddressingMode mode) -{ - int sw = m.getSW(); - int cc = getCC(sw); - if (cc == CC_LT) { - int target = resolveJumpTarget(m, ea, mode); - m.setPC(target); - } -} - -void jsub_handler(Machine &m, int ea, AddressingMode mode) -{ - int target = resolveJumpTarget(m, ea, mode); - m.setL(m.getPC()); - m.setPC(target); -} - -void lda_handler(Machine& m, int ea, AddressingMode mode) -{ - m.setA(resolveWordOperand(m, ea, mode)); -} - -void ldb_handler(Machine &m, int ea, AddressingMode mode) -{ - m.setB(resolveWordOperand(m, ea, mode)); -} - -void ldch_handler(Machine &m, int ea, AddressingMode mode) -{ - int val; - if (mode == AddressingMode::IMMEDIATE) { - val = ea & 0xFF; - } else if (mode == AddressingMode::INDIRECT) { - val = m.getByte(m.getWord(ea)); - } else { - val = m.getByte(ea); - } - m.setA((m.getA() & 0xFFFF00) | (val & 0xFF)); -} - -void ldf_handler(Machine &m, int ea, AddressingMode mode) -{ - m.setF(resolveFloatOperand(m, ea, mode)); -} - -void ldl_handler(Machine &m, int ea, AddressingMode mode) -{ - m.setL(resolveWordOperand(m, ea, mode)); -} - -void lds_handler(Machine &m, int ea, AddressingMode mode) -{ - m.setS(resolveWordOperand(m, ea, mode)); -} - -void ldt_handler(Machine &m, int ea, AddressingMode mode) -{ - m.setT(resolveWordOperand(m, ea, mode)); -} - -void ldx_handler(Machine &m, int ea, AddressingMode mode) -{ - m.setX(resolveWordOperand(m, ea, mode)); -} - -void mul_handler(Machine &m, int ea, AddressingMode mode) -{ - int val = resolveWordOperand(m, ea, mode); - m.setA(m.getA() * val); -} - -void mulf_handler(Machine &m, int ea, AddressingMode mode) -{ - m.setF(m.getF() * resolveFloatOperand(m, ea, mode)); -} - -void or_handler(Machine &m, int ea, AddressingMode mode) -{ - int val = resolveWordOperand(m, ea, mode); - m.setA(m.getA() | val); -} - -void rd_handler(Machine &m, int ea, AddressingMode mode) -{ - int deviceNum = resolveWordOperand(m, ea, mode); - Device& device = m.getDevice(deviceNum); - // Load byte into rightmost byte of A register - m.setA((m.getA() & 0xFFFF00) | device.read()); -} - -void rsub_handler(Machine &m, int ea, AddressingMode mode) -{ - m.setPC(m.getL()); -} - -void sta_handler(Machine &m, int ea, AddressingMode mode) -{ - writeWordOperand(m, ea, mode, m.getA()); -} - -void stb_handler(Machine &m, int ea, AddressingMode mode) -{ - writeWordOperand(m, ea, mode, m.getB()); -} -// Rightmost byte of A register is stored -void stch_handler(Machine &m, int ea, AddressingMode mode) -{ - int val = m.getA() & 0xFF; - switch (mode) - { - case AddressingMode::SIMPLE: - case AddressingMode::SIC_DIRECT: m.setByte(ea, val); break; // direct store - case AddressingMode::INDIRECT: m.setByte(m.getWord(ea), val); break; // store via pointer - default: m.invalidAddressing(); break; - } -} - -void stf_handler(Machine &m, int ea, AddressingMode mode) -{ - writeFloatOperand(m, ea, mode, m.getF()); -} - -void stl_handler(Machine &m, int ea, AddressingMode mode) -{ - writeWordOperand(m, ea, mode, m.getL()); -} - -void sts_handler(Machine &m, int ea, AddressingMode mode) -{ - writeWordOperand(m, ea, mode, m.getS()); -} - -void stsw_handler(Machine &m, int ea, AddressingMode mode) -{ - writeWordOperand(m, ea, mode, m.getSW()); -} - -void stt_handler(Machine &m, int ea, AddressingMode mode) -{ - writeWordOperand(m, ea, mode, m.getT()); -} - -void stx_handler(Machine &m, int ea, AddressingMode mode) -{ - writeWordOperand(m, ea, mode, m.getX()); -} - -void sub_handler(Machine &m, int ea, AddressingMode mode) -{ - int val = resolveWordOperand(m, ea, mode); - m.setA(m.getA() - val); -} - -void subf_handler(Machine &m, int ea, AddressingMode mode) -{ - double val = resolveFloatOperand(m, ea, mode); - m.setF(m.getF() - val); -} - -void td_handler(Machine &m, int ea, AddressingMode mode) -{ - int deviceNum = resolveWordOperand(m, ea, mode); - Device& device = m.getDevice(deviceNum); - // Test device and set SW accordingly - if (device.test()) { - m.setSW(setCC(m.getSW(), CC_EQ)); - } else { - m.setSW(setCC(m.getSW(), CC_LT)); - } -} - -void tix_handler(Machine &m, int ea, AddressingMode mode) -{ - m.setX(m.getX() + 1); - int valX = m.getX(); - int memVal = resolveWordOperand(m, ea, mode); - m.setSW(sic_comp(valX, memVal, m.getSW())); -} - -void wd_handler(Machine &m, int ea, AddressingMode mode) -{ - int deviceNum = resolveWordOperand(m, ea, mode); - Device& device = m.getDevice(deviceNum); - // Write rightmost byte of A register to device - device.write(static_cast(m.getA() & 0xFF)); -} - -void xexe_handler(Machine &m) -{ - m.enableExtendedMode(); - m.execute(); - m.disableExtendedMode(); -} - -void halt_handler(Machine &m) -{ - m.halt(); -} - -void nop_handler(Machine &m) -{ - // Do nothing -} - -void vaddr_handler(Machine &m, int r1, int r2) -{ - int result[VECTOR_REG_SIZE]; - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - result[i] = m.getVectorRegister(r1)[i] + m.getVectorRegister(r2)[i]; - } - m.setVectorRegister(r2, result); -} - -void vsubr_handler(Machine &m, int r1, int r2) -{ - int result[VECTOR_REG_SIZE]; - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - result[i] = m.getVectorRegister(r2)[i] - m.getVectorRegister(r1)[i]; - } - m.setVectorRegister(r2, result); -} - -void vmulr_handler(Machine &m, int r1, int r2) -{ - int result[VECTOR_REG_SIZE]; - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - result[i] = m.getVectorRegister(r1)[i] * m.getVectorRegister(r2)[i]; - } - m.setVectorRegister(r2, result); -} - -void vdivr_handler(Machine &m, int r1, int r2) -{ - int result[VECTOR_REG_SIZE]; - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - if (m.getVectorRegister(r1)[i] == 0) { - m.divisionByZero(VDIVR); - return; - } - result[i] = m.getVectorRegister(r2)[i] / m.getVectorRegister(r1)[i]; - } - m.setVT(result); -} - -void vadd_handler(Machine &m, int ea, AddressingMode mode) -{ - int baseAddr = resolveWordOperand(m, ea, mode); - int vec[VECTOR_REG_SIZE]; - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - vec[i] = m.getWord(baseAddr + i * 3); - } - int result[VECTOR_REG_SIZE]; - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - result[i] = m.getVA()[i] + vec[i]; - } - m.setVA(result); -} - -void vsub_handler(Machine &m, int ea, AddressingMode mode) -{ - int baseAddr = resolveWordOperand(m, ea, mode); - int vec[VECTOR_REG_SIZE]; - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - vec[i] = m.getWord(baseAddr + i * 3); - } - int result[VECTOR_REG_SIZE]; - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - result[i] = m.getVA()[i] - vec[i]; - } - m.setVA(result); -} - -void vmul_handler(Machine &m, int ea, AddressingMode mode) -{ - int baseAddr = resolveWordOperand(m, ea, mode); - int vec[VECTOR_REG_SIZE]; - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - vec[i] = m.getWord(baseAddr + i * 3); - } - int result[VECTOR_REG_SIZE]; - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - result[i] = m.getVA()[i] * vec[i]; - } - m.setVA(result); -} - -void vdiv_handler(Machine &m, int ea, AddressingMode mode) -{ - int baseAddr = resolveWordOperand(m, ea, mode); - int vec[VECTOR_REG_SIZE]; - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - vec[i] = m.getWord(baseAddr + i * 3); - } - int result[VECTOR_REG_SIZE]; - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - if (vec[i] == 0) { - m.divisionByZero(VDIV); - return; - } - result[i] = m.getVA()[i] / vec[i]; - } - m.setVA(result); -} - -void stva_handler(Machine &m, int ea, AddressingMode mode) -{ - int baseAddr = resolveWordOperand(m, ea, mode); - const int* vec = m.getVA(); - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - m.setWord(baseAddr + i * 3, vec[i]); - } -} - -void stvs_handler(Machine &m, int ea, AddressingMode mode) -{ - int baseAddr = resolveWordOperand(m, ea, mode); - const int* vec = m.getVS(); - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - m.setWord(baseAddr + i * 3, vec[i]); - } -} - -void stvt_handler(Machine &m, int ea, AddressingMode mode) -{ - int baseAddr = resolveWordOperand(m, ea, mode); - const int* vec = m.getVT(); - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - m.setWord(baseAddr + i * 3, vec[i]); - } -} - -void ldva_handler(Machine &m, int ea, AddressingMode mode) -{ - int baseAddr = resolveWordOperand(m, ea, mode); - int vec[VECTOR_REG_SIZE]; - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - vec[i] = m.getWord(baseAddr + i * 3); - } - m.setVA(vec); -} - -void ldvs_handler(Machine &m, int ea, AddressingMode mode) -{ - int baseAddr = resolveWordOperand(m, ea, mode); - int vec[VECTOR_REG_SIZE]; - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - vec[i] = m.getWord(baseAddr + i * 3); - } - m.setVS(vec); -} - -void ldvt_handler(Machine &m, int ea, AddressingMode mode) -{ - int baseAddr = resolveWordOperand(m, ea, mode); - int vec[VECTOR_REG_SIZE]; - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - vec[i] = m.getWord(baseAddr + i * 3); - } - m.setVT(vec); -} diff --git a/simulator_SIC_XE/src/loader.cpp b/simulator_SIC_XE/src/loader.cpp deleted file mode 100644 index 8d3aa17..0000000 --- a/simulator_SIC_XE/src/loader.cpp +++ /dev/null @@ -1,134 +0,0 @@ -#include "loader.h" -#include "file_reader.h" -#include "string_reader.h" -#include "machine.h" -#include "constants.h" -#include -#include - -Loader::~Loader() -{ - _machine.reset(); -} - - - - -void Loader::load() -{ - HeaderMetadata header = readHeader(); - - while(true) { - RecordType type = parseRecordType(static_cast(_file_reader->readByte())); - switch (type) { - case RecordType::TEXT: { - TextRecord textRecord = readTextRecord(); - if (!load_into_memory(textRecord.start_address, textRecord.data)) { - throw std::runtime_error("Failed to load text record into memory"); - } - break; - } - case RecordType::END: { - EndRecord endRecord = readEndRecord(); - _machine->setPC(endRecord.execution_start_address); - return; // Loading complete - } - case RecordType::UNKNOWN: - default: - throw std::runtime_error("Unknown record type encountered"); - } - } -} - -Loader::RecordType Loader::parseRecordType(char c) -{ - switch (c) { - case 'H': return RecordType::HEADER; - case 'T': return RecordType::TEXT; - case 'E': return RecordType::END; - default: return RecordType::UNKNOWN; // fallback; adjust as needed - } -} - -Loader::HeaderMetadata Loader::readHeader() -{ - - RecordType type = parseRecordType(static_cast(_file_reader->readByte())); - if (type != RecordType::HEADER) { - throw std::runtime_error("Expected HEADER record"); - } - if(FILE_CONTAINS_WHITE_SPACES) _file_reader->readByte(); - - HeaderMetadata header; - // Read program name (6 bytes) - header.program_name = _file_reader->readString(6); - if(FILE_CONTAINS_WHITE_SPACES) _file_reader->readByte(); - - // Read start address (6 hex digits) - header.start_address = std::stoi(_file_reader->readString(6), nullptr, 16); - if(FILE_CONTAINS_WHITE_SPACES) _file_reader->readByte(); - - // Read length (6 hex digits) - header.length = std::stoi(_file_reader->readString(6), nullptr, 16); - // consume newline - _file_reader->readLine(); - return header; -} - -Loader::TextRecord Loader::readTextRecord() -{ - if(FILE_CONTAINS_WHITE_SPACES) _file_reader->readByte(); - TextRecord record; - // Assume 'T' has already been read - record.start_address = std::stoi(_file_reader->readString(6), nullptr, 16); - if(FILE_CONTAINS_WHITE_SPACES) _file_reader->readByte(); - - // Read length (1 byte, 2 hex digits) - 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); - - for (int i = 0; i < length; ++i) { - std::string byteHex = stringReader.readString(2); - record.data[i] = static_cast(std::stoi(byteHex, nullptr, 16)); - } - - return record; -} - -Loader::EndRecord Loader::readEndRecord() -{ - EndRecord record; - if(FILE_CONTAINS_WHITE_SPACES) _file_reader->readByte(); - // Assume 'E' has already been read - std::string addrStr = _file_reader->readString(6); - if (!addrStr.empty()) { - record.execution_start_address = std::stoi(addrStr, nullptr, 16); - } else { - record.execution_start_address = 0; - } - // consume newline - _file_reader->readLine(); - return record; -} - -bool Loader::load_into_memory(int start_address, const std::vector &data) -{ - for(size_t i = 0; i < data.size(); ++i) { - int addr = start_address + static_cast(i); - if (addr < 0 || addr >= MEMORY_SIZE) { - return false; - } - _machine->setByte(addr, data[i]); - } - return true; -} diff --git a/simulator_SIC_XE/src/machine.cpp b/simulator_SIC_XE/src/machine.cpp index d8d0356..d190f6d 100644 --- a/simulator_SIC_XE/src/machine.cpp +++ b/simulator_SIC_XE/src/machine.cpp @@ -4,8 +4,6 @@ #include "opcode.h" #include "instructions.h" -#include -#include using std::make_shared; @@ -14,37 +12,13 @@ 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); // device 1: standard output devices[1] = make_shared(std::cout); - - // Initialize devices >= 2 as FileDevice with hex names in devices directory - for (int i = 2; i < NUM_DEVICES; i++) { - char hex[3]; - snprintf(hex, sizeof(hex), "%02X", i); - std::string filename = "devices/" + std::string(hex) + ".dev"; - try { - devices[i] = std::make_shared(filename); - } catch (const std::exception &e) { - cerr << prefix << "Warning: Failed to initialize FileDevice for device " << i << ": " << e.what() << endl; - } - } - - _exex_mode = false; - _instructionsTable = instructions; + // device 2: standard error + devices[2] = make_shared(std::cerr); } Machine::~Machine() @@ -54,17 +28,6 @@ Machine::~Machine() } } -int Machine::getSpeed() const -{ - return speedHz.load(); -} - -void Machine::setSpeed(int Hz) -{ - speedHz.store(Hz); -} - -// TODO: implement errors void Machine::notImplemented(string mnemonic) { cout << prefix << "Not implemented: " << mnemonic << endl; @@ -75,7 +38,6 @@ void Machine::invalidOpcode(int opcode) cout << prefix << "Invalid opcode: " << opcode << endl; } - void Machine::invalidAddressing() { cout << prefix << "Invalid addressing mode" << endl; @@ -91,97 +53,6 @@ void Machine::undefinedHandler(int opcode) cout << prefix << "Undefined handler for opcode: " << opcode << endl; } -void Machine::enableExtendedMode() -{ - if(!USE_EXTENDED_MODE) return; - _exex_mode = true; - _instructionsTable = instructionsEXEX; -} - -void Machine::disableExtendedMode() -{ - if(!USE_EXTENDED_MODE) return; - _exex_mode = false; - _instructionsTable = instructions; -} - -int *Machine::getVectorRegister(int regNum) -{ - switch (regNum) { - case 0: return VA; - case 4: return VS; - case 5: return VT; - default: - cerr << prefix << "Invalid register number: " << regNum << endl; - return nullptr; - } -} - -void Machine::setVectorRegister(int regNum, const int *values) -{ - int* targetReg = getVectorRegister(regNum); - if (targetReg == nullptr) return; - for (int i = 0; i < VECTOR_REG_SIZE; i++) { - targetReg[i] = toSIC24(values[i]); - } -} - -void Machine::setVA(const int *values) -{ - for (int i = 0; i < VECTOR_REG_SIZE; i++) { - VA[i] = toSIC24(values[i]); - } -} - -void Machine::setVS(const int *values) -{ - for (int i = 0; i < VECTOR_REG_SIZE; i++) { - VS[i] = toSIC24(values[i]); - } -} - -void Machine::setVT(const int *values) -{ - for (int i = 0; i < VECTOR_REG_SIZE; i++) { - VT[i] = toSIC24(values[i]); - } -} - -void Machine::tick() -{ - const int speed = speedHz.load(); - if (speed <= 0) throw std::runtime_error("Invalid speed setting in Machine::tick"); - - const auto delay = std::chrono::milliseconds(1000 / speed); - std::this_thread::sleep_for(delay); -} - -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) { @@ -247,8 +118,7 @@ int Machine::getWord(int address) cerr << prefix << "Invalid memory address: " << address << endl; return -1; } - // Big-endian: high byte first - return (static_cast(memory[address]) << 16) | (static_cast(memory[address + 1]) << 8) | static_cast(memory[address + 2]); + return static_cast(memory[address]) | (static_cast(memory[address + 1]) << 8) | (static_cast(memory[address + 2]) << 16); } // Assuming word is 3 bytes @@ -258,94 +128,23 @@ void Machine::setWord(int address, int value) cerr << prefix << "Invalid memory address: " << address << endl; return; } - value &= 0xFFFFFF; - // Big-endian: high byte first - memory[address] = static_cast((value >> 16) & 0xFF); + memory[address] = static_cast(value & 0xFF); memory[address + 1] = static_cast((value >> 8) & 0xFF); - memory[address + 2] = static_cast(value & 0xFF); + memory[address + 2] = static_cast((value >> 16) & 0xFF); } +// TODO: implement proper float storage and retrieval double Machine::getFloat(int address) { - if (address < 0 || address + 5 >= MEMORY_SIZE) { - cerr << prefix << "Invalid float address: " << address << endl; - return 0.0; - } - - // load 6 bytes, big-endian → 48-bit word - unsigned long long raw = - ((unsigned long long)memory[address] << 40) | - ((unsigned long long)memory[address+1] << 32) | - ((unsigned long long)memory[address+2] << 24) | - ((unsigned long long)memory[address+3] << 16) | - ((unsigned long long)memory[address+4] << 8) | - (unsigned long long)memory[address+5]; - - int sign = (raw >> 47) & 0x1; - int exponent = (raw >> 40) & 0x7F; - unsigned long long frac = raw & SICF_FRAC_MASK; // 40 bits - - if (raw == 0) return 0.0; - - // value = (1 + frac/2^40) * 2^(exp - 64) - double mant = 1.0 + (double)frac / (double)(1ULL << SICF_FRAC_BITS); - int e = exponent - SICF_EXP_BIAS; - double val = std::ldexp(mant, e); // ldexp is fast enough here - return sign ? -val : val; + return 0.0; } void Machine::setFloat(int address, double value) { - if (address < 0 || address + 5 >= MEMORY_SIZE) { - cerr << prefix << "Invalid float address: " << address << endl; - return; - } - - if (value == 0.0) { - memory[address] = 0; - memory[address+1] = 0; - memory[address+2] = 0; - memory[address+3] = 0; - memory[address+4] = 0; - memory[address+5] = 0; - return; - } - - int sign = value < 0; - double x = sign ? -value : value; - - // normalize x to [1, 2) - int exp2 = 0; - x = std::frexp(x, &exp2); - x *= 2.0; - exp2 -= 1; - - int exp_field = exp2 + SICF_EXP_BIAS; - if (exp_field < 0) exp_field = 0; - if (exp_field > 127) exp_field = 127; - - // mantissa = (x - 1) * 2^40 - double frac_d = (x - 1.0) * (double)(1ULL << SICF_FRAC_BITS); - unsigned long long frac = (unsigned long long)(frac_d + 0.5); // round - frac &= SICF_FRAC_MASK; - - unsigned long long raw = - ((unsigned long long)sign << 47) | - ((unsigned long long)exp_field << 40) | - frac; - - // store 6 bytes big-endian - memory[address] = (unsigned char)((raw >> 40) & 0xFF); - memory[address+1] = (unsigned char)((raw >> 32) & 0xFF); - memory[address+2] = (unsigned char)((raw >> 24) & 0xFF); - memory[address+3] = (unsigned char)((raw >> 16) & 0xFF); - memory[address+4] = (unsigned char)((raw >> 8) & 0xFF); - memory[address+5] = (unsigned char)( raw & 0xFF); + // TODO: implement proper float storage } - - Device &Machine::getDevice(int num) { if(num < 0 || num >= static_cast(devices.size()) || !devices[num]) { @@ -396,56 +195,49 @@ int Machine::fetch() return getByte(PC++); } -void Machine::execute() { - if (_stopped) return; - - int b1 = fetch(); - - InstructionInfo &info = _instructionsTable[b1]; - - if (info.type == InstructionType::TYPE1) { execF1(b1); return; } - if (info.type == InstructionType::TYPE2) { execF2(b1, fetch()); return; } - - int opcode = b1 & TYPE3_4_SIC_MASK; - InstructionInfo &info34 = _instructionsTable[opcode]; - int ni = b1 & NI_MASK; - - if (info34.type == InstructionType::TYPE3_4) { - int b2 = fetch(), b3 = fetch(); - int x = (b2 & 0x80) ? 1 : 0; - int b = (b2 & 0x40) ? 1 : 0; - int p = (b2 & 0x20) ? 1 : 0; - int e = (b2 & 0x10) ? 1 : 0; - - int operand; - if (ni == NI_SIC) { - // PURE SIC - operand = ((b2 & 0x7F) << 8) | b3; - } else { - // SIC/XE - operand = e - ? (((b2 & 0x0F) << 16) | (b3 << 8) | fetch()) // F4: 20-bit - : (((b2 & 0x0F) << 8) | b3); // F3: 12-bit - } - - execSICF3F4(opcode, ni, x, b, p, e, operand); - return; +void Machine::execute() +{ + int opcode = fetch(); + InstructionType type = instructions[opcode].type; + switch (type) { + case InstructionType::TYPE1: execF1(opcode);break; + case InstructionType::TYPE2: execF2(opcode, fetch());break; + case InstructionType::TYPE3_4: // extract n and i bits + { + int ni = opcode & 0x3; + int operand = fetch(); + execSICF3F4(opcode, ni, operand); + } + break; + default: invalidOpcode(opcode); break; } - - invalidOpcode(b1); } - - - bool Machine::execF1(int opcode) { - if (_instructionsTable[opcode].handler) { - auto handler = reinterpret_cast(_instructionsTable[opcode].handler); - handler(*this); + switch (opcode) + { + case FIX: + setA(static_cast(getF())); return true; + case FLOAT: + setF(static_cast(getA())); + return true; + case HIO: + notImplemented("HIO"); + return true; + case NORM: + notImplemented("NORM"); + return true; + case SIO: + notImplemented("SIO"); + return true; + case TIO: + notImplemented("TIO"); + return true; + default: + break; } - undefinedHandler(opcode); return false; } @@ -454,8 +246,8 @@ bool Machine::execF2(int opcode, int operand) int r1 = (operand >> 4) & 0xF; int r2 = operand & 0xF; - if (_instructionsTable[opcode].handler) { - auto handler = reinterpret_cast(_instructionsTable[opcode].handler); + if (instructions[opcode].handler) { + auto handler = reinterpret_cast(instructions[opcode].handler); handler(*this, r1, r2); return true; } @@ -463,63 +255,7 @@ bool Machine::execF2(int opcode, int operand) return false; } - -bool Machine::execSICF3F4(int opcode, int ni, int x, int b, int p, int e, int operand) +bool Machine::execSICF3F4(int opcode, int ni, int operand) { - int ea_part = operand; - int base = 0; - AddressingMode mode = getAddressingMode(ni); - - // --- PURE SIC --- - if (mode == AddressingMode::SIC_DIRECT) { - int ea = ea_part + (x ? getX() : 0); - if (_instructionsTable[opcode].handler) { - auto h = reinterpret_cast(_instructionsTable[opcode].handler); - h(*this, ea, mode); - return true; - } - undefinedHandler(opcode); - return false; - } - - // --- SIC/XE EA calc --- - - if (!e) { // format 3 - if (b && !p) { - base = getB(); // base-relative, unsigned 12-bit - } else if (p && !b) { - // PC-relative, signed 12-bit - if (ea_part & 0x800) // bit 11 set? - ea_part |= 0xFFFFF000; // sign-extend - base = getPC(); - } - } - // format 4 (e=1): b/p ignored, ea_part is 20-bit absolute - int ea = base + ea_part + (x ? getX() : 0); - - if (_instructionsTable[opcode].handler) { - auto h = reinterpret_cast(_instructionsTable[opcode].handler); - h(*this, ea, mode); - return true; - } - - undefinedHandler(opcode); return false; } - -void Machine::start() -{ - running.store(true); - - // Main execution loop - // TODO: consider running in separate thread - while (running.load()) { - execute(); - tick(); - } -} - -void Machine::stop() -{ - running.store(false); -} diff --git a/simulator_SIC_XE/src/main.cpp b/simulator_SIC_XE/src/main.cpp index 433a3f1..1c285b9 100644 --- a/simulator_SIC_XE/src/main.cpp +++ b/simulator_SIC_XE/src/main.cpp @@ -1,140 +1,27 @@ #include -#include -#include #include "machine.h" #include "file_device.h" #include "opcode.h" #include "instructions.h" -#include "constants.h" -#include "loader.h" using std::cout; using std::endl; -struct VectorAddProgram { - int x, y; -}; - - - int main() { - /* loadInstructionSet(); Machine machine; - cout << "SIC/XE Program: Accumulator Loop" << endl; - - const int TEMP_ADDR = 0x50; - const int LOOP_ADDR = 0x03; - - // clear TEMP - machine.setByte(TEMP_ADDR, 0); - loadInstructionSet(); - - cout << "SIC/XE Program: Vector add test" << endl; - - const int VA_ADDR = 0x100; // source vector A - const int VB_ADDR = 0x200; // source vector B - const int VR_ADDR = 0x300; // result store (STVA) - - // Prepare two 4-element vectors (WORD = 3 bytes) for VA and VB - int a_vals[VECTOR_REG_SIZE] = {1,2,3,4}; - int b_vals[VECTOR_REG_SIZE] = {5,6,7,8}; - - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - machine.setWord(VA_ADDR + i * 3, a_vals[i]); - machine.setWord(VB_ADDR + i * 3, b_vals[i]); - } - - // Assemble program at address 0x000 (we use XEXE before each extended op) - // Offsets and bytes (hex): - // 0x00: XEXE -> 0xEE - // 0x01: LDVA (format 4) -> b1=0x03 (LDVA|ni=0x00|0x03), b2=0x10 (e=1), b3=0x01, b4=0x00 (addr 0x100) - // 0x05: XEXE -> 0xEE - // 0x06: LDVS (format 4) -> b1=0x6B (0x68|0x03), b2=0x10, b3=0x02, b4=0x00 (addr 0x200) - // 0x0A: XEXE -> 0xEE - // 0x0B: VADDR B->A (type 2) -> opcode 0x90, operand r1=4 (VS), r2=0 (VA) => operand=(4<<4)|0=0x40 - // 0x0D: XEXE -> 0xEE - // 0x0E: STVA (format4) -> b1=0x0F (0x0C|0x03), b2=0x10, b3=0x03, b4=0x00 (addr 0x300) - // 0x12: J (format4) to self -> b1=0x3F (0x3C|0x03), b2=0x10, b3=0x00, b4=0x12 - - unsigned char prog[] = { - 0xEE, - 0x01, 0x10, 0x01, 0x00, // LDVA (format 4) with ni=IMMEDIATE -> b1=0x01 - 0xEE, - 0x69, 0x10, 0x02, 0x00, // LDVS (format 4) with ni=IMMEDIATE -> b1=0x69 (0x68|0x01) - 0xEE, - 0x90, 0x40, // VADDR VS->VA (type2) - 0xEE, - 0x0D, 0x10, 0x03, 0x00, // STVA (format4) with ni=IMMEDIATE -> b1=0x0D - 0x3F, 0x10, 0x00, 0x12 // J (format4) loop to 0x12 - }; - - const int PROG_START = 0x00; - for (size_t i = 0; i < sizeof(prog); ++i) { - machine.setByte(PROG_START + static_cast(i), prog[i]); - } - - machine.setPC(PROG_START); - - cout << "Program loaded. VA@0x" << std::hex << VA_ADDR << " VB@0x" << VB_ADDR << " -> store@0x" << VR_ADDR << std::dec << endl; + cout << "Machine initialized successfully." << endl; - const int MAX_STEPS = 100; - for (int i = 0; i < MAX_STEPS; ++i) { - machine.execute(); - } - - // Read back result vector stored at VR_ADDR - cout << "Result vector at 0x" << std::hex << VR_ADDR << std::dec << ": "; - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - int val = machine.getWord(VR_ADDR + i * 3); - cout << val << (i + 1 < VECTOR_REG_SIZE ? ", " : "\n"); - } - */ - - loadInstructionSet(); - std::shared_ptr machine = std::make_shared(); - Loader loader(machine, std::string(PATH_RESOURCES) + "rec.obj"); - loader.load(); - - cout << "=== Starting execution of rec.obj ===" << endl; - cout << "Initial PC: 0x" << std::hex << machine->getPC() << std::dec << endl; - - int maxSteps = 10000; - for (int step = 0; step < maxSteps; step++) { - int pc = machine->getPC(); - int opcode = machine->getByte(pc) & 0xFC; - const char* instName = (opcode < 256 && instructions[opcode].type != InstructionType::INVALID) - ? instructions[opcode].name : "???"; - - int regA = machine->getA(); - int regB = machine->getB(); - int regX = machine->getX(); - int regL = machine->getL(); - int sw = machine->getSW(); - - printf("Step %4d: PC=0x%05X %-6s A=0x%06X B=0x%06X X=0x%06X L=0x%06X SW=0x%06X\n", - step, pc, instName, regA, regB, regX, regL, sw); - - machine->execute(); - - if (machine->isStopped()) { - cout << "Machine halted at step " << step << endl; - break; - } - - if (step > 100 && machine->getPC() == pc) { - cout << "ERROR: Infinite loop detected at PC=0x" << std::hex << pc << std::dec << endl; - break; - } - } - - cout << "\n=== Final state ===" << endl; - cout << "A: " << machine->getA() << endl; - cout << "B: " << machine->getB() << endl; - cout << "X: " << machine->getX() << endl; - + // COMPUTE A + B and store result in B + machine.setA(10); + machine.setB(20); + machine.setByte(0, ADDR); + machine.setByte(1, 0x03); // r1 = 0 (A), r2 = 3 (B) + cout << "Before ADDR: A = " << machine.getA() << ", B = " << machine.getB() << endl; + machine.execute(); + cout << "After ADDR: A = " << machine.getA() << ", B = " << machine.getB() << endl; return 0; } \ No newline at end of file diff --git a/simulator_SIC_XE/src/opcode.cpp b/simulator_SIC_XE/src/opcode.cpp index 0b63ce8..febc489 100644 --- a/simulator_SIC_XE/src/opcode.cpp +++ b/simulator_SIC_XE/src/opcode.cpp @@ -1,109 +1,75 @@ #include "opcode.h" #include "instructions.h" -#include "utils.h" #include InstructionInfo instructions[0xff]; -InstructionInfo instructionsEXEX[0xff]; void loadInstructionSet() { - instructions[ADD] = {"ADD", InstructionType::TYPE3_4, reinterpret_cast(add_handler)}; - instructions[ADDF] = {"ADDF", InstructionType::TYPE3_4, reinterpret_cast(addf_handler)}; - instructions[ADDR] = {"ADDR", InstructionType::TYPE2, reinterpret_cast(addr_handler)}; - instructions[AND] = {"AND", InstructionType::TYPE3_4, reinterpret_cast(and_handler)}; - instructions[CLEAR] = {"CLEAR", InstructionType::TYPE2, reinterpret_cast(clear_handler)}; - instructions[COMP] = {"COMP", InstructionType::TYPE3_4, reinterpret_cast(comp_handler)}; - instructions[COMPF] = {"COMPF", InstructionType::TYPE3_4, reinterpret_cast(compf_handler)}; - instructions[COMPR] = {"COMPR", InstructionType::TYPE2, reinterpret_cast(compr_handler)}; - instructions[DIV] = {"DIV", InstructionType::TYPE3_4, reinterpret_cast(div_handler)}; - instructions[DIVF] = {"DIVF", InstructionType::TYPE3_4, reinterpret_cast(divf_handler)}; - instructions[DIVR] = {"DIVR", InstructionType::TYPE2, reinterpret_cast(divr_handler)}; - instructions[FIX] = {"FIX", InstructionType::TYPE1, reinterpret_cast(fix_handler)}; - instructions[FLOAT] = {"FLOAT", InstructionType::TYPE1, reinterpret_cast(float_handler)}; - instructions[HIO] = {"HIO", InstructionType::TYPE1, nullptr}; - instructions[J] = {"J", InstructionType::TYPE3_4, reinterpret_cast(j_handler)}; - instructions[JEQ] = {"JEQ", InstructionType::TYPE3_4, reinterpret_cast(jeq_handler)}; - instructions[JGT] = {"JGT", InstructionType::TYPE3_4, reinterpret_cast(jgt_handler)}; - instructions[JLT] = {"JLT", InstructionType::TYPE3_4, reinterpret_cast(jlt_handler)}; - instructions[JSUB] = {"JSUB", InstructionType::TYPE3_4, reinterpret_cast(jsub_handler)}; - instructions[LDA] = {"LDA", InstructionType::TYPE3_4, reinterpret_cast(lda_handler)}; - instructions[LDB] = {"LDB", InstructionType::TYPE3_4, reinterpret_cast(ldb_handler)}; - instructions[LDCH] = {"LDCH", InstructionType::TYPE3_4, reinterpret_cast(ldch_handler)}; - instructions[LDF] = {"LDF", InstructionType::TYPE3_4, reinterpret_cast(ldf_handler)}; - instructions[LDL] = {"LDL", InstructionType::TYPE3_4, reinterpret_cast(ldl_handler)}; - instructions[LDS] = {"LDS", InstructionType::TYPE3_4, reinterpret_cast(lds_handler)}; - instructions[LDT] = {"LDT", InstructionType::TYPE3_4, reinterpret_cast(ldt_handler)}; - instructions[LDX] = {"LDX", InstructionType::TYPE3_4, reinterpret_cast(ldx_handler)}; - instructions[LPS] = {"LPS", InstructionType::TYPE3_4, nullptr}; - instructions[MUL] = {"MUL", InstructionType::TYPE3_4, reinterpret_cast(mul_handler)}; - instructions[MULF] = {"MULF", InstructionType::TYPE3_4, reinterpret_cast(mulf_handler)}; - instructions[MULR] = {"MULR", InstructionType::TYPE2, reinterpret_cast(mulr_handler)}; - instructions[NORM] = {"NORM", InstructionType::TYPE1, reinterpret_cast(norm_handler)}; - instructions[OR] = {"OR", InstructionType::TYPE3_4, reinterpret_cast(or_handler)}; - instructions[RD] = {"RD", InstructionType::TYPE3_4, reinterpret_cast(rd_handler)}; - instructions[RMO] = {"RMO", InstructionType::TYPE2, reinterpret_cast(rmo_handler)}; - instructions[RSUB] = {"RSUB", InstructionType::TYPE3_4, reinterpret_cast(rsub_handler)}; - instructions[SHIFTL] = {"SHIFTL", InstructionType::TYPE2, reinterpret_cast(shiftl_handler)}; - instructions[SHIFTR] = {"SHIFTR", InstructionType::TYPE2, reinterpret_cast(shiftr_handler)}; - instructions[SIO] = {"SIO", InstructionType::TYPE1, nullptr}; - instructions[SSK] = {"SSK", InstructionType::TYPE3_4, nullptr}; - instructions[STA] = {"STA", InstructionType::TYPE3_4, reinterpret_cast(sta_handler)}; - instructions[STB] = {"STB", InstructionType::TYPE3_4, reinterpret_cast(stb_handler)}; - instructions[STCH] = {"STCH", InstructionType::TYPE3_4, reinterpret_cast(stch_handler)}; - instructions[STF] = {"STF", InstructionType::TYPE3_4, reinterpret_cast(stf_handler)}; - instructions[STI] = {"STI", InstructionType::TYPE3_4, nullptr}; - instructions[STL] = {"STL", InstructionType::TYPE3_4, reinterpret_cast(stl_handler)}; - instructions[STS] = {"STS", InstructionType::TYPE3_4, reinterpret_cast(sts_handler)}; - instructions[STSW] = {"STSW", InstructionType::TYPE3_4, reinterpret_cast(stsw_handler)}; - instructions[STT] = {"STT", InstructionType::TYPE3_4, reinterpret_cast(stt_handler)}; - instructions[STX] = {"STX", InstructionType::TYPE3_4, reinterpret_cast(stx_handler)}; - instructions[SUB] = {"SUB", InstructionType::TYPE3_4, reinterpret_cast(sub_handler)}; - instructions[SUBF] = {"SUBF", InstructionType::TYPE3_4, reinterpret_cast(subf_handler)}; - instructions[SUBR] = {"SUBR", InstructionType::TYPE2, reinterpret_cast(subr_handler)}; - instructions[SVC] = {"SVC", InstructionType::TYPE2, reinterpret_cast(svc_handler)}; - instructions[TIXR] = {"TIXR", InstructionType::TYPE2, reinterpret_cast(tixr_handler)}; - instructions[TD] = {"TD", InstructionType::TYPE3_4, reinterpret_cast(td_handler)}; - instructions[TIX] = {"TIX", InstructionType::TYPE3_4, reinterpret_cast(tix_handler)}; - instructions[TIO] = {"TIO", InstructionType::TYPE1, nullptr}; - instructions[WD] = {"WD", InstructionType::TYPE3_4, reinterpret_cast(wd_handler)}; + instructions[ADD] = {"ADD", InstructionType::TYPE3_4, nullptr}; + instructions[ADDF] = {"ADDF", InstructionType::TYPE3_4, nullptr}; + instructions[ADDR] = {"ADDR", InstructionType::TYPE2, reinterpret_cast(addr_handler)}; + instructions[AND] = {"AND", InstructionType::TYPE3_4, nullptr}; + instructions[CLEAR] = {"CLEAR", InstructionType::TYPE2, reinterpret_cast(clear_handler)}; + instructions[COMP] = {"COMP", InstructionType::TYPE3_4, nullptr}; + instructions[COMPF] = {"COMPF", InstructionType::TYPE3_4, nullptr}; + instructions[COMPR] = {"COMPR", InstructionType::TYPE2, nullptr}; + instructions[DIV] = {"DIV", InstructionType::TYPE3_4, nullptr}; + instructions[DIVF] = {"DIVF", InstructionType::TYPE3_4, nullptr}; + instructions[DIVR] = {"DIVR", InstructionType::TYPE2, reinterpret_cast(divr_handler)}; + instructions[FIX] = {"FIX", InstructionType::TYPE1, nullptr}; + instructions[FLOAT] = {"FLOAT", InstructionType::TYPE1, nullptr}; + instructions[HIO] = {"HIO", InstructionType::TYPE1, nullptr}; + instructions[J] = {"J", InstructionType::TYPE3_4, nullptr}; + instructions[JEQ] = {"JEQ", InstructionType::TYPE3_4, nullptr}; + instructions[JGT] = {"JGT", InstructionType::TYPE3_4, nullptr}; + instructions[JLT] = {"JLT", InstructionType::TYPE3_4, nullptr}; + instructions[JSUB] = {"JSUB", InstructionType::TYPE3_4, nullptr}; + instructions[LDA] = {"LDA", InstructionType::TYPE3_4, nullptr}; + instructions[LDB] = {"LDB", InstructionType::TYPE3_4, nullptr}; + instructions[LDCH] = {"LDCH", InstructionType::TYPE3_4, nullptr}; + instructions[LDF] = {"LDF", InstructionType::TYPE3_4, nullptr}; + instructions[LDL] = {"LDL", InstructionType::TYPE3_4, nullptr}; + instructions[LDS] = {"LDS", InstructionType::TYPE3_4, nullptr}; + instructions[LDT] = {"LDT", InstructionType::TYPE3_4, nullptr}; + instructions[LDX] = {"LDX", InstructionType::TYPE3_4, nullptr}; + instructions[LPS] = {"LPS", InstructionType::TYPE3_4, nullptr}; + instructions[MUL] = {"MUL", InstructionType::TYPE3_4, nullptr}; + instructions[MULF] = {"MULF", InstructionType::TYPE3_4, nullptr}; + instructions[MULR] = {"MULR", InstructionType::TYPE2, reinterpret_cast(mulr_handler)}; + instructions[NORM] = {"NORM", InstructionType::TYPE1, nullptr}; + instructions[OR] = {"OR", InstructionType::TYPE3_4, nullptr}; + instructions[RD] = {"RD", InstructionType::TYPE3_4, nullptr}; + instructions[RMO] = {"RMO", InstructionType::TYPE2, reinterpret_cast(rmo_handler)}; + instructions[RSUB] = {"RSUB", InstructionType::TYPE3_4, nullptr}; + instructions[SHIFTL] = {"SHIFTL", InstructionType::TYPE2, reinterpret_cast(shiftl_handler)}; + instructions[SHIFTR] = {"SHIFTR", InstructionType::TYPE2, reinterpret_cast(shiftr_handler)}; + instructions[SIO] = {"SIO", InstructionType::TYPE1, nullptr}; + instructions[SSK] = {"SSK", InstructionType::TYPE3_4, nullptr}; + instructions[STA] = {"STA", InstructionType::TYPE3_4, nullptr}; + instructions[STB] = {"STB", InstructionType::TYPE3_4, nullptr}; + instructions[STCH] = {"STCH", InstructionType::TYPE3_4, nullptr}; + instructions[STF] = {"STF", InstructionType::TYPE3_4, nullptr}; + instructions[STI] = {"STI", InstructionType::TYPE3_4, nullptr}; + instructions[STL] = {"STL", InstructionType::TYPE3_4, nullptr}; + instructions[STS] = {"STS", InstructionType::TYPE3_4, nullptr}; + instructions[STSW] = {"STSW", InstructionType::TYPE3_4, nullptr}; + instructions[STT] = {"STT", InstructionType::TYPE3_4, nullptr}; + instructions[STX] = {"STX", InstructionType::TYPE3_4, nullptr}; + instructions[SUB] = {"SUB", InstructionType::TYPE3_4, nullptr}; + instructions[SUBF] = {"SUBF", InstructionType::TYPE3_4, nullptr}; + instructions[SUBR] = {"SUBR", InstructionType::TYPE2, reinterpret_cast(subr_handler)}; + instructions[SVC] = {"SVC", InstructionType::TYPE2, reinterpret_cast(svc_handler)}; + instructions[TIXR] = {"TIXR", InstructionType::TYPE2, reinterpret_cast(tixr_handler)}; + instructions[TD] = {"TD", InstructionType::TYPE3_4, nullptr}; + instructions[TIX] = {"TIX", InstructionType::TYPE3_4, nullptr}; + instructions[TIO] = {"TIO", InstructionType::TYPE1, nullptr}; + instructions[WD] = {"WD", InstructionType::TYPE3_4, nullptr}; - // Load SIC/XE/XE extended instructions - if (USE_EXTENDED_MODE) { - // Still in main table - instructions[NOP] = {"NOP", InstructionType::TYPE1, reinterpret_cast(nop_handler)}; - instructions[HALT] = {"HALT", InstructionType::TYPE1, reinterpret_cast(halt_handler)}; - instructions[XEXE] = {"XEXE", InstructionType::TYPE1, reinterpret_cast(xexe_handler)}; - - instructionsEXEX[VADD] = {"VADD", InstructionType::TYPE3_4, reinterpret_cast(vadd_handler)}; - instructionsEXEX[VADDR] = {"VADDR", InstructionType::TYPE2, reinterpret_cast(vaddr_handler)}; - instructionsEXEX[VSUB] = {"VSUB", InstructionType::TYPE3_4, reinterpret_cast(vsub_handler)}; - instructionsEXEX[VSUBR] = {"VSUBR", InstructionType::TYPE2, reinterpret_cast(vsubr_handler)}; - instructionsEXEX[VMUL] = {"VMUL", InstructionType::TYPE3_4, reinterpret_cast(vmul_handler)}; - instructionsEXEX[VMULR] = {"VMULR", InstructionType::TYPE2, reinterpret_cast(vmulr_handler)}; - instructionsEXEX[VDIV] = {"VDIV", InstructionType::TYPE3_4, reinterpret_cast(vdiv_handler)}; - instructionsEXEX[VDIVR] = {"VDIVR", InstructionType::TYPE2, reinterpret_cast(vdivr_handler)}; - instructionsEXEX[STVA] = {"STVA", InstructionType::TYPE3_4, reinterpret_cast(stva_handler)}; - instructionsEXEX[STVS] = {"STVS", InstructionType::TYPE3_4, reinterpret_cast(stvs_handler)}; - instructionsEXEX[STVT] = {"STVT", InstructionType::TYPE3_4, reinterpret_cast(stvt_handler)}; - instructionsEXEX[LDVA] = {"LDVA", InstructionType::TYPE3_4, reinterpret_cast(ldva_handler)}; - instructionsEXEX[LDVS] = {"LDVS", InstructionType::TYPE3_4, reinterpret_cast(ldvs_handler)}; - instructionsEXEX[LDVT] = {"LDVT", InstructionType::TYPE3_4, reinterpret_cast(ldvt_handler)}; - } - // Mark uninitialized opcodes as INVALID + // Mark uninitialized opcodes as INVALID for (int i = 0; i < 0xff; ++i) { - if (instructions[i].name == nullptr) instructions[i] = {"INVALID", InstructionType::INVALID, nullptr}; - if (instructionsEXEX[i].name == nullptr) instructionsEXEX[i] = {"INVALID", InstructionType::INVALID, nullptr}; + if (instructions[i].name == nullptr) { + instructions[i] = {"INVALID", InstructionType::INVALID, nullptr}; + } } -} - -AddressingMode getAddressingMode(int ni) -{ - switch (ni) { - case 0x0: return AddressingMode::SIC_DIRECT; - case 0x1: return AddressingMode::IMMEDIATE; - case 0x2: return AddressingMode::INDIRECT; - case 0x3: return AddressingMode::SIMPLE; - default: return AddressingMode::INVALID; // Should not happen - } -} +} \ No newline at end of file diff --git a/simulator_SIC_XE/src/string_reader.cpp b/simulator_SIC_XE/src/string_reader.cpp deleted file mode 100644 index b87cc02..0000000 --- a/simulator_SIC_XE/src/string_reader.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "string_reader.h" - -StringReader::StringReader(const std::string &s) - : in(s) -{} - -StringReader::~StringReader() = default; - -int StringReader::readByte() { - char c; - if (!in.get(c)) return -1; - return static_cast(c); -} - -bool StringReader::readBytes(uint8_t* buf, size_t len) { - in.read(reinterpret_cast(buf), static_cast(len)); - return static_cast(in.gcount()) == len; -} - -std::string StringReader::readString(size_t len) { - std::string s; - s.resize(len); - in.read(reinterpret_cast(&s[0]), static_cast(len)); - std::streamsize got = in.gcount(); - if (static_cast(got) < len) s.resize(static_cast(got)); - return s; -} - -std::string StringReader::readLine() { - std::string s; - if (!std::getline(in, s)) return std::string(); - return s; -} diff --git a/test.asm b/test.asm deleted file mode 100644 index e25da30..0000000 --- a/test.asm +++ /dev/null @@ -1,7 +0,0 @@ -test START 0 - LDA #1 - LDB #2 - ADDR B, A - -halt J halt - END test \ No newline at end of file