From 6b3f4989ae63e5fff9502b457d0748bbe6bc33c8 Mon Sep 17 00:00:00 2001 From: zanostro Date: Wed, 12 Nov 2025 12:13:26 +0100 Subject: [PATCH] added new instructions and new test --- simulator_SIC_XE/include/instructions.h | 10 ++- simulator_SIC_XE/include/machine.h | 16 ++++- simulator_SIC_XE/src/instructions.cpp | 12 +++- simulator_SIC_XE/src/machine.cpp | 43 +++++++++++ simulator_SIC_XE/src/main.cpp | 95 ++++++++++++++++--------- simulator_SIC_XE/src/opcode.cpp | 4 +- 6 files changed, 142 insertions(+), 38 deletions(-) diff --git a/simulator_SIC_XE/include/instructions.h b/simulator_SIC_XE/include/instructions.h index e085a9d..61cc452 100644 --- a/simulator_SIC_XE/include/instructions.h +++ b/simulator_SIC_XE/include/instructions.h @@ -5,8 +5,16 @@ 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); - +/* IDEJE ZA SIC_XE_XE :)*/ +// void nop(Machine& m); // Type 2 instruction handlers void addr_handler(Machine& m, int r1, int r2); diff --git a/simulator_SIC_XE/include/machine.h b/simulator_SIC_XE/include/machine.h index 9ee4fca..0bcb448 100644 --- a/simulator_SIC_XE/include/machine.h +++ b/simulator_SIC_XE/include/machine.h @@ -5,6 +5,9 @@ #include #include #include +#include +#include + #include "constants.h" #include "device.h" @@ -23,6 +26,7 @@ using std::cout; class Machine { public: Machine(); + Machine(int speedkHz) : Machine() { this->speedkHz = speedkHz; } ~Machine(); int getA() const { return A; } @@ -74,7 +78,6 @@ public: // Set a file device at index `num` using the provided filename. void setFileDevice(int num, const std::string &filename); - // Fetch and execute instructions int fetch(); void execute(); @@ -83,6 +86,12 @@ public: bool execF2(int opcode, int operand); bool execSICF3F4(int opcode, int ni, int x, int b, int p, int e, int operand); + // Execution and speed control + int getSpeed() const; + void setSpeed(int kHz); + void start(); + void stop(); + // error handling methods void notImplemented(string mnemonic); void invalidOpcode(int opcode); @@ -102,6 +111,11 @@ private: std::vector> devices; // fallback device returned when device slot is empty/invalid Device fallbackDevice; + + // Execution control + std::atomic running{false}; + std::atomic speedkHz{1}; // Default 1 kHz + void tick(); // simulate a clock tick }; diff --git a/simulator_SIC_XE/src/instructions.cpp b/simulator_SIC_XE/src/instructions.cpp index a0a96dd..85e3bd9 100644 --- a/simulator_SIC_XE/src/instructions.cpp +++ b/simulator_SIC_XE/src/instructions.cpp @@ -63,8 +63,18 @@ inline int resolveJumpTarget(Machine& m, int ea, AddressingMode mode) } } +void fix_handler(Machine &m) +{ + m.setA(static_cast(m.getF())); +} -void addr_handler(Machine& m, int r1, int r2) { +void float_handler(Machine &m) +{ + m.setF(static_cast(m.getA())); +} + +void addr_handler(Machine &m, int r1, int r2) +{ m.setReg(r2, m.getReg(r1) + m.getReg(r2)); } diff --git a/simulator_SIC_XE/src/machine.cpp b/simulator_SIC_XE/src/machine.cpp index 8180727..e4ee364 100644 --- a/simulator_SIC_XE/src/machine.cpp +++ b/simulator_SIC_XE/src/machine.cpp @@ -5,6 +5,7 @@ #include "opcode.h" #include "instructions.h" #include +#include using std::make_shared; @@ -29,6 +30,17 @@ Machine::~Machine() } } +int Machine::getSpeed() const +{ + return speedkHz.load(); +} + +void Machine::setSpeed(int kHz) +{ + speedkHz.store(kHz); +} + +// TODO: implement errors void Machine::notImplemented(string mnemonic) { cout << prefix << "Not implemented: " << mnemonic << endl; @@ -39,6 +51,7 @@ void Machine::invalidOpcode(int opcode) cout << prefix << "Invalid opcode: " << opcode << endl; } + void Machine::invalidAddressing() { cout << prefix << "Invalid addressing mode" << endl; @@ -54,6 +67,15 @@ void Machine::undefinedHandler(int opcode) cout << prefix << "Undefined handler for opcode: " << opcode << endl; } +void Machine::tick() +{ + const int speed = speedkHz.load(); + if (speed <= 0) throw std::runtime_error("Invalid speed setting in Machine::tick"); + + const auto delay = std::chrono::microseconds(1000 / speed); + std::this_thread::sleep_for(delay); +} + int Machine::getReg(int regNum) const { switch (regNum) { @@ -307,6 +329,11 @@ void Machine::execute() { bool Machine::execF1(int opcode) { + if (instructions[opcode].handler) { + auto handler = reinterpret_cast(instructions[opcode].handler); + handler(*this); + return true; + } undefinedHandler(opcode); return false; } @@ -369,3 +396,19 @@ bool Machine::execSICF3F4(int opcode, int ni, int x, int b, int p, int e, int op return false; } +void Machine::start() +{ + running.store(true); + + // Main execution loop + // TODO: consider running in separate thread + while (running.load()) { + execute(); + tick(); + } +} + +void Machine::stop() +{ + running.store(false); +} diff --git a/simulator_SIC_XE/src/main.cpp b/simulator_SIC_XE/src/main.cpp index 4171396..16dcd0c 100644 --- a/simulator_SIC_XE/src/main.cpp +++ b/simulator_SIC_XE/src/main.cpp @@ -1,4 +1,6 @@ #include +#include +#include #include "machine.h" #include "file_device.h" #include "opcode.h" @@ -12,42 +14,69 @@ int main() loadInstructionSet(); Machine machine; - cout << "Machine initialized successfully." << endl; + cout << "SIC/XE Program: Accumulator Loop" << endl; - // Test 1: ADD immediate 0x0030 (ADD #48) - machine.setA(10); - cout << "Test 1 - Immediate ADD:" << endl; - cout << " A before: " << machine.getA() << endl; - machine.setByte(0x0, 0x19); // ADD with ni=01 (immediate addressing) - machine.setByte(0x1, 0x00); - machine.setByte(0x2, 0x30); // Immediate value 48 (0x30) - machine.execute(); - cout << " A after ADD #48: " << machine.getA() << endl; + const int TEMP_ADDR = 0x50; + const int LOOP_ADDR = 0x03; - // Test 2: ADD direct 0x0020 (ADD 0x20) - machine.setA(5); - machine.setPC(0x10); // Move PC for next instruction - cout << "\nTest 2 - Direct ADD:" << endl; - cout << " A before: " << machine.getA() << endl; - machine.setByte(0x20, 25); // Store value 25 at address 0x20 - machine.setByte(0x10, 0x1B); // ADD with ni=11 (simple/direct addressing) - machine.setByte(0x11, 0x00); - machine.setByte(0x12, 0x20); // Address 0x20 - machine.execute(); - cout << " A after ADD [0x20]: " << machine.getA() << endl; + // clear TEMP + machine.setByte(TEMP_ADDR, 0); - // Test 3: ADD indirect @0x0030 (ADD @0x30) - machine.setA(15); - machine.setPC(0x20); // Move PC for next instruction - cout << "\nTest 3 - Indirect ADD:" << endl; - cout << " A before: " << machine.getA() << endl; - machine.setWord(0x30, 0x40); // Address 0x30 contains address 0x40 - machine.setByte(0x40, 35); // Store value 35 at address 0x40 - machine.setByte(0x20, 0x1A); // ADD with ni=10 (indirect addressing) - machine.setByte(0x21, 0x00); - machine.setByte(0x22, 0x30); // Address 0x30 (which points to 0x40) - machine.execute(); - cout << " A after ADD @0x30: " << machine.getA() << endl; + // Program (addresses): + // 0x00 LDA #1 + // 0x03 LDB TEMP + // 0x06 ADDR A,B + // 0x08 RMO B,A + // 0x0A STA TEMP + // 0x0D J LOOP + + // LDA #1 + machine.setByte(0x00, 0x01); + machine.setByte(0x01, 0x00); + machine.setByte(0x02, 0x01); + + // LDB TEMP + machine.setByte(0x03, 0x6B); + machine.setByte(0x04, 0x00); + machine.setByte(0x05, TEMP_ADDR); + + // ADDR A,B + machine.setByte(0x06, 0x90); + machine.setByte(0x07, 0x03); + + // RMO B,A + machine.setByte(0x08, 0xAC); + machine.setByte(0x09, 0x30); + + // STA TEMP + machine.setByte(0x0A, 0x0F); + machine.setByte(0x0B, 0x00); + machine.setByte(0x0C, TEMP_ADDR); + + // J LOOP + machine.setByte(0x0D, 0x3F); + machine.setByte(0x0E, 0x00); + machine.setByte(0x0F, LOOP_ADDR); + + machine.setPC(0x00); + + cout << "Program loaded. TEMP at 0x" << std::hex << TEMP_ADDR << std::dec << endl; + + // run a few iterations + for (int i = 0; i < 10; ++i) { + cout << "Iter " << (i + 1) << ": A=" << machine.getA() + << " B=" << machine.getB() + << " TEMP=" << machine.getByte(TEMP_ADDR); + + // advance the program by executing the next 6 instructions + for (int k = 0; k < 6; ++k) machine.execute(); + + cout << " -> A=" << machine.getA() + << " B=" << machine.getB() + << " TEMP=" << machine.getByte(TEMP_ADDR) << "\n"; + + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } return 0; } \ No newline at end of file diff --git a/simulator_SIC_XE/src/opcode.cpp b/simulator_SIC_XE/src/opcode.cpp index 04fa3b8..6095307 100644 --- a/simulator_SIC_XE/src/opcode.cpp +++ b/simulator_SIC_XE/src/opcode.cpp @@ -18,8 +18,8 @@ void loadInstructionSet() 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, nullptr}; - instructions[FLOAT] = {"FLOAT", InstructionType::TYPE1, nullptr}; + 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)};