added instruction functionality
This commit is contained in:
parent
483a16c194
commit
d4754a048d
9 changed files with 754 additions and 170 deletions
38
simulator_SIC_XE/include/constants.h
Normal file
38
simulator_SIC_XE/include/constants.h
Normal file
|
|
@ -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
|
||||||
|
|
@ -1,11 +1,17 @@
|
||||||
#ifndef INSTRUCTIONS_H
|
#ifndef INSTRUCTIONS_H
|
||||||
#define INSTRUCTIONS_H
|
#define INSTRUCTIONS_H
|
||||||
|
|
||||||
#include "opcode.h"
|
#include "utils.h"
|
||||||
|
|
||||||
|
class Machine; // forward declaration
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Type 2 instruction handlers
|
// Type 2 instruction handlers
|
||||||
void addr_handler(Machine& m, int r1, int r2);
|
void addr_handler(Machine& m, int r1, int r2);
|
||||||
void clear_handler(Machine& m, int r, int unused);
|
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 divr_handler(Machine& m, int r1, int r2);
|
||||||
void mulr_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 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);
|
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
|
#endif // INSTRUCTIONS_H
|
||||||
|
|
@ -4,18 +4,15 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "constants.h"
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
#include "input_device.h"
|
#include "input_device.h"
|
||||||
#include "output_device.h"
|
#include "output_device.h"
|
||||||
#include "file_device.h"
|
#include "file_device.h"
|
||||||
#include "opcode.h"
|
#include "opcode.h"
|
||||||
|
#include "utils.h"
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#define MEMORY_SIZE 65536
|
|
||||||
#define NUM_DEVICES 256
|
|
||||||
|
|
||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
using std::cerr;
|
using std::cerr;
|
||||||
|
|
@ -28,28 +25,29 @@ public:
|
||||||
Machine();
|
Machine();
|
||||||
~Machine();
|
~Machine();
|
||||||
|
|
||||||
// Accessor methods for registers
|
|
||||||
int getA() const { return A; }
|
int getA() const { return A; }
|
||||||
void setA(int value) { A = value; }
|
void setA(int value) { A = toSIC24(value); }
|
||||||
|
|
||||||
int getB() const { return B; }
|
int getB() const { return B; }
|
||||||
void setB(int value) { B = value; }
|
void setB(int value) { B = toSIC24(value); }
|
||||||
|
|
||||||
int getX() const { return X; }
|
int getX() const { return X; }
|
||||||
void setX(int value) { X = value; }
|
void setX(int value) { X = toSIC24(value); }
|
||||||
|
|
||||||
int getL() const { return L; }
|
int getL() const { return L; }
|
||||||
void setL(int value) { L = value; }
|
void setL(int value) { L = toSIC24(value); }
|
||||||
|
|
||||||
int getS() const { return S; }
|
int getS() const { return S; }
|
||||||
void setS(int value) { S = value; }
|
void setS(int value) { S = toSIC24(value); }
|
||||||
|
|
||||||
int getT() const { return T; }
|
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; }
|
int getPC() const { return PC; }
|
||||||
void setPC(int value) { PC = value; }
|
void setPC(int value) { PC = value; }
|
||||||
|
|
||||||
|
// status word: keep as-is
|
||||||
int getSW() const { return SW; }
|
int getSW() const { return SW; }
|
||||||
void setSW(int value) { SW = value; }
|
void setSW(int value) { SW = value; }
|
||||||
|
|
||||||
|
|
@ -83,7 +81,7 @@ public:
|
||||||
|
|
||||||
bool execF1(int opcode);
|
bool execF1(int opcode);
|
||||||
bool execF2(int opcode, int operand);
|
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
|
// error handling methods
|
||||||
void notImplemented(string mnemonic);
|
void notImplemented(string mnemonic);
|
||||||
|
|
@ -106,40 +104,6 @@ private:
|
||||||
Device fallbackDevice;
|
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
|
#endif // MACHINE_H
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
#ifndef OPCODE_H
|
#ifndef OPCODE_H
|
||||||
#define OPCODE_H
|
#define OPCODE_H
|
||||||
|
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
// ==============================
|
// ==============================
|
||||||
// Opcode definitions (SIC/XE)
|
// Opcode definitions (SIC/XE)
|
||||||
// ==============================
|
// ==============================
|
||||||
|
|
@ -65,15 +67,6 @@
|
||||||
#define WD 0xDC
|
#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 {
|
enum class InstructionType {
|
||||||
TYPE1,
|
TYPE1,
|
||||||
TYPE2,
|
TYPE2,
|
||||||
|
|
|
||||||
80
simulator_SIC_XE/include/utils.h
Normal file
80
simulator_SIC_XE/include/utils.h
Normal file
|
|
@ -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
|
||||||
|
|
@ -1,16 +1,81 @@
|
||||||
#include "instructions.h"
|
#include "instructions.h"
|
||||||
#include "machine.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<double>(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) {
|
void addr_handler(Machine& m, int r1, int r2) {
|
||||||
m.setReg(r2, m.getReg(r1) + m.getReg(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) {
|
void clear_handler(Machine& m, int r, int unused) {
|
||||||
m.setReg(r, 0);
|
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) {
|
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));
|
m.setReg(r2, m.getReg(r1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// SHIFTL r1, n → left *circular* shift n bits
|
||||||
void shiftl_handler(Machine &m, int r1, int n)
|
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)
|
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)
|
void subr_handler(Machine &m, int r1, int r2)
|
||||||
{
|
{
|
||||||
m.setReg(r2, m.getReg(r2) - m.getReg(r1));
|
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);
|
int valR1 = m.getReg(r1);
|
||||||
m.setSW(sic_comp(valX, valR1, m.getSW()));
|
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()));
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#include "opcode.h"
|
#include "opcode.h"
|
||||||
#include "instructions.h"
|
#include "instructions.h"
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
using std::make_shared;
|
using std::make_shared;
|
||||||
|
|
||||||
|
|
@ -128,23 +129,93 @@ void Machine::setWord(int address, int value)
|
||||||
cerr << prefix << "Invalid memory address: " << address << endl;
|
cerr << prefix << "Invalid memory address: " << address << endl;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
value &= 0xFFFFFF;
|
||||||
|
|
||||||
memory[address] = static_cast<unsigned char>(value & 0xFF);
|
memory[address] = static_cast<unsigned char>(value & 0xFF);
|
||||||
memory[address + 1] = static_cast<unsigned char>((value >> 8) & 0xFF);
|
memory[address + 1] = static_cast<unsigned char>((value >> 8) & 0xFF);
|
||||||
memory[address + 2] = static_cast<unsigned char>((value >> 16) & 0xFF);
|
memory[address + 2] = static_cast<unsigned char>((value >> 16) & 0xFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: implement proper float storage and retrieval
|
|
||||||
double Machine::getFloat(int address)
|
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)
|
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)
|
Device &Machine::getDevice(int num)
|
||||||
{
|
{
|
||||||
if(num < 0 || num >= static_cast<int>(devices.size()) || !devices[num]) {
|
if(num < 0 || num >= static_cast<int>(devices.size()) || !devices[num]) {
|
||||||
|
|
@ -195,49 +266,48 @@ int Machine::fetch()
|
||||||
return getByte(PC++);
|
return getByte(PC++);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Machine::execute()
|
void Machine::execute() {
|
||||||
{
|
int b1 = fetch();
|
||||||
int opcode = fetch();
|
InstructionInfo &info = instructions[b1];
|
||||||
InstructionType type = instructions[opcode].type;
|
|
||||||
switch (type) {
|
if (info.type == InstructionType::TYPE1) { execF1(b1); return; }
|
||||||
case InstructionType::TYPE1: execF1(opcode);break;
|
if (info.type == InstructionType::TYPE2) { execF2(b1, fetch()); return; }
|
||||||
case InstructionType::TYPE2: execF2(opcode, fetch());break;
|
|
||||||
case InstructionType::TYPE3_4: // extract n and i bits
|
int opcode = b1 & TYPE3_4_SIC_MASK;
|
||||||
{
|
InstructionInfo &info34 = instructions[opcode];
|
||||||
int ni = opcode & 0x3;
|
int ni = b1 & NI_MASK;
|
||||||
int operand = fetch();
|
|
||||||
execSICF3F4(opcode, ni, operand);
|
if (info34.type == InstructionType::TYPE3_4) {
|
||||||
}
|
int b2 = fetch(), b3 = fetch();
|
||||||
break;
|
int x = (b2 & 0x80) ? 1 : 0;
|
||||||
default: invalidOpcode(opcode); break;
|
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)
|
bool Machine::execF1(int opcode)
|
||||||
{
|
{
|
||||||
switch (opcode)
|
undefinedHandler(opcode);
|
||||||
{
|
|
||||||
case FIX:
|
|
||||||
setA(static_cast<int>(getF()));
|
|
||||||
return true;
|
|
||||||
case FLOAT:
|
|
||||||
setF(static_cast<double>(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;
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -255,7 +325,47 @@ bool Machine::execF2(int opcode, int operand)
|
||||||
return false;
|
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<void(*)(Machine&, int, AddressingMode)>(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<void(*)(Machine&, int, AddressingMode)>(instructions[opcode].handler);
|
||||||
|
h(*this, ea, mode);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
undefinedHandler(opcode);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,15 +13,41 @@ int main()
|
||||||
Machine machine;
|
Machine machine;
|
||||||
|
|
||||||
cout << "Machine initialized successfully." << endl;
|
cout << "Machine initialized successfully." << endl;
|
||||||
|
|
||||||
// COMPUTE A + B and store result in B
|
// Test 1: ADD immediate 0x0030 (ADD #48)
|
||||||
machine.setA(10);
|
machine.setA(10);
|
||||||
machine.setB(20);
|
cout << "Test 1 - Immediate ADD:" << endl;
|
||||||
machine.setByte(0, ADDR);
|
cout << " A before: " << machine.getA() << endl;
|
||||||
machine.setByte(1, 0x03); // r1 = 0 (A), r2 = 3 (B)
|
machine.setByte(0x0, 0x19); // ADD with ni=01 (immediate addressing)
|
||||||
cout << "Before ADDR: A = " << machine.getA() << ", B = " << machine.getB() << endl;
|
machine.setByte(0x1, 0x00);
|
||||||
|
machine.setByte(0x2, 0x30); // Immediate value 48 (0x30)
|
||||||
machine.execute();
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -1,70 +1,71 @@
|
||||||
#include "opcode.h"
|
#include "opcode.h"
|
||||||
#include "instructions.h"
|
#include "instructions.h"
|
||||||
|
#include "utils.h"
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
InstructionInfo instructions[0xff];
|
InstructionInfo instructions[0xff];
|
||||||
|
|
||||||
void loadInstructionSet()
|
void loadInstructionSet()
|
||||||
{
|
{
|
||||||
instructions[ADD] = {"ADD", InstructionType::TYPE3_4, nullptr};
|
instructions[ADD] = {"ADD", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(add_handler)};
|
||||||
instructions[ADDF] = {"ADDF", InstructionType::TYPE3_4, nullptr};
|
instructions[ADDF] = {"ADDF", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(addf_handler)};
|
||||||
instructions[ADDR] = {"ADDR", InstructionType::TYPE2, reinterpret_cast<RawHandler>(addr_handler)};
|
instructions[ADDR] = {"ADDR", InstructionType::TYPE2, reinterpret_cast<RawHandler>(addr_handler)};
|
||||||
instructions[AND] = {"AND", InstructionType::TYPE3_4, nullptr};
|
instructions[AND] = {"AND", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(and_handler)};
|
||||||
instructions[CLEAR] = {"CLEAR", InstructionType::TYPE2, reinterpret_cast<RawHandler>(clear_handler)};
|
instructions[CLEAR] = {"CLEAR", InstructionType::TYPE2, reinterpret_cast<RawHandler>(clear_handler)};
|
||||||
instructions[COMP] = {"COMP", InstructionType::TYPE3_4, nullptr};
|
instructions[COMP] = {"COMP", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(comp_handler)};
|
||||||
instructions[COMPF] = {"COMPF", InstructionType::TYPE3_4, nullptr};
|
instructions[COMPF] = {"COMPF", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(compf_handler)};
|
||||||
instructions[COMPR] = {"COMPR", InstructionType::TYPE2, nullptr};
|
instructions[COMPR] = {"COMPR", InstructionType::TYPE2, reinterpret_cast<RawHandler>(compr_handler)};
|
||||||
instructions[DIV] = {"DIV", InstructionType::TYPE3_4, nullptr};
|
instructions[DIV] = {"DIV", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(div_handler)};
|
||||||
instructions[DIVF] = {"DIVF", InstructionType::TYPE3_4, nullptr};
|
instructions[DIVF] = {"DIVF", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(divf_handler)};
|
||||||
instructions[DIVR] = {"DIVR", InstructionType::TYPE2, reinterpret_cast<RawHandler>(divr_handler)};
|
instructions[DIVR] = {"DIVR", InstructionType::TYPE2, reinterpret_cast<RawHandler>(divr_handler)};
|
||||||
instructions[FIX] = {"FIX", InstructionType::TYPE1, nullptr};
|
instructions[FIX] = {"FIX", InstructionType::TYPE1, nullptr};
|
||||||
instructions[FLOAT] = {"FLOAT", InstructionType::TYPE1, nullptr};
|
instructions[FLOAT] = {"FLOAT", InstructionType::TYPE1, nullptr};
|
||||||
instructions[HIO] = {"HIO", InstructionType::TYPE1, nullptr};
|
instructions[HIO] = {"HIO", InstructionType::TYPE1, nullptr};
|
||||||
instructions[J] = {"J", InstructionType::TYPE3_4, nullptr};
|
instructions[J] = {"J", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(j_handler)};
|
||||||
instructions[JEQ] = {"JEQ", InstructionType::TYPE3_4, nullptr};
|
instructions[JEQ] = {"JEQ", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(jeq_handler)};
|
||||||
instructions[JGT] = {"JGT", InstructionType::TYPE3_4, nullptr};
|
instructions[JGT] = {"JGT", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(jgt_handler)};
|
||||||
instructions[JLT] = {"JLT", InstructionType::TYPE3_4, nullptr};
|
instructions[JLT] = {"JLT", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(jlt_handler)};
|
||||||
instructions[JSUB] = {"JSUB", InstructionType::TYPE3_4, nullptr};
|
instructions[JSUB] = {"JSUB", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(jsub_handler)};
|
||||||
instructions[LDA] = {"LDA", InstructionType::TYPE3_4, nullptr};
|
instructions[LDA] = {"LDA", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(lda_handler)};
|
||||||
instructions[LDB] = {"LDB", InstructionType::TYPE3_4, nullptr};
|
instructions[LDB] = {"LDB", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(ldb_handler)};
|
||||||
instructions[LDCH] = {"LDCH", InstructionType::TYPE3_4, nullptr};
|
instructions[LDCH] = {"LDCH", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(ldch_handler)};
|
||||||
instructions[LDF] = {"LDF", InstructionType::TYPE3_4, nullptr};
|
instructions[LDF] = {"LDF", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(ldf_handler)};
|
||||||
instructions[LDL] = {"LDL", InstructionType::TYPE3_4, nullptr};
|
instructions[LDL] = {"LDL", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(ldl_handler)};
|
||||||
instructions[LDS] = {"LDS", InstructionType::TYPE3_4, nullptr};
|
instructions[LDS] = {"LDS", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(lds_handler)};
|
||||||
instructions[LDT] = {"LDT", InstructionType::TYPE3_4, nullptr};
|
instructions[LDT] = {"LDT", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(ldt_handler)};
|
||||||
instructions[LDX] = {"LDX", InstructionType::TYPE3_4, nullptr};
|
instructions[LDX] = {"LDX", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(ldx_handler)};
|
||||||
instructions[LPS] = {"LPS", InstructionType::TYPE3_4, nullptr};
|
instructions[LPS] = {"LPS", InstructionType::TYPE3_4, nullptr};
|
||||||
instructions[MUL] = {"MUL", InstructionType::TYPE3_4, nullptr};
|
instructions[MUL] = {"MUL", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(mul_handler)};
|
||||||
instructions[MULF] = {"MULF", InstructionType::TYPE3_4, nullptr};
|
instructions[MULF] = {"MULF", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(mulf_handler)};
|
||||||
instructions[MULR] = {"MULR", InstructionType::TYPE2, reinterpret_cast<RawHandler>(mulr_handler)};
|
instructions[MULR] = {"MULR", InstructionType::TYPE2, reinterpret_cast<RawHandler>(mulr_handler)};
|
||||||
instructions[NORM] = {"NORM", InstructionType::TYPE1, nullptr};
|
instructions[NORM] = {"NORM", InstructionType::TYPE1, nullptr};
|
||||||
instructions[OR] = {"OR", InstructionType::TYPE3_4, nullptr};
|
instructions[OR] = {"OR", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(or_handler)};
|
||||||
instructions[RD] = {"RD", InstructionType::TYPE3_4, nullptr};
|
instructions[RD] = {"RD", InstructionType::TYPE3_4, nullptr};
|
||||||
instructions[RMO] = {"RMO", InstructionType::TYPE2, reinterpret_cast<RawHandler>(rmo_handler)};
|
instructions[RMO] = {"RMO", InstructionType::TYPE2, reinterpret_cast<RawHandler>(rmo_handler)};
|
||||||
instructions[RSUB] = {"RSUB", InstructionType::TYPE3_4, nullptr};
|
instructions[RSUB] = {"RSUB", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(rsub_handler)};
|
||||||
instructions[SHIFTL] = {"SHIFTL", InstructionType::TYPE2, reinterpret_cast<RawHandler>(shiftl_handler)};
|
instructions[SHIFTL] = {"SHIFTL", InstructionType::TYPE2, reinterpret_cast<RawHandler>(shiftl_handler)};
|
||||||
instructions[SHIFTR] = {"SHIFTR", InstructionType::TYPE2, reinterpret_cast<RawHandler>(shiftr_handler)};
|
instructions[SHIFTR] = {"SHIFTR", InstructionType::TYPE2, reinterpret_cast<RawHandler>(shiftr_handler)};
|
||||||
instructions[SIO] = {"SIO", InstructionType::TYPE1, nullptr};
|
instructions[SIO] = {"SIO", InstructionType::TYPE1, nullptr};
|
||||||
instructions[SSK] = {"SSK", InstructionType::TYPE3_4, nullptr};
|
instructions[SSK] = {"SSK", InstructionType::TYPE3_4, nullptr};
|
||||||
instructions[STA] = {"STA", InstructionType::TYPE3_4, nullptr};
|
instructions[STA] = {"STA", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(sta_handler)};
|
||||||
instructions[STB] = {"STB", InstructionType::TYPE3_4, nullptr};
|
instructions[STB] = {"STB", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(stb_handler)};
|
||||||
instructions[STCH] = {"STCH", InstructionType::TYPE3_4, nullptr};
|
instructions[STCH] = {"STCH", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(stch_handler)};
|
||||||
instructions[STF] = {"STF", InstructionType::TYPE3_4, nullptr};
|
instructions[STF] = {"STF", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(stf_handler)};
|
||||||
instructions[STI] = {"STI", InstructionType::TYPE3_4, nullptr};
|
instructions[STI] = {"STI", InstructionType::TYPE3_4, nullptr};
|
||||||
instructions[STL] = {"STL", InstructionType::TYPE3_4, nullptr};
|
instructions[STL] = {"STL", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(stl_handler)};
|
||||||
instructions[STS] = {"STS", InstructionType::TYPE3_4, nullptr};
|
instructions[STS] = {"STS", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(sts_handler)};
|
||||||
instructions[STSW] = {"STSW", InstructionType::TYPE3_4, nullptr};
|
instructions[STSW] = {"STSW", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(stsw_handler)};
|
||||||
instructions[STT] = {"STT", InstructionType::TYPE3_4, nullptr};
|
instructions[STT] = {"STT", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(stt_handler)};
|
||||||
instructions[STX] = {"STX", InstructionType::TYPE3_4, nullptr};
|
instructions[STX] = {"STX", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(stx_handler)};
|
||||||
instructions[SUB] = {"SUB", InstructionType::TYPE3_4, nullptr};
|
instructions[SUB] = {"SUB", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(sub_handler)};
|
||||||
instructions[SUBF] = {"SUBF", InstructionType::TYPE3_4, nullptr};
|
instructions[SUBF] = {"SUBF", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(subf_handler)};
|
||||||
instructions[SUBR] = {"SUBR", InstructionType::TYPE2, reinterpret_cast<RawHandler>(subr_handler)};
|
instructions[SUBR] = {"SUBR", InstructionType::TYPE2, reinterpret_cast<RawHandler>(subr_handler)};
|
||||||
instructions[SVC] = {"SVC", InstructionType::TYPE2, reinterpret_cast<RawHandler>(svc_handler)};
|
instructions[SVC] = {"SVC", InstructionType::TYPE2, reinterpret_cast<RawHandler>(svc_handler)};
|
||||||
instructions[TIXR] = {"TIXR", InstructionType::TYPE2, reinterpret_cast<RawHandler>(tixr_handler)};
|
instructions[TIXR] = {"TIXR", InstructionType::TYPE2, reinterpret_cast<RawHandler>(tixr_handler)};
|
||||||
instructions[TD] = {"TD", InstructionType::TYPE3_4, nullptr};
|
instructions[TD] = {"TD", InstructionType::TYPE3_4, nullptr};
|
||||||
instructions[TIX] = {"TIX", InstructionType::TYPE3_4, nullptr};
|
instructions[TIX] = {"TIX", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(tix_handler)};
|
||||||
instructions[TIO] = {"TIO", InstructionType::TYPE1, nullptr};
|
instructions[TIO] = {"TIO", InstructionType::TYPE1, nullptr};
|
||||||
instructions[WD] = {"WD", InstructionType::TYPE3_4, nullptr};
|
instructions[WD] = {"WD", InstructionType::TYPE3_4, nullptr};
|
||||||
|
|
||||||
// Mark uninitialized opcodes as INVALID
|
// Mark uninitialized opcodes as INVALID
|
||||||
for (int i = 0; i < 0xff; ++i) {
|
for (int i = 0; i < 0xff; ++i) {
|
||||||
|
|
@ -72,4 +73,15 @@ void loadInstructionSet()
|
||||||
instructions[i] = {"INVALID", InstructionType::INVALID, nullptr};
|
instructions[i] = {"INVALID", InstructionType::INVALID, nullptr};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue