diff --git a/.gitignore b/.gitignore index 6f03a8e..6a3fb13 100644 --- a/.gitignore +++ b/.gitignore @@ -19,8 +19,7 @@ node_modules/ __pycache__/ *.pyc - -*.dev autotester sictools.jar -simulator_SIC_XE/CMakeLists.txt.user + +/build/ diff --git a/ass1/arith.asm b/ass1/arith.asm deleted file mode 100644 index 24354b0..0000000 --- a/ass1/arith.asm +++ /dev/null @@ -1,49 +0,0 @@ -arith START 0 - - . seštevek: sum = x + y - LDA x - ADD y - STA sum - - . razlika: diff = x - y - LDA x - SUB y - STA diff - - . produkt: prod = x * y - LDA x - MUL y - STA prod - - . količnik: quot = x / y - LDA x - DIV y . - STA quot - - . ostanek: mod = x - y * (x / y) - STA qtemp - - LDA y - MUL qtemp - STA prodtmp - - LDA x - SUB prodtmp - STA mod - -HALT J HALT - -.data -x WORD 5 -y WORD 2 - -sum RESW 1 -diff RESW 1 -prod RESW 1 -quot RESW 1 -mod RESW 1 - -qtemp RESW 1 -prodtmp RESW 1 - - END arith diff --git a/ass1/arithr.asm b/ass1/arithr.asm deleted file mode 100644 index 69453f4..0000000 --- a/ass1/arithr.asm +++ /dev/null @@ -1,59 +0,0 @@ -.code -arithr START 0 - - LDA x ; A = x - LDB y ; B = y - - RMO A,S ; S = x - RMO B,T ; T = y - -. sum = x + y - RMO S,A ; A = x - ADDR T,A ; A = x + y - STA sum - -. diff = x - y - RMO S,A ; A = x - SUBR T,A ; A = x - y - STA diff - -. prod = x * y - RMO S,A ; A = x - RMO T,B ; B = y - MULR B,A ; A = x * y - STA prod - -. quot = x / y - RMO S,A ; A = x - RMO T,B ; B = y - DIVR B,A ; A = x / y - STA quot - - -. mod = x % y = x - (x / y)*y - RMO S,A - RMO T,B - DIVR B,A ; A = q = x/y - RMO A,L ; L = q (shrani) - - RMO T,A ; A = y - RMO L,B ; B = q - MULR B,A ; A = y*q = produkt - - RMO S,B ; B = x - SUBR A,B ; B = x - (y*q) - STB mod - -HALT J HALT - -.data -x WORD 5 -y WORD 2 - -sum RESW 1 -diff RESW 1 -prod RESW 1 -quot RESW 1 -mod RESW 1 - - END arithr diff --git a/ass1/poly.asm b/ass1/poly.asm deleted file mode 100644 index 6fcddae..0000000 --- a/ass1/poly.asm +++ /dev/null @@ -1,57 +0,0 @@ -poly START 0 - - . potence x^1 .. x^4 - LDA x - STA x1 - - MUL x - STA x2 - - MUL x - STA x3 - - MUL x - STA x4 - - - . x3 = 2 * x^3 - LDA x3 - LDB #2 - MULR A,B - STB x3 - - . x2 = 3 * x^2 - LDA x2 - LDB #3 - MULR A,B - STB x2 - - . x1 = 4 * x - LDA x1 - LDB #4 - MULR A,B - STB x1 - - . vsota vseh - LDA x0 - ADD x1 - ADD x2 - ADD x3 - ADD x4 - STA result - - -HALT J HALT - END poly -.data -x WORD 2 ; vrednost x - -x4 RESW 1 -x3 RESW 1 -x2 RESW 1 -x1 RESW 1 -x0 WORD 5 ; konstanta - -result RESW 1 - - END poly diff --git a/ass1/print.asm b/ass1/print.asm deleted file mode 100644 index 4b7d0ae..0000000 --- a/ass1/print.asm +++ /dev/null @@ -1,23 +0,0 @@ -.code -prog START 0 - - LDX #0 - -loop LDCH msg,X - WD #0xAA - - TIX msglen - JLT loop - - LDA #0x0D - WD #0xAA - LDA #0x0A - WD #0xAA - -halt J halt - -.data -msg BYTE C'SIC/XE' -msglen WORD 6 - - END prog diff --git a/ass1/rec.asm b/ass1/rec.asm deleted file mode 100644 index 212bf23..0000000 --- a/ass1/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/ass1/stack.asm b/ass1/stack.asm deleted file mode 100644 index a61cbea..0000000 --- a/ass1/stack.asm +++ /dev/null @@ -1,56 +0,0 @@ -.code - -stack START 0 - - LDA #9 - STA @stackptr - JSUB stackpush - - JSUB stackpop - LDA @stackptr - -halt J halt - - -stackinit - STA stacktmp - - LDA #STACK - STA stackptr - - LDA stacktmp - RSUB - - -stackpush - STA stacktmp - - LDA stackptr - ADD #3 - STA stackptr - - LDA stacktmp - RSUB - - -stackpop - STA stacktmp - - LDA stackptr - SUB #3 - STA stackptr - - LDA stacktmp - RSUB - - -.data - -stackptr WORD 0 - -stacktmp WORD 0 - -STACKSIZE EQU 50 -STACK RESW STACKSIZE - - END stack diff --git a/ass2/simulator_SIC_XE/.gitignore b/ass2/simulator_SIC_XE/.gitignore deleted file mode 100644 index 4cbe372..0000000 --- a/ass2/simulator_SIC_XE/.gitignore +++ /dev/null @@ -1,95 +0,0 @@ -# Build directories -build/ -target/ - -# CMake generated files -CMakeCache.txt -CMakeFiles/ -CMakeScripts/ -cmake_install.cmake -*.cmake -!CMakeLists.txt - -# Compiled Object files -*.o -*.obj - -# Precompiled Headers -*.gch -*.pch - -# Compiled Dynamic libraries -*.so -*.dylib -*.dll - -# Fortran module files -*.mod -*.smod - -# Compiled Static libraries -*.lai -*.la -*.a -*.lib - -# Executables -*.exe -*.out -*.app - -# Debug files -*.dSYM/ -*.su -*.idb -*.pdb - -# VS Code -.vscode/ -*.code-workspace - -# CLion -.idea/ -cmake-build-*/ - -# Xcode -*.pbxuser -*.mode1v3 -*.mode2v3 -*.perspectivev3 -*.xcuserstate -project.xcworkspace/ -xcuserdata/ - -# Qt Creator -*.pro.user -*.pro.user.* -*.qbs.user -*.qbs.user.* -*.moc -*.moc.cpp -*.qm -*.prl -CMakeLists.txt.user - -# OS generated files -.DS_Store -.DS_Store? -._* -.Spotlight-V100 -.Trashes -ehthumbs.db -Thumbs.db - -# Temporary files -*~ -*.swp -*.swo -*.tmp -*.bak - -# Log files -*.log - -# Core dumps -core \ No newline at end of file diff --git a/ass2/simulator_SIC_XE/CMakeLists.txt b/ass2/simulator_SIC_XE/CMakeLists.txt deleted file mode 100644 index c6c37e1..0000000 --- a/ass2/simulator_SIC_XE/CMakeLists.txt +++ /dev/null @@ -1,60 +0,0 @@ -cmake_minimum_required(VERSION 3.10) -project(simulator_SIC_XE VERSION 1.0 LANGUAGES CXX) - -set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_STANDARD_REQUIRED ON) - -# Put all build outputs under target/bin -set(OUTPUT_DIR ${CMAKE_SOURCE_DIR}/target/bin) -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${OUTPUT_DIR}) -set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${OUTPUT_DIR}) -set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${OUTPUT_DIR}) - -# Collect all .cpp sources under src/ -file(GLOB_RECURSE SOURCES "${PROJECT_SOURCE_DIR}/src/*.cpp") - -if(NOT SOURCES) - message(WARNING "No source files found in ${PROJECT_SOURCE_DIR}/src — the build will create an empty library") -endif() - -# Build a static library from all sources -add_library(simulator_lib STATIC ${SOURCES}) -target_include_directories(simulator_lib PUBLIC ${PROJECT_SOURCE_DIR}/include) -set_target_properties(simulator_lib PROPERTIES OUTPUT_NAME "simulator") - -# If a main.cpp exists, create an executable that links the library. -if(EXISTS "${PROJECT_SOURCE_DIR}/src/main.cpp") - add_executable(simulator_exec "${PROJECT_SOURCE_DIR}/src/main.cpp") - target_link_libraries(simulator_exec PRIVATE simulator_lib) -endif() - - -if(TARGET simulator_exec) - add_custom_target(run - DEPENDS simulator_exec - COMMAND ${CMAKE_COMMAND} -E echo "Running simulator_exec..." - COMMAND $ - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - COMMENT "Builds and runs simulator_exec" - ) -endif() - -message(STATUS "Project: ${PROJECT_NAME}") -message(STATUS "Sources found: ${SOURCES}") -message(STATUS "Output directory: ${OUTPUT_DIR}") - -if(EXISTS "${CMAKE_SOURCE_DIR}/gui/qt/CMakeLists.txt") - add_subdirectory(gui/qt) -endif() - -# Copy resources directory (if present) to target/res so build output includes them -if(EXISTS "${CMAKE_SOURCE_DIR}/res") - add_custom_target(copy_resources - COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_SOURCE_DIR}/target/res - COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/res ${CMAKE_SOURCE_DIR}/target/res - COMMENT "Copying resources from res/ to target/res/" - ) - if(TARGET simulator_exec) - add_dependencies(simulator_exec copy_resources) - endif() -endif() diff --git a/ass2/simulator_SIC_XE/Makefile b/ass2/simulator_SIC_XE/Makefile deleted file mode 100644 index 93bc1f6..0000000 --- a/ass2/simulator_SIC_XE/Makefile +++ /dev/null @@ -1,68 +0,0 @@ -# Simple Makefile wrapper to configure, build and run the CMake project. -# Usage: -# make # configure + build with all cores -# make build # configure + build with all cores -# make all # clean + configure + build + run -# make run # just run the executable (no build) -# make clean # run CMake clean (or remove build files) -# make distclean # remove build dir and generated targets - -CMAKE ?= cmake -BUILD_DIR := build -CMAKE_BUILD_TYPE ?= Release -TARGET := target/bin/simulator_exec -GUI_TARGET := target/bin/simulator_qt -NPROC := $(shell nproc) - -.PHONY: all configure build run clean distclean - -# Default target: just build -default: build - -# make all: clean, build, then run -all: clean build run - -configure: - @echo "Configuring (build dir: $(BUILD_DIR), type: $(CMAKE_BUILD_TYPE))" - $(CMAKE) -S . -B $(BUILD_DIR) -DCMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE) - -build: configure - @echo "Building with $(NPROC) cores..." - $(CMAKE) --build $(BUILD_DIR) -j$(NPROC) - -# make run: just launch the executable (no build) -run: - @echo "Running primary target..." - # Prefer GUI if available, otherwise fall back to console executable - @if [ -x "$(GUI_TARGET)" ]; then \ - echo "Launching GUI: $(GUI_TARGET)"; \ - ./$(GUI_TARGET); \ - elif [ -x "$(TARGET)" ]; then \ - ./$(TARGET); \ - else \ - echo "No runnable target found (tried $(GUI_TARGET) and $(TARGET))."; exit 1; \ - fi - -.PHONY: run-gui -run-gui: build - @echo "Running GUI target ($(GUI_TARGET))" - @if [ -x "$(GUI_TARGET)" ]; then \ - echo "Starting GUI..."; ./$(GUI_TARGET) -platform xcb; \ - else \ - echo "GUI executable not found: $(GUI_TARGET)"; exit 1; \ - fi - -.PHONY: build-gui -build-gui: configure - @echo "Building GUI (and core)..." - $(CMAKE) --build $(BUILD_DIR) -j$(shell nproc) --target simulator_qt || true - -clean: - @echo "Cleaning build (CMake clean)..." - -$(CMAKE) --build $(BUILD_DIR) --target clean || true - @echo "Removing target directory..." - -rm -rf target/ - -distclean: - @echo "Removing build artifacts and generated files..." - -rm -rf $(BUILD_DIR) CMakeFiles CMakeCache.txt cmake_install.cmake target/ diff --git a/ass2/simulator_SIC_XE/README.md b/ass2/simulator_SIC_XE/README.md deleted file mode 100644 index aac6331..0000000 --- a/ass2/simulator_SIC_XE/README.md +++ /dev/null @@ -1,55 +0,0 @@ -# SIC/XE Simulator - -A complete SIC/XE architecture simulator with instruction execution, device I/O, and memory management. - -## Quick Start - -The easiest way to build and run the simulator: - -```bash -make run -``` - -This single command will: -- Configure the build system (if needed) -- Compile all source files -- Link the executable -- Run the simulator - -## Build Commands - -| Command | Description | -|--------------|----------------------------------------------------| -| `make` | Build the project | -| `make build` | Build the project | -| `make run` | Build run the simulator | -| `make clean` | Clean build artifacts | -| `make run` | Clean build artifacts, build and run the simulator | - - -## Project Structure - -``` -simulator_SIC_XE/ -├── include/ # Header files (.h) -├── src/ # Source files (.cpp) -├── target/bin/ # Build output (executables, libraries) -└── build/ # CMake build directory -``` - -## Features - -- **SIC/XE Architecture**: Complete register set (A, X, L, B, S, T, F, PC, SW) -- **Instruction Execution**: Format 1, 2, and 3/4 instruction support -- **Device I/O**: Input, output, and file device management -- **Memory Management**: 24-bit address space with proper bounds checking - -## Development - -The project uses CMake with a convenient Makefile wrapper. All build artifacts are placed in `target/bin/` for easy access. - -For manual CMake usage: -```bash -cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -cmake --build build -j -``` diff --git a/ass2/simulator_SIC_XE/gui/qt/CMakeLists.txt b/ass2/simulator_SIC_XE/gui/qt/CMakeLists.txt deleted file mode 100644 index cf8072a..0000000 --- a/ass2/simulator_SIC_XE/gui/qt/CMakeLists.txt +++ /dev/null @@ -1,54 +0,0 @@ -cmake_minimum_required(VERSION 3.16) -project(simulator_qt LANGUAGES CXX) - -set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_STANDARD_REQUIRED ON) - -set(CMAKE_AUTOMOC ON) -set(CMAKE_AUTOUIC ON) -set(CMAKE_AUTORCC ON) - -# Prefer Qt6, fall back to Qt5 -find_package(Qt6 COMPONENTS Widgets QUIET) -if(NOT Qt6_FOUND) - # Try explicitly the system Qt6 cmake prefix on Debian/Ubuntu - find_package(Qt6 COMPONENTS Widgets QUIET PATHS /usr/lib/x86_64-linux-gnu) -endif() - -if(NOT Qt6_FOUND) - # Fallback: try Qt5 if Qt6 is unavailable - find_package(Qt5 COMPONENTS Widgets QUIET) -endif() - -if(Qt6_FOUND) - set(QT_LIB Qt6::Widgets) -elseif(Qt5_FOUND) - set(QT_LIB Qt5::Widgets) -else() - message(FATAL_ERROR "Qt6 or Qt5 not found. Install Qt development packages or set CMAKE_PREFIX_PATH to your Qt installation.") -endif() - -set(GUI_SRCS - main.cpp - mainwindow.cpp - MachineController.cpp -) - -set(GUI_HDRS - mainwindow.h - MachineController.h -) - -add_executable(simulator_qt ${GUI_SRCS} ${GUI_HDRS}) - -# Allow the generated UI headers (from AUTOUIC) to be found in the build dir -# and also include the top-level include folder (works when added with add_subdirectory) -target_include_directories(simulator_qt PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_SOURCE_DIR}/include) - -# Link to core library target (must be defined by top-level CMake) -target_link_libraries(simulator_qt PRIVATE simulator_lib ${QT_LIB}) - -# Place runtime binary under repo/target/bin to match project layout -set_target_properties(simulator_qt PROPERTIES - RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/target/bin -) \ No newline at end of file diff --git a/ass2/simulator_SIC_XE/gui/qt/MachineController.cpp b/ass2/simulator_SIC_XE/gui/qt/MachineController.cpp deleted file mode 100644 index 881e97d..0000000 --- a/ass2/simulator_SIC_XE/gui/qt/MachineController.cpp +++ /dev/null @@ -1,76 +0,0 @@ -#include "MachineController.h" -#include "../../include/machine.h" -#include -#include - -using namespace std::chrono; - -MachineController::MachineController(std::shared_ptr machine, QObject *parent) - : QObject(parent), m_machine(std::move(machine)) -{ - if (!m_machine) { - m_machine = std::make_shared(); - } - m_lastUpdateTime = steady_clock::now(); -} - -MachineController::~MachineController() { - stop(); -} - -void MachineController::start() { - if (m_running.exchange(true)) return; - m_thread = std::thread([this]{ runLoop(); }); -} - -void MachineController::stop() { - if (!m_running.exchange(false)) return; - if (m_thread.joinable()) m_thread.join(); -} - -void MachineController::step() { - try { - if (m_machine) { - m_machine->execute(); - m_machine->tick(); - emit tick(); - } - } catch (const std::exception &e) { - emit error(QString::fromStdString(e.what())); - } -} - -void MachineController::runLoop() { - const auto minUpdateInterval = milliseconds(16); - - while (m_running.load()) { - try { - if (m_machine) { - m_machine->execute(); - m_machine->tick(); - m_ticksSinceLastUpdate++; - - // Throttle GUI updates to 60 Hz - auto now = steady_clock::now(); - auto elapsed = duration_cast(now - m_lastUpdateTime); - - if (elapsed >= minUpdateInterval) { - emit tick(); - m_lastUpdateTime = now; - m_ticksSinceLastUpdate = 0; - } - - if (m_machine->isStopped()) { - emit tick(); - m_running.store(false); - break; - } - } - } catch (const std::exception &e) { - emit error(QString::fromStdString(e.what())); - // Stop on fatal error - m_running.store(false); - break; - } - } -} diff --git a/ass2/simulator_SIC_XE/gui/qt/MachineController.h b/ass2/simulator_SIC_XE/gui/qt/MachineController.h deleted file mode 100644 index 801b5f4..0000000 --- a/ass2/simulator_SIC_XE/gui/qt/MachineController.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef MACHINECONTROLLER_H -#define MACHINECONTROLLER_H - -#include -#include -#include -#include - -class Machine; - -class MachineController : public QObject { - Q_OBJECT -public: - explicit MachineController(std::shared_ptr machine = nullptr, QObject *parent = nullptr); - ~MachineController() override; - - void start(); - void stop(); - void step(); - -signals: - void tick(); - void error(const QString &msg); - -private: - void runLoop(); - std::atomic m_running{false}; - std::thread m_thread; - std::shared_ptr m_machine; - std::atomic m_ticksSinceLastUpdate{0}; - std::chrono::steady_clock::time_point m_lastUpdateTime; -}; - -#endif // MACHINECONTROLLER_H diff --git a/ass2/simulator_SIC_XE/gui/qt/main.cpp b/ass2/simulator_SIC_XE/gui/qt/main.cpp deleted file mode 100644 index 707d916..0000000 --- a/ass2/simulator_SIC_XE/gui/qt/main.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include -#include "mainwindow.h" -#include "../../include/opcode.h" - -int main(int argc, char **argv) { - loadInstructionSet(); - - qputenv("QT_QPA_PLATFORM", "xcb"); - - QApplication app(argc, argv); - MainWindow w; - w.show(); - return app.exec(); -} \ No newline at end of file diff --git a/ass2/simulator_SIC_XE/gui/qt/mainwindow.cpp b/ass2/simulator_SIC_XE/gui/qt/mainwindow.cpp deleted file mode 100644 index b53aa72..0000000 --- a/ass2/simulator_SIC_XE/gui/qt/mainwindow.cpp +++ /dev/null @@ -1,1030 +0,0 @@ -#include "mainwindow.h" -#include "ui_mainwindow.h" -#include "MachineController.h" -#include "../../include/machine.h" -#include "../../include/instructions.h" -#include "../../include/opcode.h" -#include "../../include/constants.h" -#include "../../../include/loader.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -class Loader; - -std::shared_ptr g_loader; - -MainWindow::MainWindow(QWidget *parent) : - QMainWindow(parent), - ui(new Ui::MainWindow), - m_machine(std::make_shared()), - m_controller(std::make_unique(m_machine, this)) -{ - ui->setupUi(this); - - ui->regA_dec_field->setValidator(new QIntValidator(-8388608, 8388607, this)); - ui->regB_dec_field->setValidator(new QIntValidator(-8388608, 8388607, this)); - ui->regS_dec_field->setValidator(new QIntValidator(-8388608, 8388607, this)); - ui->regT_dec_field->setValidator(new QIntValidator(-8388608, 8388607, this)); - ui->regX_dec_field->setValidator(new QIntValidator(-8388608, 8388607, this)); - // unsigned 24 bit - ui->regL_dec_field->setValidator(new QIntValidator(0, 16777215, this)); - ui->regPC_dec_field->setValidator(new QIntValidator(0, 16777215, this)); - ui->regSW_dec_field->setValidator(new QIntValidator(0, 16777215, this)); - // float - ui->regF_dec_field->setValidator(new QDoubleValidator(-3.402823e38, 3.402823e38, 6, this)); - - QRegularExpressionValidator* hexValidator = new QRegularExpressionValidator(QRegularExpression("^(0x)?[0-9A-Fa-f]{1,6}$"), this); - ui->regA_hex_field->setValidator(hexValidator); - ui->regB_hex_field->setValidator(hexValidator); - ui->regX_hex_field->setValidator(hexValidator); - ui->regS_hex_field->setValidator(hexValidator); - ui->regT_hex_field->setValidator(hexValidator); - ui->regL_hex_field->setValidator(hexValidator); - ui->regPC_hex_field->setValidator(hexValidator); - ui->regSW_hex_field->setValidator(hexValidator); - - QRegularExpressionValidator* binValidator = new QRegularExpressionValidator(QRegularExpression("^[01]{1,24}$"), this); - ui->regA_bin_field->setValidator(binValidator); - ui->regB_bin_field->setValidator(binValidator); - ui->regX_bin_field->setValidator(binValidator); - ui->regS_bin_field->setValidator(binValidator); - ui->regT_bin_field->setValidator(binValidator); - ui->regL_bin_field->setValidator(binValidator); - ui->regPC_bin_field->setValidator(binValidator); - ui->regSW_bin_field->setValidator(binValidator); - - QRegularExpressionValidator* floatHexValidator = new QRegularExpressionValidator(QRegularExpression("^(0x)?[0-9A-Fa-f]{1,12}$"), this); - ui->regF_hex_field->setValidator(floatHexValidator); - - QRegularExpressionValidator* floatBinValidator = new QRegularExpressionValidator(QRegularExpression("^[01]{1,48}$"), this); - ui->regF_bin_field->setValidator(floatBinValidator); - - - connect(m_controller.get(), &MachineController::tick, this, &MainWindow::updateRegisterDisplays, Qt::QueuedConnection); - connect(m_controller.get(), &MachineController::tick, this, &MainWindow::updateMemoryDisplay, Qt::QueuedConnection); - - connectRegisterFields(); - - connect(ui->StartBtn, &QPushButton::clicked, this, &MainWindow::startExecution); - connect(ui->StopBtn, &QPushButton::clicked, this, &MainWindow::stopExecution); - connect(ui->StepBtn, &QPushButton::clicked, this, &MainWindow::stepExecution); - - connect(ui->MemoryInc256Btn, &QPushButton::clicked, this, &MainWindow::onMemoryInc256); - connect(ui->MemoryInc4096Btn, &QPushButton::clicked, this, &MainWindow::onMemoryInc4096); - connect(ui->MemoryInc65536Btn, &QPushButton::clicked, this, &MainWindow::onMemoryInc65536); - connect(ui->MemoryDec256Btn, &QPushButton::clicked, this, &MainWindow::onMemoryDec256); - connect(ui->MemoryDec4096Btn, &QPushButton::clicked, this, &MainWindow::onMemoryDec4096); - connect(ui->MemoryDec65536Btn, &QPushButton::clicked, this, &MainWindow::onMemoryDec65536); - connect(ui->MemoryGoToStart_2, &QPushButton::clicked, this, &MainWindow::onMemoryGoToStart); - connect(ui->MemoryGoToEnd, &QPushButton::clicked, this, &MainWindow::onMemoryGoToEnd); - - connect(ui->DisasmInc256Btn, &QPushButton::clicked, this, &MainWindow::onDisassemblyInc); - connect(ui->DisasmInc4096Btn, &QPushButton::clicked, this, &MainWindow::onDisassemblyInc16); - connect(ui->DisasmInc65536Btn, &QPushButton::clicked, this, &MainWindow::onDisassemblyInc256); - connect(ui->DisasmDec256Btn, &QPushButton::clicked, this, &MainWindow::onDisassemblyDec); - connect(ui->DisasmDec4096Btn, &QPushButton::clicked, this, &MainWindow::onDisassemblyDec16); - connect(ui->DisasmDec65536Btn, &QPushButton::clicked, this, &MainWindow::onDisassemblyDec256); - connect(ui->DisasmGoToStart, &QPushButton::clicked, this, &MainWindow::onDisassemblyGoToStart); - connect(ui->DisasmGoToEnd, &QPushButton::clicked, this, &MainWindow::onDisassemblyGoToEnd); - connect(m_controller.get(), &MachineController::tick, this, &MainWindow::updateDisassemblyDisplay, Qt::QueuedConnection); - - // Connect menu actions - connect(ui->actionLoad_Object_File, &QAction::triggered, this, &MainWindow::loadObjectFile); - connect(ui->actionAbout, &QAction::triggered, this, &MainWindow::showAboutDialog); - connect(ui->actionFrequency, &QAction::triggered, this, &MainWindow::showFrequencyDialog); - - setupMemoryDisplay(); - setupDisassemblyDisplay(); - - loadInstructionSet(); - // Don't load any program by default - user will load via File menu - - updateRegisterDisplays(); - updateMemoryDisplay(); - updateDisassemblyDisplay(); -} - -MainWindow::~MainWindow() -{ - delete ui; -} - -void MainWindow::updateRegisterDisplays() -{ - if (!m_machine) return; - - // Update all register display formats (decimal, hex, binary) - updateAllFormatsForRegister("regA", m_machine->getA()); - updateAllFormatsForRegister("regB", m_machine->getB()); - updateAllFormatsForRegister("regX", m_machine->getX()); - updateAllFormatsForRegister("regS", m_machine->getS()); - updateAllFormatsForRegister("regT", m_machine->getT()); - updateAllFormatsForRegister("regL", m_machine->getL()); - updateAllFormatsForRegister("regPC", m_machine->getPC()); - updateAllFormatsForRegister("regSW", m_machine->getSW()); - updateFloatRegisterFormats("regF", m_machine->getF()); -} - -void MainWindow::updateSingleRegisterDisplay(const QString& fieldName, int value) -{ - QLineEdit* field = findChild(fieldName); - if (field) { - // Only update if the field doesn't have focus (to avoid interfering with user input) - if (!field->hasFocus()) { - field->setText(QString::number(value)); - } - } -} - -void MainWindow::updateAllFormatsForRegister(const QString& regPrefix, int value) -{ - // Update decimal field - QLineEdit* decField = findChild(regPrefix + "_dec_field"); - if (decField && !decField->hasFocus()) { - decField->setText(QString::number(value)); - } - - // Update hex field - QLineEdit* hexField = findChild(regPrefix + "_hex_field"); - if (hexField && !hexField->hasFocus()) { - // Convert to 24-bit representation, handle negative numbers - unsigned int unsignedValue = static_cast(value) & 0xFFFFFF; - hexField->setText(QString("0x%1").arg(unsignedValue, 6, 16, QChar('0')).toUpper()); - } - - // Update binary field - QLineEdit* binField = findChild(regPrefix + "_bin_field"); - if (binField && !binField->hasFocus()) { - // Convert to 24-bit binary representation - unsigned int unsignedValue = static_cast(value) & 0xFFFFFF; - QString binaryStr = QString::number(unsignedValue, 2); - // Pad to 24 bits - binaryStr = binaryStr.rightJustified(24, '0'); - binField->setText(binaryStr); - } -} - -void MainWindow::updateFloatRegisterFormats(const QString& regPrefix, double value) -{ - // Update decimal field - QLineEdit* decField = findChild(regPrefix + "_dec_field"); - if (decField && !decField->hasFocus()) { - decField->setText(QString::number(value, 'g', 10)); - } - - // Update hex field (48-bit float representation) - QLineEdit* hexField = findChild(regPrefix + "_hex_field"); - if (hexField && !hexField->hasFocus()) { - // Convert double to 48-bit hex representation - // For SIC/XE, we need to convert to the 48-bit float format - uint64_t* intPtr = reinterpret_cast(&value); - uint64_t bits48 = (*intPtr) & 0xFFFFFFFFFFFFULL; // Mask to 48 bits - hexField->setText(QString("0x%1").arg(bits48, 12, 16, QChar('0')).toUpper()); - } - - // Update binary field (48-bit float representation) - QLineEdit* binField = findChild(regPrefix + "_bin_field"); - if (binField && !binField->hasFocus()) { - // Convert double to 48-bit binary representation - uint64_t* intPtr = reinterpret_cast(&value); - uint64_t bits48 = (*intPtr) & 0xFFFFFFFFFFFFULL; // Mask to 48 bits - QString binaryStr = QString::number(bits48, 2); - // Pad to 48 bits - binaryStr = binaryStr.rightJustified(48, '0'); - binField->setText(binaryStr); - } -} - -void MainWindow::connectRegisterFields() -{ - // Connect decimal register fields to update machine registers when changed - connect(ui->regA_dec_field, &QLineEdit::editingFinished, this, &MainWindow::onRegisterFieldChanged); - connect(ui->regB_dec_field, &QLineEdit::editingFinished, this, &MainWindow::onRegisterFieldChanged); - connect(ui->regX_dec_field, &QLineEdit::editingFinished, this, &MainWindow::onRegisterFieldChanged); - connect(ui->regS_dec_field, &QLineEdit::editingFinished, this, &MainWindow::onRegisterFieldChanged); - connect(ui->regT_dec_field, &QLineEdit::editingFinished, this, &MainWindow::onRegisterFieldChanged); - connect(ui->regL_dec_field, &QLineEdit::editingFinished, this, &MainWindow::onRegisterFieldChanged); - connect(ui->regPC_dec_field, &QLineEdit::editingFinished, this, &MainWindow::onRegisterFieldChanged); - connect(ui->regSW_dec_field, &QLineEdit::editingFinished, this, &MainWindow::onRegisterFieldChanged); - connect(ui->regF_dec_field, &QLineEdit::editingFinished, this, &MainWindow::onRegisterFieldChanged); - - // Connect hex register fields - QLineEdit* hexFields[] = { - ui->regA_hex_field, ui->regB_hex_field, ui->regX_hex_field, - ui->regS_hex_field, ui->regT_hex_field, ui->regL_hex_field, - ui->regPC_hex_field, ui->regSW_hex_field, ui->regF_hex_field - }; - for (auto* field : hexFields) { - if (field) { - connect(field, &QLineEdit::editingFinished, this, &MainWindow::onRegisterFieldChanged); - } - } - - // Connect binary register fields - QLineEdit* binFields[] = { - ui->regA_bin_field, ui->regB_bin_field, ui->regX_bin_field, - ui->regS_bin_field, ui->regT_bin_field, ui->regL_bin_field, - ui->regPC_bin_field, ui->regSW_bin_field, ui->regF_bin_field - }; - for (auto* field : binFields) { - if (field) { - connect(field, &QLineEdit::editingFinished, this, &MainWindow::onRegisterFieldChanged); - } - } -} - -void MainWindow::onRegisterFieldChanged() -{ - if (!m_machine) return; - - QLineEdit* field = qobject_cast(sender()); - if (!field) return; - - QString objectName = field->objectName(); - QString regName = objectName.split('_')[0]; - - - if (regName == "regF") { - handleFloatRegisterFieldChanged(field, objectName); - return; - } - - // Handle integer registers - int value = 0; - bool ok = false; - - // Parse value based on field type - if (objectName.contains("_dec_field")) { - value = field->text().toInt(&ok); - } else if (objectName.contains("_hex_field")) { - QString hexText = field->text(); - // Remove 0x prefix if present - if (hexText.startsWith("0x", Qt::CaseInsensitive)) { - hexText = hexText.mid(2); - } - value = hexText.toInt(&ok, 16); - - if (ok && (regName == "regA" || regName == "regB" || regName == "regX" || - regName == "regS" || regName == "regT")) { - if (value > 0x7FFFFF) { - value = value - 0x1000000; - } - } - } else if (objectName.contains("_bin_field")) { - value = field->text().toInt(&ok, 2); - - if (ok && (regName == "regA" || regName == "regB" || regName == "regX" || - regName == "regS" || regName == "regT")) { - if (value > 0x7FFFFF) { - value = value - 0x1000000; - } - } - } - - if (!ok) { - - updateRegisterDisplays(); - return; - } - - if (regName == "regA") { - m_machine->setA(value); - updateAllFormatsForRegister("regA", m_machine->getA()); - } else if (regName == "regB") { - m_machine->setB(value); - updateAllFormatsForRegister("regB", m_machine->getB()); - } else if (regName == "regX") { - m_machine->setX(value); - updateAllFormatsForRegister("regX", m_machine->getX()); - } else if (regName == "regS") { - m_machine->setS(value); - updateAllFormatsForRegister("regS", m_machine->getS()); - } else if (regName == "regT") { - m_machine->setT(value); - updateAllFormatsForRegister("regT", m_machine->getT()); - } else if (regName == "regL") { - m_machine->setL(value); - updateAllFormatsForRegister("regL", m_machine->getL()); - } else if (regName == "regPC") { - m_machine->setPC(value); - updateAllFormatsForRegister("regPC", m_machine->getPC()); - } else if (regName == "regSW") { - m_machine->setSW(value); - updateAllFormatsForRegister("regSW", m_machine->getSW()); - } -} - -void MainWindow::handleFloatRegisterFieldChanged(QLineEdit* field, const QString& objectName) -{ - double value = 0.0; - bool ok = false; - - if (objectName.contains("_dec_field")) { - value = field->text().toDouble(&ok); - } else if (objectName.contains("_hex_field")) { - QString hexText = field->text(); - if (hexText.startsWith("0x", Qt::CaseInsensitive)) { - hexText = hexText.mid(2); - } - - uint64_t intValue = hexText.toULongLong(&ok, 16); - if (ok) { - intValue &= 0xFFFFFFFFFFFFULL; - double* floatPtr = reinterpret_cast(&intValue); - value = *floatPtr; - } - } else if (objectName.contains("_bin_field")) { - uint64_t intValue = field->text().toULongLong(&ok, 2); - if (ok) { - intValue &= 0xFFFFFFFFFFFFULL; - double* floatPtr = reinterpret_cast(&intValue); - value = *floatPtr; - } - } - - if (!ok) { - updateRegisterDisplays(); - return; - } - - m_machine->setF(value); - updateFloatRegisterFormats("regF", m_machine->getF()); -} - -void MainWindow::setTestRegisterValues() -{ - if (!m_machine) return; - - // Set some test values to demonstrate the register updating - m_machine->setA(12345); // Decimal: 12345, Hex: 0x003039, Binary: 000000011000000111001 - m_machine->setB(-1000); // Negative value to test signed representation - m_machine->setX(0xABCDEF); // Hex value to test various formats - m_machine->setS(255); // Simple power of 2 minus 1 - m_machine->setT(0x7FFFFF); // Maximum positive 24-bit value - - // Update all displays - updateRegisterDisplays(); -} - -void MainWindow::startExecution() -{ - if (m_controller) { - m_controller->start(); - } -} - -void MainWindow::stopExecution() -{ - if (m_controller) { - m_controller->stop(); - } -} - -void MainWindow::stepExecution() -{ - if (m_controller) { - m_controller->step(); - } -} - -void MainWindow::loadDemoProgram() -{ - if (!m_machine) return; - - // Load the instruction set first - loadInstructionSet(); - - qDebug() << "Loading SIC/XE Demo Program: Array Sum with Indirect Addressing"; - - // Memory layout - const int ARRAY_ADDR = 0x100; // Array of 3 numbers - const int PTR_ADDR = 0x200; // Pointer to array - const int SUM_ADDR = 0x300; // Result storage - const int COUNTER_ADDR = 0x310; // Loop counter - - // Initialize array with values: 10, 20, 30 - m_machine->setWord(ARRAY_ADDR, 10); - m_machine->setWord(ARRAY_ADDR + 3, 20); - m_machine->setWord(ARRAY_ADDR + 6, 30); - - // Initialize pointer to point to array - m_machine->setWord(PTR_ADDR, ARRAY_ADDR); - - // Initialize counter to 3 - m_machine->setWord(COUNTER_ADDR, 3); - - // Initialize sum to 0 - m_machine->setWord(SUM_ADDR, 0); - - int addr = 0x00; - - // Program: Sum array elements using indirect addressing - // 0x00: LDA #0 ; Initialize accumulator to 0 - m_machine->setByte(addr++, 0x01); // LDA with immediate (n=0,i=1) - m_machine->setByte(addr++, 0x00); - m_machine->setByte(addr++, 0x00); - - // 0x03: STA SUM_ADDR ; Store 0 in SUM - m_machine->setByte(addr++, 0x0F); // STA - m_machine->setByte(addr++, (SUM_ADDR >> 8) & 0xFF); - m_machine->setByte(addr++, SUM_ADDR & 0xFF); - - // 0x06: LDX #0 ; Initialize index to 0 - m_machine->setByte(addr++, 0x05); // LDX with immediate - m_machine->setByte(addr++, 0x00); - m_machine->setByte(addr++, 0x00); - - // LOOP (0x09): - const int LOOP_START = addr; - - // 0x09: LDA @PTR_ADDR ; Load value indirectly through pointer - m_machine->setByte(addr++, 0x02); // LDA with indirect (n=1,i=0) - m_machine->setByte(addr++, (PTR_ADDR >> 8) & 0xFF); - m_machine->setByte(addr++, PTR_ADDR & 0xFF); - - // 0x0C: ADD SUM_ADDR ; Add to sum - m_machine->setByte(addr++, 0x1B); // ADD - m_machine->setByte(addr++, (SUM_ADDR >> 8) & 0xFF); - m_machine->setByte(addr++, SUM_ADDR & 0xFF); - - // 0x0F: STA SUM_ADDR ; Store result back - m_machine->setByte(addr++, 0x0F); // STA - m_machine->setByte(addr++, (SUM_ADDR >> 8) & 0xFF); - m_machine->setByte(addr++, SUM_ADDR & 0xFF); - - // 0x12: LDA PTR_ADDR ; Load current pointer value - m_machine->setByte(addr++, 0x03); // LDA - m_machine->setByte(addr++, (PTR_ADDR >> 8) & 0xFF); - m_machine->setByte(addr++, PTR_ADDR & 0xFF); - - // 0x15: ADD #3 ; Add 3 to move to next array element - m_machine->setByte(addr++, 0x19); // ADD with immediate - m_machine->setByte(addr++, 0x00); - m_machine->setByte(addr++, 0x03); - - // 0x18: STA PTR_ADDR ; Store updated pointer - m_machine->setByte(addr++, 0x0F); // STA - m_machine->setByte(addr++, (PTR_ADDR >> 8) & 0xFF); - m_machine->setByte(addr++, PTR_ADDR & 0xFF); - - // 0x1B: LDA COUNTER_ADDR ; Load counter - m_machine->setByte(addr++, 0x03); // LDA - m_machine->setByte(addr++, (COUNTER_ADDR >> 8) & 0xFF); - m_machine->setByte(addr++, COUNTER_ADDR & 0xFF); - - // 0x1E: ADD #-1 ; Decrement counter (add -1) - m_machine->setByte(addr++, 0x19); // ADD with immediate - m_machine->setByte(addr++, 0x0F); // -1 in 12-bit two's complement - m_machine->setByte(addr++, 0xFF); - - // 0x21: STA COUNTER_ADDR ; Store counter - m_machine->setByte(addr++, 0x0F); // STA - m_machine->setByte(addr++, (COUNTER_ADDR >> 8) & 0xFF); - m_machine->setByte(addr++, COUNTER_ADDR & 0xFF); - - // 0x24: COMP #0 ; Compare with 0 - m_machine->setByte(addr++, 0x29); // COMP with immediate - m_machine->setByte(addr++, 0x00); - m_machine->setByte(addr++, 0x00); - - // 0x27: JGT LOOP ; Jump if greater than 0 - m_machine->setByte(addr++, 0x37); // JGT - m_machine->setByte(addr++, (LOOP_START >> 8) & 0xFF); - m_machine->setByte(addr++, LOOP_START & 0xFF); - - // 0x2A: J 0x2A ; Infinite loop (halt) - m_machine->setByte(addr++, 0x3F); // J - m_machine->setByte(addr++, 0x00); - m_machine->setByte(addr++, 0x2A); - - // Set PC to start of program - m_machine->setPC(0x00); - - qDebug() << "Program loaded:"; - qDebug() << " Array at 0x" << QString::number(ARRAY_ADDR, 16).toUpper() << " = [10, 20, 30]"; - qDebug() << " Pointer at 0x" << QString::number(PTR_ADDR, 16).toUpper(); - qDebug() << " Sum will be stored at 0x" << QString::number(SUM_ADDR, 16).toUpper(); - qDebug() << " Expected result: 60 (0x3C)"; -} - -void MainWindow::setupMemoryDisplay() -{ - // Set the title - ui->MemorygroupBox->setTitle("Memory (RAM)"); -} - -void MainWindow::onMemoryInc256() -{ - m_memoryOffset += 256; - if (m_memoryOffset > 1048576 - 256) { - m_memoryOffset = 1048576 - 256; - } - updateMemoryDisplay(); -} - -void MainWindow::onMemoryInc4096() -{ - m_memoryOffset += 4096; - if (m_memoryOffset > 1048576 - 256) { - m_memoryOffset = 1048576 - 256; - } - updateMemoryDisplay(); -} - -void MainWindow::onMemoryInc65536() -{ - m_memoryOffset += 65536; - if (m_memoryOffset > 1048576 - 256) { - m_memoryOffset = 1048576 - 256; - } - updateMemoryDisplay(); -} - -void MainWindow::onMemoryDec256() -{ - m_memoryOffset -= 256; - if (m_memoryOffset < 0) { - m_memoryOffset = 0; - } - updateMemoryDisplay(); -} - -void MainWindow::onMemoryDec4096() -{ - m_memoryOffset -= 4096; - if (m_memoryOffset < 0) { - m_memoryOffset = 0; - } - updateMemoryDisplay(); -} - -void MainWindow::onMemoryDec65536() -{ - m_memoryOffset -= 65536; - if (m_memoryOffset < 0) { - m_memoryOffset = 0; - } - updateMemoryDisplay(); -} - -void MainWindow::onMemoryGoToStart() -{ - m_memoryOffset = 0; - updateMemoryDisplay(); -} - -void MainWindow::onMemoryGoToEnd() -{ - m_memoryOffset = 1048576 - 256; - updateMemoryDisplay(); -} - -void MainWindow::setupDisassemblyDisplay() -{ - ui->MemorygroupBox_3->setTitle("Disassembly"); -} - -void MainWindow::onDisassemblyInc() -{ - // Move forward by 1 instruction - auto instr = disassembleAt(m_disassemblyOffset); - m_disassemblyOffset += instr.size; - if (m_disassemblyOffset > 1048576 - 16) { - m_disassemblyOffset = 1048576 - 16; - } - updateDisassemblyDisplay(); -} - -void MainWindow::onDisassemblyInc16() -{ - // Move forward by 16 instructions - for (int i = 0; i < 16 && m_disassemblyOffset < 1048576 - 16; i++) { - auto instr = disassembleAt(m_disassemblyOffset); - m_disassemblyOffset += instr.size; - } - updateDisassemblyDisplay(); -} - -void MainWindow::onDisassemblyInc256() -{ - // Move forward by 256 instructions - for (int i = 0; i < 256 && m_disassemblyOffset < 1048576 - 16; i++) { - auto instr = disassembleAt(m_disassemblyOffset); - m_disassemblyOffset += instr.size; - } - updateDisassemblyDisplay(); -} - -void MainWindow::onDisassemblyDec() -{ - // Move back by trying to find previous instruction (assume max 4 bytes) - m_disassemblyOffset = std::max(0, m_disassemblyOffset - 4); - updateDisassemblyDisplay(); -} - -void MainWindow::onDisassemblyDec16() -{ - // Move back by approximately 16 instructions (16*3 = 48 bytes avg) - m_disassemblyOffset = std::max(0, m_disassemblyOffset - 48); - updateDisassemblyDisplay(); -} - -void MainWindow::onDisassemblyDec256() -{ - // Move back by approximately 256 instructions (256*3 = 768 bytes avg) - m_disassemblyOffset = std::max(0, m_disassemblyOffset - 768); - updateDisassemblyDisplay(); -} - -void MainWindow::onDisassemblyGoToStart() -{ - m_disassemblyOffset = 0; - updateDisassemblyDisplay(); -} - -void MainWindow::onDisassemblyGoToEnd() -{ - m_disassemblyOffset = std::max(0, 1048576 - 1024); - updateDisassemblyDisplay(); -} - -MainWindow::DisassembledInstruction MainWindow::disassembleAt(int address) -{ - DisassembledInstruction result; - result.address = address; - result.size = 1; - result.mnemonic = "???"; - result.operand = ""; - result.effectiveAddr = -1; - result.isImmediate = false; - result.isIndirect = false; - - if (address >= 1048576) { - return result; - } - - int byte1 = m_machine->getByte(address); - int opcode = byte1 & 0xFC; // Mask off lower 2 bits (n, i flags) - - if (opcode >= 0xff || instructions[opcode].type == InstructionType::INVALID) { - result.mnemonic = QString("BYTE 0x%1").arg(byte1, 2, 16, QChar('0')).toUpper(); - return result; - } - - result.mnemonic = QString(instructions[opcode].name); - - switch (instructions[opcode].type) { - case InstructionType::TYPE1: - result.size = 1; - break; - - case InstructionType::TYPE2: { - result.size = 2; - if (address + 1 < 1048576) { - int byte2 = m_machine->getByte(address + 1); - int r1 = (byte2 >> 4) & 0xF; - int r2 = byte2 & 0xF; - - const char* regNames[] = {"A", "X", "L", "B", "S", "T", "F", "?", "PC", "SW"}; - QString reg1Str = (r1 < 10) ? regNames[r1] : "?"; - QString reg2Str = (r2 < 10) ? regNames[r2] : "?"; - - // Check if this is a single-operand Format 2 instruction - QString mnem = result.mnemonic.toUpper(); - if (mnem == "CLEAR" || mnem == "TIXR") { - result.operand = reg1Str; - } else if (mnem == "SVC") { - result.operand = QString::number(r1); - } else if (mnem == "SHIFTL" || mnem == "SHIFTR") { - result.operand = QString("%1, %2").arg(reg1Str).arg(r2); - } else { - // Two register operands (ADDR, SUBR, COMPR, etc.) - result.operand = QString("%1, %2").arg(reg1Str).arg(reg2Str); - } - } - break; - } - - case InstructionType::TYPE3_4: { - if (address + 2 >= 1048576) { - result.size = 3; - break; - } - - int byte2 = m_machine->getByte(address + 1); - int byte3 = m_machine->getByte(address + 2); - - int ni = (byte1 >> 0) & 0x3; - int x = (byte2 >> 7) & 0x1; - int b = (byte2 >> 6) & 0x1; - int p = (byte2 >> 5) & 0x1; - int e = (byte2 >> 4) & 0x1; - - if (e) { - // Format 4 - add + prefix to mnemonic - result.mnemonic = "+" + result.mnemonic; - result.size = 4; - if (address + 3 < 1048576) { - int byte4 = m_machine->getByte(address + 3); - int addr = ((byte2 & 0xF) << 16) | (byte3 << 8) | byte4; - - result.isImmediate = (ni == 0x1); - result.isIndirect = (ni == 0x2); - - if (!result.isImmediate) { - result.effectiveAddr = addr; - } - - QString prefix = ""; - if (ni == 0x1) prefix = "#"; // Immediate - else if (ni == 0x2) prefix = "@"; // Indirect - - result.operand = QString("%1%2").arg(prefix).arg(addr, 5, 16, QChar('0')).toUpper(); - if (x) result.operand += ",X"; - } - } else { - result.size = 3; - int disp = ((byte2 & 0xF) << 8) | byte3; - - if (disp & 0x800) { - disp |= 0xFFFFF000; - } - - result.isImmediate = (ni == 0x1); - result.isIndirect = (ni == 0x2); - - QString prefix = ""; - if (ni == 0x1) prefix = "#"; // Immediate - else if (ni == 0x2) prefix = "@"; // Indirect - - if (ni == 0x1 && !p && !b) { - result.operand = QString("#%1").arg(disp & 0xFFF); - } else { - // Calculate effective address for display - int ea = disp; - QString addrMode = ""; - - if (p) { - ea += (address + 3); - addrMode = " (PC)"; - } else if (b) { - ea += m_machine->getB(); - addrMode = " (B)"; - } - - if (!result.isImmediate && !x) { - result.effectiveAddr = ea & 0xFFFFF; - } - - result.operand = QString("%1%2%3").arg(prefix).arg(ea & 0xFFFFF, 4, 16, QChar('0')).toUpper().arg(addrMode); - if (x) result.operand += ",X"; - } - } - break; - } - - default: - break; - } - - return result; -} - -void MainWindow::updateDisassemblyDisplay() -{ - if (!m_machine) return; - - QWidget* container = new QWidget(); - QVBoxLayout* layout = new QVBoxLayout(container); - layout->setSpacing(1); - layout->setContentsMargins(5, 5, 5, 5); - - QFont monoFont("Courier New"); - monoFont.setPointSize(9); - - // Header - QString headerText = QString("Address Mnemonic Operand *var **var"); - QLabel* header = new QLabel(headerText); - QFont headerFont = monoFont; - headerFont.setBold(true); - header->setFont(headerFont); - layout->addWidget(header); - - int pc = m_machine->getPC(); - int currentAddr = m_disassemblyOffset; - - // Disassemble up to 255 instructions - for (int i = 0; i < 255 && currentAddr < 1048576; i++) { - auto instr = disassembleAt(currentAddr); - - QString varCol = ""; - QString varVar = ""; - - // *var column - show value at effective address (if not immediate) - if (instr.effectiveAddr >= 0 && instr.effectiveAddr < 1048576) { - int value = m_machine->getWord(instr.effectiveAddr); - varCol = QString("0x%1").arg(value & 0xFFFFFF, 6, 16, QChar('0')).toUpper(); - - // **var column - if indirect (@), dereference again - if (instr.isIndirect && value >= 0 && value < 1048576) { - int derefValue = m_machine->getWord(value); - varVar = QString("0x%1").arg(derefValue & 0xFFFFFF, 6, 16, QChar('0')).toUpper(); - } - } - - QString line = QString("0x%1 %2 %3 %4 %5") - .arg(instr.address, 5, 16, QChar('0')).toUpper() - .arg(instr.mnemonic, -9) - .arg(instr.operand, -14) - .arg(varCol, -9) - .arg(varVar, -9); - - QLabel* instrLine = new QLabel(line); - instrLine->setFont(monoFont); - - // Highlight current PC - if (pc == instr.address) { - instrLine->setStyleSheet("background-color: #FFFF99; font-weight: bold;"); - } - - layout->addWidget(instrLine); - currentAddr += instr.size; - } - - layout->addStretch(); - container->setLayout(layout); - - // Save scroll position before updating - int scrollPos = ui->DisasemblyScrollArea->verticalScrollBar()->value(); - - ui->DisasemblyScrollArea->setWidget(container); - - // Restore scroll position after updating - ui->DisasemblyScrollArea->verticalScrollBar()->setValue(scrollPos); -} - -void MainWindow::updateMemoryDisplay() -{ - if (!m_machine) return; - - // Create a widget to hold the memory display - QWidget* container = new QWidget(); - QVBoxLayout* layout = new QVBoxLayout(container); - layout->setSpacing(1); - layout->setContentsMargins(5, 5, 5, 5); - - // Create monospace font for memory display - QFont monoFont("Courier New"); - monoFont.setPointSize(9); - - // Header with current offset range - QString headerText = QString("Address Hex Value Char [0x%1 - 0x%2]") - .arg(m_memoryOffset, 5, 16, QChar('0')).toUpper() - .arg(m_memoryOffset + 255, 5, 16, QChar('0')).toUpper(); - QLabel* header = new QLabel(headerText); - QFont headerFont = monoFont; - headerFont.setBold(true); - header->setFont(headerFont); - layout->addWidget(header); - - // Get PC for highlighting - int pc = m_machine->getPC(); - - // Display memory byte by byte - ONLY 256 bytes from current offset - for (int i = 0; i < 256; i++) { - int addr = m_memoryOffset + i; - int byte = m_machine->getByte(addr); - - QString addressStr = QString("0x%1").arg(addr, 5, 16, QChar('0')).toUpper(); - - // Hex value column - QString hexStr = QString("0x%1").arg(byte, 2, 16, QChar('0')).toUpper(); - - // Char representation - QString charStr; - if (byte >= 32 && byte <= 126) { - charStr = QChar(byte); - } else { - charStr = '.'; - } - - QString line = QString("%1 %2 %3") - .arg(addressStr, -12) - .arg(hexStr, -12) - .arg(charStr); - - QLabel* memLine = new QLabel(line); - memLine->setFont(monoFont); - - // Highlight the current PC address - if (pc == addr) { - memLine->setStyleSheet("background-color: #FFFF99; font-weight: bold;"); - } - - layout->addWidget(memLine); - } - - layout->addStretch(); - container->setLayout(layout); - - int scrollPos = ui->MemoryScrollArea->verticalScrollBar()->value(); - - ui->MemoryScrollArea->setWidget(container); - - ui->MemoryScrollArea->verticalScrollBar()->setValue(scrollPos); -} - -void MainWindow::loadObjectFile() -{ - QString fileName = QFileDialog::getOpenFileName(this, - tr("Load Object File"), - QString(), - tr("Object Files (*.obj);;All Files (*)")); - - if (fileName.isEmpty()) { - return; - } - - try { - // Stop execution if running - m_controller->stop(); - - // Reset machine state - m_machine->reset(); - - // Load the object file - Loader loader(m_machine, fileName.toStdString()); - loader.load(); - - // Update displays - updateRegisterDisplays(); - updateMemoryDisplay(); - updateDisassemblyDisplay(); - - QMessageBox::information(this, tr("Success"), - tr("Object file loaded successfully")); - } catch (const std::exception &e) { - QMessageBox::critical(this, tr("Error"), - tr("Failed to load object file: %1").arg(e.what())); - } -} - -void MainWindow::showAboutDialog() -{ - QMessageBox::about(this, tr("About SIC/XE Simulator"), - tr("SIC/XE Simulator\nby Zan Skvarca\n2025")); -} - -void MainWindow::showFrequencyDialog() -{ - if (!m_machine) return; - - QDialog dialog(this); - dialog.setWindowTitle(tr("Set Frequency")); - dialog.setModal(true); - - QVBoxLayout *layout = new QVBoxLayout(&dialog); - - QLabel *currentLabel = new QLabel(tr("Current frequency: %1 Hz").arg(m_machine->getSpeed()), &dialog); - layout->addWidget(currentLabel); - - QLabel *newLabel = new QLabel(tr("New frequency (Hz):"), &dialog); - layout->addWidget(newLabel); - - QLineEdit *freqInput = new QLineEdit(&dialog); - freqInput->setValidator(new QIntValidator(1, 1000000000, &dialog)); - freqInput->setText(QString::number(m_machine->getSpeed())); - layout->addWidget(freqInput); - - QHBoxLayout *buttonLayout = new QHBoxLayout(); - QPushButton *submitBtn = new QPushButton(tr("Submit"), &dialog); - QPushButton *cancelBtn = new QPushButton(tr("Cancel"), &dialog); - buttonLayout->addWidget(submitBtn); - buttonLayout->addWidget(cancelBtn); - layout->addLayout(buttonLayout); - - connect(submitBtn, &QPushButton::clicked, &dialog, &QDialog::accept); - connect(cancelBtn, &QPushButton::clicked, &dialog, &QDialog::reject); - - if (dialog.exec() == QDialog::Accepted) { - bool ok; - int newFreq = freqInput->text().toInt(&ok); - if (ok && newFreq > 0) { - m_machine->setSpeed(newFreq); - QMessageBox::information(this, tr("Success"), - tr("Frequency set to %1 Hz").arg(newFreq)); - } - } -} diff --git a/ass2/simulator_SIC_XE/gui/qt/mainwindow.h b/ass2/simulator_SIC_XE/gui/qt/mainwindow.h deleted file mode 100644 index 2dba671..0000000 --- a/ass2/simulator_SIC_XE/gui/qt/mainwindow.h +++ /dev/null @@ -1,85 +0,0 @@ -#ifndef MAINWINDOW_H -#define MAINWINDOW_H - -#include -#include - -class MachineController; -class Machine; -class QLineEdit; - -namespace Ui { -class MainWindow; -} - -class MainWindow : public QMainWindow -{ - Q_OBJECT - -public: - explicit MainWindow(QWidget *parent = nullptr); - ~MainWindow(); - - std::shared_ptr machine() const { return m_machine; } - MachineController* controller() const { return m_controller.get(); } - - void startExecution(); - void stopExecution(); - void stepExecution(); - - void setTestRegisterValues(); - -private slots: - void updateRegisterDisplays(); - void updateMemoryDisplay(); - void updateDisassemblyDisplay(); - void onRegisterFieldChanged(); - void onMemoryInc256(); - void onMemoryInc4096(); - void onMemoryInc65536(); - void onMemoryDec256(); - void onMemoryDec4096(); - void onMemoryDec65536(); - void onMemoryGoToStart(); - void onMemoryGoToEnd(); - void onDisassemblyInc(); - void onDisassemblyInc16(); - void onDisassemblyInc256(); - void onDisassemblyDec(); - void onDisassemblyDec16(); - void onDisassemblyDec256(); - void onDisassemblyGoToStart(); - void onDisassemblyGoToEnd(); - void loadObjectFile(); - void showAboutDialog(); - void showFrequencyDialog(); - -private: - Ui::MainWindow *ui; - std::shared_ptr m_machine; - std::unique_ptr m_controller; - int m_memoryOffset = 0; - int m_disassemblyOffset = 0; - - void connectRegisterFields(); - void updateSingleRegisterDisplay(const QString& fieldName, int value); - void updateAllFormatsForRegister(const QString& regPrefix, int value); - void updateFloatRegisterFormats(const QString& regPrefix, double value); - void handleFloatRegisterFieldChanged(QLineEdit* field, const QString& objectName); - void loadDemoProgram(); - void setupMemoryDisplay(); - void setupDisassemblyDisplay(); - - struct DisassembledInstruction { - int address; - int size; - QString mnemonic; - QString operand; - int effectiveAddr; - bool isImmediate; - bool isIndirect; - }; - DisassembledInstruction disassembleAt(int address); -}; - -#endif // MAINWINDOW_H diff --git a/ass2/simulator_SIC_XE/gui/qt/mainwindow.ui b/ass2/simulator_SIC_XE/gui/qt/mainwindow.ui deleted file mode 100644 index e9084bd..0000000 --- a/ass2/simulator_SIC_XE/gui/qt/mainwindow.ui +++ /dev/null @@ -1,930 +0,0 @@ - - - MainWindow - - - - 0 - 0 - 1172 - 649 - - - - MainWindow - - - - - - 10 - 0 - 431 - 601 - - - - - - 0 - 80 - 431 - 321 - - - - Register values - - - - - 70 - 40 - 113 - 23 - - - - - - - 10 - 40 - 57 - 20 - - - - - 10 - - - - Reg A - - - - - - 190 - 40 - 113 - 23 - - - - - - - 310 - 40 - 113 - 23 - - - - - - - 110 - 20 - 57 - 20 - - - - - 10 - - - - Bin - - - - - - 230 - 20 - 57 - 20 - - - - - 10 - - - - Hex - - - - - - 350 - 20 - 57 - 20 - - - - - 10 - - - - Dec - - - - - - 310 - 70 - 113 - 23 - - - - - - - 10 - 70 - 57 - 20 - - - - - 10 - - - - Reg B - - - - - - 190 - 70 - 113 - 23 - - - - - - - 70 - 70 - 113 - 23 - - - - - - - 310 - 100 - 113 - 23 - - - - - - - 10 - 100 - 57 - 20 - - - - - 10 - - - - Reg X - - - - - - 190 - 100 - 113 - 23 - - - - - - - 70 - 100 - 113 - 23 - - - - - - - 310 - 130 - 113 - 23 - - - - - - - 10 - 130 - 57 - 20 - - - - - 10 - - - - Reg S - - - - - - 190 - 130 - 113 - 23 - - - - - - - 70 - 130 - 113 - 23 - - - - - - - 310 - 160 - 113 - 23 - - - - - - - 10 - 160 - 57 - 20 - - - - - 10 - - - - Reg T - - - - - - 190 - 160 - 113 - 23 - - - - - - - 70 - 160 - 113 - 23 - - - - - - - 190 - 190 - 113 - 23 - - - - - - - 70 - 190 - 113 - 23 - - - - - - - 10 - 190 - 57 - 20 - - - - - 10 - - - - Reg L - - - - - - 310 - 190 - 113 - 23 - - - - - - - 10 - 220 - 57 - 20 - - - - - 10 - - - - Reg PC - - - - - - 310 - 220 - 113 - 23 - - - - - - - 70 - 220 - 113 - 23 - - - - - - - 190 - 220 - 113 - 23 - - - - - - - 10 - 249 - 57 - 20 - - - - - 10 - - - - Reg SW - - - - - - 310 - 249 - 113 - 23 - - - - - - - 70 - 249 - 113 - 23 - - - - - - - 190 - 249 - 113 - 23 - - - - - - - 10 - 280 - 57 - 20 - - - - - 10 - - - - Reg L - - - - - - 310 - 280 - 113 - 23 - - - - - - - 70 - 280 - 113 - 23 - - - - - - - 190 - 280 - 113 - 23 - - - - - - - - 0 - 0 - 431 - 81 - - - - Control - - - - - 30 - 40 - 80 - 23 - - - - Start - - - - - - 170 - 40 - 80 - 23 - - - - Stop - - - - - - 310 - 40 - 80 - 23 - - - - Step - - - - - - - - 450 - 0 - 721 - 601 - - - - - - 0 - 0 - 711 - 291 - - - - Memory - - - - - 0 - 20 - 711 - 221 - - - - true - - - - - 0 - 0 - 709 - 219 - - - - - - - - 450 - 250 - 71 - 23 - - - - >> - - - - - - 370 - 250 - 71 - 23 - - - - > - - - - - - 530 - 250 - 71 - 23 - - - - >>> - - - - - - 290 - 250 - 71 - 23 - - - - < - - - - - - 210 - 250 - 71 - 23 - - - - << - - - - - - 130 - 250 - 71 - 21 - - - - <<< - - - - - - 50 - 250 - 71 - 21 - - - - O - - - - - - 610 - 250 - 71 - 21 - - - - | - - - - - - - 0 - 300 - 711 - 301 - - - - Disasembly - - - - - 0 - 20 - 711 - 221 - - - - true - - - - - 0 - 0 - 709 - 219 - - - - - - - - 440 - 250 - 71 - 23 - - - - >> - - - - - - 360 - 250 - 71 - 23 - - - - > - - - - - - 520 - 250 - 71 - 23 - - - - >>> - - - - - - 280 - 250 - 71 - 23 - - - - < - - - - - - 200 - 250 - 71 - 23 - - - - << - - - - - - 120 - 250 - 71 - 21 - - - - <<< - - - - - - 40 - 250 - 71 - 21 - - - - O - - - - - - 600 - 250 - 71 - 21 - - - - | - - - - - - - - - toolBar - - - TopToolBarArea - - - false - - - - - - 0 - 0 - 1172 - 20 - - - - - File - - - - - - Machine - - - - - - Help - - - - - - - - - - Load Object File - - - - - Frequency - - - - - About - - - - - - diff --git a/ass2/simulator_SIC_XE/include/constants.h b/ass2/simulator_SIC_XE/include/constants.h deleted file mode 100644 index 6f2195a..0000000 --- a/ass2/simulator_SIC_XE/include/constants.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef CONSTANTS_H -#define CONSTANTS_H - -#include -// ============================== -// SIC/XE Architecture Constants -// ============================== - -// Memory and system constants -constexpr int MEMORY_SIZE = 1 << 20; // 1 MB memory -constexpr int NUM_DEVICES = 256; -constexpr int WORD_SIZE = 24; -constexpr int WORD_MASK = 0xFFFFFF; - -// SIC/XE floating point constants -constexpr int SICF_BITS = 48; -constexpr int SICF_FRAC_BITS = 40; -constexpr int SICF_EXP_BITS = 7; -constexpr int SICF_EXP_BIAS = 64; -constexpr unsigned long long SICF_FRAC_MASK = (1ULL << SICF_FRAC_BITS) - 1; - -// SW register condition codes -constexpr int CC_LT = 0x0; // 00 -constexpr int CC_EQ = 0x1; // 01 -constexpr int CC_GT = 0x2; // 10 -constexpr int CC_MASK = 0x3; // mask for 2 bits - -// Instruction format bit masks -constexpr int TYPE3_4_SIC_MASK = 0xFC; -constexpr int NI_MASK = 0x03; // mask for n and i bits -constexpr int NI_SIC = 0x0; - -constexpr int BP_BASE_REL_MASK = 0b10; -constexpr int BP_PC_REL_MASK = 0b01; -constexpr int BP_DIRECT_MASK = 0b00; - -constexpr int BIT_E_MASK = 0x10; // mask for e bit in F4 and F3 instructions - -//SIC/XE/XE -constexpr bool USE_EXTENDED_MODE = true; -constexpr int VECTOR_REG_SIZE = 4; - -/* if structure is -/target/ - |-> bin/simulator_exec - |-> res/ -*/ -// When running from project root (./target/bin/simulator_exec), resources are in ./target/res/ -constexpr char PATH_RESOURCES[] = "./target/res/"; -constexpr bool FILE_CONTAINS_WHITE_SPACES = true; - -#endif // CONSTANTS_H \ No newline at end of file diff --git a/ass2/simulator_SIC_XE/include/device.h b/ass2/simulator_SIC_XE/include/device.h deleted file mode 100644 index 6b5acb7..0000000 --- a/ass2/simulator_SIC_XE/include/device.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef DEVICE_H -#define DEVICE_H - - -class Device { -public: - Device(); - - bool test(); - virtual unsigned char read(); - virtual void write(unsigned char value); -}; - - - -#endif // DEVICE_H \ No newline at end of file diff --git a/ass2/simulator_SIC_XE/include/file_device.h b/ass2/simulator_SIC_XE/include/file_device.h deleted file mode 100644 index 01b433c..0000000 --- a/ass2/simulator_SIC_XE/include/file_device.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef FILE_DEVICE_H -#define FILE_DEVICE_H - -#include "device.h" -#include -#include - -class FileDevice : public Device { -public: - explicit FileDevice(const std::string &filename); - ~FileDevice(); - unsigned char read() override; - void write(unsigned char value) override; - -private: - void ensureFileOpen(); - std::fstream fileStream; - std::string filename; - bool fileCreated; - std::streampos readPosition; -}; - -#endif // FILE_DEVICE_H \ No newline at end of file diff --git a/ass2/simulator_SIC_XE/include/file_reader.h b/ass2/simulator_SIC_XE/include/file_reader.h deleted file mode 100644 index 87b8a17..0000000 --- a/ass2/simulator_SIC_XE/include/file_reader.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef FILE_READER_H -#define FILE_READER_H - -#include "reader.h" -#include -#include - -class FileReader : public Reader { -public: - explicit FileReader(const std::string &path, std::ios::openmode m = std::ios::binary); - ~FileReader() override; - - int readByte() override; - - bool readBytes(uint8_t* buf, size_t len) override; - std::string readString(size_t len) override; - std::string readLine() override; - - bool good() const; - -private: - std::ifstream in; -}; - -#endif // FILE_READER_H \ No newline at end of file diff --git a/ass2/simulator_SIC_XE/include/input_device.h b/ass2/simulator_SIC_XE/include/input_device.h deleted file mode 100644 index 40b01d3..0000000 --- a/ass2/simulator_SIC_XE/include/input_device.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef INPUT_DEVICE_H -#define INPUT_DEVICE_H - -#include "device.h" -#include - -class InputDevice : public Device { -public: - explicit InputDevice(std::istream &in); - ~InputDevice(); - - unsigned char read(); - -private: - std::istream &inStream; -}; - -#endif // INPUT_DEVICE_H \ No newline at end of file diff --git a/ass2/simulator_SIC_XE/include/instructions.h b/ass2/simulator_SIC_XE/include/instructions.h deleted file mode 100644 index 5bef303..0000000 --- a/ass2/simulator_SIC_XE/include/instructions.h +++ /dev/null @@ -1,101 +0,0 @@ -#ifndef INSTRUCTIONS_H -#define INSTRUCTIONS_H - -#include "utils.h" - -class Machine; // forward declaration - -// Type 1 instruction handlers -void fix_handler(Machine& m); -void float_handler(Machine& m); -void hio_handler(Machine& m); -void norm_handler(Machine& m); -void sio_handler(Machine& m); -void tio_handler(Machine& m); -void nop_handler(Machine& m); - -/* IDEJE ZA SIC_XE_XE :)*/ -// void nop(Machine& m); - -// Type 2 instruction handlers -void addr_handler(Machine& m, int r1, int r2); -void clear_handler(Machine& m, int r, int unused); -void compr_handler(Machine& m, int r1, int r2); -void divr_handler(Machine& m, int r1, int r2); -void mulr_handler(Machine& m, int r1, int r2); -void rmo_handler(Machine& m, int r1, int r2); -void shiftl_handler(Machine& m, int r1, int n); -void shiftr_handler(Machine& m, int r1, int n); -void subr_handler(Machine& m, int r1, int r2); -void svc_handler(Machine& m, int n, int unused); -void tixr_handler(Machine& m, int r1, int unused); - - -// Type 3/4 instruction handlers -void add_handler(Machine& m, int ea, AddressingMode mode); -void addf_handler(Machine& m, int ea, AddressingMode mode); -void and_handler(Machine& m, int ea, AddressingMode mode); -void comp_handler(Machine& m, int ea, AddressingMode mode); -void compf_handler(Machine& m, int ea, AddressingMode mode); -void div_handler(Machine& m, int ea, AddressingMode mode); -void divf_handler(Machine& m, int ea, AddressingMode mode); -void j_handler(Machine& m, int ea, AddressingMode mode); -void jeq_handler(Machine& m, int ea, AddressingMode mode); -void jgt_handler(Machine& m, int ea, AddressingMode mode); -void jlt_handler(Machine& m, int ea, AddressingMode mode); -void jsub_handler(Machine& m, int ea, AddressingMode mode); -void lda_handler(Machine& m, int ea, AddressingMode mode); -void ldb_handler(Machine& m, int ea, AddressingMode mode); -void ldch_handler(Machine& m, int ea, AddressingMode mode); -void ldf_handler(Machine& m, int ea, AddressingMode mode); -void ldl_handler(Machine& m, int ea, AddressingMode mode); -void lds_handler(Machine& m, int ea, AddressingMode mode); -void ldt_handler(Machine& m, int ea, AddressingMode mode); -void ldx_handler(Machine& m, int ea, AddressingMode mode); -void lps_handler(Machine& m, int ea, AddressingMode mode); -void mul_handler(Machine& m, int ea, AddressingMode mode); -void mulf_handler(Machine& m, int ea, AddressingMode mode); -void or_handler(Machine& m, int ea, AddressingMode mode); -void rd_handler(Machine& m, int ea, AddressingMode mode); -void rsub_handler(Machine& m, int ea, AddressingMode mode); -void ssk_handler(Machine& m, int ea, AddressingMode mode); -void sta_handler(Machine& m, int ea, AddressingMode mode); -void stb_handler(Machine& m, int ea, AddressingMode mode); -void stch_handler(Machine& m, int ea, AddressingMode mode); -void stf_handler(Machine& m, int ea, AddressingMode mode); -void sti_handler(Machine& m, int ea, AddressingMode mode); -void stl_handler(Machine& m, int ea, AddressingMode mode); -void sts_handler(Machine& m, int ea, AddressingMode mode); -void stsw_handler(Machine& m, int ea, AddressingMode mode); -void stt_handler(Machine& m, int ea, AddressingMode mode); -void stx_handler(Machine& m, int ea, AddressingMode mode); -void sub_handler(Machine& m, int ea, AddressingMode mode); -void subf_handler(Machine& m, int ea, AddressingMode mode); -void td_handler(Machine& m, int ea, AddressingMode mode); -void tix_handler(Machine& m, int ea, AddressingMode mode); -void wd_handler(Machine& m, int ea, AddressingMode mode); - - -// SIC/XE/XE Extended instruction handlers -void xexe_handler(Machine& m); -void halt_handler(Machine& m); -void nop_handler(Machine& m); - -void vaddr_handler(Machine& m, int r1, int r2); -void vsubr_handler(Machine& m, int r1, int r2); -void vmulr_handler(Machine& m, int r1, int r2); -void vdivr_handler(Machine& m, int r1, int r2); - -void vadd_handler(Machine& m, int ea, AddressingMode mode); -void vsub_handler(Machine& m, int ea, AddressingMode mode); -void vmul_handler(Machine& m, int ea, AddressingMode mode); -void vdiv_handler(Machine& m, int ea, AddressingMode mode); -void stva_handler(Machine& m, int ea, AddressingMode mode); -void stvs_handler(Machine& m, int ea, AddressingMode mode); -void stvt_handler(Machine& m, int ea, AddressingMode mode); -void ldva_handler(Machine& m, int ea, AddressingMode mode); -void ldvs_handler(Machine& m, int ea, AddressingMode mode); -void ldvt_handler(Machine& m, int ea, AddressingMode mode); - - -#endif // INSTRUCTIONS_H \ No newline at end of file diff --git a/ass2/simulator_SIC_XE/include/loader.h b/ass2/simulator_SIC_XE/include/loader.h deleted file mode 100644 index 41899c2..0000000 --- a/ass2/simulator_SIC_XE/include/loader.h +++ /dev/null @@ -1,68 +0,0 @@ -#ifndef LOADER_H -#define LOADER_H - -#include -#include -#include -#include "file_reader.h" -#include - -class Machine; - -using std::shared_ptr; -using std::string; - - -class Loader { -public: - Loader( shared_ptr machine, string filename) : _machine(machine), _filename(filename) { - _file_reader = std::make_shared(filename, std::ios::in); - if (!_file_reader->good()) { - throw std::runtime_error("Loader: failed to open file: " + filename); - } - } - ~Loader(); - - - enum class RecordType { - HEADER, - TEXT, - END, - UNKNOWN - }; - - struct HeaderMetadata { - string program_name; - int start_address; - int length; - }; - struct TextRecord { - int start_address; - std::vector data; - }; - struct EndRecord { - int execution_start_address; - }; - - void load(); - -private : - - static RecordType parseRecordType(char c); - - - shared_ptr _machine; - string _filename; - shared_ptr _file_reader; - HeaderMetadata readHeader(); - TextRecord readTextRecord(); - EndRecord readEndRecord(); - bool load_into_memory(int start_address, const std::vector& data); - -}; - - - - - -#endif // LOADER_H \ No newline at end of file diff --git a/ass2/simulator_SIC_XE/include/machine.h b/ass2/simulator_SIC_XE/include/machine.h deleted file mode 100644 index cd14f74..0000000 --- a/ass2/simulator_SIC_XE/include/machine.h +++ /dev/null @@ -1,149 +0,0 @@ -#ifndef MACHINE_H -#define MACHINE_H - -#include -#include -#include -#include -#include -#include - - -#include "constants.h" -#include "device.h" -#include "input_device.h" -#include "output_device.h" -#include "file_device.h" -#include "opcode.h" -#include "utils.h" - -using std::string; -using std::cerr; -using std::endl; -using std::cout; - - -class Machine { -public: - Machine(); - Machine(int speedHz) : Machine() { this->speedHz = speedHz; _instructionsTable = instructions; } - ~Machine(); - - int getA() const { return A; } - void setA(int value) { A = toSIC24(value); } - - int getB() const { return B; } - void setB(int value) { B = toSIC24(value); } - - int getX() const { return X; } - void setX(int value) { X = toSIC24(value); } - - int getL() const { return L; } - void setL(int value) { L = toSIC24(value); } - - int getS() const { return S; } - void setS(int value) { S = toSIC24(value); } - - int getT() const { return T; } - void setT(int value) { T = toSIC24(value); } - - // PC is an address → don't mask to 24 unless you want 24-bit addressing - int getPC() const { return PC; } - void setPC(int value) { PC = value; } - - // status word: keep as-is - int getSW() const { return SW; } - void setSW(int value) { SW = value; } - - double getF() const { return F; } - void setF(double value) { F = value; } - - int getReg(int regNum) const; - void setReg(int regNum, int value); - - // Memory access methods - int getByte(int address); - void setByte(int address, int value); - - int getWord(int address); - void setWord(int address, int value); - - double getFloat(int address); - void setFloat(int address, double value); - - - // Device access methods - Device& getDevice(int num); - void setDevice(int num, std::shared_ptr device); - // Set a file device at index `num` using the provided filename. - void setFileDevice(int num, const std::string &filename); - - // Fetch and execute instructions - int fetch(); - void execute(); - - // Execution and speed control - int getSpeed() const; - void setSpeed(int Hz); - void start(); - void stop(); - void tick(); - void halt(); - bool isStopped() const { return _stopped; } - void reset(); - - // error handling methods - void notImplemented(string mnemonic); - void invalidOpcode(int opcode); - void invalidAddressing(); - void divisionByZero(int opcode); - void undefinedHandler(int opcode); - - bool getExtendedMode() const { return _exex_mode; } - void enableExtendedMode(); - void disableExtendedMode(); - - - int* getVectorRegister(int regNum); - void setVectorRegister(int regNum, const int* values); - - const int* getVA() const { return VA; } - const int* getVS() const { return VS; } - const int* getVT() const { return VT; } - void setVA(const int* values); - void setVS(const int* values); - void setVT(const int* values); - - -private: - // registers - int A, B, X, L, S, T, PC, SW; - double F; - - // memory - unsigned char memory[MEMORY_SIZE]; - - // devices - std::vector> devices; - // fallback device returned when device slot is empty/invalid - Device fallbackDevice; - - // Execution control - std::atomic running{false}; - std::atomic speedHz{10}; // Default 10 Hz - - bool execF1(int opcode); - bool execF2(int opcode, int operand); - bool execSICF3F4(int opcode, int ni, int x, int b, int p, int e, int operand); - - - // Extended mode - bool _stopped{false}; - bool _exex_mode{false}; - InstructionInfo* _instructionsTable; - int VA[VECTOR_REG_SIZE], VS[VECTOR_REG_SIZE], VT[VECTOR_REG_SIZE]; // vector operation registers -}; - - - -#endif // MACHINE_H \ No newline at end of file diff --git a/ass2/simulator_SIC_XE/include/opcode.h b/ass2/simulator_SIC_XE/include/opcode.h deleted file mode 100644 index a467488..0000000 --- a/ass2/simulator_SIC_XE/include/opcode.h +++ /dev/null @@ -1,116 +0,0 @@ -#ifndef OPCODE_H -#define OPCODE_H - -#include "utils.h" - -// ============================== -// Opcode definitions (SIC/XE) -// ============================== -#define ADD 0x18 -#define ADDF 0x58 -#define ADDR 0x90 -#define AND 0x40 -#define CLEAR 0xB4 -#define COMP 0x28 -#define COMPF 0x88 -#define COMPR 0xA0 -#define DIV 0x24 -#define DIVF 0x64 -#define DIVR 0x9C -#define FIX 0xC4 -#define FLOAT 0xC0 -#define HIO 0xF4 -#define J 0x3C -#define JEQ 0x30 -#define JGT 0x34 -#define JLT 0x38 -#define JSUB 0x48 -#define LDA 0x00 -#define LDB 0x68 -#define LDCH 0x50 -#define LDF 0x70 -#define LDL 0x08 -#define LDS 0x6C -#define LDT 0x74 -#define LDX 0x04 -#define LPS 0xD0 -#define MUL 0x20 -#define MULF 0x60 -#define MULR 0x98 -#define NORM 0xC8 -#define OR 0x44 -#define RD 0xD8 -#define RMO 0xAC -#define RSUB 0x4C -#define SHIFTL 0xA4 -#define SHIFTR 0xA8 -#define SIO 0xF0 -#define SSK 0xEC -#define STA 0x0C -#define STB 0x78 -#define STCH 0x54 -#define STF 0x80 -#define STI 0xD4 -#define STL 0x14 -#define STS 0x7C -#define STSW 0xE8 -#define STT 0x84 -#define STX 0x10 -#define SUB 0x1C -#define SUBF 0x5C -#define SUBR 0x94 -#define SVC 0xB0 -#define TD 0xE0 -#define TIO 0xF8 -#define TIX 0x2C -#define TIXR 0xB8 -#define WD 0xDC - -// ============================== -// Extended opcodes (SIC/XE/XE) -// ============================== -#define NOP 0xF1 -#define HALT 0xF2 -#define XEXE 0xEE // Enable extended mode -#define VADD 0x18 -#define VADDR 0x90 -#define VSUB 0x1C -#define VSUBR 0x94 -#define VMUL 0x20 -#define VMULR 0x98 -#define VDIV 0x24 -#define VDIVR 0x9C -#define STVA 0x0C -#define STVS 0x7C -#define STVT 0x84 -#define LDVA 0x00 -#define LDVS 0x68 -#define LDVT 0x04 - - - -enum class InstructionType { - TYPE1, - TYPE2, - TYPE3_4, - INVALID -}; - -class Machine; // forward - -// Store raw function pointer (void*) to allow different handler signatures -using RawHandler = void*; - -struct InstructionInfo { - const char* name; - InstructionType type; - RawHandler handler; -}; - -extern InstructionInfo instructions[]; -extern InstructionInfo instructionsEXEX[]; - -// Initialize the instruction table -void loadInstructionSet(); - -#endif // OPCODE_H diff --git a/ass2/simulator_SIC_XE/include/output_device.h b/ass2/simulator_SIC_XE/include/output_device.h deleted file mode 100644 index 94ba8b8..0000000 --- a/ass2/simulator_SIC_XE/include/output_device.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef OUTPUT_DEVICE_H -#define OUTPUT_DEVICE_H - -#include "device.h" -#include - -class OutputDevice : public Device { -public: - explicit OutputDevice(std::ostream &out); - ~OutputDevice(); - - void write(unsigned char value) override; - -private: - std::ostream &outStream; -}; - -#endif // OUTPUT_DEVICE_H \ No newline at end of file diff --git a/ass2/simulator_SIC_XE/include/reader.h b/ass2/simulator_SIC_XE/include/reader.h deleted file mode 100644 index e582161..0000000 --- a/ass2/simulator_SIC_XE/include/reader.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef READER_H -#define READER_H - -#include -#include - -// Abstract Reader class: read bytes/strings from a source (file, string, etc.) -class Reader { -public: - virtual ~Reader() = default; - // return 0..255 on success, -1 on EOF/error - virtual int readByte() = 0; - // read exactly len bytes into buf; return true on success - virtual bool readBytes(uint8_t* buf, size_t len) = 0; - // read up to len bytes into a std::string; may return shorter string on EOF - virtual std::string readString(size_t len) = 0; - // read a line (up to newline), return empty string on EOF - virtual std::string readLine() = 0; -}; - -#endif // READER_H \ No newline at end of file diff --git a/ass2/simulator_SIC_XE/include/string_reader.h b/ass2/simulator_SIC_XE/include/string_reader.h deleted file mode 100644 index 71c3da9..0000000 --- a/ass2/simulator_SIC_XE/include/string_reader.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef STRING_READER_H -#define STRING_READER_H - -#include "reader.h" -#include -#include - -class StringReader : public Reader { -public: - explicit StringReader(const std::string &s); - ~StringReader() override; - - int readByte() override; - bool readBytes(uint8_t* buf, size_t len) override; - std::string readString(size_t len) override; - std::string readLine() override; - -private: - std::istringstream in; -}; - -#endif // STRING_READER_H \ No newline at end of file diff --git a/ass2/simulator_SIC_XE/include/utils.h b/ass2/simulator_SIC_XE/include/utils.h deleted file mode 100644 index 3197a95..0000000 --- a/ass2/simulator_SIC_XE/include/utils.h +++ /dev/null @@ -1,95 +0,0 @@ -#ifndef UTILS_H -#define UTILS_H - -#include "constants.h" - -#include - -// ============================== -// SIC/XE Utility Functions -// ============================== - -// Instruction bit extraction utilities -inline int getXBit(int b2) { - return (b2 & 0x80) ? 1 : 0; -} - -inline int getBPBits(int b2) { - return (b2 >> 5) & 0x03; -} - -enum class AddressingMode { - IMMEDIATE, - INDIRECT, - SIMPLE, - SIC_DIRECT, - INVALID -}; - -// Get addressing mode from ni bits -AddressingMode getAddressingMode(int ni); - - -// convert to signed 24-bit integer -inline int toSIC24(int value) { - value &= 0xFFFFFF; - if (value & 0x800000) { - value -= 0x1000000; - } - return value; -} - -inline int setCC(int sw, int cc) { - sw &= ~CC_MASK; - sw |= (cc & CC_MASK); - return sw; -} - -inline int sic_comp(int a, int b, int sw) { - int sa = toSIC24(a); - int sb = toSIC24(b); - - int cc; - if (sa < sb) { - cc = CC_LT; - } else if (sa == sb) { - cc = CC_EQ; - } else { - cc = CC_GT; - } - - return setCC(sw, cc); -} - -inline int sic_comp(double a, double b, int sw) { - int cc; - if (a < b) { - cc = CC_LT; - } else if (a == b) { - cc = CC_EQ; - } else { - cc = CC_GT; - } - - return setCC(sw, cc); -} - - -inline int getCC(int sw) { - return sw & CC_MASK; -} - -inline double normaliseFloat(double value) -{ - if (value == 0.0 )return 0.0; - if (!std::isfinite(value)) return value; - double mantissa = value; - while (std::fabs(mantissa) >= 10.0) mantissa /= 10.0; - while (std::fabs(mantissa) < 1.0) mantissa *= 10.0; - return mantissa; -} - - - - -#endif // UTILS_H \ No newline at end of file diff --git a/ass2/simulator_SIC_XE/src/device.cpp b/ass2/simulator_SIC_XE/src/device.cpp deleted file mode 100644 index 87ab0d7..0000000 --- a/ass2/simulator_SIC_XE/src/device.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "device.h" - -Device::Device() -{ -} - -bool Device::test() -{ - return true; -} - -unsigned char Device::read() -{ - return 0; -} - -void Device::write(unsigned char value) -{ -} diff --git a/ass2/simulator_SIC_XE/src/file_device.cpp b/ass2/simulator_SIC_XE/src/file_device.cpp deleted file mode 100644 index 781a9b6..0000000 --- a/ass2/simulator_SIC_XE/src/file_device.cpp +++ /dev/null @@ -1,68 +0,0 @@ -#include "file_device.h" -#include -#include - -FileDevice::FileDevice(const std::string &filename) - : filename(filename), fileCreated(false), readPosition(0) -{ -} - -FileDevice::~FileDevice() -{ - if (fileStream.is_open()) { - fileStream.close(); - } -} - -void FileDevice::ensureFileOpen() -{ - if (!fileStream.is_open()) { - // Check if file exists - std::ifstream checkFile(filename); - bool fileExists = checkFile.good(); - checkFile.close(); - - if (fileExists) { - fileStream.open(filename, std::ios::in | std::ios::out | std::ios::ate); - fileCreated = true; - } else { - // Create new file - std::ofstream create(filename); - if (!create) { - throw std::runtime_error("Failed to create file: " + filename); - } - create.close(); - fileCreated = true; - - fileStream.open(filename, std::ios::in | std::ios::out); - if (!fileStream.is_open()) { - throw std::runtime_error("Failed to open file after creating: " + filename); - } - } - } -} - -unsigned char FileDevice::read() -{ - unsigned char value = 0; - ensureFileOpen(); - if (fileStream.is_open()) { - fileStream.seekg(readPosition); - char ch; - if (fileStream.get(ch)) { - value = static_cast(ch); - readPosition = fileStream.tellg(); - } - } - return value; -} - -void FileDevice::write(unsigned char value) -{ - ensureFileOpen(); - if (fileStream.is_open()) { - fileStream.seekp(0, std::ios::end); - fileStream.put(static_cast(value)); - fileStream.flush(); - } -} \ No newline at end of file diff --git a/ass2/simulator_SIC_XE/src/file_reader.cpp b/ass2/simulator_SIC_XE/src/file_reader.cpp deleted file mode 100644 index 2a800cc..0000000 --- a/ass2/simulator_SIC_XE/src/file_reader.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include "file_reader.h" - -FileReader::FileReader(const std::string &path, std::ios::openmode m) - : in(path, m) -{} - -FileReader::~FileReader() = default; - -int FileReader::readByte() { - char c; - if (!in.get(c)) return -1; - return static_cast(c); -} - - -bool FileReader::readBytes(uint8_t* buf, size_t len) { - in.read(reinterpret_cast(buf), static_cast(len)); - return static_cast(in.gcount()) == len; -} - -std::string FileReader::readString(size_t len) { - std::string s; - s.resize(len); - in.read(reinterpret_cast(&s[0]), static_cast(len)); - std::streamsize got = in.gcount(); - if (static_cast(got) < len) s.resize(static_cast(got)); - return s; -} - -bool FileReader::good() const { return static_cast(in); } - -std::string FileReader::readLine() { - std::string s; - if (!std::getline(in, s)) return std::string(); - return s; -} diff --git a/ass2/simulator_SIC_XE/src/input_device.cpp b/ass2/simulator_SIC_XE/src/input_device.cpp deleted file mode 100644 index 340c721..0000000 --- a/ass2/simulator_SIC_XE/src/input_device.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "input_device.h" - -InputDevice::InputDevice(std::istream &in) - : inStream(in) -{ -} - -InputDevice::~InputDevice() -{ -} - -unsigned char InputDevice::read() -{ - char c; - if (!inStream.get(c)) { - // If stream is at EOF or error, return 0 - return 0; - } - return static_cast(c); -} \ No newline at end of file diff --git a/ass2/simulator_SIC_XE/src/instructions.cpp b/ass2/simulator_SIC_XE/src/instructions.cpp deleted file mode 100644 index a1c4e55..0000000 --- a/ass2/simulator_SIC_XE/src/instructions.cpp +++ /dev/null @@ -1,603 +0,0 @@ -#include "instructions.h" -#include "machine.h" -#include "utils.h" - -inline int resolveWordOperand(Machine& m, int ea, AddressingMode mode) -{ - switch (mode) - { - case AddressingMode::IMMEDIATE: return ea; - case AddressingMode::SIMPLE: - case AddressingMode::SIC_DIRECT: return m.getWord(ea); - case AddressingMode::INDIRECT: return m.getWord(m.getWord(ea)); - default: m.invalidAddressing(); return 0; - } -} - -inline double resolveFloatOperand(Machine& m, int ea, AddressingMode mode) -{ - switch (mode) - { - case AddressingMode::IMMEDIATE: return static_cast(ea); - case AddressingMode::SIMPLE: - case AddressingMode::SIC_DIRECT: return m.getFloat(ea); - case AddressingMode::INDIRECT: return m.getFloat(m.getWord(ea)); - default: m.invalidAddressing(); return 0.0; - } -} - - -inline void writeWordOperand(Machine& m, int ea, AddressingMode mode, int value) -{ - switch (mode) - { - case AddressingMode::SIMPLE: - case AddressingMode::SIC_DIRECT: m.setWord(ea, value); break; // direct store - case AddressingMode::INDIRECT: m.setWord(m.getWord(ea), value); break; // store via pointer - default: m.invalidAddressing(); break; - } -} - -inline void writeFloatOperand(Machine& m, int ea, AddressingMode mode, double value) -{ - switch (mode) - { - case AddressingMode::SIMPLE: - case AddressingMode::SIC_DIRECT: m.setFloat(ea, value); break; - case AddressingMode::INDIRECT: m.setFloat(m.getWord(ea), value); break; - default: m.invalidAddressing(); break; - } -} - - -// For jump-like ops: what PC should become? -inline int resolveJumpTarget(Machine& m, int ea, AddressingMode mode) -{ - switch (mode) - { - case AddressingMode::IMMEDIATE: - case AddressingMode::SIMPLE: - case AddressingMode::SIC_DIRECT: return ea; // jump to EA (normal case) - case AddressingMode::INDIRECT: return m.getWord(ea); // jump via pointer - default: m.invalidAddressing(); return m.getPC(); - } -} - -void fix_handler(Machine &m) -{ - m.setA(static_cast(m.getF())); -} - -void float_handler(Machine &m) -{ - m.setF(static_cast(m.getA())); -} - -void norm_handler(Machine &m) -{ - m.setF(normaliseFloat(m.getF())); -} - -void addr_handler(Machine &m, int r1, int r2) -{ - m.setReg(r2, m.getReg(r1) + m.getReg(r2)); -} - -void clear_handler(Machine& m, int r, int unused) { - m.setReg(r, 0); -} - -void compr_handler(Machine &m, int r1, int r2) -{ - m.setSW(sic_comp(m.getReg(r1), m.getReg(r2), m.getSW())); -} - -void divr_handler(Machine& m, int r1, int r2) { - - if (m.getReg(r2) == 0) { - m.invalidOpcode(DIVR); - return; - } - m.setReg(r2, m.getReg(r2) / m.getReg(r1)); -} - -void mulr_handler(Machine &m, int r1, int r2) -{ - m.setReg(r2, m.getReg(r1) * m.getReg(r2)); -} - -void rmo_handler(Machine &m, int r1, int r2) -{ - m.setReg(r2, m.getReg(r1)); -} - - -// SHIFTL r1, n → left *circular* shift n bits -void shiftl_handler(Machine &m, int r1, int n) -{ - unsigned int v = m.getReg(r1) & WORD_MASK; - n %= WORD_SIZE; - unsigned int res = ((v << n) | (v >> (WORD_SIZE - n))) & WORD_MASK; - m.setReg(r1, res); -} - -// SHIFTR r1, n → right shift n bits, fill with original leftmost bit -void shiftr_handler(Machine &m, int r1, int n) -{ - unsigned int v = m.getReg(r1) & WORD_MASK; - n %= WORD_SIZE; - unsigned int msb = (v & 0x800000) ? 1u : 0u; - unsigned int shifted = v >> n; - unsigned int fill = 0; - if (msb) { - fill = (~0u) << (WORD_SIZE - n); - fill &= WORD_MASK; - } - - unsigned int res = (shifted | fill) & WORD_MASK; - m.setReg(r1, res); -} - -void subr_handler(Machine &m, int r1, int r2) -{ - m.setReg(r2, m.getReg(r2) - m.getReg(r1)); -} - -// TODO: implement SVC functionality -void svc_handler(Machine &m, int n, int unused) -{ - m.notImplemented("SVC"); -} - -void tixr_handler(Machine &m, int r1, int unused) -{ - m.setX(m.getX() + 1); - int valX = m.getX(); - int valR1 = m.getReg(r1); - m.setSW(sic_comp(valX, valR1, m.getSW())); -} - -void add_handler(Machine &m, int ea, AddressingMode mode) -{ - int val = resolveWordOperand(m, ea, mode); - m.setA(m.getA() + val); -} - -void addf_handler(Machine &m, int ea, AddressingMode mode) -{ - double val = resolveFloatOperand(m, ea, mode); - m.setA(m.getA() + val); -} - -void and_handler(Machine &m, int ea, AddressingMode mode) -{ - int val = resolveWordOperand(m, ea, mode); - m.setA(m.getA() & val); -} - -void comp_handler(Machine &m, int ea, AddressingMode mode) -{ - int operand = resolveWordOperand(m, ea, mode); - m.setSW(sic_comp(m.getA(), operand, m.getSW())); -} - -void compf_handler(Machine &m, int ea, AddressingMode mode) -{ - double operand = resolveFloatOperand(m, ea, mode); - m.setSW(sic_comp(m.getF(), operand, m.getSW())); -} - -void div_handler(Machine &m, int ea, AddressingMode mode) -{ - int divisor = resolveWordOperand(m, ea, mode); - if (divisor == 0) { - m.divisionByZero(DIV); - return; - } - m.setA(m.getA() / divisor); -} - -void divf_handler(Machine &m, int ea, AddressingMode mode) -{ - double divisor = resolveFloatOperand(m, ea, mode); - if (divisor == 0.0) { - m.divisionByZero(DIVF); - return; - } - m.setF(m.getF() / divisor); -} - -void j_handler(Machine &m, int ea, AddressingMode mode) -{ - int target = resolveJumpTarget(m, ea, mode); - - int instrSize = 3; - int instrAddr = m.getPC() - instrSize; - // Check if jumping to itself (halt pattern) - if (target == instrAddr) { - m.halt(); - } - - m.setPC(target); -} - -void jeq_handler(Machine &m, int ea, AddressingMode mode) -{ - int sw = m.getSW(); - int cc = getCC(sw); - if (cc == CC_EQ) { - int target = resolveJumpTarget(m, ea, mode); - m.setPC(target); - } -} - -void jgt_handler(Machine &m, int ea, AddressingMode mode) -{ - int sw = m.getSW(); - int cc = getCC(sw); - if (cc == CC_GT) { - int target = resolveJumpTarget(m, ea, mode); - m.setPC(target); - } -} - -void jlt_handler(Machine &m, int ea, AddressingMode mode) -{ - int sw = m.getSW(); - int cc = getCC(sw); - if (cc == CC_LT) { - int target = resolveJumpTarget(m, ea, mode); - m.setPC(target); - } -} - -void jsub_handler(Machine &m, int ea, AddressingMode mode) -{ - int target = resolveJumpTarget(m, ea, mode); - m.setL(m.getPC()); - m.setPC(target); -} - -void lda_handler(Machine& m, int ea, AddressingMode mode) -{ - m.setA(resolveWordOperand(m, ea, mode)); -} - -void ldb_handler(Machine &m, int ea, AddressingMode mode) -{ - m.setB(resolveWordOperand(m, ea, mode)); -} - -void ldch_handler(Machine &m, int ea, AddressingMode mode) -{ - int val; - if (mode == AddressingMode::IMMEDIATE) { - val = ea & 0xFF; - } else if (mode == AddressingMode::INDIRECT) { - val = m.getByte(m.getWord(ea)); - } else { - val = m.getByte(ea); - } - m.setA((m.getA() & 0xFFFF00) | (val & 0xFF)); -} - -void ldf_handler(Machine &m, int ea, AddressingMode mode) -{ - m.setF(resolveFloatOperand(m, ea, mode)); -} - -void ldl_handler(Machine &m, int ea, AddressingMode mode) -{ - m.setL(resolveWordOperand(m, ea, mode)); -} - -void lds_handler(Machine &m, int ea, AddressingMode mode) -{ - m.setS(resolveWordOperand(m, ea, mode)); -} - -void ldt_handler(Machine &m, int ea, AddressingMode mode) -{ - m.setT(resolveWordOperand(m, ea, mode)); -} - -void ldx_handler(Machine &m, int ea, AddressingMode mode) -{ - m.setX(resolveWordOperand(m, ea, mode)); -} - -void mul_handler(Machine &m, int ea, AddressingMode mode) -{ - int val = resolveWordOperand(m, ea, mode); - m.setA(m.getA() * val); -} - -void mulf_handler(Machine &m, int ea, AddressingMode mode) -{ - m.setF(m.getF() * resolveFloatOperand(m, ea, mode)); -} - -void or_handler(Machine &m, int ea, AddressingMode mode) -{ - int val = resolveWordOperand(m, ea, mode); - m.setA(m.getA() | val); -} - -void rd_handler(Machine &m, int ea, AddressingMode mode) -{ - int deviceNum = resolveWordOperand(m, ea, mode); - Device& device = m.getDevice(deviceNum); - // Load byte into rightmost byte of A register - m.setA((m.getA() & 0xFFFF00) | device.read()); -} - -void rsub_handler(Machine &m, int ea, AddressingMode mode) -{ - m.setPC(m.getL()); -} - -void sta_handler(Machine &m, int ea, AddressingMode mode) -{ - writeWordOperand(m, ea, mode, m.getA()); -} - -void stb_handler(Machine &m, int ea, AddressingMode mode) -{ - writeWordOperand(m, ea, mode, m.getB()); -} -// Rightmost byte of A register is stored -void stch_handler(Machine &m, int ea, AddressingMode mode) -{ - int val = m.getA() & 0xFF; - switch (mode) - { - case AddressingMode::SIMPLE: - case AddressingMode::SIC_DIRECT: m.setByte(ea, val); break; // direct store - case AddressingMode::INDIRECT: m.setByte(m.getWord(ea), val); break; // store via pointer - default: m.invalidAddressing(); break; - } -} - -void stf_handler(Machine &m, int ea, AddressingMode mode) -{ - writeFloatOperand(m, ea, mode, m.getF()); -} - -void stl_handler(Machine &m, int ea, AddressingMode mode) -{ - writeWordOperand(m, ea, mode, m.getL()); -} - -void sts_handler(Machine &m, int ea, AddressingMode mode) -{ - writeWordOperand(m, ea, mode, m.getS()); -} - -void stsw_handler(Machine &m, int ea, AddressingMode mode) -{ - writeWordOperand(m, ea, mode, m.getSW()); -} - -void stt_handler(Machine &m, int ea, AddressingMode mode) -{ - writeWordOperand(m, ea, mode, m.getT()); -} - -void stx_handler(Machine &m, int ea, AddressingMode mode) -{ - writeWordOperand(m, ea, mode, m.getX()); -} - -void sub_handler(Machine &m, int ea, AddressingMode mode) -{ - int val = resolveWordOperand(m, ea, mode); - m.setA(m.getA() - val); -} - -void subf_handler(Machine &m, int ea, AddressingMode mode) -{ - double val = resolveFloatOperand(m, ea, mode); - m.setF(m.getF() - val); -} - -void td_handler(Machine &m, int ea, AddressingMode mode) -{ - int deviceNum = resolveWordOperand(m, ea, mode); - Device& device = m.getDevice(deviceNum); - // Test device and set SW accordingly - if (device.test()) { - m.setSW(setCC(m.getSW(), CC_EQ)); - } else { - m.setSW(setCC(m.getSW(), CC_LT)); - } -} - -void tix_handler(Machine &m, int ea, AddressingMode mode) -{ - m.setX(m.getX() + 1); - int valX = m.getX(); - int memVal = resolveWordOperand(m, ea, mode); - m.setSW(sic_comp(valX, memVal, m.getSW())); -} - -void wd_handler(Machine &m, int ea, AddressingMode mode) -{ - int deviceNum = resolveWordOperand(m, ea, mode); - Device& device = m.getDevice(deviceNum); - // Write rightmost byte of A register to device - device.write(static_cast(m.getA() & 0xFF)); -} - -void xexe_handler(Machine &m) -{ - m.enableExtendedMode(); - m.execute(); - m.disableExtendedMode(); -} - -void halt_handler(Machine &m) -{ - m.halt(); -} - -void nop_handler(Machine &m) -{ - // Do nothing -} - -void vaddr_handler(Machine &m, int r1, int r2) -{ - int result[VECTOR_REG_SIZE]; - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - result[i] = m.getVectorRegister(r1)[i] + m.getVectorRegister(r2)[i]; - } - m.setVectorRegister(r2, result); -} - -void vsubr_handler(Machine &m, int r1, int r2) -{ - int result[VECTOR_REG_SIZE]; - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - result[i] = m.getVectorRegister(r2)[i] - m.getVectorRegister(r1)[i]; - } - m.setVectorRegister(r2, result); -} - -void vmulr_handler(Machine &m, int r1, int r2) -{ - int result[VECTOR_REG_SIZE]; - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - result[i] = m.getVectorRegister(r1)[i] * m.getVectorRegister(r2)[i]; - } - m.setVectorRegister(r2, result); -} - -void vdivr_handler(Machine &m, int r1, int r2) -{ - int result[VECTOR_REG_SIZE]; - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - if (m.getVectorRegister(r1)[i] == 0) { - m.divisionByZero(VDIVR); - return; - } - result[i] = m.getVectorRegister(r2)[i] / m.getVectorRegister(r1)[i]; - } - m.setVT(result); -} - -void vadd_handler(Machine &m, int ea, AddressingMode mode) -{ - int baseAddr = resolveWordOperand(m, ea, mode); - int vec[VECTOR_REG_SIZE]; - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - vec[i] = m.getWord(baseAddr + i * 3); - } - int result[VECTOR_REG_SIZE]; - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - result[i] = m.getVA()[i] + vec[i]; - } - m.setVA(result); -} - -void vsub_handler(Machine &m, int ea, AddressingMode mode) -{ - int baseAddr = resolveWordOperand(m, ea, mode); - int vec[VECTOR_REG_SIZE]; - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - vec[i] = m.getWord(baseAddr + i * 3); - } - int result[VECTOR_REG_SIZE]; - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - result[i] = m.getVA()[i] - vec[i]; - } - m.setVA(result); -} - -void vmul_handler(Machine &m, int ea, AddressingMode mode) -{ - int baseAddr = resolveWordOperand(m, ea, mode); - int vec[VECTOR_REG_SIZE]; - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - vec[i] = m.getWord(baseAddr + i * 3); - } - int result[VECTOR_REG_SIZE]; - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - result[i] = m.getVA()[i] * vec[i]; - } - m.setVA(result); -} - -void vdiv_handler(Machine &m, int ea, AddressingMode mode) -{ - int baseAddr = resolveWordOperand(m, ea, mode); - int vec[VECTOR_REG_SIZE]; - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - vec[i] = m.getWord(baseAddr + i * 3); - } - int result[VECTOR_REG_SIZE]; - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - if (vec[i] == 0) { - m.divisionByZero(VDIV); - return; - } - result[i] = m.getVA()[i] / vec[i]; - } - m.setVA(result); -} - -void stva_handler(Machine &m, int ea, AddressingMode mode) -{ - int baseAddr = resolveWordOperand(m, ea, mode); - const int* vec = m.getVA(); - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - m.setWord(baseAddr + i * 3, vec[i]); - } -} - -void stvs_handler(Machine &m, int ea, AddressingMode mode) -{ - int baseAddr = resolveWordOperand(m, ea, mode); - const int* vec = m.getVS(); - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - m.setWord(baseAddr + i * 3, vec[i]); - } -} - -void stvt_handler(Machine &m, int ea, AddressingMode mode) -{ - int baseAddr = resolveWordOperand(m, ea, mode); - const int* vec = m.getVT(); - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - m.setWord(baseAddr + i * 3, vec[i]); - } -} - -void ldva_handler(Machine &m, int ea, AddressingMode mode) -{ - int baseAddr = resolveWordOperand(m, ea, mode); - int vec[VECTOR_REG_SIZE]; - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - vec[i] = m.getWord(baseAddr + i * 3); - } - m.setVA(vec); -} - -void ldvs_handler(Machine &m, int ea, AddressingMode mode) -{ - int baseAddr = resolveWordOperand(m, ea, mode); - int vec[VECTOR_REG_SIZE]; - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - vec[i] = m.getWord(baseAddr + i * 3); - } - m.setVS(vec); -} - -void ldvt_handler(Machine &m, int ea, AddressingMode mode) -{ - int baseAddr = resolveWordOperand(m, ea, mode); - int vec[VECTOR_REG_SIZE]; - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - vec[i] = m.getWord(baseAddr + i * 3); - } - m.setVT(vec); -} diff --git a/ass2/simulator_SIC_XE/src/loader.cpp b/ass2/simulator_SIC_XE/src/loader.cpp deleted file mode 100644 index 8d3aa17..0000000 --- a/ass2/simulator_SIC_XE/src/loader.cpp +++ /dev/null @@ -1,134 +0,0 @@ -#include "loader.h" -#include "file_reader.h" -#include "string_reader.h" -#include "machine.h" -#include "constants.h" -#include -#include - -Loader::~Loader() -{ - _machine.reset(); -} - - - - -void Loader::load() -{ - HeaderMetadata header = readHeader(); - - while(true) { - RecordType type = parseRecordType(static_cast(_file_reader->readByte())); - switch (type) { - case RecordType::TEXT: { - TextRecord textRecord = readTextRecord(); - if (!load_into_memory(textRecord.start_address, textRecord.data)) { - throw std::runtime_error("Failed to load text record into memory"); - } - break; - } - case RecordType::END: { - EndRecord endRecord = readEndRecord(); - _machine->setPC(endRecord.execution_start_address); - return; // Loading complete - } - case RecordType::UNKNOWN: - default: - throw std::runtime_error("Unknown record type encountered"); - } - } -} - -Loader::RecordType Loader::parseRecordType(char c) -{ - switch (c) { - case 'H': return RecordType::HEADER; - case 'T': return RecordType::TEXT; - case 'E': return RecordType::END; - default: return RecordType::UNKNOWN; // fallback; adjust as needed - } -} - -Loader::HeaderMetadata Loader::readHeader() -{ - - RecordType type = parseRecordType(static_cast(_file_reader->readByte())); - if (type != RecordType::HEADER) { - throw std::runtime_error("Expected HEADER record"); - } - if(FILE_CONTAINS_WHITE_SPACES) _file_reader->readByte(); - - HeaderMetadata header; - // Read program name (6 bytes) - header.program_name = _file_reader->readString(6); - if(FILE_CONTAINS_WHITE_SPACES) _file_reader->readByte(); - - // Read start address (6 hex digits) - header.start_address = std::stoi(_file_reader->readString(6), nullptr, 16); - if(FILE_CONTAINS_WHITE_SPACES) _file_reader->readByte(); - - // Read length (6 hex digits) - header.length = std::stoi(_file_reader->readString(6), nullptr, 16); - // consume newline - _file_reader->readLine(); - return header; -} - -Loader::TextRecord Loader::readTextRecord() -{ - if(FILE_CONTAINS_WHITE_SPACES) _file_reader->readByte(); - TextRecord record; - // Assume 'T' has already been read - record.start_address = std::stoi(_file_reader->readString(6), nullptr, 16); - if(FILE_CONTAINS_WHITE_SPACES) _file_reader->readByte(); - - // Read length (1 byte, 2 hex digits) - std::string lengthStr = _file_reader->readString(2); - int length = std::stoi(lengthStr, nullptr, 16); - - // Read the rest of the line (data bytes with spaces) - std::string dataLine = _file_reader->readLine(); - - // Remove all whitespace from the data line - dataLine.erase(std::remove_if(dataLine.begin(), dataLine.end(), ::isspace), dataLine.end()); - - // Now use StringReader to parse the hex bytes - StringReader stringReader(dataLine); - record.data.resize(length); - - for (int i = 0; i < length; ++i) { - std::string byteHex = stringReader.readString(2); - record.data[i] = static_cast(std::stoi(byteHex, nullptr, 16)); - } - - return record; -} - -Loader::EndRecord Loader::readEndRecord() -{ - EndRecord record; - if(FILE_CONTAINS_WHITE_SPACES) _file_reader->readByte(); - // Assume 'E' has already been read - std::string addrStr = _file_reader->readString(6); - if (!addrStr.empty()) { - record.execution_start_address = std::stoi(addrStr, nullptr, 16); - } else { - record.execution_start_address = 0; - } - // consume newline - _file_reader->readLine(); - return record; -} - -bool Loader::load_into_memory(int start_address, const std::vector &data) -{ - for(size_t i = 0; i < data.size(); ++i) { - int addr = start_address + static_cast(i); - if (addr < 0 || addr >= MEMORY_SIZE) { - return false; - } - _machine->setByte(addr, data[i]); - } - return true; -} diff --git a/ass2/simulator_SIC_XE/src/machine.cpp b/ass2/simulator_SIC_XE/src/machine.cpp deleted file mode 100644 index d8d0356..0000000 --- a/ass2/simulator_SIC_XE/src/machine.cpp +++ /dev/null @@ -1,525 +0,0 @@ -#include "machine.h" - -#include - -#include "opcode.h" -#include "instructions.h" -#include -#include - -using std::make_shared; - -string prefix = "Machine error: "; - - -Machine::Machine() -{ - // Initialize registers and memory to zero - A = B = X = L = S = T = PC = SW = 0; - F = 0.0; - for (int i = 0; i < MEMORY_SIZE; i++) { - memory[i] = 0; - } - for (int i = 0; i < VECTOR_REG_SIZE; i++) { - VA[i] = VS[i] = VT[i] = 0; - } - _stopped = false; - - devices.resize(NUM_DEVICES); - // device 0: standard input - devices[0] = make_shared(std::cin); - // device 1: standard output - devices[1] = make_shared(std::cout); - - // Initialize devices >= 2 as FileDevice with hex names in devices directory - for (int i = 2; i < NUM_DEVICES; i++) { - char hex[3]; - snprintf(hex, sizeof(hex), "%02X", i); - std::string filename = "devices/" + std::string(hex) + ".dev"; - try { - devices[i] = std::make_shared(filename); - } catch (const std::exception &e) { - cerr << prefix << "Warning: Failed to initialize FileDevice for device " << i << ": " << e.what() << endl; - } - } - - _exex_mode = false; - _instructionsTable = instructions; -} - -Machine::~Machine() -{ - for (auto& device : devices) { - device.reset(); - } -} - -int Machine::getSpeed() const -{ - return speedHz.load(); -} - -void Machine::setSpeed(int Hz) -{ - speedHz.store(Hz); -} - -// TODO: implement errors -void Machine::notImplemented(string mnemonic) -{ - cout << prefix << "Not implemented: " << mnemonic << endl; -} - -void Machine::invalidOpcode(int opcode) -{ - cout << prefix << "Invalid opcode: " << opcode << endl; -} - - -void Machine::invalidAddressing() -{ - cout << prefix << "Invalid addressing mode" << endl; -} - -void Machine::divisionByZero(int opcode) -{ - cout << prefix << "Division by zero error in opcode: " << opcode << endl; -} - -void Machine::undefinedHandler(int opcode) -{ - cout << prefix << "Undefined handler for opcode: " << opcode << endl; -} - -void Machine::enableExtendedMode() -{ - if(!USE_EXTENDED_MODE) return; - _exex_mode = true; - _instructionsTable = instructionsEXEX; -} - -void Machine::disableExtendedMode() -{ - if(!USE_EXTENDED_MODE) return; - _exex_mode = false; - _instructionsTable = instructions; -} - -int *Machine::getVectorRegister(int regNum) -{ - switch (regNum) { - case 0: return VA; - case 4: return VS; - case 5: return VT; - default: - cerr << prefix << "Invalid register number: " << regNum << endl; - return nullptr; - } -} - -void Machine::setVectorRegister(int regNum, const int *values) -{ - int* targetReg = getVectorRegister(regNum); - if (targetReg == nullptr) return; - for (int i = 0; i < VECTOR_REG_SIZE; i++) { - targetReg[i] = toSIC24(values[i]); - } -} - -void Machine::setVA(const int *values) -{ - for (int i = 0; i < VECTOR_REG_SIZE; i++) { - VA[i] = toSIC24(values[i]); - } -} - -void Machine::setVS(const int *values) -{ - for (int i = 0; i < VECTOR_REG_SIZE; i++) { - VS[i] = toSIC24(values[i]); - } -} - -void Machine::setVT(const int *values) -{ - for (int i = 0; i < VECTOR_REG_SIZE; i++) { - VT[i] = toSIC24(values[i]); - } -} - -void Machine::tick() -{ - const int speed = speedHz.load(); - if (speed <= 0) throw std::runtime_error("Invalid speed setting in Machine::tick"); - - const auto delay = std::chrono::milliseconds(1000 / speed); - std::this_thread::sleep_for(delay); -} - -void Machine::halt() -{ - _stopped = true; -} - -void Machine::reset() -{ - // Reset all registers - A = B = X = L = S = T = PC = SW = 0; - F = 0.0; - - // Clear memory - for (int i = 0; i < MEMORY_SIZE; i++) { - memory[i] = 0; - } - - // Reset execution state - _stopped = false; - running.store(false); - - // Reset vector registers - for (int i = 0; i < VECTOR_REG_SIZE; i++) { - VA[i] = VS[i] = VT[i] = 0; - } -} - -int Machine::getReg(int regNum) const -{ - switch (regNum) { - case 0: return A; - case 1: return X; - case 2: return L; - case 3: return B; - case 4: return S; - case 5: return T; - case 6: return F; - case 8: return PC; - case 9: return SW; - default: - cerr << prefix << "Invalid register number: " << regNum << endl; - return -1; - } -} - -// TODO: handle double for F register -void Machine::setReg(int regNum, int value) -{ - value = toSIC24(value); - switch (regNum) { - case 0: A = value; break; - case 1: X = value; break; - case 2: L = value; break; - case 3: B = value; break; - case 4: S = value; break; - case 5: T = value; break; - case 6: F = value; break; - case 8: PC = value; break; - case 9: SW = value; break; - default: - cerr << prefix << "Invalid register number: " << regNum << endl; - break; - } -} - -int Machine::getByte(int address) -{ - if (address < 0 || address >= MEMORY_SIZE) { - cerr << prefix << "Invalid memory address: " << address << endl; - return -1; - } - return static_cast(memory[address]); -} - -void Machine::setByte(int address, int value) -{ - if(address < 0 || address >= MEMORY_SIZE) { - cerr << prefix << "Invalid memory address: " << address << endl; - return; - } - - memory[address] = static_cast(value); -} - -// Assuming word is 3 bytes - -int Machine::getWord(int address) -{ - if (address < 0 || address + 2 >= MEMORY_SIZE) { - cerr << prefix << "Invalid memory address: " << address << endl; - return -1; - } - // Big-endian: high byte first - return (static_cast(memory[address]) << 16) | (static_cast(memory[address + 1]) << 8) | static_cast(memory[address + 2]); -} - -// Assuming word is 3 bytes -void Machine::setWord(int address, int value) -{ - if(address < 0 || address + 2 >= MEMORY_SIZE) { - cerr << prefix << "Invalid memory address: " << address << endl; - return; - } - value &= 0xFFFFFF; - - // Big-endian: high byte first - memory[address] = static_cast((value >> 16) & 0xFF); - memory[address + 1] = static_cast((value >> 8) & 0xFF); - memory[address + 2] = static_cast(value & 0xFF); -} - -double Machine::getFloat(int address) -{ - if (address < 0 || address + 5 >= MEMORY_SIZE) { - cerr << prefix << "Invalid float address: " << address << endl; - return 0.0; - } - - // load 6 bytes, big-endian → 48-bit word - unsigned long long raw = - ((unsigned long long)memory[address] << 40) | - ((unsigned long long)memory[address+1] << 32) | - ((unsigned long long)memory[address+2] << 24) | - ((unsigned long long)memory[address+3] << 16) | - ((unsigned long long)memory[address+4] << 8) | - (unsigned long long)memory[address+5]; - - int sign = (raw >> 47) & 0x1; - int exponent = (raw >> 40) & 0x7F; - unsigned long long frac = raw & SICF_FRAC_MASK; // 40 bits - - if (raw == 0) return 0.0; - - // value = (1 + frac/2^40) * 2^(exp - 64) - double mant = 1.0 + (double)frac / (double)(1ULL << SICF_FRAC_BITS); - int e = exponent - SICF_EXP_BIAS; - double val = std::ldexp(mant, e); // ldexp is fast enough here - return sign ? -val : val; -} - -void Machine::setFloat(int address, double value) -{ - if (address < 0 || address + 5 >= MEMORY_SIZE) { - cerr << prefix << "Invalid float address: " << address << endl; - return; - } - - if (value == 0.0) { - memory[address] = 0; - memory[address+1] = 0; - memory[address+2] = 0; - memory[address+3] = 0; - memory[address+4] = 0; - memory[address+5] = 0; - return; - } - - int sign = value < 0; - double x = sign ? -value : value; - - // normalize x to [1, 2) - int exp2 = 0; - x = std::frexp(x, &exp2); - x *= 2.0; - exp2 -= 1; - - int exp_field = exp2 + SICF_EXP_BIAS; - if (exp_field < 0) exp_field = 0; - if (exp_field > 127) exp_field = 127; - - // mantissa = (x - 1) * 2^40 - double frac_d = (x - 1.0) * (double)(1ULL << SICF_FRAC_BITS); - unsigned long long frac = (unsigned long long)(frac_d + 0.5); // round - frac &= SICF_FRAC_MASK; - - unsigned long long raw = - ((unsigned long long)sign << 47) | - ((unsigned long long)exp_field << 40) | - frac; - - // store 6 bytes big-endian - memory[address] = (unsigned char)((raw >> 40) & 0xFF); - memory[address+1] = (unsigned char)((raw >> 32) & 0xFF); - memory[address+2] = (unsigned char)((raw >> 24) & 0xFF); - memory[address+3] = (unsigned char)((raw >> 16) & 0xFF); - memory[address+4] = (unsigned char)((raw >> 8) & 0xFF); - memory[address+5] = (unsigned char)( raw & 0xFF); -} - - - -Device &Machine::getDevice(int num) -{ - if(num < 0 || num >= static_cast(devices.size()) || !devices[num]) { - cerr << prefix << "Invalid device number: " << num << endl; - return fallbackDevice; - } - return *devices[num]; -} - -void Machine::setDevice(int num, std::shared_ptr device) -{ - if(num < 0 || num >= NUM_DEVICES) { - cerr << prefix << "Invalid device number: " << num << endl; - return; - } - if(static_cast(devices.size()) != NUM_DEVICES) { - devices.resize(NUM_DEVICES); - } - // Enforce: devices with index >= 2 must be FileDevice instances - if (num >= 2) { - // try dynamic cast - if (std::dynamic_pointer_cast(device) == nullptr) { - cerr << prefix << "Device at index " << num << " must be a FileDevice." << endl; - return; - } - } - devices[num] = device; -} - -void Machine::setFileDevice(int num, const std::string &filename) -{ - if(num < 0 || num >= NUM_DEVICES) { - cerr << prefix << "Invalid device number: " << num << endl; - return; - } - if(static_cast(devices.size()) != NUM_DEVICES) { - devices.resize(NUM_DEVICES); - } - try { - devices[num] = std::make_shared(filename); - } catch (const std::exception &e) { - cerr << prefix << "Failed to create FileDevice for index " << num << ": " << e.what() << endl; - } -} - -int Machine::fetch() -{ - return getByte(PC++); -} - -void Machine::execute() { - if (_stopped) return; - - int b1 = fetch(); - - InstructionInfo &info = _instructionsTable[b1]; - - if (info.type == InstructionType::TYPE1) { execF1(b1); return; } - if (info.type == InstructionType::TYPE2) { execF2(b1, fetch()); return; } - - int opcode = b1 & TYPE3_4_SIC_MASK; - InstructionInfo &info34 = _instructionsTable[opcode]; - int ni = b1 & NI_MASK; - - if (info34.type == InstructionType::TYPE3_4) { - int b2 = fetch(), b3 = fetch(); - int x = (b2 & 0x80) ? 1 : 0; - int b = (b2 & 0x40) ? 1 : 0; - int p = (b2 & 0x20) ? 1 : 0; - int e = (b2 & 0x10) ? 1 : 0; - - int operand; - if (ni == NI_SIC) { - // PURE SIC - operand = ((b2 & 0x7F) << 8) | b3; - } else { - // SIC/XE - operand = e - ? (((b2 & 0x0F) << 16) | (b3 << 8) | fetch()) // F4: 20-bit - : (((b2 & 0x0F) << 8) | b3); // F3: 12-bit - } - - execSICF3F4(opcode, ni, x, b, p, e, operand); - return; - } - - invalidOpcode(b1); -} - - - - -bool Machine::execF1(int opcode) -{ - if (_instructionsTable[opcode].handler) { - auto handler = reinterpret_cast(_instructionsTable[opcode].handler); - handler(*this); - return true; - } - undefinedHandler(opcode); - return false; -} - -bool Machine::execF2(int opcode, int operand) -{ - int r1 = (operand >> 4) & 0xF; - int r2 = operand & 0xF; - - if (_instructionsTable[opcode].handler) { - auto handler = reinterpret_cast(_instructionsTable[opcode].handler); - handler(*this, r1, r2); - return true; - } - undefinedHandler(opcode); - return false; -} - - -bool Machine::execSICF3F4(int opcode, int ni, int x, int b, int p, int e, int operand) -{ - int ea_part = operand; - int base = 0; - AddressingMode mode = getAddressingMode(ni); - - // --- PURE SIC --- - if (mode == AddressingMode::SIC_DIRECT) { - int ea = ea_part + (x ? getX() : 0); - if (_instructionsTable[opcode].handler) { - auto h = reinterpret_cast(_instructionsTable[opcode].handler); - h(*this, ea, mode); - return true; - } - undefinedHandler(opcode); - return false; - } - - // --- SIC/XE EA calc --- - - if (!e) { // format 3 - if (b && !p) { - base = getB(); // base-relative, unsigned 12-bit - } else if (p && !b) { - // PC-relative, signed 12-bit - if (ea_part & 0x800) // bit 11 set? - ea_part |= 0xFFFFF000; // sign-extend - base = getPC(); - } - } - // format 4 (e=1): b/p ignored, ea_part is 20-bit absolute - int ea = base + ea_part + (x ? getX() : 0); - - if (_instructionsTable[opcode].handler) { - auto h = reinterpret_cast(_instructionsTable[opcode].handler); - h(*this, ea, mode); - return true; - } - - undefinedHandler(opcode); - return false; -} - -void Machine::start() -{ - running.store(true); - - // Main execution loop - // TODO: consider running in separate thread - while (running.load()) { - execute(); - tick(); - } -} - -void Machine::stop() -{ - running.store(false); -} diff --git a/ass2/simulator_SIC_XE/src/main.cpp b/ass2/simulator_SIC_XE/src/main.cpp deleted file mode 100644 index 433a3f1..0000000 --- a/ass2/simulator_SIC_XE/src/main.cpp +++ /dev/null @@ -1,140 +0,0 @@ -#include -#include -#include -#include "machine.h" -#include "file_device.h" -#include "opcode.h" -#include "instructions.h" -#include "constants.h" -#include "loader.h" - -using std::cout; -using std::endl; - -struct VectorAddProgram { - int x, y; -}; - - - -int main() -{ - /* - loadInstructionSet(); - Machine machine; - cout << "SIC/XE Program: Accumulator Loop" << endl; - - const int TEMP_ADDR = 0x50; - const int LOOP_ADDR = 0x03; - - // clear TEMP - machine.setByte(TEMP_ADDR, 0); - loadInstructionSet(); - - cout << "SIC/XE Program: Vector add test" << endl; - - const int VA_ADDR = 0x100; // source vector A - const int VB_ADDR = 0x200; // source vector B - const int VR_ADDR = 0x300; // result store (STVA) - - // Prepare two 4-element vectors (WORD = 3 bytes) for VA and VB - int a_vals[VECTOR_REG_SIZE] = {1,2,3,4}; - int b_vals[VECTOR_REG_SIZE] = {5,6,7,8}; - - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - machine.setWord(VA_ADDR + i * 3, a_vals[i]); - machine.setWord(VB_ADDR + i * 3, b_vals[i]); - } - - // Assemble program at address 0x000 (we use XEXE before each extended op) - // Offsets and bytes (hex): - // 0x00: XEXE -> 0xEE - // 0x01: LDVA (format 4) -> b1=0x03 (LDVA|ni=0x00|0x03), b2=0x10 (e=1), b3=0x01, b4=0x00 (addr 0x100) - // 0x05: XEXE -> 0xEE - // 0x06: LDVS (format 4) -> b1=0x6B (0x68|0x03), b2=0x10, b3=0x02, b4=0x00 (addr 0x200) - // 0x0A: XEXE -> 0xEE - // 0x0B: VADDR B->A (type 2) -> opcode 0x90, operand r1=4 (VS), r2=0 (VA) => operand=(4<<4)|0=0x40 - // 0x0D: XEXE -> 0xEE - // 0x0E: STVA (format4) -> b1=0x0F (0x0C|0x03), b2=0x10, b3=0x03, b4=0x00 (addr 0x300) - // 0x12: J (format4) to self -> b1=0x3F (0x3C|0x03), b2=0x10, b3=0x00, b4=0x12 - - unsigned char prog[] = { - 0xEE, - 0x01, 0x10, 0x01, 0x00, // LDVA (format 4) with ni=IMMEDIATE -> b1=0x01 - 0xEE, - 0x69, 0x10, 0x02, 0x00, // LDVS (format 4) with ni=IMMEDIATE -> b1=0x69 (0x68|0x01) - 0xEE, - 0x90, 0x40, // VADDR VS->VA (type2) - 0xEE, - 0x0D, 0x10, 0x03, 0x00, // STVA (format4) with ni=IMMEDIATE -> b1=0x0D - 0x3F, 0x10, 0x00, 0x12 // J (format4) loop to 0x12 - }; - - const int PROG_START = 0x00; - for (size_t i = 0; i < sizeof(prog); ++i) { - machine.setByte(PROG_START + static_cast(i), prog[i]); - } - - machine.setPC(PROG_START); - - cout << "Program loaded. VA@0x" << std::hex << VA_ADDR << " VB@0x" << VB_ADDR << " -> store@0x" << VR_ADDR << std::dec << endl; - - - const int MAX_STEPS = 100; - for (int i = 0; i < MAX_STEPS; ++i) { - machine.execute(); - } - - // Read back result vector stored at VR_ADDR - cout << "Result vector at 0x" << std::hex << VR_ADDR << std::dec << ": "; - for (int i = 0; i < VECTOR_REG_SIZE; ++i) { - int val = machine.getWord(VR_ADDR + i * 3); - cout << val << (i + 1 < VECTOR_REG_SIZE ? ", " : "\n"); - } - */ - - loadInstructionSet(); - std::shared_ptr machine = std::make_shared(); - Loader loader(machine, std::string(PATH_RESOURCES) + "rec.obj"); - loader.load(); - - cout << "=== Starting execution of rec.obj ===" << endl; - cout << "Initial PC: 0x" << std::hex << machine->getPC() << std::dec << endl; - - int maxSteps = 10000; - for (int step = 0; step < maxSteps; step++) { - int pc = machine->getPC(); - int opcode = machine->getByte(pc) & 0xFC; - const char* instName = (opcode < 256 && instructions[opcode].type != InstructionType::INVALID) - ? instructions[opcode].name : "???"; - - int regA = machine->getA(); - int regB = machine->getB(); - int regX = machine->getX(); - int regL = machine->getL(); - int sw = machine->getSW(); - - printf("Step %4d: PC=0x%05X %-6s A=0x%06X B=0x%06X X=0x%06X L=0x%06X SW=0x%06X\n", - step, pc, instName, regA, regB, regX, regL, sw); - - machine->execute(); - - if (machine->isStopped()) { - cout << "Machine halted at step " << step << endl; - break; - } - - if (step > 100 && machine->getPC() == pc) { - cout << "ERROR: Infinite loop detected at PC=0x" << std::hex << pc << std::dec << endl; - break; - } - } - - cout << "\n=== Final state ===" << endl; - cout << "A: " << machine->getA() << endl; - cout << "B: " << machine->getB() << endl; - cout << "X: " << machine->getX() << endl; - - - return 0; -} \ No newline at end of file diff --git a/ass2/simulator_SIC_XE/src/opcode.cpp b/ass2/simulator_SIC_XE/src/opcode.cpp deleted file mode 100644 index 0b63ce8..0000000 --- a/ass2/simulator_SIC_XE/src/opcode.cpp +++ /dev/null @@ -1,109 +0,0 @@ -#include "opcode.h" -#include "instructions.h" -#include "utils.h" -#include - -InstructionInfo instructions[0xff]; -InstructionInfo instructionsEXEX[0xff]; - -void loadInstructionSet() -{ - instructions[ADD] = {"ADD", InstructionType::TYPE3_4, reinterpret_cast(add_handler)}; - instructions[ADDF] = {"ADDF", InstructionType::TYPE3_4, reinterpret_cast(addf_handler)}; - instructions[ADDR] = {"ADDR", InstructionType::TYPE2, reinterpret_cast(addr_handler)}; - instructions[AND] = {"AND", InstructionType::TYPE3_4, reinterpret_cast(and_handler)}; - instructions[CLEAR] = {"CLEAR", InstructionType::TYPE2, reinterpret_cast(clear_handler)}; - instructions[COMP] = {"COMP", InstructionType::TYPE3_4, reinterpret_cast(comp_handler)}; - instructions[COMPF] = {"COMPF", InstructionType::TYPE3_4, reinterpret_cast(compf_handler)}; - instructions[COMPR] = {"COMPR", InstructionType::TYPE2, reinterpret_cast(compr_handler)}; - instructions[DIV] = {"DIV", InstructionType::TYPE3_4, reinterpret_cast(div_handler)}; - instructions[DIVF] = {"DIVF", InstructionType::TYPE3_4, reinterpret_cast(divf_handler)}; - instructions[DIVR] = {"DIVR", InstructionType::TYPE2, reinterpret_cast(divr_handler)}; - instructions[FIX] = {"FIX", InstructionType::TYPE1, reinterpret_cast(fix_handler)}; - instructions[FLOAT] = {"FLOAT", InstructionType::TYPE1, reinterpret_cast(float_handler)}; - instructions[HIO] = {"HIO", InstructionType::TYPE1, nullptr}; - instructions[J] = {"J", InstructionType::TYPE3_4, reinterpret_cast(j_handler)}; - instructions[JEQ] = {"JEQ", InstructionType::TYPE3_4, reinterpret_cast(jeq_handler)}; - instructions[JGT] = {"JGT", InstructionType::TYPE3_4, reinterpret_cast(jgt_handler)}; - instructions[JLT] = {"JLT", InstructionType::TYPE3_4, reinterpret_cast(jlt_handler)}; - instructions[JSUB] = {"JSUB", InstructionType::TYPE3_4, reinterpret_cast(jsub_handler)}; - instructions[LDA] = {"LDA", InstructionType::TYPE3_4, reinterpret_cast(lda_handler)}; - instructions[LDB] = {"LDB", InstructionType::TYPE3_4, reinterpret_cast(ldb_handler)}; - instructions[LDCH] = {"LDCH", InstructionType::TYPE3_4, reinterpret_cast(ldch_handler)}; - instructions[LDF] = {"LDF", InstructionType::TYPE3_4, reinterpret_cast(ldf_handler)}; - instructions[LDL] = {"LDL", InstructionType::TYPE3_4, reinterpret_cast(ldl_handler)}; - instructions[LDS] = {"LDS", InstructionType::TYPE3_4, reinterpret_cast(lds_handler)}; - instructions[LDT] = {"LDT", InstructionType::TYPE3_4, reinterpret_cast(ldt_handler)}; - instructions[LDX] = {"LDX", InstructionType::TYPE3_4, reinterpret_cast(ldx_handler)}; - instructions[LPS] = {"LPS", InstructionType::TYPE3_4, nullptr}; - instructions[MUL] = {"MUL", InstructionType::TYPE3_4, reinterpret_cast(mul_handler)}; - instructions[MULF] = {"MULF", InstructionType::TYPE3_4, reinterpret_cast(mulf_handler)}; - instructions[MULR] = {"MULR", InstructionType::TYPE2, reinterpret_cast(mulr_handler)}; - instructions[NORM] = {"NORM", InstructionType::TYPE1, reinterpret_cast(norm_handler)}; - instructions[OR] = {"OR", InstructionType::TYPE3_4, reinterpret_cast(or_handler)}; - instructions[RD] = {"RD", InstructionType::TYPE3_4, reinterpret_cast(rd_handler)}; - instructions[RMO] = {"RMO", InstructionType::TYPE2, reinterpret_cast(rmo_handler)}; - instructions[RSUB] = {"RSUB", InstructionType::TYPE3_4, reinterpret_cast(rsub_handler)}; - instructions[SHIFTL] = {"SHIFTL", InstructionType::TYPE2, reinterpret_cast(shiftl_handler)}; - instructions[SHIFTR] = {"SHIFTR", InstructionType::TYPE2, reinterpret_cast(shiftr_handler)}; - instructions[SIO] = {"SIO", InstructionType::TYPE1, nullptr}; - instructions[SSK] = {"SSK", InstructionType::TYPE3_4, nullptr}; - instructions[STA] = {"STA", InstructionType::TYPE3_4, reinterpret_cast(sta_handler)}; - instructions[STB] = {"STB", InstructionType::TYPE3_4, reinterpret_cast(stb_handler)}; - instructions[STCH] = {"STCH", InstructionType::TYPE3_4, reinterpret_cast(stch_handler)}; - instructions[STF] = {"STF", InstructionType::TYPE3_4, reinterpret_cast(stf_handler)}; - instructions[STI] = {"STI", InstructionType::TYPE3_4, nullptr}; - instructions[STL] = {"STL", InstructionType::TYPE3_4, reinterpret_cast(stl_handler)}; - instructions[STS] = {"STS", InstructionType::TYPE3_4, reinterpret_cast(sts_handler)}; - instructions[STSW] = {"STSW", InstructionType::TYPE3_4, reinterpret_cast(stsw_handler)}; - instructions[STT] = {"STT", InstructionType::TYPE3_4, reinterpret_cast(stt_handler)}; - instructions[STX] = {"STX", InstructionType::TYPE3_4, reinterpret_cast(stx_handler)}; - instructions[SUB] = {"SUB", InstructionType::TYPE3_4, reinterpret_cast(sub_handler)}; - instructions[SUBF] = {"SUBF", InstructionType::TYPE3_4, reinterpret_cast(subf_handler)}; - instructions[SUBR] = {"SUBR", InstructionType::TYPE2, reinterpret_cast(subr_handler)}; - instructions[SVC] = {"SVC", InstructionType::TYPE2, reinterpret_cast(svc_handler)}; - instructions[TIXR] = {"TIXR", InstructionType::TYPE2, reinterpret_cast(tixr_handler)}; - instructions[TD] = {"TD", InstructionType::TYPE3_4, reinterpret_cast(td_handler)}; - instructions[TIX] = {"TIX", InstructionType::TYPE3_4, reinterpret_cast(tix_handler)}; - instructions[TIO] = {"TIO", InstructionType::TYPE1, nullptr}; - instructions[WD] = {"WD", InstructionType::TYPE3_4, reinterpret_cast(wd_handler)}; - - // Load SIC/XE/XE extended instructions - if (USE_EXTENDED_MODE) { - // Still in main table - instructions[NOP] = {"NOP", InstructionType::TYPE1, reinterpret_cast(nop_handler)}; - instructions[HALT] = {"HALT", InstructionType::TYPE1, reinterpret_cast(halt_handler)}; - instructions[XEXE] = {"XEXE", InstructionType::TYPE1, reinterpret_cast(xexe_handler)}; - - instructionsEXEX[VADD] = {"VADD", InstructionType::TYPE3_4, reinterpret_cast(vadd_handler)}; - instructionsEXEX[VADDR] = {"VADDR", InstructionType::TYPE2, reinterpret_cast(vaddr_handler)}; - instructionsEXEX[VSUB] = {"VSUB", InstructionType::TYPE3_4, reinterpret_cast(vsub_handler)}; - instructionsEXEX[VSUBR] = {"VSUBR", InstructionType::TYPE2, reinterpret_cast(vsubr_handler)}; - instructionsEXEX[VMUL] = {"VMUL", InstructionType::TYPE3_4, reinterpret_cast(vmul_handler)}; - instructionsEXEX[VMULR] = {"VMULR", InstructionType::TYPE2, reinterpret_cast(vmulr_handler)}; - instructionsEXEX[VDIV] = {"VDIV", InstructionType::TYPE3_4, reinterpret_cast(vdiv_handler)}; - instructionsEXEX[VDIVR] = {"VDIVR", InstructionType::TYPE2, reinterpret_cast(vdivr_handler)}; - instructionsEXEX[STVA] = {"STVA", InstructionType::TYPE3_4, reinterpret_cast(stva_handler)}; - instructionsEXEX[STVS] = {"STVS", InstructionType::TYPE3_4, reinterpret_cast(stvs_handler)}; - instructionsEXEX[STVT] = {"STVT", InstructionType::TYPE3_4, reinterpret_cast(stvt_handler)}; - instructionsEXEX[LDVA] = {"LDVA", InstructionType::TYPE3_4, reinterpret_cast(ldva_handler)}; - instructionsEXEX[LDVS] = {"LDVS", InstructionType::TYPE3_4, reinterpret_cast(ldvs_handler)}; - instructionsEXEX[LDVT] = {"LDVT", InstructionType::TYPE3_4, reinterpret_cast(ldvt_handler)}; - } - // Mark uninitialized opcodes as INVALID - for (int i = 0; i < 0xff; ++i) { - if (instructions[i].name == nullptr) instructions[i] = {"INVALID", InstructionType::INVALID, nullptr}; - if (instructionsEXEX[i].name == nullptr) instructionsEXEX[i] = {"INVALID", InstructionType::INVALID, nullptr}; - } -} - -AddressingMode getAddressingMode(int ni) -{ - switch (ni) { - case 0x0: return AddressingMode::SIC_DIRECT; - case 0x1: return AddressingMode::IMMEDIATE; - case 0x2: return AddressingMode::INDIRECT; - case 0x3: return AddressingMode::SIMPLE; - default: return AddressingMode::INVALID; // Should not happen - } -} diff --git a/ass2/simulator_SIC_XE/src/output_device.cpp b/ass2/simulator_SIC_XE/src/output_device.cpp deleted file mode 100644 index ce7b4ec..0000000 --- a/ass2/simulator_SIC_XE/src/output_device.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "output_device.h" - -OutputDevice::OutputDevice(std::ostream &out) - : outStream(out) -{ -} - -OutputDevice::~OutputDevice() -{ -} - -void OutputDevice::write(unsigned char value) -{ - outStream.put(static_cast(value)); - outStream.flush(); -} diff --git a/ass2/simulator_SIC_XE/src/string_reader.cpp b/ass2/simulator_SIC_XE/src/string_reader.cpp deleted file mode 100644 index b87cc02..0000000 --- a/ass2/simulator_SIC_XE/src/string_reader.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "string_reader.h" - -StringReader::StringReader(const std::string &s) - : in(s) -{} - -StringReader::~StringReader() = default; - -int StringReader::readByte() { - char c; - if (!in.get(c)) return -1; - return static_cast(c); -} - -bool StringReader::readBytes(uint8_t* buf, size_t len) { - in.read(reinterpret_cast(buf), static_cast(len)); - return static_cast(in.gcount()) == len; -} - -std::string StringReader::readString(size_t len) { - std::string s; - s.resize(len); - in.read(reinterpret_cast(&s[0]), static_cast(len)); - std::streamsize got = in.gcount(); - if (static_cast(got) < len) s.resize(static_cast(got)); - return s; -} - -std::string StringReader::readLine() { - std::string s; - if (!std::getline(in, s)) return std::string(); - return s; -} diff --git a/simulator_SIC_XE/CMakeLists.txt b/simulator_SIC_XE/CMakeLists.txt index c6c37e1..e06a422 100644 --- a/simulator_SIC_XE/CMakeLists.txt +++ b/simulator_SIC_XE/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.10) project(simulator_SIC_XE VERSION 1.0 LANGUAGES CXX) -set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) # Put all build outputs under target/bin @@ -13,6 +13,10 @@ 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") +list(REMOVE_ITEM SOURCES ${MAIN_SRC}) + if(NOT SOURCES) message(WARNING "No source files found in ${PROJECT_SOURCE_DIR}/src — the build will create an empty library") endif() diff --git a/simulator_SIC_XE/devices/FA.dev b/simulator_SIC_XE/devices/FA.dev new file mode 100644 index 0000000..cb6e5ed --- /dev/null +++ b/simulator_SIC_XE/devices/FA.dev @@ -0,0 +1,2 @@ +5 +0 diff --git a/simulator_SIC_XE/gui/qt/mainwindow.cpp b/simulator_SIC_XE/gui/qt/mainwindow.cpp index b53aa72..b3d7525 100644 --- a/simulator_SIC_XE/gui/qt/mainwindow.cpp +++ b/simulator_SIC_XE/gui/qt/mainwindow.cpp @@ -5,7 +5,7 @@ #include "../../include/instructions.h" #include "../../include/opcode.h" #include "../../include/constants.h" -#include "../../../include/loader.h" +#include "../../include/loader.h" #include #include diff --git a/simulator_SIC_XE/include/code.h b/simulator_SIC_XE/include/code.h new file mode 100644 index 0000000..6a0c9b7 --- /dev/null +++ b/simulator_SIC_XE/include/code.h @@ -0,0 +1,26 @@ +#ifndef CODE_H +#define CODE_H + +#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; + +private: + std::vector> _lines; +}; + + + +#endif // CODE_H \ No newline at end of file diff --git a/simulator_SIC_XE/include/lexer.h b/simulator_SIC_XE/include/lexer.h new file mode 100644 index 0000000..f9bdd70 --- /dev/null +++ b/simulator_SIC_XE/include/lexer.h @@ -0,0 +1,55 @@ +#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/mnemonic.h b/simulator_SIC_XE/include/mnemonic.h new file mode 100644 index 0000000..3cdddab --- /dev/null +++ b/simulator_SIC_XE/include/mnemonic.h @@ -0,0 +1,45 @@ +// 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 new file mode 100644 index 0000000..2ad0d86 --- /dev/null +++ b/simulator_SIC_XE/include/node.h @@ -0,0 +1,98 @@ +#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 a467488..1034473 100644 --- a/simulator_SIC_XE/include/opcode.h +++ b/simulator_SIC_XE/include/opcode.h @@ -3,6 +3,10 @@ #include "utils.h" +#include +#include +#include + // ============================== // Opcode definitions (SIC/XE) // ============================== @@ -87,6 +91,8 @@ #define LDVS 0x68 #define LDVT 0x04 +static std::unordered_map mnemonicToOpcode; +static bool opcodeTablesInitialized = false; enum class InstructionType { @@ -110,6 +116,10 @@ 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 new file mode 100644 index 0000000..8ae126a --- /dev/null +++ b/simulator_SIC_XE/include/parser.h @@ -0,0 +1,52 @@ +// 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/src/code.cpp b/simulator_SIC_XE/src/code.cpp new file mode 100644 index 0000000..0db062a --- /dev/null +++ b/simulator_SIC_XE/src/code.cpp @@ -0,0 +1,20 @@ +#include "code.h" + +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; +} diff --git a/simulator_SIC_XE/src/lexer.cpp b/simulator_SIC_XE/src/lexer.cpp new file mode 100644 index 0000000..7ac9344 --- /dev/null +++ b/simulator_SIC_XE/src/lexer.cpp @@ -0,0 +1,138 @@ +#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/node.cpp b/simulator_SIC_XE/src/node.cpp new file mode 100644 index 0000000..c0b52fd --- /dev/null +++ b/simulator_SIC_XE/src/node.cpp @@ -0,0 +1,120 @@ +#include "node.h" +#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 0b63ce8..fcda0c4 100644 --- a/simulator_SIC_XE/src/opcode.cpp +++ b/simulator_SIC_XE/src/opcode.cpp @@ -95,8 +95,36 @@ void loadInstructionSet() 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) { diff --git a/simulator_SIC_XE/src/parser.cpp b/simulator_SIC_XE/src/parser.cpp new file mode 100644 index 0000000..c5bf939 --- /dev/null +++ b/simulator_SIC_XE/src/parser.cpp @@ -0,0 +1,449 @@ +// 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 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", 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/ass1/cat.asm b/vhod_izhod/cat.asm similarity index 99% rename from ass1/cat.asm rename to vhod_izhod/cat.asm index 6bb74d4..32b9908 100644 --- a/ass1/cat.asm +++ b/vhod_izhod/cat.asm @@ -3,7 +3,6 @@ cat START 0 CLEAR X - read RD #0 STCH BUFF, X