added to aas3
This commit is contained in:
parent
527d2e7346
commit
9ac28aa798
48 changed files with 7134 additions and 0 deletions
68
ass3/simulator_SIC_XE/include/code.h
Normal file
68
ass3/simulator_SIC_XE/include/code.h
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
#ifndef CODE_H
|
||||
#define CODE_H
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <cstdint>
|
||||
|
||||
#include "node.h"
|
||||
|
||||
class Code {
|
||||
|
||||
public:
|
||||
Code() = default;
|
||||
|
||||
void addLine(const std::shared_ptr<Node>& line);
|
||||
|
||||
const std::vector<std::shared_ptr<Node>>& getLines() const;
|
||||
|
||||
const string toString() const;
|
||||
|
||||
// Two-pass assembler methods
|
||||
void assemble();
|
||||
std::vector<uint8_t> emitCode();
|
||||
std::string emitText();
|
||||
std::string dumpSymbols() const;
|
||||
std::string dumpCode() const;
|
||||
|
||||
private:
|
||||
std::vector<std::shared_ptr<Node>> _lines;
|
||||
|
||||
// Assembler state
|
||||
std::unordered_map<std::string, int> _symbolTable;
|
||||
std::vector<int> _locationCounters; // Location counter per line
|
||||
int _startAddress = 0;
|
||||
int _programLength = 0;
|
||||
std::string _programName;
|
||||
int _baseRegister = -1; // -1 means not set
|
||||
|
||||
struct ModificationRecord {
|
||||
int address;
|
||||
int halfBytes;
|
||||
};
|
||||
mutable std::vector<ModificationRecord> _modificationRecords;
|
||||
|
||||
// Pass 1: build symbol table and assign addresses
|
||||
void firstPass();
|
||||
|
||||
// Pass 2: generate code
|
||||
void secondPass();
|
||||
|
||||
// Helper methods
|
||||
int getInstructionLength(const std::shared_ptr<Node>& node, int locationCounter) const;
|
||||
std::vector<uint8_t> generateInstruction(const InstructionNode* inst, int address);
|
||||
std::vector<uint8_t> generateData(const DataNode* data);
|
||||
|
||||
// Addressing mode selection
|
||||
struct AddressingResult {
|
||||
int nixbpe; // ni, x, b, p, e bits
|
||||
int displacement; // 12-bit or 20-bit
|
||||
bool success;
|
||||
};
|
||||
AddressingResult selectAddressingMode(int targetAddress, int pc, bool indexed, bool immediate, bool indirect, bool extended) const;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // CODE_H
|
||||
52
ass3/simulator_SIC_XE/include/constants.h
Normal file
52
ass3/simulator_SIC_XE/include/constants.h
Normal 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
|
||||
16
ass3/simulator_SIC_XE/include/device.h
Normal file
16
ass3/simulator_SIC_XE/include/device.h
Normal 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
|
||||
23
ass3/simulator_SIC_XE/include/file_device.h
Normal file
23
ass3/simulator_SIC_XE/include/file_device.h
Normal 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
|
||||
25
ass3/simulator_SIC_XE/include/file_reader.h
Normal file
25
ass3/simulator_SIC_XE/include/file_reader.h
Normal 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
|
||||
18
ass3/simulator_SIC_XE/include/input_device.h
Normal file
18
ass3/simulator_SIC_XE/include/input_device.h
Normal 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
|
||||
101
ass3/simulator_SIC_XE/include/instructions.h
Normal file
101
ass3/simulator_SIC_XE/include/instructions.h
Normal 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
|
||||
55
ass3/simulator_SIC_XE/include/lexer.h
Normal file
55
ass3/simulator_SIC_XE/include/lexer.h
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
#ifndef LEXER_H
|
||||
#define LEXER_H
|
||||
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <cstddef>
|
||||
|
||||
class SyntaxError : public std::runtime_error {
|
||||
public:
|
||||
int row;
|
||||
int col;
|
||||
|
||||
SyntaxError(const std::string& msg, int row_, int col_)
|
||||
: std::runtime_error(msg), row(row_), col(col_) {}
|
||||
};
|
||||
|
||||
|
||||
class Lexer {
|
||||
public:
|
||||
int row;
|
||||
int col;
|
||||
|
||||
explicit Lexer(std::string input);
|
||||
|
||||
Lexer& mark();
|
||||
|
||||
std::string extract(int ofs);
|
||||
std::string extract();
|
||||
|
||||
char peek(int ahead) const;
|
||||
char peek() const;
|
||||
|
||||
char advance();
|
||||
|
||||
bool advanceIf(char ch);
|
||||
void advance(char ch);
|
||||
|
||||
|
||||
bool skipWhitespace();
|
||||
|
||||
std::string readTo(char delimiter);
|
||||
|
||||
std::string readAlphanumeric();
|
||||
|
||||
std::string readDigits(int radix);
|
||||
|
||||
private:
|
||||
std::string input_;
|
||||
std::size_t pos_;
|
||||
std::size_t start_;
|
||||
|
||||
static int digitValue(char c, int radix);
|
||||
};
|
||||
|
||||
#endif // LEXER_H
|
||||
77
ass3/simulator_SIC_XE/include/loader.h
Normal file
77
ass3/simulator_SIC_XE/include/loader.h
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
#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,
|
||||
MODIFICATION,
|
||||
END,
|
||||
UNKNOWN
|
||||
};
|
||||
|
||||
struct HeaderMetadata {
|
||||
string program_name;
|
||||
int start_address;
|
||||
int length;
|
||||
};
|
||||
struct TextRecord {
|
||||
int start_address;
|
||||
std::vector<uint8_t> data;
|
||||
};
|
||||
struct ModificationRecord {
|
||||
int address; // Address to be modified
|
||||
int length; // Length in nibbles
|
||||
bool add; // true for +, false for -
|
||||
};
|
||||
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;
|
||||
int _relocation_address;
|
||||
HeaderMetadata readHeader();
|
||||
TextRecord readTextRecord();
|
||||
ModificationRecord readModificationRecord();
|
||||
EndRecord readEndRecord();
|
||||
bool load_into_memory(int start_address, const std::vector<uint8_t>& data);
|
||||
void applyModification(const ModificationRecord& mod);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // LOADER_H
|
||||
149
ass3/simulator_SIC_XE/include/machine.h
Normal file
149
ass3/simulator_SIC_XE/include/machine.h
Normal 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
|
||||
45
ass3/simulator_SIC_XE/include/mnemonic.h
Normal file
45
ass3/simulator_SIC_XE/include/mnemonic.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
// mnemonic.h
|
||||
#ifndef MNEMONIC_H
|
||||
#define MNEMONIC_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <variant>
|
||||
|
||||
#include "opcode.h"
|
||||
|
||||
struct Empty {};
|
||||
struct Register { int num; };
|
||||
struct Immediate { int value; };
|
||||
struct SymbolRef {
|
||||
std::string name;
|
||||
bool indexed = false;
|
||||
bool immediate = false;
|
||||
bool indirect = false;
|
||||
};
|
||||
|
||||
using Operand = std::variant<Empty, Register, Immediate, SymbolRef>;
|
||||
|
||||
class Mnemonic {
|
||||
public:
|
||||
Mnemonic(std::uint8_t opcode, InstructionType type, bool extended)
|
||||
: _opcode(opcode), _extended(extended), _type(type) {}
|
||||
|
||||
std::uint8_t opcode() const { return _opcode; }
|
||||
bool extended() const { return _extended; }
|
||||
InstructionType type() const { return _type; }
|
||||
|
||||
std::vector<Operand>& operands() { return _operands; }
|
||||
const std::vector<Operand>& operands() const { return _operands; }
|
||||
|
||||
std::string toString() const;
|
||||
|
||||
private:
|
||||
std::uint8_t _opcode;
|
||||
bool _extended;
|
||||
InstructionType _type;
|
||||
std::vector<Operand> _operands;
|
||||
};
|
||||
|
||||
#endif // MNEMONIC_H
|
||||
98
ass3/simulator_SIC_XE/include/node.h
Normal file
98
ass3/simulator_SIC_XE/include/node.h
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
#ifndef NODE_H
|
||||
#define NODE_H
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <variant>
|
||||
#include <cstdint>
|
||||
#include "mnemonic.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
class Node {
|
||||
public:
|
||||
virtual ~Node() = default;
|
||||
|
||||
string getLabel() const { return _label; }
|
||||
string getComment() const { return _comment; }
|
||||
std::shared_ptr<Mnemonic> getMnemonic() const { return _mnemonic; }
|
||||
|
||||
virtual string toString() const;
|
||||
|
||||
protected:
|
||||
string _label;
|
||||
std::shared_ptr<Mnemonic> _mnemonic;
|
||||
string _comment;
|
||||
};
|
||||
|
||||
class InstructionNode : public Node {
|
||||
public:
|
||||
InstructionNode(string label,
|
||||
std::shared_ptr<Mnemonic> mnemonic,
|
||||
string comment) {
|
||||
_label = std::move(label);
|
||||
_mnemonic = std::move(mnemonic);
|
||||
_comment = std::move(comment);
|
||||
}
|
||||
|
||||
string toString() const override;
|
||||
};
|
||||
|
||||
class CommentNode : public Node {
|
||||
public:
|
||||
explicit CommentNode(string text) {
|
||||
_comment = std::move(text);
|
||||
}
|
||||
|
||||
string toString() const override;
|
||||
};
|
||||
|
||||
enum class DirectiveKind {
|
||||
START, END, BASE, NOBASE, EQU, ORG, LTORG,
|
||||
EXTDEF, EXTREF, CSECT
|
||||
};
|
||||
|
||||
using DirectiveArg = std::variant<std::monostate, int, std::string, std::vector<std::string>>;
|
||||
|
||||
class DirectiveNode : public Node {
|
||||
public:
|
||||
DirectiveNode(string label, DirectiveKind kind, DirectiveArg arg, string comment)
|
||||
: _kind(kind), _arg(std::move(arg)) {
|
||||
_label = std::move(label);
|
||||
_comment = std::move(comment);
|
||||
}
|
||||
|
||||
DirectiveKind kind() const { return _kind; }
|
||||
const DirectiveArg& arg() const { return _arg; }
|
||||
|
||||
string toString() const override;
|
||||
|
||||
private:
|
||||
DirectiveKind _kind;
|
||||
DirectiveArg _arg;
|
||||
};
|
||||
|
||||
enum class DataKind { WORD, BYTE, RESW, RESB };
|
||||
|
||||
using DataValue = std::variant<std::monostate, int, std::vector<uint8_t>>;
|
||||
|
||||
class DataNode : public Node {
|
||||
public:
|
||||
DataNode(string label, DataKind kind, DataValue value, string comment)
|
||||
: _kind(kind), _value(std::move(value)) {
|
||||
_label = std::move(label);
|
||||
_comment = std::move(comment);
|
||||
}
|
||||
|
||||
DataKind kind() const { return _kind; }
|
||||
const DataValue& value() const { return _value; }
|
||||
|
||||
string toString() const override;
|
||||
|
||||
private:
|
||||
DataKind _kind;
|
||||
DataValue _value;
|
||||
};
|
||||
|
||||
#endif // NODE_H
|
||||
127
ass3/simulator_SIC_XE/include/opcode.h
Normal file
127
ass3/simulator_SIC_XE/include/opcode.h
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
#ifndef OPCODE_H
|
||||
#define OPCODE_H
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <string_view>
|
||||
#include <optional>
|
||||
#include <cstdint>
|
||||
|
||||
// ==============================
|
||||
// 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
|
||||
|
||||
static std::unordered_map<std::string_view, uint8_t> mnemonicToOpcode;
|
||||
static bool opcodeTablesInitialized = false;
|
||||
|
||||
|
||||
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[];
|
||||
|
||||
extern std::optional<uint8_t> findOpcodeByMnemonic(std::string_view name);
|
||||
extern const InstructionInfo& getInstructionInfo(uint8_t opcode);
|
||||
|
||||
|
||||
// Initialize the instruction table
|
||||
void loadInstructionSet();
|
||||
|
||||
#endif // OPCODE_H
|
||||
18
ass3/simulator_SIC_XE/include/output_device.h
Normal file
18
ass3/simulator_SIC_XE/include/output_device.h
Normal 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
|
||||
52
ass3/simulator_SIC_XE/include/parser.h
Normal file
52
ass3/simulator_SIC_XE/include/parser.h
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
// parser.h
|
||||
#ifndef PARSER_H
|
||||
#define PARSER_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <cstdint>
|
||||
|
||||
#include "lexer.h"
|
||||
#include "code.h"
|
||||
#include "opcode.h"
|
||||
#include "mnemonic.h"
|
||||
|
||||
class Parser {
|
||||
public:
|
||||
Parser() = default;
|
||||
|
||||
Code parse(const std::string& input);
|
||||
|
||||
private:
|
||||
std::string parseLabel();
|
||||
std::shared_ptr<Mnemonic> parseMnemonic();
|
||||
std::string parseSymbol();
|
||||
int parseRegister();
|
||||
void parseComma();
|
||||
bool parseIndexed();
|
||||
int parseNumber(int lo, int hi);
|
||||
std::vector<std::uint8_t> parseData();
|
||||
|
||||
void parseOperands(Mnemonic& m);
|
||||
|
||||
bool isDirective(const std::string& name);
|
||||
bool isDataDirective(const std::string& name);
|
||||
std::shared_ptr<Node> parseDirective(const std::string& label, const std::string& directive);
|
||||
std::shared_ptr<Node> parseDataDirective(const std::string& label, const std::string& directive);
|
||||
|
||||
std::shared_ptr<Node> parseInstruction();
|
||||
Code parseCode();
|
||||
|
||||
std::shared_ptr<Mnemonic> makeMnemonic(const std::string& name, bool extended);
|
||||
static void initMnemonicMap();
|
||||
|
||||
private:
|
||||
Lexer lexer_{""};
|
||||
|
||||
static inline std::unordered_map<std::string, std::uint8_t> s_nameToOpcode{};
|
||||
static inline bool s_mnemonicMapInitialized = false;
|
||||
};
|
||||
|
||||
#endif // PARSER_H
|
||||
21
ass3/simulator_SIC_XE/include/reader.h
Normal file
21
ass3/simulator_SIC_XE/include/reader.h
Normal 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
|
||||
22
ass3/simulator_SIC_XE/include/string_reader.h
Normal file
22
ass3/simulator_SIC_XE/include/string_reader.h
Normal 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
|
||||
95
ass3/simulator_SIC_XE/include/utils.h
Normal file
95
ass3/simulator_SIC_XE/include/utils.h
Normal 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
|
||||
Loading…
Add table
Add a link
Reference in a new issue