From 3332b2971bacbdd0653b56c4504c55f8319f19f2 Mon Sep 17 00:00:00 2001 From: zanostro Date: Tue, 11 Nov 2025 11:03:25 +0100 Subject: [PATCH] created sicxe emulator project --- simulator_SIC_XE/.gitignore | 95 +++++++++ simulator_SIC_XE/CMakeLists.txt | 45 ++++ simulator_SIC_XE/README.md | 52 +++++ simulator_SIC_XE/include/device.h | 16 ++ simulator_SIC_XE/include/file_device.h | 19 ++ simulator_SIC_XE/include/input_device.h | 18 ++ simulator_SIC_XE/include/instructions.h | 20 ++ simulator_SIC_XE/include/machine.h | 145 +++++++++++++ simulator_SIC_XE/include/opcode.h | 100 +++++++++ simulator_SIC_XE/include/output_device.h | 18 ++ simulator_SIC_XE/src/device.cpp | 19 ++ simulator_SIC_XE/src/file_device.cpp | 45 ++++ simulator_SIC_XE/src/input_device.cpp | 20 ++ simulator_SIC_XE/src/instructions.cpp | 60 ++++++ simulator_SIC_XE/src/machine.cpp | 261 +++++++++++++++++++++++ simulator_SIC_XE/src/main.cpp | 27 +++ simulator_SIC_XE/src/opcode.cpp | 75 +++++++ simulator_SIC_XE/src/output_device.cpp | 16 ++ 18 files changed, 1051 insertions(+) create mode 100644 simulator_SIC_XE/.gitignore create mode 100644 simulator_SIC_XE/CMakeLists.txt create mode 100644 simulator_SIC_XE/README.md create mode 100644 simulator_SIC_XE/include/device.h create mode 100644 simulator_SIC_XE/include/file_device.h create mode 100644 simulator_SIC_XE/include/input_device.h create mode 100644 simulator_SIC_XE/include/instructions.h create mode 100644 simulator_SIC_XE/include/machine.h create mode 100644 simulator_SIC_XE/include/opcode.h create mode 100644 simulator_SIC_XE/include/output_device.h create mode 100644 simulator_SIC_XE/src/device.cpp create mode 100644 simulator_SIC_XE/src/file_device.cpp create mode 100644 simulator_SIC_XE/src/input_device.cpp create mode 100644 simulator_SIC_XE/src/instructions.cpp create mode 100644 simulator_SIC_XE/src/machine.cpp create mode 100644 simulator_SIC_XE/src/main.cpp create mode 100644 simulator_SIC_XE/src/opcode.cpp create mode 100644 simulator_SIC_XE/src/output_device.cpp diff --git a/simulator_SIC_XE/.gitignore b/simulator_SIC_XE/.gitignore new file mode 100644 index 0000000..6b70294 --- /dev/null +++ b/simulator_SIC_XE/.gitignore @@ -0,0 +1,95 @@ +# Build directories +build/ +target/ + +# CMake generated files +CMakeCache.txt +CMakeFiles/ +CMakeScripts/ +cmake_install.cmake +Makefile +*.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 + +# 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/simulator_SIC_XE/CMakeLists.txt b/simulator_SIC_XE/CMakeLists.txt new file mode 100644 index 0000000..242ebd3 --- /dev/null +++ b/simulator_SIC_XE/CMakeLists.txt @@ -0,0 +1,45 @@ +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 as requested +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() + +# Convenience target: `cmake --build build --target run` +# This target will build `simulator_exec` (if present) and then execute it. +if(TARGET simulator_exec) + add_custom_target(run + DEPENDS simulator_exec + COMMAND ${CMAKE_COMMAND} -E echo "Running simulator_exec..." + COMMAND $ + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + COMMENT "Builds and runs simulator_exec" + ) +endif() + +message(STATUS "Project: ${PROJECT_NAME}") +message(STATUS "Sources found: ${SOURCES}") +message(STATUS "Output directory: ${OUTPUT_DIR}") diff --git a/simulator_SIC_XE/README.md b/simulator_SIC_XE/README.md new file mode 100644 index 0000000..9842788 --- /dev/null +++ b/simulator_SIC_XE/README.md @@ -0,0 +1,52 @@ +# 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 run` | Build and run the simulator | +| `make clean` | Clean build artifacts | + +## Project Structure + +``` +simulator_SIC_XE/ +├── include/ # Header files (.h) +├── src/ # Source files (.cpp) +├── target/bin/ # Build output (executables, libraries) +└── build/ # CMake build directory +``` + +## Features + +- **SIC/XE Architecture**: Complete register set (A, X, L, B, S, T, F, PC, SW) +- **Instruction Execution**: Format 1, 2, and 3/4 instruction support +- **Device I/O**: Input, output, and file device management +- **Memory Management**: 24-bit address space with proper bounds checking + +## Development + +The project uses CMake with a convenient Makefile wrapper. All build artifacts are placed in `target/bin/` for easy access. + +For manual CMake usage: +```bash +cmake -S . -B build -DCMAKE_BUILD_TYPE=Release +cmake --build build -j +``` diff --git a/simulator_SIC_XE/include/device.h b/simulator_SIC_XE/include/device.h new file mode 100644 index 0000000..6b5acb7 --- /dev/null +++ b/simulator_SIC_XE/include/device.h @@ -0,0 +1,16 @@ +#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/simulator_SIC_XE/include/file_device.h b/simulator_SIC_XE/include/file_device.h new file mode 100644 index 0000000..e98bfc6 --- /dev/null +++ b/simulator_SIC_XE/include/file_device.h @@ -0,0 +1,19 @@ +#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: + std::fstream fileStream; +}; + +#endif // FILE_DEVICE_H \ No newline at end of file diff --git a/simulator_SIC_XE/include/input_device.h b/simulator_SIC_XE/include/input_device.h new file mode 100644 index 0000000..40b01d3 --- /dev/null +++ b/simulator_SIC_XE/include/input_device.h @@ -0,0 +1,18 @@ +#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/simulator_SIC_XE/include/instructions.h b/simulator_SIC_XE/include/instructions.h new file mode 100644 index 0000000..ff2e532 --- /dev/null +++ b/simulator_SIC_XE/include/instructions.h @@ -0,0 +1,20 @@ +#ifndef INSTRUCTIONS_H +#define INSTRUCTIONS_H + +#include "opcode.h" + +// Type 2 instruction handlers +void addr_handler(Machine& m, int r1, int r2); +void clear_handler(Machine& m, int r, int unused); +void 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); + + + +#endif // INSTRUCTIONS_H \ No newline at end of file diff --git a/simulator_SIC_XE/include/machine.h b/simulator_SIC_XE/include/machine.h new file mode 100644 index 0000000..e0920da --- /dev/null +++ b/simulator_SIC_XE/include/machine.h @@ -0,0 +1,145 @@ +#ifndef MACHINE_H +#define MACHINE_H + +#include +#include +#include + +#include "device.h" +#include "input_device.h" +#include "output_device.h" +#include "file_device.h" +#include "opcode.h" + +#include + +#define MEMORY_SIZE 65536 +#define NUM_DEVICES 256 + + +using std::string; +using std::cerr; +using std::endl; +using std::cout; + + +class Machine { +public: + Machine(); + ~Machine(); + + // Accessor methods for registers + int getA() const { return A; } + void setA(int value) { A = value; } + + int getB() const { return B; } + void setB(int value) { B = value; } + + int getX() const { return X; } + void setX(int value) { X = value; } + + int getL() const { return L; } + void setL(int value) { L = value; } + + int getS() const { return S; } + void setS(int value) { S = value; } + + int getT() const { return T; } + void setT(int value) { T = value; } + + int getPC() const { return PC; } + void setPC(int value) { PC = value; } + + 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(); + + bool execF1(int opcode); + bool execF2(int opcode, int operand); + bool execSICF3F4(int opcode, int ni, int operand); + + // error handling methods + void notImplemented(string mnemonic); + void invalidOpcode(int opcode); + void invalidAddressing(); + void divisionByZero(int opcode); + void undefinedHandler(int opcode); + +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; +}; + + // Convert integer to 24-bit signed SIC representation +inline int toSIC24(int value) { + value &= 0xFFFFFF; + if (value & 0x800000) { + value -= 0x1000000; + } + return value; +} + +inline int setCC(int sw, int cc) { + sw &= ~CC_MASK; + sw |= (cc & CC_MASK); + return sw; +} + +inline int sic_comp(int a, int b, int sw) { + int sa = toSIC24(a); + int sb = toSIC24(b); + + int cc; + if (sa < sb) { + cc = CC_LT; + } else if (sa == sb) { + cc = CC_EQ; + } else { + cc = CC_GT; + } + + return setCC(sw, cc); +} + +inline int getCC(int sw) { + return sw & CC_MASK; +} + + +#endif // MACHINE_H \ No newline at end of file diff --git a/simulator_SIC_XE/include/opcode.h b/simulator_SIC_XE/include/opcode.h new file mode 100644 index 0000000..93df629 --- /dev/null +++ b/simulator_SIC_XE/include/opcode.h @@ -0,0 +1,100 @@ +#ifndef OPCODE_H +#define OPCODE_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 + + + +// SW register condition codes +constexpr int CC_LT = 0x0; // 00 +constexpr int CC_EQ = 0x1; // 01 +constexpr int CC_GT = 0x2; // 10 +constexpr int CC_MASK = 0x3; // mask for 2 bits + + + +enum class InstructionType { + 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[]; + +// Initialize the instruction table +void loadInstructionSet(); + +#endif // OPCODE_H diff --git a/simulator_SIC_XE/include/output_device.h b/simulator_SIC_XE/include/output_device.h new file mode 100644 index 0000000..94ba8b8 --- /dev/null +++ b/simulator_SIC_XE/include/output_device.h @@ -0,0 +1,18 @@ +#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/simulator_SIC_XE/src/device.cpp b/simulator_SIC_XE/src/device.cpp new file mode 100644 index 0000000..87ab0d7 --- /dev/null +++ b/simulator_SIC_XE/src/device.cpp @@ -0,0 +1,19 @@ +#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/simulator_SIC_XE/src/file_device.cpp b/simulator_SIC_XE/src/file_device.cpp new file mode 100644 index 0000000..3dd404f --- /dev/null +++ b/simulator_SIC_XE/src/file_device.cpp @@ -0,0 +1,45 @@ +#include "file_device.h" +#include +#include + +FileDevice::FileDevice(const std::string &filename) +{ + fileStream.open(filename, std::ios::in | std::ios::out | std::ios::binary); + if (!fileStream.is_open()) { + std::ofstream create(filename, std::ios::binary); + if (!create) { + throw std::runtime_error("Failed to create file: " + filename); + } + create.close(); + + fileStream.clear(); + fileStream.open(filename, std::ios::in | std::ios::out | std::ios::binary); + if (!fileStream.is_open()) { + throw std::runtime_error("Failed to open file after creating: " + filename); + } + } +} + +FileDevice::~FileDevice() +{ + if (fileStream.is_open()) { + fileStream.close(); + } +} + +unsigned char FileDevice::read() +{ + unsigned char value = 0; + if (fileStream.is_open()) { + fileStream.read(reinterpret_cast(&value), sizeof(value)); + } + return value; +} + +void FileDevice::write(unsigned char value) +{ + if (fileStream.is_open()) { + fileStream.write(reinterpret_cast(&value), sizeof(value)); + fileStream.flush(); + } +} \ No newline at end of file diff --git a/simulator_SIC_XE/src/input_device.cpp b/simulator_SIC_XE/src/input_device.cpp new file mode 100644 index 0000000..340c721 --- /dev/null +++ b/simulator_SIC_XE/src/input_device.cpp @@ -0,0 +1,20 @@ +#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/simulator_SIC_XE/src/instructions.cpp b/simulator_SIC_XE/src/instructions.cpp new file mode 100644 index 0000000..364fed1 --- /dev/null +++ b/simulator_SIC_XE/src/instructions.cpp @@ -0,0 +1,60 @@ +#include "instructions.h" +#include "machine.h" + + +void addr_handler(Machine& m, int r1, int r2) { + m.setReg(r2, m.getReg(r1) + m.getReg(r2)); +} + +// CLEAR instruction: clears register r (first nibble), second nibble unused +void clear_handler(Machine& m, int r, int unused) { + m.setReg(r, 0); +} + + +void 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)); +} + +void shiftl_handler(Machine &m, int r1, int n) +{ + m.setReg(r1, m.getReg(r1) << n); +} + +void shiftr_handler(Machine &m, int r1, int n) +{ + m.setReg(r1, m.getReg(r1) >> n); +} +void subr_handler(Machine &m, int r1, int r2) +{ + m.setReg(r2, m.getReg(r2) - m.getReg(r1)); +} + +// 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())); +} diff --git a/simulator_SIC_XE/src/machine.cpp b/simulator_SIC_XE/src/machine.cpp new file mode 100644 index 0000000..d190f6d --- /dev/null +++ b/simulator_SIC_XE/src/machine.cpp @@ -0,0 +1,261 @@ +#include "machine.h" + +#include + +#include "opcode.h" +#include "instructions.h" + +using std::make_shared; + +string prefix = "Machine error: "; + + +Machine::Machine() +{ + devices.resize(NUM_DEVICES); + // device 0: standard input + devices[0] = make_shared(std::cin); + // device 1: standard output + devices[1] = make_shared(std::cout); + // device 2: standard error + devices[2] = make_shared(std::cerr); +} + +Machine::~Machine() +{ + for (auto& device : devices) { + device.reset(); + } +} + +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; +} + +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; + } + return static_cast(memory[address]) | (static_cast(memory[address + 1]) << 8) | (static_cast(memory[address + 2]) << 16); +} + +// 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; + } + + memory[address] = static_cast(value & 0xFF); + memory[address + 1] = static_cast((value >> 8) & 0xFF); + memory[address + 2] = static_cast((value >> 16) & 0xFF); +} + +// TODO: implement proper float storage and retrieval +double Machine::getFloat(int address) +{ + return 0.0; +} + +void Machine::setFloat(int address, double value) +{ + // TODO: implement proper float storage +} + +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() +{ + int opcode = fetch(); + InstructionType type = instructions[opcode].type; + switch (type) { + case InstructionType::TYPE1: execF1(opcode);break; + case InstructionType::TYPE2: execF2(opcode, fetch());break; + case InstructionType::TYPE3_4: // extract n and i bits + { + int ni = opcode & 0x3; + int operand = fetch(); + execSICF3F4(opcode, ni, operand); + } + break; + default: invalidOpcode(opcode); break; + } +} + +bool Machine::execF1(int opcode) +{ + switch (opcode) + { + case FIX: + setA(static_cast(getF())); + return true; + case FLOAT: + setF(static_cast(getA())); + return true; + case HIO: + notImplemented("HIO"); + return true; + case NORM: + notImplemented("NORM"); + return true; + case SIO: + notImplemented("SIO"); + return true; + case TIO: + notImplemented("TIO"); + return true; + default: + break; + } + return false; +} + +bool Machine::execF2(int opcode, int operand) +{ + int r1 = (operand >> 4) & 0xF; + int r2 = operand & 0xF; + + if (instructions[opcode].handler) { + auto handler = reinterpret_cast(instructions[opcode].handler); + handler(*this, r1, r2); + return true; + } + undefinedHandler(opcode); + return false; +} + +bool Machine::execSICF3F4(int opcode, int ni, int operand) +{ + return false; +} diff --git a/simulator_SIC_XE/src/main.cpp b/simulator_SIC_XE/src/main.cpp new file mode 100644 index 0000000..1c285b9 --- /dev/null +++ b/simulator_SIC_XE/src/main.cpp @@ -0,0 +1,27 @@ +#include +#include "machine.h" +#include "file_device.h" +#include "opcode.h" +#include "instructions.h" + +using std::cout; +using std::endl; + +int main() +{ + loadInstructionSet(); + Machine machine; + + cout << "Machine initialized successfully." << endl; + + // COMPUTE A + B and store result in B + machine.setA(10); + machine.setB(20); + machine.setByte(0, ADDR); + machine.setByte(1, 0x03); // r1 = 0 (A), r2 = 3 (B) + cout << "Before ADDR: A = " << machine.getA() << ", B = " << machine.getB() << endl; + machine.execute(); + cout << "After ADDR: A = " << machine.getA() << ", B = " << machine.getB() << endl; + + return 0; +} \ No newline at end of file diff --git a/simulator_SIC_XE/src/opcode.cpp b/simulator_SIC_XE/src/opcode.cpp new file mode 100644 index 0000000..febc489 --- /dev/null +++ b/simulator_SIC_XE/src/opcode.cpp @@ -0,0 +1,75 @@ +#include "opcode.h" +#include "instructions.h" +#include + +InstructionInfo instructions[0xff]; + +void loadInstructionSet() +{ + instructions[ADD] = {"ADD", InstructionType::TYPE3_4, nullptr}; + instructions[ADDF] = {"ADDF", InstructionType::TYPE3_4, nullptr}; + instructions[ADDR] = {"ADDR", InstructionType::TYPE2, reinterpret_cast(addr_handler)}; + instructions[AND] = {"AND", InstructionType::TYPE3_4, nullptr}; + instructions[CLEAR] = {"CLEAR", InstructionType::TYPE2, reinterpret_cast(clear_handler)}; + instructions[COMP] = {"COMP", InstructionType::TYPE3_4, nullptr}; + instructions[COMPF] = {"COMPF", InstructionType::TYPE3_4, nullptr}; + instructions[COMPR] = {"COMPR", InstructionType::TYPE2, nullptr}; + instructions[DIV] = {"DIV", InstructionType::TYPE3_4, nullptr}; + instructions[DIVF] = {"DIVF", InstructionType::TYPE3_4, nullptr}; + instructions[DIVR] = {"DIVR", InstructionType::TYPE2, reinterpret_cast(divr_handler)}; + instructions[FIX] = {"FIX", InstructionType::TYPE1, nullptr}; + instructions[FLOAT] = {"FLOAT", InstructionType::TYPE1, nullptr}; + instructions[HIO] = {"HIO", InstructionType::TYPE1, nullptr}; + instructions[J] = {"J", InstructionType::TYPE3_4, nullptr}; + instructions[JEQ] = {"JEQ", InstructionType::TYPE3_4, nullptr}; + instructions[JGT] = {"JGT", InstructionType::TYPE3_4, nullptr}; + instructions[JLT] = {"JLT", InstructionType::TYPE3_4, nullptr}; + instructions[JSUB] = {"JSUB", InstructionType::TYPE3_4, nullptr}; + instructions[LDA] = {"LDA", InstructionType::TYPE3_4, nullptr}; + instructions[LDB] = {"LDB", InstructionType::TYPE3_4, nullptr}; + instructions[LDCH] = {"LDCH", InstructionType::TYPE3_4, nullptr}; + instructions[LDF] = {"LDF", InstructionType::TYPE3_4, nullptr}; + instructions[LDL] = {"LDL", InstructionType::TYPE3_4, nullptr}; + instructions[LDS] = {"LDS", InstructionType::TYPE3_4, nullptr}; + instructions[LDT] = {"LDT", InstructionType::TYPE3_4, nullptr}; + instructions[LDX] = {"LDX", InstructionType::TYPE3_4, nullptr}; + instructions[LPS] = {"LPS", InstructionType::TYPE3_4, nullptr}; + instructions[MUL] = {"MUL", InstructionType::TYPE3_4, nullptr}; + instructions[MULF] = {"MULF", InstructionType::TYPE3_4, nullptr}; + instructions[MULR] = {"MULR", InstructionType::TYPE2, reinterpret_cast(mulr_handler)}; + instructions[NORM] = {"NORM", InstructionType::TYPE1, nullptr}; + instructions[OR] = {"OR", InstructionType::TYPE3_4, nullptr}; + instructions[RD] = {"RD", InstructionType::TYPE3_4, nullptr}; + instructions[RMO] = {"RMO", InstructionType::TYPE2, reinterpret_cast(rmo_handler)}; + instructions[RSUB] = {"RSUB", InstructionType::TYPE3_4, nullptr}; + instructions[SHIFTL] = {"SHIFTL", InstructionType::TYPE2, reinterpret_cast(shiftl_handler)}; + instructions[SHIFTR] = {"SHIFTR", InstructionType::TYPE2, reinterpret_cast(shiftr_handler)}; + instructions[SIO] = {"SIO", InstructionType::TYPE1, nullptr}; + instructions[SSK] = {"SSK", InstructionType::TYPE3_4, nullptr}; + instructions[STA] = {"STA", InstructionType::TYPE3_4, nullptr}; + instructions[STB] = {"STB", InstructionType::TYPE3_4, nullptr}; + instructions[STCH] = {"STCH", InstructionType::TYPE3_4, nullptr}; + instructions[STF] = {"STF", InstructionType::TYPE3_4, nullptr}; + instructions[STI] = {"STI", InstructionType::TYPE3_4, nullptr}; + instructions[STL] = {"STL", InstructionType::TYPE3_4, nullptr}; + instructions[STS] = {"STS", InstructionType::TYPE3_4, nullptr}; + instructions[STSW] = {"STSW", InstructionType::TYPE3_4, nullptr}; + instructions[STT] = {"STT", InstructionType::TYPE3_4, nullptr}; + instructions[STX] = {"STX", InstructionType::TYPE3_4, nullptr}; + instructions[SUB] = {"SUB", InstructionType::TYPE3_4, nullptr}; + instructions[SUBF] = {"SUBF", InstructionType::TYPE3_4, nullptr}; + instructions[SUBR] = {"SUBR", InstructionType::TYPE2, reinterpret_cast(subr_handler)}; + instructions[SVC] = {"SVC", InstructionType::TYPE2, reinterpret_cast(svc_handler)}; + instructions[TIXR] = {"TIXR", InstructionType::TYPE2, reinterpret_cast(tixr_handler)}; + instructions[TD] = {"TD", InstructionType::TYPE3_4, nullptr}; + instructions[TIX] = {"TIX", InstructionType::TYPE3_4, nullptr}; + instructions[TIO] = {"TIO", InstructionType::TYPE1, nullptr}; + instructions[WD] = {"WD", InstructionType::TYPE3_4, nullptr}; + + // Mark uninitialized opcodes as INVALID + for (int i = 0; i < 0xff; ++i) { + if (instructions[i].name == nullptr) { + instructions[i] = {"INVALID", InstructionType::INVALID, nullptr}; + } + } +} \ No newline at end of file diff --git a/simulator_SIC_XE/src/output_device.cpp b/simulator_SIC_XE/src/output_device.cpp new file mode 100644 index 0000000..ce7b4ec --- /dev/null +++ b/simulator_SIC_XE/src/output_device.cpp @@ -0,0 +1,16 @@ +#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(); +}