saved snapshot for naloga2

This commit is contained in:
zanostro 2025-12-07 11:33:03 +01:00
parent e764bf53e7
commit 9e7a9101b0
35 changed files with 4928 additions and 0 deletions

View file

@ -0,0 +1,52 @@
#ifndef CONSTANTS_H
#define CONSTANTS_H
#include <string>
// ==============================
// 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

View file

@ -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

View file

@ -0,0 +1,23 @@
#ifndef FILE_DEVICE_H
#define FILE_DEVICE_H
#include "device.h"
#include <fstream>
#include <string>
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

View file

@ -0,0 +1,25 @@
#ifndef FILE_READER_H
#define FILE_READER_H
#include "reader.h"
#include <string>
#include <fstream>
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

View file

@ -0,0 +1,18 @@
#ifndef INPUT_DEVICE_H
#define INPUT_DEVICE_H
#include "device.h"
#include <istream>
class InputDevice : public Device {
public:
explicit InputDevice(std::istream &in);
~InputDevice();
unsigned char read();
private:
std::istream &inStream;
};
#endif // INPUT_DEVICE_H

View file

@ -0,0 +1,101 @@
#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

View file

@ -0,0 +1,68 @@
#ifndef LOADER_H
#define LOADER_H
#include <memory>
#include <string>
#include <vector>
#include "file_reader.h"
#include <stdexcept>
class Machine;
using std::shared_ptr;
using std::string;
class Loader {
public:
Loader( shared_ptr<Machine> machine, string filename) : _machine(machine), _filename(filename) {
_file_reader = std::make_shared<FileReader>(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<uint8_t> data;
};
struct EndRecord {
int execution_start_address;
};
void load();
private :
static RecordType parseRecordType(char c);
shared_ptr<Machine> _machine;
string _filename;
shared_ptr<FileReader> _file_reader;
HeaderMetadata readHeader();
TextRecord readTextRecord();
EndRecord readEndRecord();
bool load_into_memory(int start_address, const std::vector<uint8_t>& data);
};
#endif // LOADER_H

View file

@ -0,0 +1,149 @@
#ifndef MACHINE_H
#define MACHINE_H
#include <string>
#include <iostream>
#include <vector>
#include <memory>
#include <atomic>
#include <mutex>
#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> 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<std::shared_ptr<Device>> devices;
// fallback device returned when device slot is empty/invalid
Device fallbackDevice;
// Execution control
std::atomic<bool> running{false};
std::atomic<int> 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

View file

@ -0,0 +1,116 @@
#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

View file

@ -0,0 +1,18 @@
#ifndef OUTPUT_DEVICE_H
#define OUTPUT_DEVICE_H
#include "device.h"
#include <ostream>
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

View file

@ -0,0 +1,21 @@
#ifndef READER_H
#define READER_H
#include <string>
#include <cstdint>
// 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

View file

@ -0,0 +1,22 @@
#ifndef STRING_READER_H
#define STRING_READER_H
#include "reader.h"
#include <string>
#include <sstream>
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

View file

@ -0,0 +1,95 @@
#ifndef UTILS_H
#define UTILS_H
#include "constants.h"
#include <cmath>
// ==============================
// 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