diff --git a/simulator_SIC_XE/include/constants.h b/simulator_SIC_XE/include/constants.h new file mode 100644 index 0000000..0034171 --- /dev/null +++ b/simulator_SIC_XE/include/constants.h @@ -0,0 +1,38 @@ +#ifndef CONSTANTS_H +#define CONSTANTS_H + +// ============================== +// SIC/XE Architecture Constants +// ============================== + +// Memory and system constants +constexpr int MEMORY_SIZE = 65536; +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 + +#endif // CONSTANTS_H \ No newline at end of file diff --git a/simulator_SIC_XE/include/instructions.h b/simulator_SIC_XE/include/instructions.h index ff2e532..e085a9d 100644 --- a/simulator_SIC_XE/include/instructions.h +++ b/simulator_SIC_XE/include/instructions.h @@ -1,11 +1,17 @@ #ifndef INSTRUCTIONS_H #define INSTRUCTIONS_H -#include "opcode.h" +#include "utils.h" + +class Machine; // forward declaration + + + // 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); @@ -16,5 +22,49 @@ 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); + #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 index e0920da..9ee4fca 100644 --- a/simulator_SIC_XE/include/machine.h +++ b/simulator_SIC_XE/include/machine.h @@ -4,18 +4,15 @@ #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 - -#define MEMORY_SIZE 65536 -#define NUM_DEVICES 256 - +#include "utils.h" using std::string; using std::cerr; @@ -28,28 +25,29 @@ public: Machine(); ~Machine(); - // Accessor methods for registers int getA() const { return A; } - void setA(int value) { A = value; } + void setA(int value) { A = toSIC24(value); } int getB() const { return B; } - void setB(int value) { B = value; } + void setB(int value) { B = toSIC24(value); } int getX() const { return X; } - void setX(int value) { X = value; } + void setX(int value) { X = toSIC24(value); } int getL() const { return L; } - void setL(int value) { L = value; } + void setL(int value) { L = toSIC24(value); } int getS() const { return S; } - void setS(int value) { S = value; } + void setS(int value) { S = toSIC24(value); } int getT() const { return T; } - void setT(int value) { T = value; } + 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; } @@ -83,7 +81,7 @@ public: bool execF1(int opcode); bool execF2(int opcode, int operand); - bool execSICF3F4(int opcode, int ni, int operand); + bool execSICF3F4(int opcode, int ni, int x, int b, int p, int e, int operand); // error handling methods void notImplemented(string mnemonic); @@ -106,40 +104,6 @@ private: 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 index 93df629..071e1bf 100644 --- a/simulator_SIC_XE/include/opcode.h +++ b/simulator_SIC_XE/include/opcode.h @@ -1,6 +1,8 @@ #ifndef OPCODE_H #define OPCODE_H +#include "utils.h" + // ============================== // Opcode definitions (SIC/XE) // ============================== @@ -65,15 +67,6 @@ #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, diff --git a/simulator_SIC_XE/include/utils.h b/simulator_SIC_XE/include/utils.h new file mode 100644 index 0000000..754b256 --- /dev/null +++ b/simulator_SIC_XE/include/utils.h @@ -0,0 +1,80 @@ +#ifndef UTILS_H +#define UTILS_H + +#include "constants.h" + +// ============================== +// 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; +} + +#endif // UTILS_H \ No newline at end of file diff --git a/simulator_SIC_XE/src/instructions.cpp b/simulator_SIC_XE/src/instructions.cpp index 364fed1..a0a96dd 100644 --- a/simulator_SIC_XE/src/instructions.cpp +++ b/simulator_SIC_XE/src/instructions.cpp @@ -1,16 +1,81 @@ #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 addr_handler(Machine& m, int r1, int r2) { m.setReg(r2, m.getReg(r1) + m.getReg(r2)); } -// CLEAR instruction: clears register r (first nibble), second nibble unused void clear_handler(Machine& m, int r, int unused) { m.setReg(r, 0); } +void compr_handler(Machine &m, int r1, int r2) +{ + m.setSW(sic_comp(m.getReg(r1), m.getReg(r2), m.getSW())); +} void divr_handler(Machine& m, int r1, int r2) { @@ -31,15 +96,33 @@ 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) { - m.setReg(r1, m.getReg(r1) << 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) { - m.setReg(r1, m.getReg(r1) >> 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)); @@ -58,3 +141,231 @@ void tixr_handler(Machine &m, int r1, int unused) int valR1 = m.getReg(r1); m.setSW(sic_comp(valX, valR1, m.getSW())); } + +void add_handler(Machine &m, int ea, AddressingMode mode) +{ + int val = resolveWordOperand(m, ea, mode); + m.setA(m.getA() + val); +} + +void addf_handler(Machine &m, int ea, AddressingMode mode) +{ + double val = resolveFloatOperand(m, ea, mode); + m.setA(m.getA() + val); +} + +void and_handler(Machine &m, int ea, AddressingMode mode) +{ + int val = resolveWordOperand(m, ea, mode); + m.setA(m.getA() & val); +} + +void comp_handler(Machine &m, int ea, AddressingMode mode) +{ + int operand = resolveWordOperand(m, ea, mode); + m.setSW(sic_comp(m.getA(), operand, m.getSW())); +} + +void compf_handler(Machine &m, int ea, AddressingMode mode) +{ + double operand = resolveFloatOperand(m, ea, mode); + m.setSW(sic_comp(m.getF(), operand, m.getSW())); +} + +void div_handler(Machine &m, int ea, AddressingMode mode) +{ + int divisor = resolveWordOperand(m, ea, mode); + if (divisor == 0) { + m.divisionByZero(DIV); + return; + } + m.setA(m.getA() / divisor); +} + +void divf_handler(Machine &m, int ea, AddressingMode mode) +{ + double divisor = resolveFloatOperand(m, ea, mode); + if (divisor == 0.0) { + m.divisionByZero(DIVF); + return; + } + m.setF(m.getF() / divisor); +} + +void j_handler(Machine &m, int ea, AddressingMode mode) +{ + int target = resolveJumpTarget(m, ea, mode); + 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 = resolveWordOperand(m, ea, mode); + 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 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 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())); +} diff --git a/simulator_SIC_XE/src/machine.cpp b/simulator_SIC_XE/src/machine.cpp index d190f6d..8180727 100644 --- a/simulator_SIC_XE/src/machine.cpp +++ b/simulator_SIC_XE/src/machine.cpp @@ -4,6 +4,7 @@ #include "opcode.h" #include "instructions.h" +#include using std::make_shared; @@ -128,23 +129,93 @@ void Machine::setWord(int address, int value) cerr << prefix << "Invalid memory address: " << address << endl; return; } + value &= 0xFFFFFF; 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; + if (address < 0 || address + 5 >= MEMORY_SIZE) { + cerr << prefix << "Invalid float address: " << address << endl; + return 0.0; + } + + // load 6 bytes, little-endian → 48-bit word + unsigned long long raw = + (unsigned long long)memory[address] | + ((unsigned long long)memory[address+1] << 8) | + ((unsigned long long)memory[address+2] << 16) | + ((unsigned long long)memory[address+3] << 24) | + ((unsigned long long)memory[address+4] << 32) | + ((unsigned long long)memory[address+5] << 40); + + 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) { - // TODO: implement proper float storage + 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 little-endian + memory[address] = (unsigned char)( raw & 0xFF); + memory[address+1] = (unsigned char)((raw >> 8) & 0xFF); + memory[address+2] = (unsigned char)((raw >> 16) & 0xFF); + memory[address+3] = (unsigned char)((raw >> 24) & 0xFF); + memory[address+4] = (unsigned char)((raw >> 32) & 0xFF); + memory[address+5] = (unsigned char)((raw >> 40) & 0xFF); } + + Device &Machine::getDevice(int num) { if(num < 0 || num >= static_cast(devices.size()) || !devices[num]) { @@ -195,49 +266,48 @@ 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; +void Machine::execute() { + int b1 = fetch(); + InstructionInfo &info = instructions[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 = instructions[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) { - switch (opcode) - { - case FIX: - setA(static_cast(getF())); - return true; - case FLOAT: - setF(static_cast(getA())); - return true; - case HIO: - notImplemented("HIO"); - return true; - case NORM: - notImplemented("NORM"); - return true; - case SIO: - notImplemented("SIO"); - return true; - case TIO: - notImplemented("TIO"); - return true; - default: - break; - } + undefinedHandler(opcode); return false; } @@ -255,7 +325,47 @@ bool Machine::execF2(int opcode, int operand) return false; } -bool Machine::execSICF3F4(int opcode, int ni, int operand) + +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 (instructions[opcode].handler) { + auto h = reinterpret_cast(instructions[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 (instructions[opcode].handler) { + auto h = reinterpret_cast(instructions[opcode].handler); + h(*this, ea, mode); + return true; + } + + undefinedHandler(opcode); return false; } + diff --git a/simulator_SIC_XE/src/main.cpp b/simulator_SIC_XE/src/main.cpp index 1c285b9..4171396 100644 --- a/simulator_SIC_XE/src/main.cpp +++ b/simulator_SIC_XE/src/main.cpp @@ -13,15 +13,41 @@ int main() Machine machine; cout << "Machine initialized successfully." << endl; - - // COMPUTE A + B and store result in B + + // Test 1: ADD immediate 0x0030 (ADD #48) 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; + 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 << "After ADDR: A = " << machine.getA() << ", B = " << machine.getB() << endl; + cout << " A after ADD #48: " << machine.getA() << endl; + + // 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; + + // 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; 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 febc489..04fa3b8 100644 --- a/simulator_SIC_XE/src/opcode.cpp +++ b/simulator_SIC_XE/src/opcode.cpp @@ -1,70 +1,71 @@ #include "opcode.h" #include "instructions.h" +#include "utils.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}; + 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, nullptr}; + instructions[FLOAT] = {"FLOAT", InstructionType::TYPE1, nullptr}; + 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, nullptr}; + instructions[OR] = {"OR", InstructionType::TYPE3_4, reinterpret_cast(or_handler)}; + instructions[RD] = {"RD", InstructionType::TYPE3_4, nullptr}; + 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, nullptr}; + instructions[TIX] = {"TIX", InstructionType::TYPE3_4, reinterpret_cast(tix_handler)}; + 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) { @@ -72,4 +73,15 @@ void loadInstructionSet() instructions[i] = {"INVALID", InstructionType::INVALID, nullptr}; } } -} \ No newline at end of file +} + +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 + } +}