added extra istructions
This commit is contained in:
parent
ad3078ba48
commit
ba18b92116
8 changed files with 470 additions and 123 deletions
|
|
@ -35,4 +35,9 @@ 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;
|
||||
|
||||
|
||||
#endif // CONSTANTS_H
|
||||
|
|
@ -12,6 +12,7 @@ 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);
|
||||
|
|
@ -75,4 +76,26 @@ 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
|
||||
|
|
@ -26,7 +26,7 @@ using std::cout;
|
|||
class Machine {
|
||||
public:
|
||||
Machine();
|
||||
Machine(int speedkHz) : Machine() { this->speedkHz = speedkHz; }
|
||||
Machine(int speedkHz) : Machine() { this->speedkHz = speedkHz; _instructionsTable = instructions; }
|
||||
~Machine();
|
||||
|
||||
int getA() const { return A; }
|
||||
|
|
@ -82,16 +82,13 @@ public:
|
|||
int fetch();
|
||||
void execute();
|
||||
|
||||
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);
|
||||
|
||||
// Execution and speed control
|
||||
int getSpeed() const;
|
||||
void setSpeed(int kHz);
|
||||
void start();
|
||||
void stop();
|
||||
void tick();
|
||||
void halt();
|
||||
|
||||
// error handling methods
|
||||
void notImplemented(string mnemonic);
|
||||
|
|
@ -100,6 +97,22 @@ public:
|
|||
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;
|
||||
|
|
@ -116,6 +129,17 @@ private:
|
|||
// Execution control
|
||||
std::atomic<bool> running{false};
|
||||
std::atomic<int> speedkHz{1}; // Default 1 kHz
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -66,6 +66,28 @@
|
|||
#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,
|
||||
|
|
@ -86,6 +108,7 @@ struct InstructionInfo {
|
|||
};
|
||||
|
||||
extern InstructionInfo instructions[];
|
||||
extern InstructionInfo instructionsEXEX[];
|
||||
|
||||
// Initialize the instruction table
|
||||
void loadInstructionSet();
|
||||
|
|
|
|||
|
|
@ -412,3 +412,177 @@ void wd_handler(Machine &m, int ea, AddressingMode mode)
|
|||
// Write rightmost byte of A register to device
|
||||
device.write(static_cast<unsigned char>(m.getA() & 0xFF));
|
||||
}
|
||||
|
||||
void xexe_handler(Machine &m)
|
||||
{
|
||||
m.enableExtendedMode();
|
||||
m.execute();
|
||||
m.disableExtendedMode();
|
||||
}
|
||||
|
||||
void halt_handler(Machine &m)
|
||||
{
|
||||
m.halt();
|
||||
}
|
||||
|
||||
void nop_handler(Machine &m)
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
void vaddr_handler(Machine &m, int r1, int r2)
|
||||
{
|
||||
int result[VECTOR_REG_SIZE];
|
||||
for (int i = 0; i < VECTOR_REG_SIZE; ++i) {
|
||||
result[i] = m.getVectorRegister(r1)[i] + m.getVectorRegister(r2)[i];
|
||||
}
|
||||
m.setVectorRegister(r2, result);
|
||||
}
|
||||
|
||||
void vsubr_handler(Machine &m, int r1, int r2)
|
||||
{
|
||||
int result[VECTOR_REG_SIZE];
|
||||
for (int i = 0; i < VECTOR_REG_SIZE; ++i) {
|
||||
result[i] = m.getVectorRegister(r2)[i] - m.getVectorRegister(r1)[i];
|
||||
}
|
||||
m.setVectorRegister(r2, result);
|
||||
}
|
||||
|
||||
void vmulr_handler(Machine &m, int r1, int r2)
|
||||
{
|
||||
int result[VECTOR_REG_SIZE];
|
||||
for (int i = 0; i < VECTOR_REG_SIZE; ++i) {
|
||||
result[i] = m.getVectorRegister(r1)[i] * m.getVectorRegister(r2)[i];
|
||||
}
|
||||
m.setVectorRegister(r2, result);
|
||||
}
|
||||
|
||||
void vdivr_handler(Machine &m, int r1, int r2)
|
||||
{
|
||||
int result[VECTOR_REG_SIZE];
|
||||
for (int i = 0; i < VECTOR_REG_SIZE; ++i) {
|
||||
if (m.getVectorRegister(r1)[i] == 0) {
|
||||
m.divisionByZero(VDIVR);
|
||||
return;
|
||||
}
|
||||
result[i] = m.getVectorRegister(r2)[i] / m.getVectorRegister(r1)[i];
|
||||
}
|
||||
m.setVT(result);
|
||||
}
|
||||
|
||||
void vadd_handler(Machine &m, int ea, AddressingMode mode)
|
||||
{
|
||||
int baseAddr = resolveWordOperand(m, ea, mode);
|
||||
int vec[VECTOR_REG_SIZE];
|
||||
for (int i = 0; i < VECTOR_REG_SIZE; ++i) {
|
||||
vec[i] = m.getWord(baseAddr + i * 3);
|
||||
}
|
||||
int result[VECTOR_REG_SIZE];
|
||||
for (int i = 0; i < VECTOR_REG_SIZE; ++i) {
|
||||
result[i] = m.getVA()[i] + vec[i];
|
||||
}
|
||||
m.setVA(result);
|
||||
}
|
||||
|
||||
void vsub_handler(Machine &m, int ea, AddressingMode mode)
|
||||
{
|
||||
int baseAddr = resolveWordOperand(m, ea, mode);
|
||||
int vec[VECTOR_REG_SIZE];
|
||||
for (int i = 0; i < VECTOR_REG_SIZE; ++i) {
|
||||
vec[i] = m.getWord(baseAddr + i * 3);
|
||||
}
|
||||
int result[VECTOR_REG_SIZE];
|
||||
for (int i = 0; i < VECTOR_REG_SIZE; ++i) {
|
||||
result[i] = m.getVA()[i] - vec[i];
|
||||
}
|
||||
m.setVA(result);
|
||||
}
|
||||
|
||||
void vmul_handler(Machine &m, int ea, AddressingMode mode)
|
||||
{
|
||||
int baseAddr = resolveWordOperand(m, ea, mode);
|
||||
int vec[VECTOR_REG_SIZE];
|
||||
for (int i = 0; i < VECTOR_REG_SIZE; ++i) {
|
||||
vec[i] = m.getWord(baseAddr + i * 3);
|
||||
}
|
||||
int result[VECTOR_REG_SIZE];
|
||||
for (int i = 0; i < VECTOR_REG_SIZE; ++i) {
|
||||
result[i] = m.getVA()[i] * vec[i];
|
||||
}
|
||||
m.setVA(result);
|
||||
}
|
||||
|
||||
void vdiv_handler(Machine &m, int ea, AddressingMode mode)
|
||||
{
|
||||
int baseAddr = resolveWordOperand(m, ea, mode);
|
||||
int vec[VECTOR_REG_SIZE];
|
||||
for (int i = 0; i < VECTOR_REG_SIZE; ++i) {
|
||||
vec[i] = m.getWord(baseAddr + i * 3);
|
||||
}
|
||||
int result[VECTOR_REG_SIZE];
|
||||
for (int i = 0; i < VECTOR_REG_SIZE; ++i) {
|
||||
if (vec[i] == 0) {
|
||||
m.divisionByZero(VDIV);
|
||||
return;
|
||||
}
|
||||
result[i] = m.getVA()[i] / vec[i];
|
||||
}
|
||||
m.setVA(result);
|
||||
}
|
||||
|
||||
void stva_handler(Machine &m, int ea, AddressingMode mode)
|
||||
{
|
||||
int baseAddr = resolveWordOperand(m, ea, mode);
|
||||
const int* vec = m.getVA();
|
||||
for (int i = 0; i < VECTOR_REG_SIZE; ++i) {
|
||||
m.setWord(baseAddr + i * 3, vec[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void stvs_handler(Machine &m, int ea, AddressingMode mode)
|
||||
{
|
||||
int baseAddr = resolveWordOperand(m, ea, mode);
|
||||
const int* vec = m.getVS();
|
||||
for (int i = 0; i < VECTOR_REG_SIZE; ++i) {
|
||||
m.setWord(baseAddr + i * 3, vec[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void stvt_handler(Machine &m, int ea, AddressingMode mode)
|
||||
{
|
||||
int baseAddr = resolveWordOperand(m, ea, mode);
|
||||
const int* vec = m.getVT();
|
||||
for (int i = 0; i < VECTOR_REG_SIZE; ++i) {
|
||||
m.setWord(baseAddr + i * 3, vec[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void ldva_handler(Machine &m, int ea, AddressingMode mode)
|
||||
{
|
||||
int baseAddr = resolveWordOperand(m, ea, mode);
|
||||
int vec[VECTOR_REG_SIZE];
|
||||
for (int i = 0; i < VECTOR_REG_SIZE; ++i) {
|
||||
vec[i] = m.getWord(baseAddr + i * 3);
|
||||
}
|
||||
m.setVA(vec);
|
||||
}
|
||||
|
||||
void ldvs_handler(Machine &m, int ea, AddressingMode mode)
|
||||
{
|
||||
int baseAddr = resolveWordOperand(m, ea, mode);
|
||||
int vec[VECTOR_REG_SIZE];
|
||||
for (int i = 0; i < VECTOR_REG_SIZE; ++i) {
|
||||
vec[i] = m.getWord(baseAddr + i * 3);
|
||||
}
|
||||
m.setVS(vec);
|
||||
}
|
||||
|
||||
void ldvt_handler(Machine &m, int ea, AddressingMode mode)
|
||||
{
|
||||
int baseAddr = resolveWordOperand(m, ea, mode);
|
||||
int vec[VECTOR_REG_SIZE];
|
||||
for (int i = 0; i < VECTOR_REG_SIZE; ++i) {
|
||||
vec[i] = m.getWord(baseAddr + i * 3);
|
||||
}
|
||||
m.setVT(vec);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ Machine::Machine()
|
|||
devices[1] = make_shared<OutputDevice>(std::cout);
|
||||
// device 2: standard error
|
||||
devices[2] = make_shared<OutputDevice>(std::cerr);
|
||||
_exex_mode = false;
|
||||
_instructionsTable = instructions;
|
||||
}
|
||||
|
||||
Machine::~Machine()
|
||||
|
|
@ -67,6 +69,62 @@ void Machine::undefinedHandler(int opcode)
|
|||
cout << prefix << "Undefined handler for opcode: " << opcode << endl;
|
||||
}
|
||||
|
||||
void Machine::enableExtendedMode()
|
||||
{
|
||||
if(!USE_EXTENDED_MODE) return;
|
||||
_exex_mode = true;
|
||||
_instructionsTable = instructionsEXEX;
|
||||
}
|
||||
|
||||
void Machine::disableExtendedMode()
|
||||
{
|
||||
if(!USE_EXTENDED_MODE) return;
|
||||
_exex_mode = false;
|
||||
_instructionsTable = instructions;
|
||||
}
|
||||
|
||||
int *Machine::getVectorRegister(int regNum)
|
||||
{
|
||||
switch (regNum) {
|
||||
case 0: return VA;
|
||||
case 4: return VS;
|
||||
case 5: return VT;
|
||||
default:
|
||||
cerr << prefix << "Invalid register number: " << regNum << endl;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Machine::setVectorRegister(int regNum, const int *values)
|
||||
{
|
||||
int* targetReg = getVectorRegister(regNum);
|
||||
if (targetReg == nullptr) return;
|
||||
for (int i = 0; i < VECTOR_REG_SIZE; i++) {
|
||||
targetReg[i] = toSIC24(values[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void Machine::setVA(const int *values)
|
||||
{
|
||||
for (int i = 0; i < VECTOR_REG_SIZE; i++) {
|
||||
VA[i] = toSIC24(values[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void Machine::setVS(const int *values)
|
||||
{
|
||||
for (int i = 0; i < VECTOR_REG_SIZE; i++) {
|
||||
VS[i] = toSIC24(values[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void Machine::setVT(const int *values)
|
||||
{
|
||||
for (int i = 0; i < VECTOR_REG_SIZE; i++) {
|
||||
VT[i] = toSIC24(values[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void Machine::tick()
|
||||
{
|
||||
const int speed = speedkHz.load();
|
||||
|
|
@ -76,6 +134,11 @@ void Machine::tick()
|
|||
std::this_thread::sleep_for(delay);
|
||||
}
|
||||
|
||||
void Machine::halt()
|
||||
{
|
||||
_stopped = true;
|
||||
}
|
||||
|
||||
int Machine::getReg(int regNum) const
|
||||
{
|
||||
switch (regNum) {
|
||||
|
|
@ -289,14 +352,16 @@ int Machine::fetch()
|
|||
}
|
||||
|
||||
void Machine::execute() {
|
||||
if (_stopped) return;
|
||||
int b1 = fetch();
|
||||
InstructionInfo &info = instructions[b1];
|
||||
|
||||
InstructionInfo &info = _instructionsTable[b1];
|
||||
|
||||
if (info.type == InstructionType::TYPE1) { execF1(b1); return; }
|
||||
if (info.type == InstructionType::TYPE2) { execF2(b1, fetch()); return; }
|
||||
|
||||
int opcode = b1 & TYPE3_4_SIC_MASK;
|
||||
InstructionInfo &info34 = instructions[opcode];
|
||||
InstructionInfo &info34 = _instructionsTable[opcode];
|
||||
int ni = b1 & NI_MASK;
|
||||
|
||||
if (info34.type == InstructionType::TYPE3_4) {
|
||||
|
|
@ -329,8 +394,8 @@ void Machine::execute() {
|
|||
|
||||
bool Machine::execF1(int opcode)
|
||||
{
|
||||
if (instructions[opcode].handler) {
|
||||
auto handler = reinterpret_cast<void(*)(Machine&)>(instructions[opcode].handler);
|
||||
if (_instructionsTable[opcode].handler) {
|
||||
auto handler = reinterpret_cast<void(*)(Machine&)>(_instructionsTable[opcode].handler);
|
||||
handler(*this);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -343,8 +408,8 @@ bool Machine::execF2(int opcode, int operand)
|
|||
int r1 = (operand >> 4) & 0xF;
|
||||
int r2 = operand & 0xF;
|
||||
|
||||
if (instructions[opcode].handler) {
|
||||
auto handler = reinterpret_cast<void(*)(Machine&, int, int)>(instructions[opcode].handler);
|
||||
if (_instructionsTable[opcode].handler) {
|
||||
auto handler = reinterpret_cast<void(*)(Machine&, int, int)>(_instructionsTable[opcode].handler);
|
||||
handler(*this, r1, r2);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -362,8 +427,8 @@ bool Machine::execSICF3F4(int opcode, int ni, int x, int b, int p, int e, int op
|
|||
// --- 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);
|
||||
if (_instructionsTable[opcode].handler) {
|
||||
auto h = reinterpret_cast<void(*)(Machine&, int, AddressingMode)>(_instructionsTable[opcode].handler);
|
||||
h(*this, ea, mode);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -386,8 +451,8 @@ bool Machine::execSICF3F4(int opcode, int ni, int x, int b, int p, int e, int op
|
|||
// 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);
|
||||
if (_instructionsTable[opcode].handler) {
|
||||
auto h = reinterpret_cast<void(*)(Machine&, int, AddressingMode)>(_instructionsTable[opcode].handler);
|
||||
h(*this, ea, mode);
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,11 +9,16 @@
|
|||
using std::cout;
|
||||
using std::endl;
|
||||
|
||||
struct VectorAddProgram {
|
||||
int x, y;
|
||||
};
|
||||
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
loadInstructionSet();
|
||||
Machine machine;
|
||||
|
||||
cout << "SIC/XE Program: Accumulator Loop" << endl;
|
||||
|
||||
const int TEMP_ADDR = 0x50;
|
||||
|
|
@ -21,61 +26,67 @@ int main()
|
|||
|
||||
// clear TEMP
|
||||
machine.setByte(TEMP_ADDR, 0);
|
||||
loadInstructionSet();
|
||||
|
||||
// Program (addresses):
|
||||
// 0x00 LDA #1
|
||||
// 0x03 LDB TEMP
|
||||
// 0x06 ADDR A,B
|
||||
// 0x08 RMO B,A
|
||||
// 0x0A STA TEMP
|
||||
// 0x0D J LOOP
|
||||
cout << "SIC/XE Program: Vector add test" << endl;
|
||||
|
||||
// LDA #1
|
||||
machine.setByte(0x00, 0x01);
|
||||
machine.setByte(0x01, 0x00);
|
||||
machine.setByte(0x02, 0x01);
|
||||
const int VA_ADDR = 0x100; // source vector A
|
||||
const int VB_ADDR = 0x200; // source vector B
|
||||
const int VR_ADDR = 0x300; // result store (STVA)
|
||||
|
||||
// LDB TEMP
|
||||
machine.setByte(0x03, 0x6B);
|
||||
machine.setByte(0x04, 0x00);
|
||||
machine.setByte(0x05, TEMP_ADDR);
|
||||
// Prepare two 4-element vectors (WORD = 3 bytes) for VA and VB
|
||||
int a_vals[VECTOR_REG_SIZE] = {1,2,3,4};
|
||||
int b_vals[VECTOR_REG_SIZE] = {5,6,7,8};
|
||||
|
||||
// ADDR A,B
|
||||
machine.setByte(0x06, 0x90);
|
||||
machine.setByte(0x07, 0x03);
|
||||
for (int i = 0; i < VECTOR_REG_SIZE; ++i) {
|
||||
machine.setWord(VA_ADDR + i * 3, a_vals[i]);
|
||||
machine.setWord(VB_ADDR + i * 3, b_vals[i]);
|
||||
}
|
||||
|
||||
// RMO B,A
|
||||
machine.setByte(0x08, 0xAC);
|
||||
machine.setByte(0x09, 0x30);
|
||||
// Assemble program at address 0x000 (we use XEXE before each extended op)
|
||||
// Offsets and bytes (hex):
|
||||
// 0x00: XEXE -> 0xEE
|
||||
// 0x01: LDVA (format 4) -> b1=0x03 (LDVA|ni=0x00|0x03), b2=0x10 (e=1), b3=0x01, b4=0x00 (addr 0x100)
|
||||
// 0x05: XEXE -> 0xEE
|
||||
// 0x06: LDVS (format 4) -> b1=0x6B (0x68|0x03), b2=0x10, b3=0x02, b4=0x00 (addr 0x200)
|
||||
// 0x0A: XEXE -> 0xEE
|
||||
// 0x0B: VADDR B->A (type 2) -> opcode 0x90, operand r1=4 (VS), r2=0 (VA) => operand=(4<<4)|0=0x40
|
||||
// 0x0D: XEXE -> 0xEE
|
||||
// 0x0E: STVA (format4) -> b1=0x0F (0x0C|0x03), b2=0x10, b3=0x03, b4=0x00 (addr 0x300)
|
||||
// 0x12: J (format4) to self -> b1=0x3F (0x3C|0x03), b2=0x10, b3=0x00, b4=0x12
|
||||
|
||||
// STA TEMP
|
||||
machine.setByte(0x0A, 0x0F);
|
||||
machine.setByte(0x0B, 0x00);
|
||||
machine.setByte(0x0C, TEMP_ADDR);
|
||||
unsigned char prog[] = {
|
||||
0xEE,
|
||||
0x01, 0x10, 0x01, 0x00, // LDVA (format 4) with ni=IMMEDIATE -> b1=0x01
|
||||
0xEE,
|
||||
0x69, 0x10, 0x02, 0x00, // LDVS (format 4) with ni=IMMEDIATE -> b1=0x69 (0x68|0x01)
|
||||
0xEE,
|
||||
0x90, 0x40, // VADDR VS->VA (type2)
|
||||
0xEE,
|
||||
0x0D, 0x10, 0x03, 0x00, // STVA (format4) with ni=IMMEDIATE -> b1=0x0D
|
||||
0x3F, 0x10, 0x00, 0x12 // J (format4) loop to 0x12
|
||||
};
|
||||
|
||||
// J LOOP
|
||||
machine.setByte(0x0D, 0x3F);
|
||||
machine.setByte(0x0E, 0x00);
|
||||
machine.setByte(0x0F, LOOP_ADDR);
|
||||
const int PROG_START = 0x00;
|
||||
for (size_t i = 0; i < sizeof(prog); ++i) {
|
||||
machine.setByte(PROG_START + static_cast<int>(i), prog[i]);
|
||||
}
|
||||
|
||||
machine.setPC(0x00);
|
||||
machine.setPC(PROG_START);
|
||||
|
||||
cout << "Program loaded. TEMP at 0x" << std::hex << TEMP_ADDR << std::dec << endl;
|
||||
cout << "Program loaded. VA@0x" << std::hex << VA_ADDR << " VB@0x" << VB_ADDR << " -> store@0x" << VR_ADDR << std::dec << endl;
|
||||
|
||||
// run a few iterations
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
cout << "Iter " << (i + 1) << ": A=" << machine.getA()
|
||||
<< " B=" << machine.getB()
|
||||
<< " TEMP=" << machine.getByte(TEMP_ADDR);
|
||||
|
||||
const int MAX_STEPS = 100;
|
||||
for (int i = 0; i < MAX_STEPS; ++i) {
|
||||
machine.execute();
|
||||
}
|
||||
|
||||
// advance the program by executing the next 6 instructions
|
||||
for (int k = 0; k < 6; ++k) machine.execute();
|
||||
|
||||
cout << " -> A=" << machine.getA()
|
||||
<< " B=" << machine.getB()
|
||||
<< " TEMP=" << machine.getByte(TEMP_ADDR) << "\n";
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
// Read back result vector stored at VR_ADDR
|
||||
cout << "Result vector at 0x" << std::hex << VR_ADDR << std::dec << ": ";
|
||||
for (int i = 0; i < VECTOR_REG_SIZE; ++i) {
|
||||
int val = machine.getWord(VR_ADDR + i * 3);
|
||||
cout << val << (i + 1 < VECTOR_REG_SIZE ? ", " : "\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -4,74 +4,96 @@
|
|||
#include <utility>
|
||||
|
||||
InstructionInfo instructions[0xff];
|
||||
InstructionInfo instructionsEXEX[0xff];
|
||||
|
||||
void loadInstructionSet()
|
||||
{
|
||||
instructions[ADD] = {"ADD", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(add_handler)};
|
||||
instructions[ADDF] = {"ADDF", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(addf_handler)};
|
||||
instructions[ADDR] = {"ADDR", InstructionType::TYPE2, reinterpret_cast<RawHandler>(addr_handler)};
|
||||
instructions[AND] = {"AND", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(and_handler)};
|
||||
instructions[CLEAR] = {"CLEAR", InstructionType::TYPE2, reinterpret_cast<RawHandler>(clear_handler)};
|
||||
instructions[COMP] = {"COMP", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(comp_handler)};
|
||||
instructions[COMPF] = {"COMPF", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(compf_handler)};
|
||||
instructions[COMPR] = {"COMPR", InstructionType::TYPE2, reinterpret_cast<RawHandler>(compr_handler)};
|
||||
instructions[DIV] = {"DIV", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(div_handler)};
|
||||
instructions[DIVF] = {"DIVF", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(divf_handler)};
|
||||
instructions[DIVR] = {"DIVR", InstructionType::TYPE2, reinterpret_cast<RawHandler>(divr_handler)};
|
||||
instructions[FIX] = {"FIX", InstructionType::TYPE1, reinterpret_cast<RawHandler>(fix_handler)};
|
||||
instructions[FLOAT] = {"FLOAT", InstructionType::TYPE1, reinterpret_cast<RawHandler>(float_handler)};
|
||||
instructions[HIO] = {"HIO", InstructionType::TYPE1, nullptr};
|
||||
instructions[J] = {"J", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(j_handler)};
|
||||
instructions[JEQ] = {"JEQ", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(jeq_handler)};
|
||||
instructions[JGT] = {"JGT", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(jgt_handler)};
|
||||
instructions[JLT] = {"JLT", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(jlt_handler)};
|
||||
instructions[JSUB] = {"JSUB", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(jsub_handler)};
|
||||
instructions[LDA] = {"LDA", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(lda_handler)};
|
||||
instructions[LDB] = {"LDB", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(ldb_handler)};
|
||||
instructions[LDCH] = {"LDCH", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(ldch_handler)};
|
||||
instructions[LDF] = {"LDF", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(ldf_handler)};
|
||||
instructions[LDL] = {"LDL", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(ldl_handler)};
|
||||
instructions[LDS] = {"LDS", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(lds_handler)};
|
||||
instructions[LDT] = {"LDT", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(ldt_handler)};
|
||||
instructions[LDX] = {"LDX", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(ldx_handler)};
|
||||
instructions[LPS] = {"LPS", InstructionType::TYPE3_4, nullptr};
|
||||
instructions[MUL] = {"MUL", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(mul_handler)};
|
||||
instructions[MULF] = {"MULF", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(mulf_handler)};
|
||||
instructions[MULR] = {"MULR", InstructionType::TYPE2, reinterpret_cast<RawHandler>(mulr_handler)};
|
||||
instructions[NORM] = {"NORM", InstructionType::TYPE1, reinterpret_cast<RawHandler>(norm_handler)};
|
||||
instructions[OR] = {"OR", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(or_handler)};
|
||||
instructions[RD] = {"RD", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(rd_handler)};
|
||||
instructions[RMO] = {"RMO", InstructionType::TYPE2, reinterpret_cast<RawHandler>(rmo_handler)};
|
||||
instructions[RSUB] = {"RSUB", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(rsub_handler)};
|
||||
instructions[SHIFTL] = {"SHIFTL", InstructionType::TYPE2, reinterpret_cast<RawHandler>(shiftl_handler)};
|
||||
instructions[SHIFTR] = {"SHIFTR", InstructionType::TYPE2, reinterpret_cast<RawHandler>(shiftr_handler)};
|
||||
instructions[SIO] = {"SIO", InstructionType::TYPE1, nullptr};
|
||||
instructions[SSK] = {"SSK", InstructionType::TYPE3_4, nullptr};
|
||||
instructions[STA] = {"STA", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(sta_handler)};
|
||||
instructions[STB] = {"STB", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(stb_handler)};
|
||||
instructions[STCH] = {"STCH", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(stch_handler)};
|
||||
instructions[STF] = {"STF", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(stf_handler)};
|
||||
instructions[STI] = {"STI", InstructionType::TYPE3_4, nullptr};
|
||||
instructions[STL] = {"STL", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(stl_handler)};
|
||||
instructions[STS] = {"STS", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(sts_handler)};
|
||||
instructions[STSW] = {"STSW", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(stsw_handler)};
|
||||
instructions[STT] = {"STT", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(stt_handler)};
|
||||
instructions[STX] = {"STX", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(stx_handler)};
|
||||
instructions[SUB] = {"SUB", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(sub_handler)};
|
||||
instructions[SUBF] = {"SUBF", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(subf_handler)};
|
||||
instructions[SUBR] = {"SUBR", InstructionType::TYPE2, reinterpret_cast<RawHandler>(subr_handler)};
|
||||
instructions[SVC] = {"SVC", InstructionType::TYPE2, reinterpret_cast<RawHandler>(svc_handler)};
|
||||
instructions[TIXR] = {"TIXR", InstructionType::TYPE2, reinterpret_cast<RawHandler>(tixr_handler)};
|
||||
instructions[TD] = {"TD", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(td_handler)};
|
||||
instructions[TIX] = {"TIX", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(tix_handler)};
|
||||
instructions[TIO] = {"TIO", InstructionType::TYPE1, nullptr};
|
||||
instructions[WD] = {"WD", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(wd_handler)};
|
||||
instructions[ADD] = {"ADD", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(add_handler)};
|
||||
instructions[ADDF] = {"ADDF", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(addf_handler)};
|
||||
instructions[ADDR] = {"ADDR", InstructionType::TYPE2, reinterpret_cast<RawHandler>(addr_handler)};
|
||||
instructions[AND] = {"AND", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(and_handler)};
|
||||
instructions[CLEAR] = {"CLEAR", InstructionType::TYPE2, reinterpret_cast<RawHandler>(clear_handler)};
|
||||
instructions[COMP] = {"COMP", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(comp_handler)};
|
||||
instructions[COMPF] = {"COMPF", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(compf_handler)};
|
||||
instructions[COMPR] = {"COMPR", InstructionType::TYPE2, reinterpret_cast<RawHandler>(compr_handler)};
|
||||
instructions[DIV] = {"DIV", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(div_handler)};
|
||||
instructions[DIVF] = {"DIVF", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(divf_handler)};
|
||||
instructions[DIVR] = {"DIVR", InstructionType::TYPE2, reinterpret_cast<RawHandler>(divr_handler)};
|
||||
instructions[FIX] = {"FIX", InstructionType::TYPE1, reinterpret_cast<RawHandler>(fix_handler)};
|
||||
instructions[FLOAT] = {"FLOAT", InstructionType::TYPE1, reinterpret_cast<RawHandler>(float_handler)};
|
||||
instructions[HIO] = {"HIO", InstructionType::TYPE1, nullptr};
|
||||
instructions[J] = {"J", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(j_handler)};
|
||||
instructions[JEQ] = {"JEQ", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(jeq_handler)};
|
||||
instructions[JGT] = {"JGT", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(jgt_handler)};
|
||||
instructions[JLT] = {"JLT", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(jlt_handler)};
|
||||
instructions[JSUB] = {"JSUB", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(jsub_handler)};
|
||||
instructions[LDA] = {"LDA", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(lda_handler)};
|
||||
instructions[LDB] = {"LDB", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(ldb_handler)};
|
||||
instructions[LDCH] = {"LDCH", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(ldch_handler)};
|
||||
instructions[LDF] = {"LDF", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(ldf_handler)};
|
||||
instructions[LDL] = {"LDL", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(ldl_handler)};
|
||||
instructions[LDS] = {"LDS", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(lds_handler)};
|
||||
instructions[LDT] = {"LDT", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(ldt_handler)};
|
||||
instructions[LDX] = {"LDX", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(ldx_handler)};
|
||||
instructions[LPS] = {"LPS", InstructionType::TYPE3_4, nullptr};
|
||||
instructions[MUL] = {"MUL", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(mul_handler)};
|
||||
instructions[MULF] = {"MULF", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(mulf_handler)};
|
||||
instructions[MULR] = {"MULR", InstructionType::TYPE2, reinterpret_cast<RawHandler>(mulr_handler)};
|
||||
instructions[NORM] = {"NORM", InstructionType::TYPE1, reinterpret_cast<RawHandler>(norm_handler)};
|
||||
instructions[OR] = {"OR", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(or_handler)};
|
||||
instructions[RD] = {"RD", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(rd_handler)};
|
||||
instructions[RMO] = {"RMO", InstructionType::TYPE2, reinterpret_cast<RawHandler>(rmo_handler)};
|
||||
instructions[RSUB] = {"RSUB", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(rsub_handler)};
|
||||
instructions[SHIFTL] = {"SHIFTL", InstructionType::TYPE2, reinterpret_cast<RawHandler>(shiftl_handler)};
|
||||
instructions[SHIFTR] = {"SHIFTR", InstructionType::TYPE2, reinterpret_cast<RawHandler>(shiftr_handler)};
|
||||
instructions[SIO] = {"SIO", InstructionType::TYPE1, nullptr};
|
||||
instructions[SSK] = {"SSK", InstructionType::TYPE3_4, nullptr};
|
||||
instructions[STA] = {"STA", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(sta_handler)};
|
||||
instructions[STB] = {"STB", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(stb_handler)};
|
||||
instructions[STCH] = {"STCH", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(stch_handler)};
|
||||
instructions[STF] = {"STF", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(stf_handler)};
|
||||
instructions[STI] = {"STI", InstructionType::TYPE3_4, nullptr};
|
||||
instructions[STL] = {"STL", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(stl_handler)};
|
||||
instructions[STS] = {"STS", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(sts_handler)};
|
||||
instructions[STSW] = {"STSW", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(stsw_handler)};
|
||||
instructions[STT] = {"STT", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(stt_handler)};
|
||||
instructions[STX] = {"STX", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(stx_handler)};
|
||||
instructions[SUB] = {"SUB", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(sub_handler)};
|
||||
instructions[SUBF] = {"SUBF", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(subf_handler)};
|
||||
instructions[SUBR] = {"SUBR", InstructionType::TYPE2, reinterpret_cast<RawHandler>(subr_handler)};
|
||||
instructions[SVC] = {"SVC", InstructionType::TYPE2, reinterpret_cast<RawHandler>(svc_handler)};
|
||||
instructions[TIXR] = {"TIXR", InstructionType::TYPE2, reinterpret_cast<RawHandler>(tixr_handler)};
|
||||
instructions[TD] = {"TD", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(td_handler)};
|
||||
instructions[TIX] = {"TIX", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(tix_handler)};
|
||||
instructions[TIO] = {"TIO", InstructionType::TYPE1, nullptr};
|
||||
instructions[WD] = {"WD", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(wd_handler)};
|
||||
|
||||
// Mark uninitialized opcodes as INVALID
|
||||
// Load SIC/XE/XE extended instructions
|
||||
if (USE_EXTENDED_MODE) {
|
||||
// Still in main table
|
||||
instructions[NOP] = {"NOP", InstructionType::TYPE1, reinterpret_cast<RawHandler>(nop_handler)};
|
||||
instructions[HALT] = {"HALT", InstructionType::TYPE1, reinterpret_cast<RawHandler>(halt_handler)};
|
||||
instructions[XEXE] = {"XEXE", InstructionType::TYPE1, reinterpret_cast<RawHandler>(xexe_handler)};
|
||||
|
||||
instructionsEXEX[VADD] = {"VADD", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(vadd_handler)};
|
||||
instructionsEXEX[VADDR] = {"VADDR", InstructionType::TYPE2, reinterpret_cast<RawHandler>(vaddr_handler)};
|
||||
instructionsEXEX[VSUB] = {"VSUB", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(vsub_handler)};
|
||||
instructionsEXEX[VSUBR] = {"VSUBR", InstructionType::TYPE2, reinterpret_cast<RawHandler>(vsubr_handler)};
|
||||
instructionsEXEX[VMUL] = {"VMUL", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(vmul_handler)};
|
||||
instructionsEXEX[VMULR] = {"VMULR", InstructionType::TYPE2, reinterpret_cast<RawHandler>(vmulr_handler)};
|
||||
instructionsEXEX[VDIV] = {"VDIV", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(vdiv_handler)};
|
||||
instructionsEXEX[VDIVR] = {"VDIVR", InstructionType::TYPE2, reinterpret_cast<RawHandler>(vdivr_handler)};
|
||||
instructionsEXEX[STVA] = {"STVA", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(stva_handler)};
|
||||
instructionsEXEX[STVS] = {"STVS", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(stvs_handler)};
|
||||
instructionsEXEX[STVT] = {"STVT", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(stvt_handler)};
|
||||
instructionsEXEX[LDVA] = {"LDVA", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(ldva_handler)};
|
||||
instructionsEXEX[LDVS] = {"LDVS", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(ldvs_handler)};
|
||||
instructionsEXEX[LDVT] = {"LDVT", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(ldvt_handler)};
|
||||
}
|
||||
// Mark uninitialized opcodes as INVALID
|
||||
for (int i = 0; i < 0xff; ++i) {
|
||||
if (instructions[i].name == nullptr) {
|
||||
instructions[i] = {"INVALID", InstructionType::INVALID, nullptr};
|
||||
}
|
||||
if (instructions[i].name == nullptr) instructions[i] = {"INVALID", InstructionType::INVALID, nullptr};
|
||||
if (instructionsEXEX[i].name == nullptr) instructionsEXEX[i] = {"INVALID", InstructionType::INVALID, nullptr};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue