From 76b2c711efeee08e56b5298b3eb4737294fede83 Mon Sep 17 00:00:00 2001 From: privsk Date: Wed, 3 Dec 2025 10:13:58 +0100 Subject: [PATCH] implemented timer, opcode decoding --- ass2/Machine.cpp | 357 +++++++++++++++++++++++++++++++++++++++++++++++ ass2/Machine.h | 28 +++- 2 files changed, 384 insertions(+), 1 deletion(-) diff --git a/ass2/Machine.cpp b/ass2/Machine.cpp index 92a2456..6aa9168 100644 --- a/ass2/Machine.cpp +++ b/ass2/Machine.cpp @@ -1,10 +1,12 @@ #include "Machine.h" +#include #include #include #include "FileDevice.h" #include "InputDevice.h" +#include "Opcode.h" #include "OutputDevice.h" Machine::Machine() { @@ -18,6 +20,10 @@ Machine::Machine() { PC = 0; SW = 0; + running = false; + timerThread = nullptr; + speed = 1000; // default 1000 kHz = 1 MHz + for (int i = 0; i <= MAX_ADDRESS; i++) { memory[i] = 0; } @@ -32,6 +38,8 @@ Machine::Machine() { } Machine::~Machine() { + stop(); + for (int i = 0; i < MAX_DEVICES; i++) { if (devices[i] != nullptr) { delete devices[i]; @@ -232,3 +240,352 @@ void Machine::setDevice(int num, Device* device) { devices[num] = device; } } + +void Machine::notImplemented(const char* mnemonic) { + std::cerr << "Error: instruction " << mnemonic << " not implemented" << std::endl; +} + +void Machine::invalidOpcode(int opcode) { + std::cerr << "Error: invalid opcode 0x" << std::hex << opcode << std::endl; +} + +void Machine::invalidAddressing() { + std::cerr << "Error: invalid addressing mode" << std::endl; +} + +int Machine::fetch() { + int byte = getByte(PC); + PC = (PC + 1) & 0xFFFFFF; + return byte; +} + +void Machine::execute() { + int byte1 = fetch(); + int opcode = byte1 & 0xFC; + int ni = byte1 & 0x03; + + // format 1 (no operand) + if (execF1(opcode)) { + return; + } + + int byte2 = fetch(); + + // format 2 (register operand) + if (execF2(opcode, byte2)) { + return; + } + + // format 3 or 4 + int xbpe = (byte2 >> 4) & 0x0F; + int disp = byte2 & 0x0F; + + int byte3 = fetch(); + disp = (disp << 8) | byte3; + + // format 4 (extended) + if (xbpe & 0x01) { + int byte4 = fetch(); + disp = (disp << 8) | byte4; + } + + int addr = disp; + + // base relative + if (xbpe & 0x04) { + addr = B + disp; + } + // pc relative + else if (xbpe & 0x02) { + // sign extend 12-bit displacement for format 3 + if (!(xbpe & 0x01) && (disp & 0x800)) { + disp = disp | 0xFFFFF000; + } + addr = PC + disp; + } + + // indexed + if (xbpe & 0x08) { + addr = addr + X; + } + + addr = addr & 0xFFFFFF; + + execSICF3F4(opcode, ni, addr); +} + +bool Machine::execF1(int opcode) { + switch (opcode) { + case Opcode::FIX: + A = (int)F; + return true; + case Opcode::FLOAT: + F = (double)A; + return true; + case Opcode::NORM: + notImplemented("NORM"); + return true; + case Opcode::SIO: + case Opcode::HIO: + case Opcode::TIO: + notImplemented("SIO/HIO/TIO"); + return true; + } + return false; +} + +bool Machine::execF2(int opcode, int operand) { + int r1 = (operand >> 4) & 0x0F; + int r2 = operand & 0x0F; + + switch (opcode) { + case Opcode::ADDR: + setReg(r2, getReg(r1) + getReg(r2)); + return true; + case Opcode::SUBR: + setReg(r2, getReg(r2) - getReg(r1)); + return true; + case Opcode::MULR: + setReg(r2, getReg(r1) * getReg(r2)); + return true; + case Opcode::DIVR: + setReg(r2, getReg(r2) / getReg(r1)); + return true; + case Opcode::COMPR: { + int val1 = getReg(r1); + int val2 = getReg(r2); + if (val1 < val2) + setCC_less(); + else if (val1 == val2) + setCC_equal(); + else + setCC_greater(); + return true; + } + case Opcode::SHIFTL: + setReg(r1, getReg(r1) << (r2 + 1)); + return true; + case Opcode::SHIFTR: + setReg(r1, getReg(r1) >> (r2 + 1)); + return true; + case Opcode::RMO: + setReg(r2, getReg(r1)); + return true; + case Opcode::CLEAR: + setReg(r1, 0); + return true; + case Opcode::TIXR: { + X = X + 1; + int val = getReg(r1); + if (X < val) + setCC_less(); + else if (X == val) + setCC_equal(); + else + setCC_greater(); + return true; + } + case Opcode::SVC: + notImplemented("SVC"); + return true; + } + return false; +} + +bool Machine::execSICF3F4(int opcode, int ni, int operand) { + int addr = operand; + int value; + + // get value based on addressing mode + if (ni == 0x00) { + // SIC format (simple) + value = getWord(addr); + } else if (ni == 0x01) { + // immediate + value = addr; + } else if (ni == 0x02) { + // indirect + addr = getWord(addr); + value = getWord(addr); + } else { + // simple (ni == 0x03) + value = getWord(addr); + } + + switch (opcode) { + case Opcode::LDA: + A = value; + return true; + case Opcode::LDX: + X = value; + return true; + case Opcode::LDL: + L = value; + return true; + case Opcode::LDB: + B = value; + return true; + case Opcode::LDS: + S = value; + return true; + case Opcode::LDT: + T = value; + return true; + case Opcode::LDCH: + if (ni == 0x01) { + A = (A & 0xFFFF00) | (addr & 0xFF); + } else { + A = (A & 0xFFFF00) | getByte(addr); + } + return true; + + case Opcode::STA: + setWord(addr, A); + return true; + case Opcode::STX: + setWord(addr, X); + return true; + case Opcode::STL: + setWord(addr, L); + return true; + case Opcode::STB: + setWord(addr, B); + return true; + case Opcode::STS: + setWord(addr, S); + return true; + case Opcode::STT: + setWord(addr, T); + return true; + case Opcode::STSW: + setWord(addr, SW); + return true; + case Opcode::STCH: + setByte(addr, A & 0xFF); + return true; + + case Opcode::ADD: + A = A + value; + return true; + case Opcode::SUB: + A = A - value; + return true; + case Opcode::MUL: + A = A * value; + return true; + case Opcode::DIV: + A = A / value; + return true; + case Opcode::AND: + A = A & value; + return true; + case Opcode::OR: + A = A | value; + return true; + + case Opcode::COMP: + if (A < value) + setCC_less(); + else if (A == value) + setCC_equal(); + else + setCC_greater(); + return true; + case Opcode::TIX: + X = X + 1; + if (X < value) + setCC_less(); + else if (X == value) + setCC_equal(); + else + setCC_greater(); + return true; + + case Opcode::J: + PC = addr; + return true; + case Opcode::JEQ: + if (getCC() == 0x40) PC = addr; + return true; + case Opcode::JGT: + if (getCC() == 0x80) PC = addr; + return true; + case Opcode::JLT: + if (getCC() == 0x00) PC = addr; + return true; + case Opcode::JSUB: + L = PC; + PC = addr; + return true; + case Opcode::RSUB: + PC = L; + return true; + + case Opcode::TD: { + Device* dev = getDevice(getByte(addr)); + if (dev != nullptr && dev->test()) { + setCC_less(); + } else { + setCC_equal(); + } + return true; + } + case Opcode::RD: { + Device* dev = getDevice(getByte(addr)); + if (dev != nullptr) { + A = (A & 0xFFFF00) | dev->read(); + } + return true; + } + case Opcode::WD: { + Device* dev = getDevice(getByte(addr)); + if (dev != nullptr) { + dev->write(A & 0xFF); + } + return true; + } + + default: + invalidOpcode(opcode); + return false; + } +} + +void Machine::start() { + if (running) return; + + running = true; + timerThread = new std::thread([this]() { + while (running) { + int instructionsPerTick = speed / 1000; + if (instructionsPerTick < 1) instructionsPerTick = 1; + + for (int i = 0; i < instructionsPerTick && running; i++) { + execute(); + } + + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + }); +} + +void Machine::stop() { + running = false; + if (timerThread != nullptr) { + timerThread->join(); + delete timerThread; + timerThread = nullptr; + } +} + +bool Machine::isRunning() const { + return running; +} + +int Machine::getSpeed() const { + return speed; +} + +void Machine::setSpeed(int kHz) { + speed = kHz; +} diff --git a/ass2/Machine.h b/ass2/Machine.h index aef0c7f..43477a4 100644 --- a/ass2/Machine.h +++ b/ass2/Machine.h @@ -2,6 +2,8 @@ #define MACHINE_H #include +#include +#include #include "Device.h" @@ -24,6 +26,11 @@ class Machine { int PC; // Program Counter (24-bit) int SW; // Status Word (24-bit) + // timer simulation + std::atomic running; + std::thread* timerThread; + int speed; // kHz + public: Machine(); ~Machine(); @@ -62,12 +69,31 @@ class Machine { int getByte(int addr) const; void setByte(int addr, int val); - + int getWord(int addr) const; void setWord(int addr, int val); Device* getDevice(int num) const; void setDevice(int num, Device* device); + + // error handling + void notImplemented(const char* mnemonic); + void invalidOpcode(int opcode); + void invalidAddressing(); + + // execution + int fetch(); + void execute(); + bool execF1(int opcode); + bool execF2(int opcode, int operand); + bool execSICF3F4(int opcode, int ni, int operand); + + // timer simulation + void start(); + void stop(); + bool isRunning() const; + int getSpeed() const; + void setSpeed(int kHz); }; #endif // MACHINE_H