diff --git a/.gitignore b/.gitignore index ebebf77..7be8ac1 100644 --- a/.gitignore +++ b/.gitignore @@ -23,6 +23,3 @@ __pycache__/ *.dev autotester sictools.jar -simulator_SIC_XE/CMakeLists.txt.user - -/build/ 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/ass3/simulator_SIC_XE/.gitignore b/ass3/simulator_SIC_XE/.gitignore deleted file mode 100644 index 4cbe372..0000000 --- a/ass3/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/ass3/simulator_SIC_XE/CMakeLists.txt b/ass3/simulator_SIC_XE/CMakeLists.txt deleted file mode 100644 index cde4cd2..0000000 --- a/ass3/simulator_SIC_XE/CMakeLists.txt +++ /dev/null @@ -1,59 +0,0 @@ -cmake_minimum_required(VERSION 3.10) -project(simulator_SIC_XE VERSION 1.0 LANGUAGES CXX) - -set(CMAKE_CXX_STANDARD 20) -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") - - -set(MAIN_SRC "${PROJECT_SOURCE_DIR}/src/main.cpp") -set(ASSEMBLER_SRC "${PROJECT_SOURCE_DIR}/src/assembler.cpp") -list(REMOVE_ITEM SOURCES ${MAIN_SRC} ${ASSEMBLER_SRC}) - -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(EXISTS "${PROJECT_SOURCE_DIR}/src/assembler.cpp") - add_executable(assembler "${PROJECT_SOURCE_DIR}/src/assembler.cpp") - target_link_libraries(assembler PRIVATE simulator_lib) -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/ass3/simulator_SIC_XE/Makefile b/ass3/simulator_SIC_XE/Makefile deleted file mode 100644 index 93bc1f6..0000000 --- a/ass3/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/ass3/simulator_SIC_XE/README.md b/ass3/simulator_SIC_XE/README.md deleted file mode 100644 index ae46366..0000000 --- a/ass3/simulator_SIC_XE/README.md +++ /dev/null @@ -1,90 +0,0 @@ -# SIC/XE Simulator - -A complete SIC/XE architecture simulator with instruction execution, device I/O, memory management, and assembler. - -## Quick Start - -### Building the Project - -```bash -make -``` - -This will build: -- `target/bin/simulator_exec` - The main simulator -- `target/bin/assembler` - The SIC/XE assembler -- `target/bin/simulator_qt` - Qt GUI version (if Qt is available) - -### Using the Assembler - -Assemble a SIC/XE assembly file to object code: - -```bash -./target/bin/assembler -``` - -**Example:** -```bash -./target/bin/assembler res/test_format4.asm -``` - -This will: -- Parse and assemble the input file -- Generate modification records (M records) for format 4 instructions -- Create `.obj` with the object code -- Display the object code and symbol table - -**Sample Output:** -``` -H TESTF4 0003E8 00001B -T 0003E8 1B 031003F70F1003FA4B1003FD4F2C090000000000000100004F2BFD -M 0003E9 05 -M 0003ED 05 -M 0003F1 05 -E 0003E8 -``` - -### Running the Simulator - -```bash -make run -``` - -This will build and run the simulator with the default program. - -## Build Commands - -| Command | Description | -|--------------|----------------------------------------------------| -| `make` | Build all executables | -| `make build` | Build the project | -| `make run` | Build and run the simulator | -| `make clean` | Clean build artifacts | - - -## 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/ass3/simulator_SIC_XE/gui/qt/CMakeLists.txt b/ass3/simulator_SIC_XE/gui/qt/CMakeLists.txt deleted file mode 100644 index cf8072a..0000000 --- a/ass3/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/ass3/simulator_SIC_XE/gui/qt/MachineController.cpp b/ass3/simulator_SIC_XE/gui/qt/MachineController.cpp deleted file mode 100644 index 881e97d..0000000 --- a/ass3/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/ass3/simulator_SIC_XE/gui/qt/MachineController.h b/ass3/simulator_SIC_XE/gui/qt/MachineController.h deleted file mode 100644 index 801b5f4..0000000 --- a/ass3/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/ass3/simulator_SIC_XE/gui/qt/main.cpp b/ass3/simulator_SIC_XE/gui/qt/main.cpp deleted file mode 100644 index 707d916..0000000 --- a/ass3/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/ass3/simulator_SIC_XE/gui/qt/mainwindow.cpp b/ass3/simulator_SIC_XE/gui/qt/mainwindow.cpp deleted file mode 100644 index da6fb69..0000000 --- a/ass3/simulator_SIC_XE/gui/qt/mainwindow.cpp +++ /dev/null @@ -1,1130 +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/parser.h" -#include "../../include/code.h" - -#include -#include -#include -#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->actionLoad_Asm_file, &QAction::triggered, this, &MainWindow::loadAsmFile); - 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::loadAsmFile() -{ - QString fileName = QFileDialog::getOpenFileName(this, - tr("Load Assembly File"), - QString(), - tr("Assembly Files (*.asm);;All Files (*)")); - - if (fileName.isEmpty()) { - return; - } - - try { - // Stop execution if running - m_controller->stop(); - - // Reset machine state - m_machine->reset(); - - // Read assembly file - std::ifstream file(fileName.toStdString()); - if (!file.is_open()) { - throw std::runtime_error("Could not open file: " + fileName.toStdString()); - } - - std::string source((std::istreambuf_iterator(file)), - std::istreambuf_iterator()); - file.close(); - - // Parse and assemble - Parser parser; - Code code = parser.parse(source); - code.assemble(); - - // Generate object code - std::string objCode = code.emitText(); - - // Create resources directory if it doesn't exist - QDir dir; - if (!dir.exists("resources")) { - dir.mkpath("resources"); - } - - // Save object file to resources directory - QFileInfo fileInfo(fileName); - QString objFileName = "resources/" + fileInfo.completeBaseName() + ".obj"; - - std::ofstream objFile(objFileName.toStdString()); - if (!objFile.is_open()) { - throw std::runtime_error("Could not create object file: " + objFileName.toStdString()); - } - objFile << objCode; - objFile.close(); - - // Generate and save log file - QString logFileName = "resources/" + fileInfo.completeBaseName() + ".log"; - std::ofstream logFile(logFileName.toStdString()); - if (!logFile.is_open()) { - throw std::runtime_error("Could not create log file: " + logFileName.toStdString()); - } - - logFile << "=== SIC/XE Assembler Log ===\n\n"; - logFile << "Source file: " << fileName.toStdString() << "\n"; - logFile << "Object file: " << objFileName.toStdString() << "\n\n"; - - logFile << "=== Symbols ===\n"; - logFile << code.dumpSymbols() << "\n\n"; - - logFile << "=== Code ===\n"; - logFile << code.dumpCode() << "\n\n"; - - logFile << "=== Object Code ===\n"; - logFile << objCode << "\n"; - - logFile.close(); - - // Load the generated object file - Loader loader(m_machine, objFileName.toStdString()); - loader.load(); - - // Update displays - updateRegisterDisplays(); - updateMemoryDisplay(); - updateDisassemblyDisplay(); - - QMessageBox::information(this, tr("Success"), - tr("Assembly successful!\nObject file: %1\nLog file: %2") - .arg(objFileName).arg(logFileName)); - - } catch (const std::exception &e) { - QMessageBox::critical(this, tr("Error"), - tr("Failed to assemble 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/ass3/simulator_SIC_XE/gui/qt/mainwindow.h b/ass3/simulator_SIC_XE/gui/qt/mainwindow.h deleted file mode 100644 index cc8f042..0000000 --- a/ass3/simulator_SIC_XE/gui/qt/mainwindow.h +++ /dev/null @@ -1,86 +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 loadAsmFile(); - 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/ass3/simulator_SIC_XE/gui/qt/mainwindow.ui b/ass3/simulator_SIC_XE/gui/qt/mainwindow.ui deleted file mode 100644 index 21085fa..0000000 --- a/ass3/simulator_SIC_XE/gui/qt/mainwindow.ui +++ /dev/null @@ -1,936 +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 - - - - - Load Asm file - - - - - - diff --git a/ass3/simulator_SIC_XE/include/code.h b/ass3/simulator_SIC_XE/include/code.h deleted file mode 100644 index 519d5f1..0000000 --- a/ass3/simulator_SIC_XE/include/code.h +++ /dev/null @@ -1,68 +0,0 @@ -#ifndef CODE_H -#define CODE_H - -#include -#include -#include -#include - -#include "node.h" - -class Code { - -public: - Code() = default; - - void addLine(const std::shared_ptr& line); - - const std::vector>& getLines() const; - - const string toString() const; - - // Two-pass assembler methods - void assemble(); - std::vector emitCode(); - std::string emitText(); - std::string dumpSymbols() const; - std::string dumpCode() const; - -private: - std::vector> _lines; - - // Assembler state - std::unordered_map _symbolTable; - std::vector _locationCounters; // Location counter per line - int _startAddress = 0; - int _programLength = 0; - std::string _programName; - int _baseRegister = -1; // -1 means not set - - struct ModificationRecord { - int address; - int halfBytes; - }; - mutable std::vector _modificationRecords; - - // Pass 1: build symbol table and assign addresses - void firstPass(); - - // Pass 2: generate code - void secondPass(); - - // Helper methods - int getInstructionLength(const std::shared_ptr& node, int locationCounter) const; - std::vector generateInstruction(const InstructionNode* inst, int address); - std::vector generateData(const DataNode* data); - - // Addressing mode selection - struct AddressingResult { - int nixbpe; // ni, x, b, p, e bits - int displacement; // 12-bit or 20-bit - bool success; - }; - AddressingResult selectAddressingMode(int targetAddress, int pc, bool indexed, bool immediate, bool indirect, bool extended) const; -}; - - - -#endif // CODE_H \ No newline at end of file diff --git a/ass3/simulator_SIC_XE/include/constants.h b/ass3/simulator_SIC_XE/include/constants.h deleted file mode 100644 index 6f2195a..0000000 --- a/ass3/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/ass3/simulator_SIC_XE/include/device.h b/ass3/simulator_SIC_XE/include/device.h deleted file mode 100644 index 6b5acb7..0000000 --- a/ass3/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/ass3/simulator_SIC_XE/include/file_device.h b/ass3/simulator_SIC_XE/include/file_device.h deleted file mode 100644 index 01b433c..0000000 --- a/ass3/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/ass3/simulator_SIC_XE/include/file_reader.h b/ass3/simulator_SIC_XE/include/file_reader.h deleted file mode 100644 index 87b8a17..0000000 --- a/ass3/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/ass3/simulator_SIC_XE/include/input_device.h b/ass3/simulator_SIC_XE/include/input_device.h deleted file mode 100644 index 40b01d3..0000000 --- a/ass3/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/ass3/simulator_SIC_XE/include/instructions.h b/ass3/simulator_SIC_XE/include/instructions.h deleted file mode 100644 index 5bef303..0000000 --- a/ass3/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/ass3/simulator_SIC_XE/include/lexer.h b/ass3/simulator_SIC_XE/include/lexer.h deleted file mode 100644 index f9bdd70..0000000 --- a/ass3/simulator_SIC_XE/include/lexer.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef LEXER_H -#define LEXER_H - -#include -#include -#include - -class SyntaxError : public std::runtime_error { -public: - int row; - int col; - - SyntaxError(const std::string& msg, int row_, int col_) - : std::runtime_error(msg), row(row_), col(col_) {} -}; - - -class Lexer { -public: - int row; - int col; - - explicit Lexer(std::string input); - - Lexer& mark(); - - std::string extract(int ofs); - std::string extract(); - - char peek(int ahead) const; - char peek() const; - - char advance(); - - bool advanceIf(char ch); - void advance(char ch); - - - bool skipWhitespace(); - - std::string readTo(char delimiter); - - std::string readAlphanumeric(); - - std::string readDigits(int radix); - -private: - std::string input_; - std::size_t pos_; - std::size_t start_; - - static int digitValue(char c, int radix); -}; - -#endif // LEXER_H diff --git a/ass3/simulator_SIC_XE/include/loader.h b/ass3/simulator_SIC_XE/include/loader.h deleted file mode 100644 index 34c31a6..0000000 --- a/ass3/simulator_SIC_XE/include/loader.h +++ /dev/null @@ -1,77 +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, - MODIFICATION, - END, - UNKNOWN - }; - - struct HeaderMetadata { - string program_name; - int start_address; - int length; - }; - struct TextRecord { - int start_address; - std::vector data; - }; - struct ModificationRecord { - int address; // Address to be modified - int length; // Length in nibbles - bool add; // true for +, false for - - }; - struct EndRecord { - int execution_start_address; - }; - - void load(); - -private : - - static RecordType parseRecordType(char c); - - - shared_ptr _machine; - string _filename; - shared_ptr _file_reader; - int _relocation_address; - HeaderMetadata readHeader(); - TextRecord readTextRecord(); - ModificationRecord readModificationRecord(); - EndRecord readEndRecord(); - bool load_into_memory(int start_address, const std::vector& data); - void applyModification(const ModificationRecord& mod); - -}; - - - - - -#endif // LOADER_H \ No newline at end of file diff --git a/ass3/simulator_SIC_XE/include/machine.h b/ass3/simulator_SIC_XE/include/machine.h deleted file mode 100644 index cd14f74..0000000 --- a/ass3/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/ass3/simulator_SIC_XE/include/mnemonic.h b/ass3/simulator_SIC_XE/include/mnemonic.h deleted file mode 100644 index 3cdddab..0000000 --- a/ass3/simulator_SIC_XE/include/mnemonic.h +++ /dev/null @@ -1,45 +0,0 @@ -// mnemonic.h -#ifndef MNEMONIC_H -#define MNEMONIC_H - -#include -#include -#include -#include - -#include "opcode.h" - -struct Empty {}; -struct Register { int num; }; -struct Immediate { int value; }; -struct SymbolRef { - std::string name; - bool indexed = false; - bool immediate = false; - bool indirect = false; -}; - -using Operand = std::variant; - -class Mnemonic { -public: - Mnemonic(std::uint8_t opcode, InstructionType type, bool extended) - : _opcode(opcode), _extended(extended), _type(type) {} - - std::uint8_t opcode() const { return _opcode; } - bool extended() const { return _extended; } - InstructionType type() const { return _type; } - - std::vector& operands() { return _operands; } - const std::vector& operands() const { return _operands; } - - std::string toString() const; - -private: - std::uint8_t _opcode; - bool _extended; - InstructionType _type; - std::vector _operands; -}; - -#endif // MNEMONIC_H diff --git a/ass3/simulator_SIC_XE/include/node.h b/ass3/simulator_SIC_XE/include/node.h deleted file mode 100644 index 2ad0d86..0000000 --- a/ass3/simulator_SIC_XE/include/node.h +++ /dev/null @@ -1,98 +0,0 @@ -#ifndef NODE_H -#define NODE_H - -#include -#include -#include -#include -#include -#include "mnemonic.h" - -using std::string; - -class Node { -public: - virtual ~Node() = default; - - string getLabel() const { return _label; } - string getComment() const { return _comment; } - std::shared_ptr getMnemonic() const { return _mnemonic; } - - virtual string toString() const; - -protected: - string _label; - std::shared_ptr _mnemonic; - string _comment; -}; - -class InstructionNode : public Node { -public: - InstructionNode(string label, - std::shared_ptr mnemonic, - string comment) { - _label = std::move(label); - _mnemonic = std::move(mnemonic); - _comment = std::move(comment); - } - - string toString() const override; -}; - -class CommentNode : public Node { -public: - explicit CommentNode(string text) { - _comment = std::move(text); - } - - string toString() const override; -}; - -enum class DirectiveKind { - START, END, BASE, NOBASE, EQU, ORG, LTORG, - EXTDEF, EXTREF, CSECT -}; - -using DirectiveArg = std::variant>; - -class DirectiveNode : public Node { -public: - DirectiveNode(string label, DirectiveKind kind, DirectiveArg arg, string comment) - : _kind(kind), _arg(std::move(arg)) { - _label = std::move(label); - _comment = std::move(comment); - } - - DirectiveKind kind() const { return _kind; } - const DirectiveArg& arg() const { return _arg; } - - string toString() const override; - -private: - DirectiveKind _kind; - DirectiveArg _arg; -}; - -enum class DataKind { WORD, BYTE, RESW, RESB }; - -using DataValue = std::variant>; - -class DataNode : public Node { -public: - DataNode(string label, DataKind kind, DataValue value, string comment) - : _kind(kind), _value(std::move(value)) { - _label = std::move(label); - _comment = std::move(comment); - } - - DataKind kind() const { return _kind; } - const DataValue& value() const { return _value; } - - string toString() const override; - -private: - DataKind _kind; - DataValue _value; -}; - -#endif // NODE_H diff --git a/ass3/simulator_SIC_XE/include/opcode.h b/ass3/simulator_SIC_XE/include/opcode.h deleted file mode 100644 index 05cb693..0000000 --- a/ass3/simulator_SIC_XE/include/opcode.h +++ /dev/null @@ -1,127 +0,0 @@ -#ifndef OPCODE_H -#define OPCODE_H - -#include "utils.h" - -#include -#include -#include -#include - -// ============================== -// 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 - -static std::unordered_map mnemonicToOpcode; -static bool opcodeTablesInitialized = false; - - -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[]; - -extern std::optional findOpcodeByMnemonic(std::string_view name); -extern const InstructionInfo& getInstructionInfo(uint8_t opcode); - - -// Initialize the instruction table -void loadInstructionSet(); - -#endif // OPCODE_H diff --git a/ass3/simulator_SIC_XE/include/output_device.h b/ass3/simulator_SIC_XE/include/output_device.h deleted file mode 100644 index 94ba8b8..0000000 --- a/ass3/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/ass3/simulator_SIC_XE/include/parser.h b/ass3/simulator_SIC_XE/include/parser.h deleted file mode 100644 index 8ae126a..0000000 --- a/ass3/simulator_SIC_XE/include/parser.h +++ /dev/null @@ -1,52 +0,0 @@ -// parser.h -#ifndef PARSER_H -#define PARSER_H - -#include -#include -#include -#include -#include - -#include "lexer.h" -#include "code.h" -#include "opcode.h" -#include "mnemonic.h" - -class Parser { -public: - Parser() = default; - - Code parse(const std::string& input); - -private: - std::string parseLabel(); - std::shared_ptr parseMnemonic(); - std::string parseSymbol(); - int parseRegister(); - void parseComma(); - bool parseIndexed(); - int parseNumber(int lo, int hi); - std::vector parseData(); - - void parseOperands(Mnemonic& m); - - bool isDirective(const std::string& name); - bool isDataDirective(const std::string& name); - std::shared_ptr parseDirective(const std::string& label, const std::string& directive); - std::shared_ptr parseDataDirective(const std::string& label, const std::string& directive); - - std::shared_ptr parseInstruction(); - Code parseCode(); - - std::shared_ptr makeMnemonic(const std::string& name, bool extended); - static void initMnemonicMap(); - -private: - Lexer lexer_{""}; - - static inline std::unordered_map s_nameToOpcode{}; - static inline bool s_mnemonicMapInitialized = false; -}; - -#endif // PARSER_H diff --git a/ass3/simulator_SIC_XE/include/reader.h b/ass3/simulator_SIC_XE/include/reader.h deleted file mode 100644 index e582161..0000000 --- a/ass3/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/ass3/simulator_SIC_XE/include/string_reader.h b/ass3/simulator_SIC_XE/include/string_reader.h deleted file mode 100644 index 71c3da9..0000000 --- a/ass3/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/ass3/simulator_SIC_XE/include/utils.h b/ass3/simulator_SIC_XE/include/utils.h deleted file mode 100644 index 3197a95..0000000 --- a/ass3/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/ass3/simulator_SIC_XE/res/rec.asm b/ass3/simulator_SIC_XE/res/rec.asm deleted file mode 100644 index 212bf23..0000000 --- a/ass3/simulator_SIC_XE/res/rec.asm +++ /dev/null @@ -1,223 +0,0 @@ -prog START 0 - -.------------------------------------------- -. MAIN LOOP -. -. Psevdo: -. sp = 0 -. while true: -. n = readFA() -. if n == 0: halt -. acc = 1 -. fact() ; rekurzivno: acc = n! -. printStdout(acc) -.------------------------------------------- - CLEAR A - STA sp - -loop JSUB readFA - COMP #0 - JEQ halt - - STA n - LDA #1 - STA acc - - JSUB fact - LDA acc - JSUB printStdout - - J loop - -halt J halt - -.------------------------------------------- -. readFA -. -. Psevdo: -. B = 0 -. while true: -. ch = RD(FA) -. if ch == CR or ch == LF: break -. digit = ch - '0' -. B = B * 10 + digit -. return B -.------------------------------------------- -readFA CLEAR B - LDS #10 - -rd_loopFA RD #0xFA - COMP #0x0D . CR? - JEQ rd_doneCR_FA - COMP #0x0A . LF? - JEQ rd_doneFA - - SUB #0x30 - MULR S,B . B = B * 10 - ADDR A,B . B = B + digit - J rd_loopFA - -rd_doneCR_FA RD #0xFA . pogoltni LF po CR -rd_doneFA CLEAR A - RMO B,A - RSUB - -.------------------------------------------- -. fact -. -. Psevdo (globalni n, acc, sklad L): -. fact(): -. push(L) -. if n <= 1: -. pop(L); return -. acc = acc * n -. n = n - 1 -. fact() -. pop(L); return -.------------------------------------------- -fact . push L - LDA sp - ADD #3 - STA sp - LDX sp - STL stackL,X - - LDA n - COMP #1 - JGT fact_rec - - . base case: n <= 1 - LDX sp - LDL stackL,X - LDA sp - SUB #3 - STA sp - RSUB - -fact_rec . recursive case: acc *= n; n--; fact() - - LDB acc - LDS n - MULR S,B - STB acc - - LDA n - SUB #1 - STA n - - JSUB fact - - . pop L in return to caller - LDX sp - LDL stackL,X - LDA sp - SUB #3 - STA sp - RSUB - -.------------------------------------------- -. printStdout -. -. Psevdo: -. if A == 0: -. print "0\n" -. return -. ps_val = A -. ps_len = 0 -. while ps_val > 0: -. q = ps_val / 10 -. r = ps_val % 10 -. buf[ps_len] = '0' + r -. ps_len++ -. ps_val = q -. for i = ps_len-1 .. 0: -. print buf[i] -. print "\r\n" -.------------------------------------------- -printStdout COMP #0 - JEQ ps_zero - - STA ps_val - LDA #0 - STA ps_len - LDS #10 - LDT #0x30 . '0' - -ps_div LDA ps_val - COMP #0 - JEQ ps_divdone - - RMO A,B - DIVR S,B . kvocient v B - RMO B,X . X = kvocient - - MULR S,B - SUBR B,A . A = ostanek - ADDR T,A . A = '0' + ostanek - STA psdigit - - LDA ps_len - STA ps_idx - LDA #psbuf - ADD ps_idx - STA ps_ptr - LDA psdigit - STCH @ps_ptr - - LDA ps_len - ADD #1 - STA ps_len - - RMO X,A - STA ps_val - J ps_div - -ps_divdone LDA ps_len - SUB #1 - STA ps_idx - -ps_print LDA ps_idx - COMP #0 - JLT ps_end - - LDA #psbuf - ADD ps_idx - STA ps_ptr - LDCH @ps_ptr - WD #1 - - LDA ps_idx - SUB #1 - STA ps_idx - J ps_print - -ps_end LDA #0x0D . CR - WD #1 - LDA #0x0A . LF - WD #1 - RSUB - -ps_zero LDA #0x30 . "0" - WD #1 - LDA #0x0D - WD #1 - LDA #0x0A - WD #1 - RSUB - -.data -. rekurzija faktoriala -sp WORD 0 . stack pointer -n WORD 0 -acc WORD 0 . akumulator za faktorial -stackL RESB 60 - -. printStdout -ps_val WORD 0 -ps_len WORD 0 -ps_idx WORD 0 -psdigit WORD 0 -ps_ptr WORD 0 -psbuf RESB 12 - - END prog diff --git a/ass3/simulator_SIC_XE/res/simple.asm b/ass3/simulator_SIC_XE/res/simple.asm deleted file mode 100644 index 20beca6..0000000 --- a/ass3/simulator_SIC_XE/res/simple.asm +++ /dev/null @@ -1,32 +0,0 @@ -SIMPLE START 0 - - +LDA NUM1 - +ADD NUM2 - +STA RESULT - - LDX NUM1 - LDL NUM2 - - LDA #0 - ADDR X,A - ADDR L,A - - +LDA RESULT - ADD #48 - RMO A,S - SHIFTL S,16 - SHIFTR S,16 - RMO S,A - STCH RESULT - LDCH RESULT - WD OUTPUT - -HALT J HALT - -OUTPUT BYTE 1 - -NUM1 WORD 1 -NUM2 WORD 2 -RESULT RESW 1 - - END SIMPLE diff --git a/ass3/simulator_SIC_XE/res/test_format4.asm b/ass3/simulator_SIC_XE/res/test_format4.asm deleted file mode 100644 index 6de136d..0000000 --- a/ass3/simulator_SIC_XE/res/test_format4.asm +++ /dev/null @@ -1,11 +0,0 @@ -TESTF4 START 1000 - +LDA BUFFER - +STA OUTPUT - +JSUB FUNC - RSUB - -BUFFER RESW 1 -OUTPUT RESW 1 -FUNC LDA #0 - RSUB - END TESTF4 diff --git a/ass3/simulator_SIC_XE/src/assembler.cpp b/ass3/simulator_SIC_XE/src/assembler.cpp deleted file mode 100644 index 2ceece9..0000000 --- a/ass3/simulator_SIC_XE/src/assembler.cpp +++ /dev/null @@ -1,77 +0,0 @@ -#include -#include -#include -#include "code.h" -#include "parser.h" -#include "opcode.h" - -using std::cout; -using std::endl; -using std::cerr; - -int main(int argc, char* argv[]) { - if (argc != 2) { - cerr << "Usage: " << argv[0] << " " << endl; - return 1; - } - - std::string inputFile = argv[1]; - - // Load instruction set - loadInstructionSet(); - - try { - // Read assembly file - cout << "Assembling: " << inputFile << endl; - std::ifstream file(inputFile); - if (!file.is_open()) { - throw std::runtime_error("Failed to open file: " + inputFile); - } - - std::string input; - std::string line; - while (std::getline(file, line)) { - input += line + "\n"; - } - file.close(); - - // Parse - Parser parser; - Code code = parser.parse(input); - - // Assemble - code.assemble(); - - // Generate object code - std::string objectCode = code.emitText(); - - // Determine output filename - std::string outputFile = inputFile; - size_t lastDot = outputFile.find_last_of('.'); - if (lastDot != std::string::npos) { - outputFile = outputFile.substr(0, lastDot); - } - outputFile += ".obj"; - - // Write to file - std::ofstream out(outputFile); - if (!out.is_open()) { - throw std::runtime_error("Failed to create output file: " + outputFile); - } - out << objectCode; - out.close(); - - // Display results - cout << "\n=== Object Code ===" << endl; - cout << objectCode; - cout << "\n=== Symbol Table ===" << endl; - cout << code.dumpSymbols(); - cout << "\nOutput written to: " << outputFile << endl; - - } catch (const std::exception& e) { - cerr << "ERROR: " << e.what() << endl; - return 1; - } - - return 0; -} diff --git a/ass3/simulator_SIC_XE/src/code.cpp b/ass3/simulator_SIC_XE/src/code.cpp deleted file mode 100644 index 2e87d12..0000000 --- a/ass3/simulator_SIC_XE/src/code.cpp +++ /dev/null @@ -1,551 +0,0 @@ -#include "code.h" -#include "opcode.h" -#include "constants.h" -#include -#include -#include -#include - -void Code::addLine(const std::shared_ptr &line) -{ - _lines.emplace_back(line); -} - -const std::vector> &Code::getLines() const -{ - return _lines; -} - -const string Code::toString() const -{ - string result; - for (const auto& line : _lines) { - result += line->toString() + "\n"; - } - return result; -} - -// ============================================================ -// TWO-PASS ASSEMBLER IMPLEMENTATION -// ============================================================ - -void Code::assemble() { - firstPass(); - secondPass(); -} - -void Code::firstPass() { - _symbolTable.clear(); - _locationCounters.clear(); - _locationCounters.resize(_lines.size(), 0); - - int locationCounter = 0; - bool startFound = false; - - for (size_t i = 0; i < _lines.size(); ++i) { - auto& line = _lines[i]; - _locationCounters[i] = locationCounter; - - // Handle label - std::string label = line->getLabel(); - if (!label.empty()) { - if (_symbolTable.find(label) != _symbolTable.end()) { - throw std::runtime_error("Duplicate symbol: " + label); - } - _symbolTable[label] = locationCounter; - } - - // Check for directives - if (auto* directive = dynamic_cast(line.get())) { - switch (directive->kind()) { - case DirectiveKind::START: { - if (std::holds_alternative(directive->arg())) { - _startAddress = std::get(directive->arg()); - locationCounter = _startAddress; - _locationCounters[i] = locationCounter; - if (!label.empty()) { - _symbolTable[label] = locationCounter; - _programName = label; - } - startFound = true; - } - break; - } - case DirectiveKind::END: - _programLength = locationCounter - _startAddress; - break; - - case DirectiveKind::BASE: { - // BASE sets base register for addressing - if (std::holds_alternative(directive->arg())) { - // Will resolve in second pass - } - break; - } - case DirectiveKind::NOBASE: - _baseRegister = -1; - break; - - case DirectiveKind::EQU: { - // EQU defines symbol value - if (!label.empty() && std::holds_alternative(directive->arg())) { - _symbolTable[label] = std::get(directive->arg()); - } - break; - } - case DirectiveKind::ORG: { - // ORG changes location counter - if (std::holds_alternative(directive->arg())) { - locationCounter = std::get(directive->arg()); - } - break; - } - default: - break; - } - continue; - } - - // Handle data directives - if (auto* data = dynamic_cast(line.get())) { - int length = 0; - switch (data->kind()) { - case DataKind::WORD: - length = 3; // 24-bit word - break; - case DataKind::BYTE: { - if (std::holds_alternative>(data->value())) { - length = std::get>(data->value()).size(); - } - break; - } - case DataKind::RESW: { - if (std::holds_alternative(data->value())) { - length = std::get(data->value()) * 3; - } - break; - } - case DataKind::RESB: { - if (std::holds_alternative(data->value())) { - length = std::get(data->value()); - } - break; - } - } - locationCounter += length; - continue; - } - - // Handle instructions - if (auto* inst = dynamic_cast(line.get())) { - int length = getInstructionLength(line, locationCounter); - locationCounter += length; - } - } - - if (!startFound) { - _startAddress = 0; - } - _programLength = locationCounter - _startAddress; -} - -int Code::getInstructionLength(const std::shared_ptr& node, int locationCounter) const { - auto* inst = dynamic_cast(node.get()); - if (!inst || !inst->getMnemonic()) { - return 0; - } - - auto mnemonic = inst->getMnemonic(); - InstructionType type = mnemonic->type(); - - switch (type) { - case InstructionType::TYPE1: - return 1; - case InstructionType::TYPE2: - return 2; - case InstructionType::TYPE3_4: - return mnemonic->extended() ? 4 : 3; - default: - return 0; - } -} - -void Code::secondPass() { - // Generate code for all instructions and data - // This will be used by emitCode() and emitText() -} - -std::vector Code::emitCode() { - std::vector code; - code.resize(_programLength, 0); - - for (size_t i = 0; i < _lines.size(); ++i) { - auto& line = _lines[i]; - int address = _locationCounters[i]; - int offset = address - _startAddress; - - if (offset < 0 || offset >= _programLength) { - continue; - } - - // Generate instruction - if (auto* inst = dynamic_cast(line.get())) { - auto bytes = generateInstruction(inst, address); - for (size_t j = 0; j < bytes.size() && (offset + j) < code.size(); ++j) { - code[offset + j] = bytes[j]; - } - } - - // Generate data - if (auto* data = dynamic_cast(line.get())) { - auto bytes = generateData(data); - for (size_t j = 0; j < bytes.size() && (offset + j) < code.size(); ++j) { - code[offset + j] = bytes[j]; - } - } - } - - return code; -} - -std::vector Code::generateInstruction(const InstructionNode* inst, int address) { - std::vector bytes; - - if (!inst || !inst->getMnemonic()) { - return bytes; - } - - auto mnemonic = inst->getMnemonic(); - uint8_t opcode = mnemonic->opcode(); - InstructionType type = mnemonic->type(); - bool extended = mnemonic->extended(); - const auto& operands = mnemonic->operands(); - - switch (type) { - case InstructionType::TYPE1: { - bytes.push_back(opcode); - break; - } - - case InstructionType::TYPE2: { - bytes.push_back(opcode); - uint8_t r1 = 0, r2 = 0; - if (operands.size() >= 1 && std::holds_alternative(operands[0])) { - r1 = std::get(operands[0]).num & 0xF; - } - if (operands.size() >= 2 && std::holds_alternative(operands[1])) { - r2 = std::get(operands[1]).num & 0xF; - } - bytes.push_back((r1 << 4) | r2); - break; - } - - case InstructionType::TYPE3_4: { - // Format 3 or 4 instruction - int ni = 0, x = 0, b = 0, p = 0, e = 0; - int targetAddress = 0; - bool immediate = false, indirect = false, indexed = false; - - // Parse operand - if (!operands.empty()) { - if (std::holds_alternative(operands[0])) { - immediate = true; - targetAddress = std::get(operands[0]).value; - ni = 0x01; // n=0, i=1 - } else if (std::holds_alternative(operands[0])) { - auto& sym = std::get(operands[0]); - immediate = sym.immediate; - indirect = sym.indirect; - indexed = sym.indexed; - - // Look up symbol - auto it = _symbolTable.find(sym.name); - if (it != _symbolTable.end()) { - targetAddress = it->second; - } - - // Set ni bits - if (immediate) { - ni = 0x01; // n=0, i=1 - } else if (indirect) { - ni = 0x02; // n=1, i=0 - } else { - ni = 0x03; // n=1, i=1 (simple/direct) - } - } - } else { - // No operand (like RSUB) - ni = 0x03; - } - - if (indexed) { - x = 1; - } - - if (extended) { - e = 1; - } - - // Calculate PC for addressing - int pc = address + (extended ? 4 : 3); - - // Select addressing mode - auto result = selectAddressingMode(targetAddress, pc, indexed, immediate, indirect, extended); - - if (result.success) { - b = (result.nixbpe >> 2) & 1; - p = (result.nixbpe >> 1) & 1; - e = result.nixbpe & 1; - } - - int displacement = result.displacement; - - // Build instruction bytes - uint8_t byte1 = (opcode & 0xFC) | ni; - uint8_t byte2 = (x << 7) | (b << 6) | (p << 5) | (e << 4); - - bytes.push_back(byte1); - - if (extended) { - // Format 4: 20-bit address - byte2 |= (displacement >> 16) & 0x0F; - bytes.push_back(byte2); - bytes.push_back((displacement >> 8) & 0xFF); - bytes.push_back(displacement & 0xFF); - - // Format 4 instructions with symbol references (not immediate values) need M records - bool needsRelocation = false; - if (!operands.empty() && std::holds_alternative(operands[0])) { - auto& sym = std::get(operands[0]); - // If it's not an immediate mode with a constant, it needs relocation - if (!sym.immediate || _symbolTable.find(sym.name) != _symbolTable.end()) { - needsRelocation = true; - } - } - - // Record modification if needed - if (needsRelocation) { - ModificationRecord mod; - mod.address = address + 1; // Skip the opcode+ni byte, start at xbpe+addr - mod.halfBytes = 5; // 5 half-bytes (20 bits) for format 4 address field - _modificationRecords.push_back(mod); - } - } else { - // Format 3: 12-bit displacement - byte2 |= (displacement >> 8) & 0x0F; - bytes.push_back(byte2); - bytes.push_back(displacement & 0xFF); - } - break; - } - - default: - break; - } - - return bytes; -} - -Code::AddressingResult Code::selectAddressingMode(int targetAddress, int pc, bool indexed, bool immediate, bool indirect, bool extended) const { - AddressingResult result; - result.success = false; - result.nixbpe = 0; - result.displacement = 0; - - // Immediate mode - use target address directly - if (immediate) { - if (extended) { - result.nixbpe = 0x01; // e=1, b=0, p=0 - result.displacement = targetAddress & 0xFFFFF; // 20 bits - } else { - result.nixbpe = 0x00; // e=0, b=0, p=0 - result.displacement = targetAddress & 0xFFF; // 12 bits - } - result.success = true; - return result; - } - - // Extended format - use absolute address - if (extended) { - result.nixbpe = 0x01; // e=1, b=0, p=0 - result.displacement = targetAddress & 0xFFFFF; - result.success = true; - return result; - } - - // Try PC-relative (-2048 to +2047) - int pcDisp = targetAddress - pc; - if (pcDisp >= -2048 && pcDisp <= 2047) { - result.nixbpe = 0x02; // p=1, b=0, e=0 - result.displacement = pcDisp & 0xFFF; - result.success = true; - return result; - } - - // Try base-relative (0 to 4095) - if (_baseRegister >= 0) { - int baseDisp = targetAddress - _baseRegister; - if (baseDisp >= 0 && baseDisp <= 4095) { - result.nixbpe = 0x04; // b=1, p=0, e=0 - result.displacement = baseDisp & 0xFFF; - result.success = true; - return result; - } - } - - // Try direct (0 to 4095) - if (targetAddress >= 0 && targetAddress <= 4095) { - result.nixbpe = 0x00; // b=0, p=0, e=0 - result.displacement = targetAddress & 0xFFF; - result.success = true; - return result; - } - - // Try SIC format (0 to 32767, 15 bits) - if (targetAddress >= 0 && targetAddress <= 32767) { - result.nixbpe = 0x00; - result.displacement = targetAddress & 0x7FFF; - result.success = true; - return result; - } - - // Could not find suitable addressing mode - result.success = false; - return result; -} - -std::vector Code::generateData(const DataNode* data) { - std::vector bytes; - - if (!data) { - return bytes; - } - - switch (data->kind()) { - case DataKind::WORD: { - if (std::holds_alternative(data->value())) { - int value = std::get(data->value()) & 0xFFFFFF; - // SIC/XE stores words in big-endian (MSB first) - bytes.push_back((value >> 16) & 0xFF); - bytes.push_back((value >> 8) & 0xFF); - bytes.push_back(value & 0xFF); - } - break; - } - - case DataKind::BYTE: { - if (std::holds_alternative>(data->value())) { - bytes = std::get>(data->value()); - } - break; - } - - case DataKind::RESW: - case DataKind::RESB: - // Reserved space - emit zeros (handled by initialized array) - break; - } - - return bytes; -} - -std::string Code::emitText() { - std::ostringstream oss; - - // H record: program name, start address, length - oss << "H "; - std::string name = _programName.empty() ? "PROG" : _programName; - name.resize(6, ' '); - oss << name << " "; - oss << std::setfill('0') << std::setw(6) << std::hex << std::uppercase << _startAddress << " "; - oss << std::setfill('0') << std::setw(6) << std::hex << std::uppercase << _programLength; - oss << "\n"; - - // Clear and rebuild modification records - _modificationRecords.clear(); - - // T records: text (code/data) - std::vector code = emitCode(); - int textStart = 0; - - while (textStart < code.size()) { - int textLength = std::min(30, (int)code.size() - textStart); - - oss << "T "; - oss << std::setfill('0') << std::setw(6) << std::hex << std::uppercase << (_startAddress + textStart) << " "; - oss << std::setfill('0') << std::setw(2) << std::hex << std::uppercase << textLength << " "; - - for (int i = 0; i < textLength; ++i) { - oss << std::setfill('0') << std::setw(2) << std::hex << std::uppercase << (int)code[textStart + i]; - } - oss << "\n"; - - textStart += textLength; - } - - // M records: modifications for format 4 instructions - for (const auto& mod : _modificationRecords) { - oss << "M "; - oss << std::setfill('0') << std::setw(6) << std::hex << std::uppercase << mod.address << " "; - oss << std::setfill('0') << std::setw(2) << std::hex << std::uppercase << mod.halfBytes; - oss << "\n"; - } - - // E record: execution start address - oss << "E "; - oss << std::setfill('0') << std::setw(6) << std::hex << std::uppercase << _startAddress; - oss << "\n"; - - return oss.str(); -} - -std::string Code::dumpSymbols() const { - std::ostringstream oss; - oss << "=== Symbol Table ===\n"; - oss << std::left << std::setw(20) << "Symbol" << "Address\n"; - oss << std::string(30, '-') << "\n"; - - for (const auto& [symbol, address] : _symbolTable) { - oss << std::left << std::setw(20) << symbol; - oss << std::hex << std::uppercase << std::setw(6) << std::setfill('0') << address << "\n"; - } - - return oss.str(); -} - -std::string Code::dumpCode() const { - std::ostringstream oss; - oss << "=== Code Listing ===\n"; - oss << std::hex << std::uppercase << std::setfill('0'); - - std::vector code = const_cast(this)->emitCode(); - - for (size_t i = 0; i < _lines.size(); ++i) { - auto& line = _lines[i]; - int address = _locationCounters[i]; - int offset = address - _startAddress; - - // Print address - oss << std::setw(6) << address << " "; - - // Print generated bytes - int length = getInstructionLength(line, address); - if (auto* data = dynamic_cast(line.get())) { - auto bytes = const_cast(this)->generateData(data); - length = bytes.size(); - } - - for (int j = 0; j < length && (offset + j) < code.size(); ++j) { - oss << std::setw(2) << (int)code[offset + j]; - } - - // Pad for alignment - for (int j = length; j < 12; ++j) { - oss << " "; - } - - oss << " " << line->toString() << "\n"; - } - - return oss.str(); -} diff --git a/ass3/simulator_SIC_XE/src/device.cpp b/ass3/simulator_SIC_XE/src/device.cpp deleted file mode 100644 index 87ab0d7..0000000 --- a/ass3/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/ass3/simulator_SIC_XE/src/file_device.cpp b/ass3/simulator_SIC_XE/src/file_device.cpp deleted file mode 100644 index 781a9b6..0000000 --- a/ass3/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/ass3/simulator_SIC_XE/src/file_reader.cpp b/ass3/simulator_SIC_XE/src/file_reader.cpp deleted file mode 100644 index 2a800cc..0000000 --- a/ass3/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/ass3/simulator_SIC_XE/src/input_device.cpp b/ass3/simulator_SIC_XE/src/input_device.cpp deleted file mode 100644 index 340c721..0000000 --- a/ass3/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/ass3/simulator_SIC_XE/src/instructions.cpp b/ass3/simulator_SIC_XE/src/instructions.cpp deleted file mode 100644 index a1c4e55..0000000 --- a/ass3/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/ass3/simulator_SIC_XE/src/lexer.cpp b/ass3/simulator_SIC_XE/src/lexer.cpp deleted file mode 100644 index 7ac9344..0000000 --- a/ass3/simulator_SIC_XE/src/lexer.cpp +++ /dev/null @@ -1,138 +0,0 @@ -#include "lexer.h" -#include -#include - -Lexer::Lexer(std::string input) - : input_(std::move(input)), - pos_(0), - start_(0), - row(1), - col(1) -{ -} - -Lexer& Lexer::mark() { - start_ = pos_; - return *this; -} - -std::string Lexer::extract(int ofs) { - std::size_t end = pos_ + static_cast(ofs); - if (end > input_.size()) { - end = input_.size(); - } - if (end < start_) { - end = start_; - } - return input_.substr(start_, end - start_); -} - -std::string Lexer::extract() { - return extract(0); -} - -char Lexer::peek(int ahead) const { - std::size_t idx = pos_ + static_cast(ahead); - if (idx < input_.size()) { - return input_[idx]; - } - return '\0'; // sentinel for "no more chars" -} - -char Lexer::peek() const { - return peek(0); -} - -char Lexer::advance() { - char ch = peek(); - if (ch == '\0') { - return '\0'; // don't move past end - } - - ++pos_; - - // update logical location - if (ch == '\n') { - ++row; - col = 1; - } else if (ch == '\t') { - col = ((col - 1) / 4) * 4 + 5; - } else { - ++col; - } - return ch; -} - -bool Lexer::advanceIf(char ch) { - if (peek() != ch) { - return false; - } - advance(); - return true; -} - -void Lexer::advance(char ch) { - if (!advanceIf(ch)) { - throw SyntaxError(std::string("'") + ch + "' expected", row, col); - } -} - -bool Lexer::skipWhitespace() { - while (true) { - char p = peek(); - if (p == ' ' || p == '\t') { - advance(); - } else { - break; - } - } - char p = peek(); - return (p == '\n' || p == '\0'); -} - -std::string Lexer::readTo(char delimiter) { - mark(); - while (peek() > 0 && peek() != delimiter) { - advance(); - } - if (peek() == delimiter) { - advance(); // consume delimiter - } - // exclude delimiter itself (like Java's extract(-1)) - return extract(-1); -} - -std::string Lexer::readAlphanumeric() { - mark(); - while (true) { - char c = peek(); - if (std::isalnum(static_cast(c)) || c == '_') { - advance(); - } else { - break; - } - } - return extract(); -} - -int Lexer::digitValue(char c, int radix) { - if (radix < 2 || radix > 36) return -1; - int v = -1; - if (c >= '0' && c <= '9') { - v = c - '0'; - } else if (c >= 'A' && c <= 'Z') { - v = c - 'A' + 10; - } else if (c >= 'a' && c <= 'z') { - v = c - 'a' + 10; - } - if (v >= 0 && v < radix) return v; - return -1; -} - -std::string Lexer::readDigits(int radix) { - mark(); - while (digitValue(peek(), radix) != -1) { - advance(); - } - return extract(); -} diff --git a/ass3/simulator_SIC_XE/src/loader.cpp b/ass3/simulator_SIC_XE/src/loader.cpp deleted file mode 100644 index 1d00ac5..0000000 --- a/ass3/simulator_SIC_XE/src/loader.cpp +++ /dev/null @@ -1,215 +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(); - _relocation_address = header.start_address; - - 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::MODIFICATION: { - ModificationRecord modRecord = readModificationRecord(); - applyModification(modRecord); - 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 'M': return RecordType::MODIFICATION; - 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::ModificationRecord Loader::readModificationRecord() -{ - ModificationRecord record; - if(FILE_CONTAINS_WHITE_SPACES) _file_reader->readByte(); - - record.address = std::stoi(_file_reader->readString(6), nullptr, 16); - if(FILE_CONTAINS_WHITE_SPACES) _file_reader->readByte(); - - record.length = std::stoi(_file_reader->readString(2), nullptr, 16); - - record.add = true; - std::string rest = _file_reader->readLine(); - // Remove whitespace - rest.erase(std::remove_if(rest.begin(), rest.end(), ::isspace), rest.end()); - if (!rest.empty()) { - if (rest[0] == '-') { - record.add = false; - } - } - - 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; -} - -void Loader::applyModification(const ModificationRecord& mod) -{ - // M record specifies address and length in half-bytes (nibbles) - // We need to modify the value at that address by adding or subtracting - // the relocation address - - int address = mod.address; - int halfBytes = mod.length; - - // Calculate how many full bytes we need to read - // halfBytes can be odd or even - int numBytes = (halfBytes + 1) / 2; - - if (address < 0 || address + numBytes > MEMORY_SIZE) { - throw std::runtime_error("Modification address out of bounds"); - } - - // Read the current value from memory - int currentValue = 0; - for (int i = 0; i < numBytes; ++i) { - currentValue = (currentValue << 8) | _machine->getByte(address + i); - } - - // If odd number of half-bytes, we only modify the relevant nibbles - // For simplicity, we'll work with the full bytes and mask appropriately - int mask = 0; - for (int i = 0; i < halfBytes; ++i) { - mask = (mask << 4) | 0xF; - } - - // Extract the value to modify - int shift = (numBytes * 2 - halfBytes) * 4; - int valueToModify = (currentValue >> shift) & mask; - - // Apply modification - int newValue = mod.add ? (valueToModify + _relocation_address) - : (valueToModify - _relocation_address); - - // Mask to keep only the relevant bits - newValue &= mask; - - // Reconstruct the full value - int preservedBits = currentValue & ~(mask << shift); - int finalValue = preservedBits | (newValue << shift); - - // Write back to memory (big-endian) - for (int i = 0; i < numBytes; ++i) { - _machine->setByte(address + i, (finalValue >> ((numBytes - 1 - i) * 8)) & 0xFF); - } -} diff --git a/ass3/simulator_SIC_XE/src/machine.cpp b/ass3/simulator_SIC_XE/src/machine.cpp deleted file mode 100644 index d8d0356..0000000 --- a/ass3/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/ass3/simulator_SIC_XE/src/main.cpp b/ass3/simulator_SIC_XE/src/main.cpp deleted file mode 100644 index 433a3f1..0000000 --- a/ass3/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/ass3/simulator_SIC_XE/src/node.cpp b/ass3/simulator_SIC_XE/src/node.cpp deleted file mode 100644 index 28c31fe..0000000 --- a/ass3/simulator_SIC_XE/src/node.cpp +++ /dev/null @@ -1,121 +0,0 @@ -#include "node.h" -#include -#include -#include - -string Node::toString() const { - std::ostringstream oss; - if (!_label.empty()) oss << _label << " "; - if (_mnemonic) oss << _mnemonic->toString() << " "; - if (!_comment.empty()) oss << "." << _comment; - return oss.str(); -} - -std::string Mnemonic::toString() const { - std::ostringstream oss; - oss << "[OP:" << std::hex << (int)_opcode << "]"; - if (_extended) oss << "+"; - // Print operands - for (size_t i = 0; i < _operands.size(); ++i) { - if (i > 0) oss << ","; - std::visit([&](auto&& arg) { - using T = std::decay_t; - if constexpr (std::is_same_v) { - // nothing - } else if constexpr (std::is_same_v) { - oss << "R" << arg.num; - } else if constexpr (std::is_same_v) { - oss << "#" << arg.value; - } else if constexpr (std::is_same_v) { - oss << arg.name; - if (arg.indexed) oss << ",X"; - } - }, _operands[i]); - } - return oss.str(); -} - -string InstructionNode::toString() const { - std::ostringstream oss; - if (!_label.empty()) oss << _label << " "; - if (_mnemonic) oss << _mnemonic->toString(); - if (!_comment.empty()) oss << " ." << _comment; - return oss.str(); -} - -string CommentNode::toString() const { - return "." + _comment; -} - -string DirectiveNode::toString() const { - std::ostringstream oss; - if (!_label.empty()) oss << _label << " "; - switch (_kind) { - case DirectiveKind::START: oss << "START"; break; - case DirectiveKind::END: oss << "END"; break; - case DirectiveKind::BASE: oss << "BASE"; break; - case DirectiveKind::NOBASE: oss << "NOBASE"; break; - case DirectiveKind::EQU: oss << "EQU"; break; - case DirectiveKind::ORG: oss << "ORG"; break; - case DirectiveKind::LTORG: oss << "LTORG"; break; - case DirectiveKind::EXTDEF: oss << "EXTDEF"; break; - case DirectiveKind::EXTREF: oss << "EXTREF"; break; - case DirectiveKind::CSECT: oss << "CSECT"; break; - } - std::visit([&](auto&& arg) { - using T = std::decay_t; - if constexpr (std::is_same_v) { - // no arg - } else if constexpr (std::is_same_v) { - oss << " " << std::hex << arg; - } else if constexpr (std::is_same_v) { - oss << " " << arg; - } else if constexpr (std::is_same_v>) { - for (size_t i = 0; i < arg.size(); ++i) { - if (i > 0) oss << ","; - oss << arg[i]; - } - } - }, _arg); - if (!_comment.empty()) oss << " ." << _comment; - return oss.str(); -} - -string DataNode::toString() const { - std::ostringstream oss; - if (!_label.empty()) oss << _label << " "; - switch (_kind) { - case DataKind::WORD: oss << "WORD"; break; - case DataKind::BYTE: oss << "BYTE"; break; - case DataKind::RESW: oss << "RESW"; break; - case DataKind::RESB: oss << "RESB"; break; - } - std::visit([&](auto&& arg) { - using T = std::decay_t; - if constexpr (std::is_same_v) { - // no value - } else if constexpr (std::is_same_v) { - oss << " " << arg; - } else if constexpr (std::is_same_v>) { - // Try to display as string if all printable ASCII - bool isPrintable = !arg.empty() && std::all_of(arg.begin(), arg.end(), - [](uint8_t b) { return b >= 32 && b <= 126; }); - - if (isPrintable) { - oss << " C'"; - for (uint8_t b : arg) oss << static_cast(b); - oss << "'"; - } else { - // Display as hex - oss << " X'"; - for (uint8_t b : arg) { - oss << std::hex << std::setw(2) << std::setfill('0') << (int)b; - } - oss << "'"; - } - } - }, _value); - if (!_comment.empty()) oss << " ." << _comment; - return oss.str(); -} - \ No newline at end of file diff --git a/ass3/simulator_SIC_XE/src/opcode.cpp b/ass3/simulator_SIC_XE/src/opcode.cpp deleted file mode 100644 index fcda0c4..0000000 --- a/ass3/simulator_SIC_XE/src/opcode.cpp +++ /dev/null @@ -1,137 +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}; - } - - // Initialize mnemonicToOpcode map - for (int i = 0; i < 0xff; ++i) { - if (instructions[i].type != InstructionType::INVALID) { - mnemonicToOpcode.emplace(instructions[i].name, static_cast(i)); - } - if (instructionsEXEX[i].type != InstructionType::INVALID) { - mnemonicToOpcode.emplace(instructionsEXEX[i].name, static_cast(i)); - } - } - opcodeTablesInitialized = true; -} - -std::optional findOpcodeByMnemonic(std::string_view name) -{ - auto it = mnemonicToOpcode.find(name); - if (it == mnemonicToOpcode.end()) - return std::nullopt; - return it->second; -} - -const InstructionInfo& getInstructionInfo(uint8_t opcode) -{ - if (instructions[opcode].type != InstructionType::INVALID) - return instructions[opcode]; - return instructionsEXEX[opcode]; -} - - - -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/ass3/simulator_SIC_XE/src/output_device.cpp b/ass3/simulator_SIC_XE/src/output_device.cpp deleted file mode 100644 index ce7b4ec..0000000 --- a/ass3/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/ass3/simulator_SIC_XE/src/parser.cpp b/ass3/simulator_SIC_XE/src/parser.cpp deleted file mode 100644 index 3decfe9..0000000 --- a/ass3/simulator_SIC_XE/src/parser.cpp +++ /dev/null @@ -1,465 +0,0 @@ -// parser.cpp -#include "parser.h" -#include -#include -#include - -void Parser::initMnemonicMap() { - if (s_mnemonicMapInitialized) return; - - loadInstructionSet(); - - for (int op = 0; op < 0xFF; ++op) { - const auto& info = instructions[op]; - if (info.name && info.type != InstructionType::INVALID) { - s_nameToOpcode.emplace(info.name, static_cast(op)); - } - const auto& ex = instructionsEXEX[op]; - if (ex.name && ex.type != InstructionType::INVALID) { - s_nameToOpcode.emplace(ex.name, static_cast(op)); - } - } - - s_mnemonicMapInitialized = true; -} - -std::shared_ptr Parser::makeMnemonic(const std::string& name, bool extended) { - initMnemonicMap(); - - auto it = s_nameToOpcode.find(name); - if (it == s_nameToOpcode.end()) { - throw SyntaxError("Invalid mnemonic '" + name + "'", lexer_.row, lexer_.col); - } - - std::uint8_t opcode = it->second; - const InstructionInfo* info = nullptr; - - if (instructions[opcode].type != InstructionType::INVALID) { - info = &instructions[opcode]; - } else if (instructionsEXEX[opcode].type != InstructionType::INVALID) { - info = &instructionsEXEX[opcode]; - } - - if (!info) { - throw SyntaxError("Invalid mnemonic '" + name + "'", lexer_.row, lexer_.col); - } - - if (extended && info->type != InstructionType::TYPE3_4) { - throw SyntaxError( - "Extended format not allowed for mnemonic '" + name + "'", - lexer_.row, - lexer_.col - ); - } - - return std::make_shared(opcode, info->type, extended); -} - -std::string Parser::parseLabel() { - if (lexer_.col == 1 && std::isalpha(static_cast(lexer_.peek()))) { - return std::string(lexer_.readAlphanumeric()); - } - return {}; -} - -std::shared_ptr Parser::parseMnemonic() { - bool isExtended = lexer_.advanceIf('+'); - std::string name(lexer_.readAlphanumeric()); - if (name.empty()) { - throw SyntaxError("Mnemonic expected", lexer_.row, lexer_.col); - } - return makeMnemonic(name, isExtended); -} - -std::string Parser::parseSymbol() { - return std::string(lexer_.readAlphanumeric()); -} - -int Parser::parseRegister() { - char ch = lexer_.advance(); - constexpr std::string_view regs = "AXLBSTF"; - auto pos = regs.find(ch); - if (pos == std::string_view::npos) { - throw SyntaxError(std::string("Invalid register '") + ch + "'", lexer_.row, lexer_.col); - } - return static_cast(pos); -} - -void Parser::parseComma() { - lexer_.skipWhitespace(); - lexer_.advance(','); - lexer_.skipWhitespace(); -} - -bool Parser::parseIndexed() { - lexer_.skipWhitespace(); - if (lexer_.advanceIf(',')) { - lexer_.skipWhitespace(); - lexer_.advance('X'); - return true; - } - return false; -} - -static int digitValue(char c, int radix) { - if (radix < 2 || radix > 36) return -1; - int v = -1; - if (c >= '0' && c <= '9') v = c - '0'; - else if (c >= 'A' && c <= 'Z') v = c - 'A' + 10; - else if (c >= 'a' && c <= 'z') v = c - 'a' + 10; - if (v >= 0 && v < radix) return v; - return -1; -} - -int Parser::parseNumber(int lo, int hi) { - auto parseDigits = [&](int radix) -> int { - std::string digits(lexer_.readDigits(radix)); - if (digits.empty()) { - throw SyntaxError("Invalid number", lexer_.row, lexer_.col); - } - - long long value = 0; - for (char c : digits) { - int d = digitValue(c, radix); - if (d < 0) throw SyntaxError("Invalid number", lexer_.row, lexer_.col); - value = value * radix + d; - if (value > std::numeric_limits::max()) { - throw SyntaxError("Invalid number", lexer_.row, lexer_.col); - } - } - return static_cast(value); - }; - - int num = 0; - - if (lexer_.peek() == '0') { - int radix = -1; - switch (lexer_.peek(1)) { - case 'b': radix = 2; break; - case 'o': radix = 8; break; - case 'x': radix = 16; break; - default: break; - } - if (radix != -1) { - lexer_.advance(); - lexer_.advance(); - num = parseDigits(radix); - } else { - num = parseDigits(10); - } - } else if (std::isdigit(static_cast(lexer_.peek()))) { - num = parseDigits(10); - } else { - throw SyntaxError("Number expected", lexer_.row, lexer_.col); - } - - if (std::isalnum(static_cast(lexer_.peek()))) { - throw SyntaxError( - std::string("invalid digit '") + lexer_.peek() + "'", - lexer_.row, - lexer_.col - ); - } - - if (num < lo || num > hi) { - throw SyntaxError( - "Number '" + std::to_string(num) + "' out of range [" + - std::to_string(lo) + ".." + std::to_string(hi) + "]", - lexer_.row, - lexer_.col - ); - } - - return num; -} - -std::vector Parser::parseData() { - if (lexer_.advanceIf('C')) { - lexer_.advance('\''); - std::string s(lexer_.readTo('\'')); - std::vector data; - data.reserve(s.size()); - for (unsigned char c : s) { - data.push_back(static_cast(c)); - } - return data; - } - - if (lexer_.advanceIf('X')) { - lexer_.advance('\''); - std::string s(lexer_.readTo('\'')); - if (s.size() % 2 != 0) { - throw SyntaxError("Invalid hex literal length", lexer_.row, lexer_.col); - } - - std::vector data; - data.reserve(s.size() / 2); - - auto hexVal = [](char c) -> int { - if (c >= '0' && c <= '9') return c - '0'; - if (c >= 'A' && c <= 'F') return c - 'A' + 10; - if (c >= 'a' && c <= 'f') return c - 'a' + 10; - return -1; - }; - - for (std::size_t i = 0; i < s.size(); i += 2) { - int hi = hexVal(s[i]); - int lo = hexVal(s[i + 1]); - if (hi < 0 || lo < 0) { - throw SyntaxError("Invalid hex digit in literal", lexer_.row, lexer_.col); - } - data.push_back(static_cast((hi << 4) | lo)); - } - return data; - } - - if (std::isdigit(static_cast(lexer_.peek()))) { - constexpr int MAX_WORD = 0xFFFFFF; - int num = parseNumber(0, MAX_WORD); - return { - static_cast((num >> 16) & 0xFF), - static_cast((num >> 8) & 0xFF), - static_cast(num & 0xFF) - }; - } - - throw SyntaxError( - std::string("Invalid storage specifier '") + lexer_.peek() + "'", - lexer_.row, - lexer_.col - ); -} - -void Parser::parseOperands(Mnemonic& m) { - InstructionType t = m.type(); - char c = lexer_.peek(); - - if (t == InstructionType::TYPE1) { - // TYPE1 has no operands - return; - } - - if (t == InstructionType::TYPE2) { - // TYPE2: r1 or r1,r2 or r1,n - if (c == '\n' || c == '\0') return; - - int r1 = parseRegister(); - m.operands().emplace_back(Register{r1}); - lexer_.skipWhitespace(); - - if (lexer_.peek() == ',') { - parseComma(); - char c2 = lexer_.peek(); - if (std::isalpha(static_cast(c2))) { - int r2 = parseRegister(); - m.operands().emplace_back(Register{r2}); - } else if (std::isdigit(static_cast(c2))) { - int n = parseNumber(0, 0xFFFF); - m.operands().emplace_back(Immediate{n}); - } else { - throw SyntaxError("Invalid second operand", lexer_.row, lexer_.col); - } - } - - return; - } - - if (t == InstructionType::TYPE3_4) { - lexer_.skipWhitespace(); - char c0 = lexer_.peek(); - if (c0 == '\n' || c0 == '\0') { - // No operand (e.g., RSUB) - return; - } - - bool immediate = false; - bool indirect = false; - - if (lexer_.advanceIf('#')) { - immediate = true; - } else if (lexer_.advanceIf('@')) { - indirect = true; - } - - char c1 = lexer_.peek(); - if (std::isdigit(static_cast(c1))) { - int num = parseNumber(0, 0x7FFFFF); - if (immediate) { - m.operands().emplace_back(Immediate{num}); - } else { - // Direct numeric addressing (rare, treat as immediate) - m.operands().emplace_back(Immediate{num}); - } - } else if (std::isalpha(static_cast(c1))) { - std::string symbol = parseSymbol(); - bool indexed = parseIndexed(); - m.operands().emplace_back(SymbolRef{symbol, indexed, immediate, indirect}); - } else { - throw SyntaxError("Invalid operand", lexer_.row, lexer_.col); - } - - return; - } -} - -bool Parser::isDirective(const std::string& name) { - return name == "START" || name == "END" || name == "BASE" || name == "NOBASE" || - name == "EQU" || name == "ORG" || name == "LTORG" || - name == "EXTDEF" || name == "EXTREF" || name == "CSECT"; -} - -bool Parser::isDataDirective(const std::string& name) { - return name == "WORD" || name == "BYTE" || name == "RESW" || name == "RESB"; -} - -std::shared_ptr Parser::parseDirective(const std::string& label, const std::string& directive) { - lexer_.skipWhitespace(); - - DirectiveArg argValue; - char c = lexer_.peek(); - - // Parse argument based on first character - if (std::isalpha(c)) { - std::string arg = std::string(lexer_.readAlphanumeric()); - argValue = arg; - } else if (std::isdigit(c) || c == '0') { - int num = parseNumber(0, 0xFFFFFF); - argValue = num; - } else { - // No argument - argValue = std::monostate{}; - } - - lexer_.skipWhitespace(); - std::string comment = std::string(lexer_.readTo('\n')); - - DirectiveKind kind; - if (directive == "START") kind = DirectiveKind::START; - else if (directive == "END") kind = DirectiveKind::END; - else if (directive == "BASE") kind = DirectiveKind::BASE; - else if (directive == "NOBASE") kind = DirectiveKind::NOBASE; - else if (directive == "EQU") kind = DirectiveKind::EQU; - else if (directive == "ORG") kind = DirectiveKind::ORG; - else if (directive == "LTORG") kind = DirectiveKind::LTORG; - else if (directive == "EXTDEF") kind = DirectiveKind::EXTDEF; - else if (directive == "EXTREF") kind = DirectiveKind::EXTREF; - else if (directive == "CSECT") kind = DirectiveKind::CSECT; - else throw SyntaxError("Unknown directive", lexer_.row, lexer_.col); - - return std::make_shared(label, kind, argValue, comment); -} - -std::shared_ptr Parser::parseDataDirective(const std::string& label, const std::string& directive) { - lexer_.skipWhitespace(); - - DataKind kind; - if (directive == "WORD") kind = DataKind::WORD; - else if (directive == "BYTE") kind = DataKind::BYTE; - else if (directive == "RESW") kind = DataKind::RESW; - else if (directive == "RESB") kind = DataKind::RESB; - else throw SyntaxError("Unknown data directive", lexer_.row, lexer_.col); - - DataValue value; - if (kind == DataKind::WORD || kind == DataKind::RESW || kind == DataKind::RESB) { - int num = parseNumber(0, 0xFFFFFF); - value = num; - } else { // BYTE - auto bytes = parseData(); - value = bytes; - } - - lexer_.skipWhitespace(); - std::string comment = std::string(lexer_.readTo('\n')); - - return std::make_shared(label, kind, value, comment); -} - -std::shared_ptr Parser::parseInstruction() { - if (lexer_.col == 1 && lexer_.peek() == '.') { - return std::make_shared( - std::string(lexer_.readTo('\n')) - ); - } - - std::string label = parseLabel(); - - if (lexer_.skipWhitespace() && label.empty()) { - lexer_.advance(); - return nullptr; - } - - lexer_.skipWhitespace(); - - // Check for comment after label - create a label-only instruction node - if (lexer_.peek() == '.') { - std::string comment = std::string(lexer_.readTo('\n')); - // Return an instruction node with just the label (null mnemonic) - auto node = std::make_shared( - std::move(label), - nullptr, - std::move(comment) - ); - return node; - } - - // Check for extended format prefix - bool isExtended = lexer_.peek() == '+'; - if (isExtended) { - lexer_.advance(); - } - - std::string name = std::string(lexer_.readAlphanumeric()); - - if (name.empty()) { - throw SyntaxError( - "Mnemonic or directive expected (label='" + label + "')", - lexer_.row, - lexer_.col - ); - } - - // Check if it's a directive or data directive - if (isDirective(name)) { - return parseDirective(label, name); - } - - if (isDataDirective(name)) { - return parseDataDirective(label, name); - } - - // It's an instruction - create mnemonic - auto mnemonic = makeMnemonic(name, isExtended); - lexer_.skipWhitespace(); - - parseOperands(*mnemonic); - lexer_.skipWhitespace(); - - std::string comment(lexer_.readTo('\n')); - - return std::make_shared( - std::move(label), - std::move(mnemonic), - std::move(comment) - ); -} - -Code Parser::parseCode() { - Code code; - - while (lexer_.peek() > 0) { - while (lexer_.peek() > 0 && lexer_.col > 1) { - lexer_.readTo('\n'); - } - - if (auto node = parseInstruction()) { - code.addLine(node); - } - } - - return code; -} - -Code Parser::parse(const std::string& input) { - lexer_ = Lexer(input); - return parseCode(); -} diff --git a/ass3/simulator_SIC_XE/src/string_reader.cpp b/ass3/simulator_SIC_XE/src/string_reader.cpp deleted file mode 100644 index b87cc02..0000000 --- a/ass3/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 cde4cd2..242ebd3 100644 --- a/simulator_SIC_XE/CMakeLists.txt +++ b/simulator_SIC_XE/CMakeLists.txt @@ -1,10 +1,10 @@ cmake_minimum_required(VERSION 3.10) project(simulator_SIC_XE VERSION 1.0 LANGUAGES CXX) -set(CMAKE_CXX_STANDARD 20) +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}) @@ -13,11 +13,6 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${OUTPUT_DIR}) # Collect all .cpp sources under src/ file(GLOB_RECURSE SOURCES "${PROJECT_SOURCE_DIR}/src/*.cpp") - -set(MAIN_SRC "${PROJECT_SOURCE_DIR}/src/main.cpp") -set(ASSEMBLER_SRC "${PROJECT_SOURCE_DIR}/src/assembler.cpp") -list(REMOVE_ITEM SOURCES ${MAIN_SRC} ${ASSEMBLER_SRC}) - if(NOT SOURCES) message(WARNING "No source files found in ${PROJECT_SOURCE_DIR}/src — the build will create an empty library") endif() @@ -33,27 +28,18 @@ if(EXISTS "${PROJECT_SOURCE_DIR}/src/main.cpp") target_link_libraries(simulator_exec PRIVATE simulator_lib) endif() -if(EXISTS "${PROJECT_SOURCE_DIR}/src/assembler.cpp") - add_executable(assembler "${PROJECT_SOURCE_DIR}/src/assembler.cpp") - target_link_libraries(assembler PRIVATE simulator_lib) +# 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 + 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/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 ae46366..9842788 100644 --- a/simulator_SIC_XE/README.md +++ b/simulator_SIC_XE/README.md @@ -1,66 +1,28 @@ # SIC/XE Simulator -A complete SIC/XE architecture simulator with instruction execution, device I/O, memory management, and assembler. +A complete SIC/XE architecture simulator with instruction execution, device I/O, and memory management. ## Quick Start -### Building the Project - -```bash -make -``` - -This will build: -- `target/bin/simulator_exec` - The main simulator -- `target/bin/assembler` - The SIC/XE assembler -- `target/bin/simulator_qt` - Qt GUI version (if Qt is available) - -### Using the Assembler - -Assemble a SIC/XE assembly file to object code: - -```bash -./target/bin/assembler -``` - -**Example:** -```bash -./target/bin/assembler res/test_format4.asm -``` - -This will: -- Parse and assemble the input file -- Generate modification records (M records) for format 4 instructions -- Create `.obj` with the object code -- Display the object code and symbol table - -**Sample Output:** -``` -H TESTF4 0003E8 00001B -T 0003E8 1B 031003F70F1003FA4B1003FD4F2C090000000000000100004F2BFD -M 0003E9 05 -M 0003ED 05 -M 0003F1 05 -E 0003E8 -``` - -### Running the Simulator +The easiest way to build and run the simulator: ```bash make run ``` -This will build and run the simulator with the default program. +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 all executables | -| `make build` | Build the project | -| `make run` | Build and run the simulator | -| `make clean` | Clean build artifacts | - +| 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/devices/FA.dev b/simulator_SIC_XE/devices/FA.dev deleted file mode 100644 index cb6e5ed..0000000 --- a/simulator_SIC_XE/devices/FA.dev +++ /dev/null @@ -1,2 +0,0 @@ -5 -0 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 da6fb69..0000000 --- a/simulator_SIC_XE/gui/qt/mainwindow.cpp +++ /dev/null @@ -1,1130 +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/parser.h" -#include "../../include/code.h" - -#include -#include -#include -#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->actionLoad_Asm_file, &QAction::triggered, this, &MainWindow::loadAsmFile); - 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::loadAsmFile() -{ - QString fileName = QFileDialog::getOpenFileName(this, - tr("Load Assembly File"), - QString(), - tr("Assembly Files (*.asm);;All Files (*)")); - - if (fileName.isEmpty()) { - return; - } - - try { - // Stop execution if running - m_controller->stop(); - - // Reset machine state - m_machine->reset(); - - // Read assembly file - std::ifstream file(fileName.toStdString()); - if (!file.is_open()) { - throw std::runtime_error("Could not open file: " + fileName.toStdString()); - } - - std::string source((std::istreambuf_iterator(file)), - std::istreambuf_iterator()); - file.close(); - - // Parse and assemble - Parser parser; - Code code = parser.parse(source); - code.assemble(); - - // Generate object code - std::string objCode = code.emitText(); - - // Create resources directory if it doesn't exist - QDir dir; - if (!dir.exists("resources")) { - dir.mkpath("resources"); - } - - // Save object file to resources directory - QFileInfo fileInfo(fileName); - QString objFileName = "resources/" + fileInfo.completeBaseName() + ".obj"; - - std::ofstream objFile(objFileName.toStdString()); - if (!objFile.is_open()) { - throw std::runtime_error("Could not create object file: " + objFileName.toStdString()); - } - objFile << objCode; - objFile.close(); - - // Generate and save log file - QString logFileName = "resources/" + fileInfo.completeBaseName() + ".log"; - std::ofstream logFile(logFileName.toStdString()); - if (!logFile.is_open()) { - throw std::runtime_error("Could not create log file: " + logFileName.toStdString()); - } - - logFile << "=== SIC/XE Assembler Log ===\n\n"; - logFile << "Source file: " << fileName.toStdString() << "\n"; - logFile << "Object file: " << objFileName.toStdString() << "\n\n"; - - logFile << "=== Symbols ===\n"; - logFile << code.dumpSymbols() << "\n\n"; - - logFile << "=== Code ===\n"; - logFile << code.dumpCode() << "\n\n"; - - logFile << "=== Object Code ===\n"; - logFile << objCode << "\n"; - - logFile.close(); - - // Load the generated object file - Loader loader(m_machine, objFileName.toStdString()); - loader.load(); - - // Update displays - updateRegisterDisplays(); - updateMemoryDisplay(); - updateDisassemblyDisplay(); - - QMessageBox::information(this, tr("Success"), - tr("Assembly successful!\nObject file: %1\nLog file: %2") - .arg(objFileName).arg(logFileName)); - - } catch (const std::exception &e) { - QMessageBox::critical(this, tr("Error"), - tr("Failed to assemble 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 cc8f042..0000000 --- a/simulator_SIC_XE/gui/qt/mainwindow.h +++ /dev/null @@ -1,86 +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 loadAsmFile(); - 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 21085fa..0000000 --- a/simulator_SIC_XE/gui/qt/mainwindow.ui +++ /dev/null @@ -1,936 +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 - - - - - Load Asm file - - - - - - diff --git a/simulator_SIC_XE/include/code.h b/simulator_SIC_XE/include/code.h deleted file mode 100644 index 519d5f1..0000000 --- a/simulator_SIC_XE/include/code.h +++ /dev/null @@ -1,68 +0,0 @@ -#ifndef CODE_H -#define CODE_H - -#include -#include -#include -#include - -#include "node.h" - -class Code { - -public: - Code() = default; - - void addLine(const std::shared_ptr& line); - - const std::vector>& getLines() const; - - const string toString() const; - - // Two-pass assembler methods - void assemble(); - std::vector emitCode(); - std::string emitText(); - std::string dumpSymbols() const; - std::string dumpCode() const; - -private: - std::vector> _lines; - - // Assembler state - std::unordered_map _symbolTable; - std::vector _locationCounters; // Location counter per line - int _startAddress = 0; - int _programLength = 0; - std::string _programName; - int _baseRegister = -1; // -1 means not set - - struct ModificationRecord { - int address; - int halfBytes; - }; - mutable std::vector _modificationRecords; - - // Pass 1: build symbol table and assign addresses - void firstPass(); - - // Pass 2: generate code - void secondPass(); - - // Helper methods - int getInstructionLength(const std::shared_ptr& node, int locationCounter) const; - std::vector generateInstruction(const InstructionNode* inst, int address); - std::vector generateData(const DataNode* data); - - // Addressing mode selection - struct AddressingResult { - int nixbpe; // ni, x, b, p, e bits - int displacement; // 12-bit or 20-bit - bool success; - }; - AddressingResult selectAddressingMode(int targetAddress, int pc, bool indexed, bool immediate, bool indirect, bool extended) const; -}; - - - -#endif // CODE_H \ No newline at end of file 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/lexer.h b/simulator_SIC_XE/include/lexer.h deleted file mode 100644 index f9bdd70..0000000 --- a/simulator_SIC_XE/include/lexer.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef LEXER_H -#define LEXER_H - -#include -#include -#include - -class SyntaxError : public std::runtime_error { -public: - int row; - int col; - - SyntaxError(const std::string& msg, int row_, int col_) - : std::runtime_error(msg), row(row_), col(col_) {} -}; - - -class Lexer { -public: - int row; - int col; - - explicit Lexer(std::string input); - - Lexer& mark(); - - std::string extract(int ofs); - std::string extract(); - - char peek(int ahead) const; - char peek() const; - - char advance(); - - bool advanceIf(char ch); - void advance(char ch); - - - bool skipWhitespace(); - - std::string readTo(char delimiter); - - std::string readAlphanumeric(); - - std::string readDigits(int radix); - -private: - std::string input_; - std::size_t pos_; - std::size_t start_; - - static int digitValue(char c, int radix); -}; - -#endif // LEXER_H diff --git a/simulator_SIC_XE/include/loader.h b/simulator_SIC_XE/include/loader.h deleted file mode 100644 index 34c31a6..0000000 --- a/simulator_SIC_XE/include/loader.h +++ /dev/null @@ -1,77 +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, - MODIFICATION, - END, - UNKNOWN - }; - - struct HeaderMetadata { - string program_name; - int start_address; - int length; - }; - struct TextRecord { - int start_address; - std::vector data; - }; - struct ModificationRecord { - int address; // Address to be modified - int length; // Length in nibbles - bool add; // true for +, false for - - }; - struct EndRecord { - int execution_start_address; - }; - - void load(); - -private : - - static RecordType parseRecordType(char c); - - - shared_ptr _machine; - string _filename; - shared_ptr _file_reader; - int _relocation_address; - HeaderMetadata readHeader(); - TextRecord readTextRecord(); - ModificationRecord readModificationRecord(); - EndRecord readEndRecord(); - bool load_into_memory(int start_address, const std::vector& data); - void applyModification(const ModificationRecord& mod); - -}; - - - - - -#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/mnemonic.h b/simulator_SIC_XE/include/mnemonic.h deleted file mode 100644 index 3cdddab..0000000 --- a/simulator_SIC_XE/include/mnemonic.h +++ /dev/null @@ -1,45 +0,0 @@ -// mnemonic.h -#ifndef MNEMONIC_H -#define MNEMONIC_H - -#include -#include -#include -#include - -#include "opcode.h" - -struct Empty {}; -struct Register { int num; }; -struct Immediate { int value; }; -struct SymbolRef { - std::string name; - bool indexed = false; - bool immediate = false; - bool indirect = false; -}; - -using Operand = std::variant; - -class Mnemonic { -public: - Mnemonic(std::uint8_t opcode, InstructionType type, bool extended) - : _opcode(opcode), _extended(extended), _type(type) {} - - std::uint8_t opcode() const { return _opcode; } - bool extended() const { return _extended; } - InstructionType type() const { return _type; } - - std::vector& operands() { return _operands; } - const std::vector& operands() const { return _operands; } - - std::string toString() const; - -private: - std::uint8_t _opcode; - bool _extended; - InstructionType _type; - std::vector _operands; -}; - -#endif // MNEMONIC_H diff --git a/simulator_SIC_XE/include/node.h b/simulator_SIC_XE/include/node.h deleted file mode 100644 index 2ad0d86..0000000 --- a/simulator_SIC_XE/include/node.h +++ /dev/null @@ -1,98 +0,0 @@ -#ifndef NODE_H -#define NODE_H - -#include -#include -#include -#include -#include -#include "mnemonic.h" - -using std::string; - -class Node { -public: - virtual ~Node() = default; - - string getLabel() const { return _label; } - string getComment() const { return _comment; } - std::shared_ptr getMnemonic() const { return _mnemonic; } - - virtual string toString() const; - -protected: - string _label; - std::shared_ptr _mnemonic; - string _comment; -}; - -class InstructionNode : public Node { -public: - InstructionNode(string label, - std::shared_ptr mnemonic, - string comment) { - _label = std::move(label); - _mnemonic = std::move(mnemonic); - _comment = std::move(comment); - } - - string toString() const override; -}; - -class CommentNode : public Node { -public: - explicit CommentNode(string text) { - _comment = std::move(text); - } - - string toString() const override; -}; - -enum class DirectiveKind { - START, END, BASE, NOBASE, EQU, ORG, LTORG, - EXTDEF, EXTREF, CSECT -}; - -using DirectiveArg = std::variant>; - -class DirectiveNode : public Node { -public: - DirectiveNode(string label, DirectiveKind kind, DirectiveArg arg, string comment) - : _kind(kind), _arg(std::move(arg)) { - _label = std::move(label); - _comment = std::move(comment); - } - - DirectiveKind kind() const { return _kind; } - const DirectiveArg& arg() const { return _arg; } - - string toString() const override; - -private: - DirectiveKind _kind; - DirectiveArg _arg; -}; - -enum class DataKind { WORD, BYTE, RESW, RESB }; - -using DataValue = std::variant>; - -class DataNode : public Node { -public: - DataNode(string label, DataKind kind, DataValue value, string comment) - : _kind(kind), _value(std::move(value)) { - _label = std::move(label); - _comment = std::move(comment); - } - - DataKind kind() const { return _kind; } - const DataValue& value() const { return _value; } - - string toString() const override; - -private: - DataKind _kind; - DataValue _value; -}; - -#endif // NODE_H diff --git a/simulator_SIC_XE/include/opcode.h b/simulator_SIC_XE/include/opcode.h index 05cb693..93df629 100644 --- a/simulator_SIC_XE/include/opcode.h +++ b/simulator_SIC_XE/include/opcode.h @@ -1,13 +1,6 @@ #ifndef OPCODE_H #define OPCODE_H -#include "utils.h" - -#include -#include -#include -#include - // ============================== // Opcode definitions (SIC/XE) // ============================== @@ -71,29 +64,14 @@ #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 -static std::unordered_map mnemonicToOpcode; -static bool opcodeTablesInitialized = false; + +// 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 + enum class InstructionType { @@ -115,11 +93,6 @@ struct InstructionInfo { }; extern InstructionInfo instructions[]; -extern InstructionInfo instructionsEXEX[]; - -extern std::optional findOpcodeByMnemonic(std::string_view name); -extern const InstructionInfo& getInstructionInfo(uint8_t opcode); - // Initialize the instruction table void loadInstructionSet(); diff --git a/simulator_SIC_XE/include/parser.h b/simulator_SIC_XE/include/parser.h deleted file mode 100644 index 8ae126a..0000000 --- a/simulator_SIC_XE/include/parser.h +++ /dev/null @@ -1,52 +0,0 @@ -// parser.h -#ifndef PARSER_H -#define PARSER_H - -#include -#include -#include -#include -#include - -#include "lexer.h" -#include "code.h" -#include "opcode.h" -#include "mnemonic.h" - -class Parser { -public: - Parser() = default; - - Code parse(const std::string& input); - -private: - std::string parseLabel(); - std::shared_ptr parseMnemonic(); - std::string parseSymbol(); - int parseRegister(); - void parseComma(); - bool parseIndexed(); - int parseNumber(int lo, int hi); - std::vector parseData(); - - void parseOperands(Mnemonic& m); - - bool isDirective(const std::string& name); - bool isDataDirective(const std::string& name); - std::shared_ptr parseDirective(const std::string& label, const std::string& directive); - std::shared_ptr parseDataDirective(const std::string& label, const std::string& directive); - - std::shared_ptr parseInstruction(); - Code parseCode(); - - std::shared_ptr makeMnemonic(const std::string& name, bool extended); - static void initMnemonicMap(); - -private: - Lexer lexer_{""}; - - static inline std::unordered_map s_nameToOpcode{}; - static inline bool s_mnemonicMapInitialized = false; -}; - -#endif // PARSER_H 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/res/rec.asm b/simulator_SIC_XE/res/rec.asm deleted file mode 100644 index 212bf23..0000000 --- a/simulator_SIC_XE/res/rec.asm +++ /dev/null @@ -1,223 +0,0 @@ -prog START 0 - -.------------------------------------------- -. MAIN LOOP -. -. Psevdo: -. sp = 0 -. while true: -. n = readFA() -. if n == 0: halt -. acc = 1 -. fact() ; rekurzivno: acc = n! -. printStdout(acc) -.------------------------------------------- - CLEAR A - STA sp - -loop JSUB readFA - COMP #0 - JEQ halt - - STA n - LDA #1 - STA acc - - JSUB fact - LDA acc - JSUB printStdout - - J loop - -halt J halt - -.------------------------------------------- -. readFA -. -. Psevdo: -. B = 0 -. while true: -. ch = RD(FA) -. if ch == CR or ch == LF: break -. digit = ch - '0' -. B = B * 10 + digit -. return B -.------------------------------------------- -readFA CLEAR B - LDS #10 - -rd_loopFA RD #0xFA - COMP #0x0D . CR? - JEQ rd_doneCR_FA - COMP #0x0A . LF? - JEQ rd_doneFA - - SUB #0x30 - MULR S,B . B = B * 10 - ADDR A,B . B = B + digit - J rd_loopFA - -rd_doneCR_FA RD #0xFA . pogoltni LF po CR -rd_doneFA CLEAR A - RMO B,A - RSUB - -.------------------------------------------- -. fact -. -. Psevdo (globalni n, acc, sklad L): -. fact(): -. push(L) -. if n <= 1: -. pop(L); return -. acc = acc * n -. n = n - 1 -. fact() -. pop(L); return -.------------------------------------------- -fact . push L - LDA sp - ADD #3 - STA sp - LDX sp - STL stackL,X - - LDA n - COMP #1 - JGT fact_rec - - . base case: n <= 1 - LDX sp - LDL stackL,X - LDA sp - SUB #3 - STA sp - RSUB - -fact_rec . recursive case: acc *= n; n--; fact() - - LDB acc - LDS n - MULR S,B - STB acc - - LDA n - SUB #1 - STA n - - JSUB fact - - . pop L in return to caller - LDX sp - LDL stackL,X - LDA sp - SUB #3 - STA sp - RSUB - -.------------------------------------------- -. printStdout -. -. Psevdo: -. if A == 0: -. print "0\n" -. return -. ps_val = A -. ps_len = 0 -. while ps_val > 0: -. q = ps_val / 10 -. r = ps_val % 10 -. buf[ps_len] = '0' + r -. ps_len++ -. ps_val = q -. for i = ps_len-1 .. 0: -. print buf[i] -. print "\r\n" -.------------------------------------------- -printStdout COMP #0 - JEQ ps_zero - - STA ps_val - LDA #0 - STA ps_len - LDS #10 - LDT #0x30 . '0' - -ps_div LDA ps_val - COMP #0 - JEQ ps_divdone - - RMO A,B - DIVR S,B . kvocient v B - RMO B,X . X = kvocient - - MULR S,B - SUBR B,A . A = ostanek - ADDR T,A . A = '0' + ostanek - STA psdigit - - LDA ps_len - STA ps_idx - LDA #psbuf - ADD ps_idx - STA ps_ptr - LDA psdigit - STCH @ps_ptr - - LDA ps_len - ADD #1 - STA ps_len - - RMO X,A - STA ps_val - J ps_div - -ps_divdone LDA ps_len - SUB #1 - STA ps_idx - -ps_print LDA ps_idx - COMP #0 - JLT ps_end - - LDA #psbuf - ADD ps_idx - STA ps_ptr - LDCH @ps_ptr - WD #1 - - LDA ps_idx - SUB #1 - STA ps_idx - J ps_print - -ps_end LDA #0x0D . CR - WD #1 - LDA #0x0A . LF - WD #1 - RSUB - -ps_zero LDA #0x30 . "0" - WD #1 - LDA #0x0D - WD #1 - LDA #0x0A - WD #1 - RSUB - -.data -. rekurzija faktoriala -sp WORD 0 . stack pointer -n WORD 0 -acc WORD 0 . akumulator za faktorial -stackL RESB 60 - -. printStdout -ps_val WORD 0 -ps_len WORD 0 -ps_idx WORD 0 -psdigit WORD 0 -ps_ptr WORD 0 -psbuf RESB 12 - - END prog diff --git a/simulator_SIC_XE/res/simple.asm b/simulator_SIC_XE/res/simple.asm deleted file mode 100644 index 20beca6..0000000 --- a/simulator_SIC_XE/res/simple.asm +++ /dev/null @@ -1,32 +0,0 @@ -SIMPLE START 0 - - +LDA NUM1 - +ADD NUM2 - +STA RESULT - - LDX NUM1 - LDL NUM2 - - LDA #0 - ADDR X,A - ADDR L,A - - +LDA RESULT - ADD #48 - RMO A,S - SHIFTL S,16 - SHIFTR S,16 - RMO S,A - STCH RESULT - LDCH RESULT - WD OUTPUT - -HALT J HALT - -OUTPUT BYTE 1 - -NUM1 WORD 1 -NUM2 WORD 2 -RESULT RESW 1 - - END SIMPLE diff --git a/simulator_SIC_XE/res/test_format4.asm b/simulator_SIC_XE/res/test_format4.asm deleted file mode 100644 index 6de136d..0000000 --- a/simulator_SIC_XE/res/test_format4.asm +++ /dev/null @@ -1,11 +0,0 @@ -TESTF4 START 1000 - +LDA BUFFER - +STA OUTPUT - +JSUB FUNC - RSUB - -BUFFER RESW 1 -OUTPUT RESW 1 -FUNC LDA #0 - RSUB - END TESTF4 diff --git a/simulator_SIC_XE/src/assembler.cpp b/simulator_SIC_XE/src/assembler.cpp deleted file mode 100644 index 2ceece9..0000000 --- a/simulator_SIC_XE/src/assembler.cpp +++ /dev/null @@ -1,77 +0,0 @@ -#include -#include -#include -#include "code.h" -#include "parser.h" -#include "opcode.h" - -using std::cout; -using std::endl; -using std::cerr; - -int main(int argc, char* argv[]) { - if (argc != 2) { - cerr << "Usage: " << argv[0] << " " << endl; - return 1; - } - - std::string inputFile = argv[1]; - - // Load instruction set - loadInstructionSet(); - - try { - // Read assembly file - cout << "Assembling: " << inputFile << endl; - std::ifstream file(inputFile); - if (!file.is_open()) { - throw std::runtime_error("Failed to open file: " + inputFile); - } - - std::string input; - std::string line; - while (std::getline(file, line)) { - input += line + "\n"; - } - file.close(); - - // Parse - Parser parser; - Code code = parser.parse(input); - - // Assemble - code.assemble(); - - // Generate object code - std::string objectCode = code.emitText(); - - // Determine output filename - std::string outputFile = inputFile; - size_t lastDot = outputFile.find_last_of('.'); - if (lastDot != std::string::npos) { - outputFile = outputFile.substr(0, lastDot); - } - outputFile += ".obj"; - - // Write to file - std::ofstream out(outputFile); - if (!out.is_open()) { - throw std::runtime_error("Failed to create output file: " + outputFile); - } - out << objectCode; - out.close(); - - // Display results - cout << "\n=== Object Code ===" << endl; - cout << objectCode; - cout << "\n=== Symbol Table ===" << endl; - cout << code.dumpSymbols(); - cout << "\nOutput written to: " << outputFile << endl; - - } catch (const std::exception& e) { - cerr << "ERROR: " << e.what() << endl; - return 1; - } - - return 0; -} diff --git a/simulator_SIC_XE/src/code.cpp b/simulator_SIC_XE/src/code.cpp deleted file mode 100644 index 2e87d12..0000000 --- a/simulator_SIC_XE/src/code.cpp +++ /dev/null @@ -1,551 +0,0 @@ -#include "code.h" -#include "opcode.h" -#include "constants.h" -#include -#include -#include -#include - -void Code::addLine(const std::shared_ptr &line) -{ - _lines.emplace_back(line); -} - -const std::vector> &Code::getLines() const -{ - return _lines; -} - -const string Code::toString() const -{ - string result; - for (const auto& line : _lines) { - result += line->toString() + "\n"; - } - return result; -} - -// ============================================================ -// TWO-PASS ASSEMBLER IMPLEMENTATION -// ============================================================ - -void Code::assemble() { - firstPass(); - secondPass(); -} - -void Code::firstPass() { - _symbolTable.clear(); - _locationCounters.clear(); - _locationCounters.resize(_lines.size(), 0); - - int locationCounter = 0; - bool startFound = false; - - for (size_t i = 0; i < _lines.size(); ++i) { - auto& line = _lines[i]; - _locationCounters[i] = locationCounter; - - // Handle label - std::string label = line->getLabel(); - if (!label.empty()) { - if (_symbolTable.find(label) != _symbolTable.end()) { - throw std::runtime_error("Duplicate symbol: " + label); - } - _symbolTable[label] = locationCounter; - } - - // Check for directives - if (auto* directive = dynamic_cast(line.get())) { - switch (directive->kind()) { - case DirectiveKind::START: { - if (std::holds_alternative(directive->arg())) { - _startAddress = std::get(directive->arg()); - locationCounter = _startAddress; - _locationCounters[i] = locationCounter; - if (!label.empty()) { - _symbolTable[label] = locationCounter; - _programName = label; - } - startFound = true; - } - break; - } - case DirectiveKind::END: - _programLength = locationCounter - _startAddress; - break; - - case DirectiveKind::BASE: { - // BASE sets base register for addressing - if (std::holds_alternative(directive->arg())) { - // Will resolve in second pass - } - break; - } - case DirectiveKind::NOBASE: - _baseRegister = -1; - break; - - case DirectiveKind::EQU: { - // EQU defines symbol value - if (!label.empty() && std::holds_alternative(directive->arg())) { - _symbolTable[label] = std::get(directive->arg()); - } - break; - } - case DirectiveKind::ORG: { - // ORG changes location counter - if (std::holds_alternative(directive->arg())) { - locationCounter = std::get(directive->arg()); - } - break; - } - default: - break; - } - continue; - } - - // Handle data directives - if (auto* data = dynamic_cast(line.get())) { - int length = 0; - switch (data->kind()) { - case DataKind::WORD: - length = 3; // 24-bit word - break; - case DataKind::BYTE: { - if (std::holds_alternative>(data->value())) { - length = std::get>(data->value()).size(); - } - break; - } - case DataKind::RESW: { - if (std::holds_alternative(data->value())) { - length = std::get(data->value()) * 3; - } - break; - } - case DataKind::RESB: { - if (std::holds_alternative(data->value())) { - length = std::get(data->value()); - } - break; - } - } - locationCounter += length; - continue; - } - - // Handle instructions - if (auto* inst = dynamic_cast(line.get())) { - int length = getInstructionLength(line, locationCounter); - locationCounter += length; - } - } - - if (!startFound) { - _startAddress = 0; - } - _programLength = locationCounter - _startAddress; -} - -int Code::getInstructionLength(const std::shared_ptr& node, int locationCounter) const { - auto* inst = dynamic_cast(node.get()); - if (!inst || !inst->getMnemonic()) { - return 0; - } - - auto mnemonic = inst->getMnemonic(); - InstructionType type = mnemonic->type(); - - switch (type) { - case InstructionType::TYPE1: - return 1; - case InstructionType::TYPE2: - return 2; - case InstructionType::TYPE3_4: - return mnemonic->extended() ? 4 : 3; - default: - return 0; - } -} - -void Code::secondPass() { - // Generate code for all instructions and data - // This will be used by emitCode() and emitText() -} - -std::vector Code::emitCode() { - std::vector code; - code.resize(_programLength, 0); - - for (size_t i = 0; i < _lines.size(); ++i) { - auto& line = _lines[i]; - int address = _locationCounters[i]; - int offset = address - _startAddress; - - if (offset < 0 || offset >= _programLength) { - continue; - } - - // Generate instruction - if (auto* inst = dynamic_cast(line.get())) { - auto bytes = generateInstruction(inst, address); - for (size_t j = 0; j < bytes.size() && (offset + j) < code.size(); ++j) { - code[offset + j] = bytes[j]; - } - } - - // Generate data - if (auto* data = dynamic_cast(line.get())) { - auto bytes = generateData(data); - for (size_t j = 0; j < bytes.size() && (offset + j) < code.size(); ++j) { - code[offset + j] = bytes[j]; - } - } - } - - return code; -} - -std::vector Code::generateInstruction(const InstructionNode* inst, int address) { - std::vector bytes; - - if (!inst || !inst->getMnemonic()) { - return bytes; - } - - auto mnemonic = inst->getMnemonic(); - uint8_t opcode = mnemonic->opcode(); - InstructionType type = mnemonic->type(); - bool extended = mnemonic->extended(); - const auto& operands = mnemonic->operands(); - - switch (type) { - case InstructionType::TYPE1: { - bytes.push_back(opcode); - break; - } - - case InstructionType::TYPE2: { - bytes.push_back(opcode); - uint8_t r1 = 0, r2 = 0; - if (operands.size() >= 1 && std::holds_alternative(operands[0])) { - r1 = std::get(operands[0]).num & 0xF; - } - if (operands.size() >= 2 && std::holds_alternative(operands[1])) { - r2 = std::get(operands[1]).num & 0xF; - } - bytes.push_back((r1 << 4) | r2); - break; - } - - case InstructionType::TYPE3_4: { - // Format 3 or 4 instruction - int ni = 0, x = 0, b = 0, p = 0, e = 0; - int targetAddress = 0; - bool immediate = false, indirect = false, indexed = false; - - // Parse operand - if (!operands.empty()) { - if (std::holds_alternative(operands[0])) { - immediate = true; - targetAddress = std::get(operands[0]).value; - ni = 0x01; // n=0, i=1 - } else if (std::holds_alternative(operands[0])) { - auto& sym = std::get(operands[0]); - immediate = sym.immediate; - indirect = sym.indirect; - indexed = sym.indexed; - - // Look up symbol - auto it = _symbolTable.find(sym.name); - if (it != _symbolTable.end()) { - targetAddress = it->second; - } - - // Set ni bits - if (immediate) { - ni = 0x01; // n=0, i=1 - } else if (indirect) { - ni = 0x02; // n=1, i=0 - } else { - ni = 0x03; // n=1, i=1 (simple/direct) - } - } - } else { - // No operand (like RSUB) - ni = 0x03; - } - - if (indexed) { - x = 1; - } - - if (extended) { - e = 1; - } - - // Calculate PC for addressing - int pc = address + (extended ? 4 : 3); - - // Select addressing mode - auto result = selectAddressingMode(targetAddress, pc, indexed, immediate, indirect, extended); - - if (result.success) { - b = (result.nixbpe >> 2) & 1; - p = (result.nixbpe >> 1) & 1; - e = result.nixbpe & 1; - } - - int displacement = result.displacement; - - // Build instruction bytes - uint8_t byte1 = (opcode & 0xFC) | ni; - uint8_t byte2 = (x << 7) | (b << 6) | (p << 5) | (e << 4); - - bytes.push_back(byte1); - - if (extended) { - // Format 4: 20-bit address - byte2 |= (displacement >> 16) & 0x0F; - bytes.push_back(byte2); - bytes.push_back((displacement >> 8) & 0xFF); - bytes.push_back(displacement & 0xFF); - - // Format 4 instructions with symbol references (not immediate values) need M records - bool needsRelocation = false; - if (!operands.empty() && std::holds_alternative(operands[0])) { - auto& sym = std::get(operands[0]); - // If it's not an immediate mode with a constant, it needs relocation - if (!sym.immediate || _symbolTable.find(sym.name) != _symbolTable.end()) { - needsRelocation = true; - } - } - - // Record modification if needed - if (needsRelocation) { - ModificationRecord mod; - mod.address = address + 1; // Skip the opcode+ni byte, start at xbpe+addr - mod.halfBytes = 5; // 5 half-bytes (20 bits) for format 4 address field - _modificationRecords.push_back(mod); - } - } else { - // Format 3: 12-bit displacement - byte2 |= (displacement >> 8) & 0x0F; - bytes.push_back(byte2); - bytes.push_back(displacement & 0xFF); - } - break; - } - - default: - break; - } - - return bytes; -} - -Code::AddressingResult Code::selectAddressingMode(int targetAddress, int pc, bool indexed, bool immediate, bool indirect, bool extended) const { - AddressingResult result; - result.success = false; - result.nixbpe = 0; - result.displacement = 0; - - // Immediate mode - use target address directly - if (immediate) { - if (extended) { - result.nixbpe = 0x01; // e=1, b=0, p=0 - result.displacement = targetAddress & 0xFFFFF; // 20 bits - } else { - result.nixbpe = 0x00; // e=0, b=0, p=0 - result.displacement = targetAddress & 0xFFF; // 12 bits - } - result.success = true; - return result; - } - - // Extended format - use absolute address - if (extended) { - result.nixbpe = 0x01; // e=1, b=0, p=0 - result.displacement = targetAddress & 0xFFFFF; - result.success = true; - return result; - } - - // Try PC-relative (-2048 to +2047) - int pcDisp = targetAddress - pc; - if (pcDisp >= -2048 && pcDisp <= 2047) { - result.nixbpe = 0x02; // p=1, b=0, e=0 - result.displacement = pcDisp & 0xFFF; - result.success = true; - return result; - } - - // Try base-relative (0 to 4095) - if (_baseRegister >= 0) { - int baseDisp = targetAddress - _baseRegister; - if (baseDisp >= 0 && baseDisp <= 4095) { - result.nixbpe = 0x04; // b=1, p=0, e=0 - result.displacement = baseDisp & 0xFFF; - result.success = true; - return result; - } - } - - // Try direct (0 to 4095) - if (targetAddress >= 0 && targetAddress <= 4095) { - result.nixbpe = 0x00; // b=0, p=0, e=0 - result.displacement = targetAddress & 0xFFF; - result.success = true; - return result; - } - - // Try SIC format (0 to 32767, 15 bits) - if (targetAddress >= 0 && targetAddress <= 32767) { - result.nixbpe = 0x00; - result.displacement = targetAddress & 0x7FFF; - result.success = true; - return result; - } - - // Could not find suitable addressing mode - result.success = false; - return result; -} - -std::vector Code::generateData(const DataNode* data) { - std::vector bytes; - - if (!data) { - return bytes; - } - - switch (data->kind()) { - case DataKind::WORD: { - if (std::holds_alternative(data->value())) { - int value = std::get(data->value()) & 0xFFFFFF; - // SIC/XE stores words in big-endian (MSB first) - bytes.push_back((value >> 16) & 0xFF); - bytes.push_back((value >> 8) & 0xFF); - bytes.push_back(value & 0xFF); - } - break; - } - - case DataKind::BYTE: { - if (std::holds_alternative>(data->value())) { - bytes = std::get>(data->value()); - } - break; - } - - case DataKind::RESW: - case DataKind::RESB: - // Reserved space - emit zeros (handled by initialized array) - break; - } - - return bytes; -} - -std::string Code::emitText() { - std::ostringstream oss; - - // H record: program name, start address, length - oss << "H "; - std::string name = _programName.empty() ? "PROG" : _programName; - name.resize(6, ' '); - oss << name << " "; - oss << std::setfill('0') << std::setw(6) << std::hex << std::uppercase << _startAddress << " "; - oss << std::setfill('0') << std::setw(6) << std::hex << std::uppercase << _programLength; - oss << "\n"; - - // Clear and rebuild modification records - _modificationRecords.clear(); - - // T records: text (code/data) - std::vector code = emitCode(); - int textStart = 0; - - while (textStart < code.size()) { - int textLength = std::min(30, (int)code.size() - textStart); - - oss << "T "; - oss << std::setfill('0') << std::setw(6) << std::hex << std::uppercase << (_startAddress + textStart) << " "; - oss << std::setfill('0') << std::setw(2) << std::hex << std::uppercase << textLength << " "; - - for (int i = 0; i < textLength; ++i) { - oss << std::setfill('0') << std::setw(2) << std::hex << std::uppercase << (int)code[textStart + i]; - } - oss << "\n"; - - textStart += textLength; - } - - // M records: modifications for format 4 instructions - for (const auto& mod : _modificationRecords) { - oss << "M "; - oss << std::setfill('0') << std::setw(6) << std::hex << std::uppercase << mod.address << " "; - oss << std::setfill('0') << std::setw(2) << std::hex << std::uppercase << mod.halfBytes; - oss << "\n"; - } - - // E record: execution start address - oss << "E "; - oss << std::setfill('0') << std::setw(6) << std::hex << std::uppercase << _startAddress; - oss << "\n"; - - return oss.str(); -} - -std::string Code::dumpSymbols() const { - std::ostringstream oss; - oss << "=== Symbol Table ===\n"; - oss << std::left << std::setw(20) << "Symbol" << "Address\n"; - oss << std::string(30, '-') << "\n"; - - for (const auto& [symbol, address] : _symbolTable) { - oss << std::left << std::setw(20) << symbol; - oss << std::hex << std::uppercase << std::setw(6) << std::setfill('0') << address << "\n"; - } - - return oss.str(); -} - -std::string Code::dumpCode() const { - std::ostringstream oss; - oss << "=== Code Listing ===\n"; - oss << std::hex << std::uppercase << std::setfill('0'); - - std::vector code = const_cast(this)->emitCode(); - - for (size_t i = 0; i < _lines.size(); ++i) { - auto& line = _lines[i]; - int address = _locationCounters[i]; - int offset = address - _startAddress; - - // Print address - oss << std::setw(6) << address << " "; - - // Print generated bytes - int length = getInstructionLength(line, address); - if (auto* data = dynamic_cast(line.get())) { - auto bytes = const_cast(this)->generateData(data); - length = bytes.size(); - } - - for (int j = 0; j < length && (offset + j) < code.size(); ++j) { - oss << std::setw(2) << (int)code[offset + j]; - } - - // Pad for alignment - for (int j = length; j < 12; ++j) { - oss << " "; - } - - oss << " " << line->toString() << "\n"; - } - - return oss.str(); -} 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/lexer.cpp b/simulator_SIC_XE/src/lexer.cpp deleted file mode 100644 index 7ac9344..0000000 --- a/simulator_SIC_XE/src/lexer.cpp +++ /dev/null @@ -1,138 +0,0 @@ -#include "lexer.h" -#include -#include - -Lexer::Lexer(std::string input) - : input_(std::move(input)), - pos_(0), - start_(0), - row(1), - col(1) -{ -} - -Lexer& Lexer::mark() { - start_ = pos_; - return *this; -} - -std::string Lexer::extract(int ofs) { - std::size_t end = pos_ + static_cast(ofs); - if (end > input_.size()) { - end = input_.size(); - } - if (end < start_) { - end = start_; - } - return input_.substr(start_, end - start_); -} - -std::string Lexer::extract() { - return extract(0); -} - -char Lexer::peek(int ahead) const { - std::size_t idx = pos_ + static_cast(ahead); - if (idx < input_.size()) { - return input_[idx]; - } - return '\0'; // sentinel for "no more chars" -} - -char Lexer::peek() const { - return peek(0); -} - -char Lexer::advance() { - char ch = peek(); - if (ch == '\0') { - return '\0'; // don't move past end - } - - ++pos_; - - // update logical location - if (ch == '\n') { - ++row; - col = 1; - } else if (ch == '\t') { - col = ((col - 1) / 4) * 4 + 5; - } else { - ++col; - } - return ch; -} - -bool Lexer::advanceIf(char ch) { - if (peek() != ch) { - return false; - } - advance(); - return true; -} - -void Lexer::advance(char ch) { - if (!advanceIf(ch)) { - throw SyntaxError(std::string("'") + ch + "' expected", row, col); - } -} - -bool Lexer::skipWhitespace() { - while (true) { - char p = peek(); - if (p == ' ' || p == '\t') { - advance(); - } else { - break; - } - } - char p = peek(); - return (p == '\n' || p == '\0'); -} - -std::string Lexer::readTo(char delimiter) { - mark(); - while (peek() > 0 && peek() != delimiter) { - advance(); - } - if (peek() == delimiter) { - advance(); // consume delimiter - } - // exclude delimiter itself (like Java's extract(-1)) - return extract(-1); -} - -std::string Lexer::readAlphanumeric() { - mark(); - while (true) { - char c = peek(); - if (std::isalnum(static_cast(c)) || c == '_') { - advance(); - } else { - break; - } - } - return extract(); -} - -int Lexer::digitValue(char c, int radix) { - if (radix < 2 || radix > 36) return -1; - int v = -1; - if (c >= '0' && c <= '9') { - v = c - '0'; - } else if (c >= 'A' && c <= 'Z') { - v = c - 'A' + 10; - } else if (c >= 'a' && c <= 'z') { - v = c - 'a' + 10; - } - if (v >= 0 && v < radix) return v; - return -1; -} - -std::string Lexer::readDigits(int radix) { - mark(); - while (digitValue(peek(), radix) != -1) { - advance(); - } - return extract(); -} diff --git a/simulator_SIC_XE/src/loader.cpp b/simulator_SIC_XE/src/loader.cpp deleted file mode 100644 index 1d00ac5..0000000 --- a/simulator_SIC_XE/src/loader.cpp +++ /dev/null @@ -1,215 +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(); - _relocation_address = header.start_address; - - 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::MODIFICATION: { - ModificationRecord modRecord = readModificationRecord(); - applyModification(modRecord); - 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 'M': return RecordType::MODIFICATION; - 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::ModificationRecord Loader::readModificationRecord() -{ - ModificationRecord record; - if(FILE_CONTAINS_WHITE_SPACES) _file_reader->readByte(); - - record.address = std::stoi(_file_reader->readString(6), nullptr, 16); - if(FILE_CONTAINS_WHITE_SPACES) _file_reader->readByte(); - - record.length = std::stoi(_file_reader->readString(2), nullptr, 16); - - record.add = true; - std::string rest = _file_reader->readLine(); - // Remove whitespace - rest.erase(std::remove_if(rest.begin(), rest.end(), ::isspace), rest.end()); - if (!rest.empty()) { - if (rest[0] == '-') { - record.add = false; - } - } - - 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; -} - -void Loader::applyModification(const ModificationRecord& mod) -{ - // M record specifies address and length in half-bytes (nibbles) - // We need to modify the value at that address by adding or subtracting - // the relocation address - - int address = mod.address; - int halfBytes = mod.length; - - // Calculate how many full bytes we need to read - // halfBytes can be odd or even - int numBytes = (halfBytes + 1) / 2; - - if (address < 0 || address + numBytes > MEMORY_SIZE) { - throw std::runtime_error("Modification address out of bounds"); - } - - // Read the current value from memory - int currentValue = 0; - for (int i = 0; i < numBytes; ++i) { - currentValue = (currentValue << 8) | _machine->getByte(address + i); - } - - // If odd number of half-bytes, we only modify the relevant nibbles - // For simplicity, we'll work with the full bytes and mask appropriately - int mask = 0; - for (int i = 0; i < halfBytes; ++i) { - mask = (mask << 4) | 0xF; - } - - // Extract the value to modify - int shift = (numBytes * 2 - halfBytes) * 4; - int valueToModify = (currentValue >> shift) & mask; - - // Apply modification - int newValue = mod.add ? (valueToModify + _relocation_address) - : (valueToModify - _relocation_address); - - // Mask to keep only the relevant bits - newValue &= mask; - - // Reconstruct the full value - int preservedBits = currentValue & ~(mask << shift); - int finalValue = preservedBits | (newValue << shift); - - // Write back to memory (big-endian) - for (int i = 0; i < numBytes; ++i) { - _machine->setByte(address + i, (finalValue >> ((numBytes - 1 - i) * 8)) & 0xFF); - } -} 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/node.cpp b/simulator_SIC_XE/src/node.cpp deleted file mode 100644 index 28c31fe..0000000 --- a/simulator_SIC_XE/src/node.cpp +++ /dev/null @@ -1,121 +0,0 @@ -#include "node.h" -#include -#include -#include - -string Node::toString() const { - std::ostringstream oss; - if (!_label.empty()) oss << _label << " "; - if (_mnemonic) oss << _mnemonic->toString() << " "; - if (!_comment.empty()) oss << "." << _comment; - return oss.str(); -} - -std::string Mnemonic::toString() const { - std::ostringstream oss; - oss << "[OP:" << std::hex << (int)_opcode << "]"; - if (_extended) oss << "+"; - // Print operands - for (size_t i = 0; i < _operands.size(); ++i) { - if (i > 0) oss << ","; - std::visit([&](auto&& arg) { - using T = std::decay_t; - if constexpr (std::is_same_v) { - // nothing - } else if constexpr (std::is_same_v) { - oss << "R" << arg.num; - } else if constexpr (std::is_same_v) { - oss << "#" << arg.value; - } else if constexpr (std::is_same_v) { - oss << arg.name; - if (arg.indexed) oss << ",X"; - } - }, _operands[i]); - } - return oss.str(); -} - -string InstructionNode::toString() const { - std::ostringstream oss; - if (!_label.empty()) oss << _label << " "; - if (_mnemonic) oss << _mnemonic->toString(); - if (!_comment.empty()) oss << " ." << _comment; - return oss.str(); -} - -string CommentNode::toString() const { - return "." + _comment; -} - -string DirectiveNode::toString() const { - std::ostringstream oss; - if (!_label.empty()) oss << _label << " "; - switch (_kind) { - case DirectiveKind::START: oss << "START"; break; - case DirectiveKind::END: oss << "END"; break; - case DirectiveKind::BASE: oss << "BASE"; break; - case DirectiveKind::NOBASE: oss << "NOBASE"; break; - case DirectiveKind::EQU: oss << "EQU"; break; - case DirectiveKind::ORG: oss << "ORG"; break; - case DirectiveKind::LTORG: oss << "LTORG"; break; - case DirectiveKind::EXTDEF: oss << "EXTDEF"; break; - case DirectiveKind::EXTREF: oss << "EXTREF"; break; - case DirectiveKind::CSECT: oss << "CSECT"; break; - } - std::visit([&](auto&& arg) { - using T = std::decay_t; - if constexpr (std::is_same_v) { - // no arg - } else if constexpr (std::is_same_v) { - oss << " " << std::hex << arg; - } else if constexpr (std::is_same_v) { - oss << " " << arg; - } else if constexpr (std::is_same_v>) { - for (size_t i = 0; i < arg.size(); ++i) { - if (i > 0) oss << ","; - oss << arg[i]; - } - } - }, _arg); - if (!_comment.empty()) oss << " ." << _comment; - return oss.str(); -} - -string DataNode::toString() const { - std::ostringstream oss; - if (!_label.empty()) oss << _label << " "; - switch (_kind) { - case DataKind::WORD: oss << "WORD"; break; - case DataKind::BYTE: oss << "BYTE"; break; - case DataKind::RESW: oss << "RESW"; break; - case DataKind::RESB: oss << "RESB"; break; - } - std::visit([&](auto&& arg) { - using T = std::decay_t; - if constexpr (std::is_same_v) { - // no value - } else if constexpr (std::is_same_v) { - oss << " " << arg; - } else if constexpr (std::is_same_v>) { - // Try to display as string if all printable ASCII - bool isPrintable = !arg.empty() && std::all_of(arg.begin(), arg.end(), - [](uint8_t b) { return b >= 32 && b <= 126; }); - - if (isPrintable) { - oss << " C'"; - for (uint8_t b : arg) oss << static_cast(b); - oss << "'"; - } else { - // Display as hex - oss << " X'"; - for (uint8_t b : arg) { - oss << std::hex << std::setw(2) << std::setfill('0') << (int)b; - } - oss << "'"; - } - } - }, _value); - if (!_comment.empty()) oss << " ." << _comment; - return oss.str(); -} - \ No newline at end of file diff --git a/simulator_SIC_XE/src/opcode.cpp b/simulator_SIC_XE/src/opcode.cpp index fcda0c4..febc489 100644 --- a/simulator_SIC_XE/src/opcode.cpp +++ b/simulator_SIC_XE/src/opcode.cpp @@ -1,137 +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}; - } - - // Initialize mnemonicToOpcode map - for (int i = 0; i < 0xff; ++i) { - if (instructions[i].type != InstructionType::INVALID) { - mnemonicToOpcode.emplace(instructions[i].name, static_cast(i)); - } - if (instructionsEXEX[i].type != InstructionType::INVALID) { - mnemonicToOpcode.emplace(instructionsEXEX[i].name, static_cast(i)); + if (instructions[i].name == nullptr) { + instructions[i] = {"INVALID", InstructionType::INVALID, nullptr}; } } - opcodeTablesInitialized = true; -} - -std::optional findOpcodeByMnemonic(std::string_view name) -{ - auto it = mnemonicToOpcode.find(name); - if (it == mnemonicToOpcode.end()) - return std::nullopt; - return it->second; -} - -const InstructionInfo& getInstructionInfo(uint8_t opcode) -{ - if (instructions[opcode].type != InstructionType::INVALID) - return instructions[opcode]; - return instructionsEXEX[opcode]; -} - - - -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/parser.cpp b/simulator_SIC_XE/src/parser.cpp deleted file mode 100644 index 3decfe9..0000000 --- a/simulator_SIC_XE/src/parser.cpp +++ /dev/null @@ -1,465 +0,0 @@ -// parser.cpp -#include "parser.h" -#include -#include -#include - -void Parser::initMnemonicMap() { - if (s_mnemonicMapInitialized) return; - - loadInstructionSet(); - - for (int op = 0; op < 0xFF; ++op) { - const auto& info = instructions[op]; - if (info.name && info.type != InstructionType::INVALID) { - s_nameToOpcode.emplace(info.name, static_cast(op)); - } - const auto& ex = instructionsEXEX[op]; - if (ex.name && ex.type != InstructionType::INVALID) { - s_nameToOpcode.emplace(ex.name, static_cast(op)); - } - } - - s_mnemonicMapInitialized = true; -} - -std::shared_ptr Parser::makeMnemonic(const std::string& name, bool extended) { - initMnemonicMap(); - - auto it = s_nameToOpcode.find(name); - if (it == s_nameToOpcode.end()) { - throw SyntaxError("Invalid mnemonic '" + name + "'", lexer_.row, lexer_.col); - } - - std::uint8_t opcode = it->second; - const InstructionInfo* info = nullptr; - - if (instructions[opcode].type != InstructionType::INVALID) { - info = &instructions[opcode]; - } else if (instructionsEXEX[opcode].type != InstructionType::INVALID) { - info = &instructionsEXEX[opcode]; - } - - if (!info) { - throw SyntaxError("Invalid mnemonic '" + name + "'", lexer_.row, lexer_.col); - } - - if (extended && info->type != InstructionType::TYPE3_4) { - throw SyntaxError( - "Extended format not allowed for mnemonic '" + name + "'", - lexer_.row, - lexer_.col - ); - } - - return std::make_shared(opcode, info->type, extended); -} - -std::string Parser::parseLabel() { - if (lexer_.col == 1 && std::isalpha(static_cast(lexer_.peek()))) { - return std::string(lexer_.readAlphanumeric()); - } - return {}; -} - -std::shared_ptr Parser::parseMnemonic() { - bool isExtended = lexer_.advanceIf('+'); - std::string name(lexer_.readAlphanumeric()); - if (name.empty()) { - throw SyntaxError("Mnemonic expected", lexer_.row, lexer_.col); - } - return makeMnemonic(name, isExtended); -} - -std::string Parser::parseSymbol() { - return std::string(lexer_.readAlphanumeric()); -} - -int Parser::parseRegister() { - char ch = lexer_.advance(); - constexpr std::string_view regs = "AXLBSTF"; - auto pos = regs.find(ch); - if (pos == std::string_view::npos) { - throw SyntaxError(std::string("Invalid register '") + ch + "'", lexer_.row, lexer_.col); - } - return static_cast(pos); -} - -void Parser::parseComma() { - lexer_.skipWhitespace(); - lexer_.advance(','); - lexer_.skipWhitespace(); -} - -bool Parser::parseIndexed() { - lexer_.skipWhitespace(); - if (lexer_.advanceIf(',')) { - lexer_.skipWhitespace(); - lexer_.advance('X'); - return true; - } - return false; -} - -static int digitValue(char c, int radix) { - if (radix < 2 || radix > 36) return -1; - int v = -1; - if (c >= '0' && c <= '9') v = c - '0'; - else if (c >= 'A' && c <= 'Z') v = c - 'A' + 10; - else if (c >= 'a' && c <= 'z') v = c - 'a' + 10; - if (v >= 0 && v < radix) return v; - return -1; -} - -int Parser::parseNumber(int lo, int hi) { - auto parseDigits = [&](int radix) -> int { - std::string digits(lexer_.readDigits(radix)); - if (digits.empty()) { - throw SyntaxError("Invalid number", lexer_.row, lexer_.col); - } - - long long value = 0; - for (char c : digits) { - int d = digitValue(c, radix); - if (d < 0) throw SyntaxError("Invalid number", lexer_.row, lexer_.col); - value = value * radix + d; - if (value > std::numeric_limits::max()) { - throw SyntaxError("Invalid number", lexer_.row, lexer_.col); - } - } - return static_cast(value); - }; - - int num = 0; - - if (lexer_.peek() == '0') { - int radix = -1; - switch (lexer_.peek(1)) { - case 'b': radix = 2; break; - case 'o': radix = 8; break; - case 'x': radix = 16; break; - default: break; - } - if (radix != -1) { - lexer_.advance(); - lexer_.advance(); - num = parseDigits(radix); - } else { - num = parseDigits(10); - } - } else if (std::isdigit(static_cast(lexer_.peek()))) { - num = parseDigits(10); - } else { - throw SyntaxError("Number expected", lexer_.row, lexer_.col); - } - - if (std::isalnum(static_cast(lexer_.peek()))) { - throw SyntaxError( - std::string("invalid digit '") + lexer_.peek() + "'", - lexer_.row, - lexer_.col - ); - } - - if (num < lo || num > hi) { - throw SyntaxError( - "Number '" + std::to_string(num) + "' out of range [" + - std::to_string(lo) + ".." + std::to_string(hi) + "]", - lexer_.row, - lexer_.col - ); - } - - return num; -} - -std::vector Parser::parseData() { - if (lexer_.advanceIf('C')) { - lexer_.advance('\''); - std::string s(lexer_.readTo('\'')); - std::vector data; - data.reserve(s.size()); - for (unsigned char c : s) { - data.push_back(static_cast(c)); - } - return data; - } - - if (lexer_.advanceIf('X')) { - lexer_.advance('\''); - std::string s(lexer_.readTo('\'')); - if (s.size() % 2 != 0) { - throw SyntaxError("Invalid hex literal length", lexer_.row, lexer_.col); - } - - std::vector data; - data.reserve(s.size() / 2); - - auto hexVal = [](char c) -> int { - if (c >= '0' && c <= '9') return c - '0'; - if (c >= 'A' && c <= 'F') return c - 'A' + 10; - if (c >= 'a' && c <= 'f') return c - 'a' + 10; - return -1; - }; - - for (std::size_t i = 0; i < s.size(); i += 2) { - int hi = hexVal(s[i]); - int lo = hexVal(s[i + 1]); - if (hi < 0 || lo < 0) { - throw SyntaxError("Invalid hex digit in literal", lexer_.row, lexer_.col); - } - data.push_back(static_cast((hi << 4) | lo)); - } - return data; - } - - if (std::isdigit(static_cast(lexer_.peek()))) { - constexpr int MAX_WORD = 0xFFFFFF; - int num = parseNumber(0, MAX_WORD); - return { - static_cast((num >> 16) & 0xFF), - static_cast((num >> 8) & 0xFF), - static_cast(num & 0xFF) - }; - } - - throw SyntaxError( - std::string("Invalid storage specifier '") + lexer_.peek() + "'", - lexer_.row, - lexer_.col - ); -} - -void Parser::parseOperands(Mnemonic& m) { - InstructionType t = m.type(); - char c = lexer_.peek(); - - if (t == InstructionType::TYPE1) { - // TYPE1 has no operands - return; - } - - if (t == InstructionType::TYPE2) { - // TYPE2: r1 or r1,r2 or r1,n - if (c == '\n' || c == '\0') return; - - int r1 = parseRegister(); - m.operands().emplace_back(Register{r1}); - lexer_.skipWhitespace(); - - if (lexer_.peek() == ',') { - parseComma(); - char c2 = lexer_.peek(); - if (std::isalpha(static_cast(c2))) { - int r2 = parseRegister(); - m.operands().emplace_back(Register{r2}); - } else if (std::isdigit(static_cast(c2))) { - int n = parseNumber(0, 0xFFFF); - m.operands().emplace_back(Immediate{n}); - } else { - throw SyntaxError("Invalid second operand", lexer_.row, lexer_.col); - } - } - - return; - } - - if (t == InstructionType::TYPE3_4) { - lexer_.skipWhitespace(); - char c0 = lexer_.peek(); - if (c0 == '\n' || c0 == '\0') { - // No operand (e.g., RSUB) - return; - } - - bool immediate = false; - bool indirect = false; - - if (lexer_.advanceIf('#')) { - immediate = true; - } else if (lexer_.advanceIf('@')) { - indirect = true; - } - - char c1 = lexer_.peek(); - if (std::isdigit(static_cast(c1))) { - int num = parseNumber(0, 0x7FFFFF); - if (immediate) { - m.operands().emplace_back(Immediate{num}); - } else { - // Direct numeric addressing (rare, treat as immediate) - m.operands().emplace_back(Immediate{num}); - } - } else if (std::isalpha(static_cast(c1))) { - std::string symbol = parseSymbol(); - bool indexed = parseIndexed(); - m.operands().emplace_back(SymbolRef{symbol, indexed, immediate, indirect}); - } else { - throw SyntaxError("Invalid operand", lexer_.row, lexer_.col); - } - - return; - } -} - -bool Parser::isDirective(const std::string& name) { - return name == "START" || name == "END" || name == "BASE" || name == "NOBASE" || - name == "EQU" || name == "ORG" || name == "LTORG" || - name == "EXTDEF" || name == "EXTREF" || name == "CSECT"; -} - -bool Parser::isDataDirective(const std::string& name) { - return name == "WORD" || name == "BYTE" || name == "RESW" || name == "RESB"; -} - -std::shared_ptr Parser::parseDirective(const std::string& label, const std::string& directive) { - lexer_.skipWhitespace(); - - DirectiveArg argValue; - char c = lexer_.peek(); - - // Parse argument based on first character - if (std::isalpha(c)) { - std::string arg = std::string(lexer_.readAlphanumeric()); - argValue = arg; - } else if (std::isdigit(c) || c == '0') { - int num = parseNumber(0, 0xFFFFFF); - argValue = num; - } else { - // No argument - argValue = std::monostate{}; - } - - lexer_.skipWhitespace(); - std::string comment = std::string(lexer_.readTo('\n')); - - DirectiveKind kind; - if (directive == "START") kind = DirectiveKind::START; - else if (directive == "END") kind = DirectiveKind::END; - else if (directive == "BASE") kind = DirectiveKind::BASE; - else if (directive == "NOBASE") kind = DirectiveKind::NOBASE; - else if (directive == "EQU") kind = DirectiveKind::EQU; - else if (directive == "ORG") kind = DirectiveKind::ORG; - else if (directive == "LTORG") kind = DirectiveKind::LTORG; - else if (directive == "EXTDEF") kind = DirectiveKind::EXTDEF; - else if (directive == "EXTREF") kind = DirectiveKind::EXTREF; - else if (directive == "CSECT") kind = DirectiveKind::CSECT; - else throw SyntaxError("Unknown directive", lexer_.row, lexer_.col); - - return std::make_shared(label, kind, argValue, comment); -} - -std::shared_ptr Parser::parseDataDirective(const std::string& label, const std::string& directive) { - lexer_.skipWhitespace(); - - DataKind kind; - if (directive == "WORD") kind = DataKind::WORD; - else if (directive == "BYTE") kind = DataKind::BYTE; - else if (directive == "RESW") kind = DataKind::RESW; - else if (directive == "RESB") kind = DataKind::RESB; - else throw SyntaxError("Unknown data directive", lexer_.row, lexer_.col); - - DataValue value; - if (kind == DataKind::WORD || kind == DataKind::RESW || kind == DataKind::RESB) { - int num = parseNumber(0, 0xFFFFFF); - value = num; - } else { // BYTE - auto bytes = parseData(); - value = bytes; - } - - lexer_.skipWhitespace(); - std::string comment = std::string(lexer_.readTo('\n')); - - return std::make_shared(label, kind, value, comment); -} - -std::shared_ptr Parser::parseInstruction() { - if (lexer_.col == 1 && lexer_.peek() == '.') { - return std::make_shared( - std::string(lexer_.readTo('\n')) - ); - } - - std::string label = parseLabel(); - - if (lexer_.skipWhitespace() && label.empty()) { - lexer_.advance(); - return nullptr; - } - - lexer_.skipWhitespace(); - - // Check for comment after label - create a label-only instruction node - if (lexer_.peek() == '.') { - std::string comment = std::string(lexer_.readTo('\n')); - // Return an instruction node with just the label (null mnemonic) - auto node = std::make_shared( - std::move(label), - nullptr, - std::move(comment) - ); - return node; - } - - // Check for extended format prefix - bool isExtended = lexer_.peek() == '+'; - if (isExtended) { - lexer_.advance(); - } - - std::string name = std::string(lexer_.readAlphanumeric()); - - if (name.empty()) { - throw SyntaxError( - "Mnemonic or directive expected (label='" + label + "')", - lexer_.row, - lexer_.col - ); - } - - // Check if it's a directive or data directive - if (isDirective(name)) { - return parseDirective(label, name); - } - - if (isDataDirective(name)) { - return parseDataDirective(label, name); - } - - // It's an instruction - create mnemonic - auto mnemonic = makeMnemonic(name, isExtended); - lexer_.skipWhitespace(); - - parseOperands(*mnemonic); - lexer_.skipWhitespace(); - - std::string comment(lexer_.readTo('\n')); - - return std::make_shared( - std::move(label), - std::move(mnemonic), - std::move(comment) - ); -} - -Code Parser::parseCode() { - Code code; - - while (lexer_.peek() > 0) { - while (lexer_.peek() > 0 && lexer_.col > 1) { - lexer_.readTo('\n'); - } - - if (auto node = parseInstruction()) { - code.addLine(node); - } - } - - return code; -} - -Code Parser::parse(const std::string& input) { - lexer_ = Lexer(input); - return parseCode(); -} 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