added new instructions and new test
This commit is contained in:
parent
d4754a048d
commit
6b3f4989ae
6 changed files with 142 additions and 38 deletions
|
|
@ -5,8 +5,16 @@
|
||||||
|
|
||||||
class Machine; // forward declaration
|
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);
|
||||||
|
|
||||||
|
/* IDEJE ZA SIC_XE_XE :)*/
|
||||||
|
// void nop(Machine& m);
|
||||||
|
|
||||||
// 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);
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,9 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <atomic>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
|
||||||
#include "constants.h"
|
#include "constants.h"
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
|
|
@ -23,6 +26,7 @@ using std::cout;
|
||||||
class Machine {
|
class Machine {
|
||||||
public:
|
public:
|
||||||
Machine();
|
Machine();
|
||||||
|
Machine(int speedkHz) : Machine() { this->speedkHz = speedkHz; }
|
||||||
~Machine();
|
~Machine();
|
||||||
|
|
||||||
int getA() const { return A; }
|
int getA() const { return A; }
|
||||||
|
|
@ -74,7 +78,6 @@ public:
|
||||||
// Set a file device at index `num` using the provided filename.
|
// Set a file device at index `num` using the provided filename.
|
||||||
void setFileDevice(int num, const std::string &filename);
|
void setFileDevice(int num, const std::string &filename);
|
||||||
|
|
||||||
|
|
||||||
// Fetch and execute instructions
|
// Fetch and execute instructions
|
||||||
int fetch();
|
int fetch();
|
||||||
void execute();
|
void execute();
|
||||||
|
|
@ -83,6 +86,12 @@ public:
|
||||||
bool execF2(int opcode, int operand);
|
bool execF2(int opcode, int operand);
|
||||||
bool execSICF3F4(int opcode, int ni, int x, int b, int p, int e, 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();
|
||||||
|
|
||||||
// error handling methods
|
// error handling methods
|
||||||
void notImplemented(string mnemonic);
|
void notImplemented(string mnemonic);
|
||||||
void invalidOpcode(int opcode);
|
void invalidOpcode(int opcode);
|
||||||
|
|
@ -102,6 +111,11 @@ private:
|
||||||
std::vector<std::shared_ptr<Device>> devices;
|
std::vector<std::shared_ptr<Device>> devices;
|
||||||
// fallback device returned when device slot is empty/invalid
|
// fallback device returned when device slot is empty/invalid
|
||||||
Device fallbackDevice;
|
Device fallbackDevice;
|
||||||
|
|
||||||
|
// Execution control
|
||||||
|
std::atomic<bool> running{false};
|
||||||
|
std::atomic<int> speedkHz{1}; // Default 1 kHz
|
||||||
|
void tick(); // simulate a clock tick
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -63,8 +63,18 @@ inline int resolveJumpTarget(Machine& m, int ea, AddressingMode mode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void fix_handler(Machine &m)
|
||||||
|
{
|
||||||
|
m.setA(static_cast<int>(m.getF()));
|
||||||
|
}
|
||||||
|
|
||||||
void addr_handler(Machine& m, int r1, int r2) {
|
void float_handler(Machine &m)
|
||||||
|
{
|
||||||
|
m.setF(static_cast<double>(m.getA()));
|
||||||
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
#include "opcode.h"
|
#include "opcode.h"
|
||||||
#include "instructions.h"
|
#include "instructions.h"
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
using std::make_shared;
|
using std::make_shared;
|
||||||
|
|
||||||
|
|
@ -29,6 +30,17 @@ Machine::~Machine()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Machine::getSpeed() const
|
||||||
|
{
|
||||||
|
return speedkHz.load();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Machine::setSpeed(int kHz)
|
||||||
|
{
|
||||||
|
speedkHz.store(kHz);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: implement errors
|
||||||
void Machine::notImplemented(string mnemonic)
|
void Machine::notImplemented(string mnemonic)
|
||||||
{
|
{
|
||||||
cout << prefix << "Not implemented: " << mnemonic << endl;
|
cout << prefix << "Not implemented: " << mnemonic << endl;
|
||||||
|
|
@ -39,6 +51,7 @@ void Machine::invalidOpcode(int opcode)
|
||||||
cout << prefix << "Invalid opcode: " << opcode << endl;
|
cout << prefix << "Invalid opcode: " << opcode << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Machine::invalidAddressing()
|
void Machine::invalidAddressing()
|
||||||
{
|
{
|
||||||
cout << prefix << "Invalid addressing mode" << endl;
|
cout << prefix << "Invalid addressing mode" << endl;
|
||||||
|
|
@ -54,6 +67,15 @@ void Machine::undefinedHandler(int opcode)
|
||||||
cout << prefix << "Undefined handler for opcode: " << opcode << endl;
|
cout << prefix << "Undefined handler for opcode: " << opcode << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Machine::tick()
|
||||||
|
{
|
||||||
|
const int speed = speedkHz.load();
|
||||||
|
if (speed <= 0) throw std::runtime_error("Invalid speed setting in Machine::tick");
|
||||||
|
|
||||||
|
const auto delay = std::chrono::microseconds(1000 / speed);
|
||||||
|
std::this_thread::sleep_for(delay);
|
||||||
|
}
|
||||||
|
|
||||||
int Machine::getReg(int regNum) const
|
int Machine::getReg(int regNum) const
|
||||||
{
|
{
|
||||||
switch (regNum) {
|
switch (regNum) {
|
||||||
|
|
@ -307,6 +329,11 @@ void Machine::execute() {
|
||||||
|
|
||||||
bool Machine::execF1(int opcode)
|
bool Machine::execF1(int opcode)
|
||||||
{
|
{
|
||||||
|
if (instructions[opcode].handler) {
|
||||||
|
auto handler = reinterpret_cast<void(*)(Machine&)>(instructions[opcode].handler);
|
||||||
|
handler(*this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
undefinedHandler(opcode);
|
undefinedHandler(opcode);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -369,3 +396,19 @@ bool Machine::execSICF3F4(int opcode, int ni, int x, int b, int p, int e, int op
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Machine::start()
|
||||||
|
{
|
||||||
|
running.store(true);
|
||||||
|
|
||||||
|
// Main execution loop
|
||||||
|
// TODO: consider running in separate thread
|
||||||
|
while (running.load()) {
|
||||||
|
execute();
|
||||||
|
tick();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Machine::stop()
|
||||||
|
{
|
||||||
|
running.store(false);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <thread>
|
||||||
|
#include <chrono>
|
||||||
#include "machine.h"
|
#include "machine.h"
|
||||||
#include "file_device.h"
|
#include "file_device.h"
|
||||||
#include "opcode.h"
|
#include "opcode.h"
|
||||||
|
|
@ -12,42 +14,69 @@ int main()
|
||||||
loadInstructionSet();
|
loadInstructionSet();
|
||||||
Machine machine;
|
Machine machine;
|
||||||
|
|
||||||
cout << "Machine initialized successfully." << endl;
|
cout << "SIC/XE Program: Accumulator Loop" << endl;
|
||||||
|
|
||||||
// Test 1: ADD immediate 0x0030 (ADD #48)
|
const int TEMP_ADDR = 0x50;
|
||||||
machine.setA(10);
|
const int LOOP_ADDR = 0x03;
|
||||||
cout << "Test 1 - Immediate ADD:" << endl;
|
|
||||||
cout << " A before: " << machine.getA() << endl;
|
|
||||||
machine.setByte(0x0, 0x19); // ADD with ni=01 (immediate addressing)
|
|
||||||
machine.setByte(0x1, 0x00);
|
|
||||||
machine.setByte(0x2, 0x30); // Immediate value 48 (0x30)
|
|
||||||
machine.execute();
|
|
||||||
cout << " A after ADD #48: " << machine.getA() << endl;
|
|
||||||
|
|
||||||
// Test 2: ADD direct 0x0020 (ADD 0x20)
|
// clear TEMP
|
||||||
machine.setA(5);
|
machine.setByte(TEMP_ADDR, 0);
|
||||||
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)
|
// Program (addresses):
|
||||||
machine.setA(15);
|
// 0x00 LDA #1
|
||||||
machine.setPC(0x20); // Move PC for next instruction
|
// 0x03 LDB TEMP
|
||||||
cout << "\nTest 3 - Indirect ADD:" << endl;
|
// 0x06 ADDR A,B
|
||||||
cout << " A before: " << machine.getA() << endl;
|
// 0x08 RMO B,A
|
||||||
machine.setWord(0x30, 0x40); // Address 0x30 contains address 0x40
|
// 0x0A STA TEMP
|
||||||
machine.setByte(0x40, 35); // Store value 35 at address 0x40
|
// 0x0D J LOOP
|
||||||
machine.setByte(0x20, 0x1A); // ADD with ni=10 (indirect addressing)
|
|
||||||
machine.setByte(0x21, 0x00);
|
// LDA #1
|
||||||
machine.setByte(0x22, 0x30); // Address 0x30 (which points to 0x40)
|
machine.setByte(0x00, 0x01);
|
||||||
machine.execute();
|
machine.setByte(0x01, 0x00);
|
||||||
cout << " A after ADD @0x30: " << machine.getA() << endl;
|
machine.setByte(0x02, 0x01);
|
||||||
|
|
||||||
|
// LDB TEMP
|
||||||
|
machine.setByte(0x03, 0x6B);
|
||||||
|
machine.setByte(0x04, 0x00);
|
||||||
|
machine.setByte(0x05, TEMP_ADDR);
|
||||||
|
|
||||||
|
// ADDR A,B
|
||||||
|
machine.setByte(0x06, 0x90);
|
||||||
|
machine.setByte(0x07, 0x03);
|
||||||
|
|
||||||
|
// RMO B,A
|
||||||
|
machine.setByte(0x08, 0xAC);
|
||||||
|
machine.setByte(0x09, 0x30);
|
||||||
|
|
||||||
|
// STA TEMP
|
||||||
|
machine.setByte(0x0A, 0x0F);
|
||||||
|
machine.setByte(0x0B, 0x00);
|
||||||
|
machine.setByte(0x0C, TEMP_ADDR);
|
||||||
|
|
||||||
|
// J LOOP
|
||||||
|
machine.setByte(0x0D, 0x3F);
|
||||||
|
machine.setByte(0x0E, 0x00);
|
||||||
|
machine.setByte(0x0F, LOOP_ADDR);
|
||||||
|
|
||||||
|
machine.setPC(0x00);
|
||||||
|
|
||||||
|
cout << "Program loaded. TEMP at 0x" << std::hex << TEMP_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);
|
||||||
|
|
||||||
|
// 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));
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -18,8 +18,8 @@ void loadInstructionSet()
|
||||||
instructions[DIV] = {"DIV", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(div_handler)};
|
instructions[DIV] = {"DIV", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(div_handler)};
|
||||||
instructions[DIVF] = {"DIVF", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(divf_handler)};
|
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, reinterpret_cast<RawHandler>(fix_handler)};
|
||||||
instructions[FLOAT] = {"FLOAT", InstructionType::TYPE1, nullptr};
|
instructions[FLOAT] = {"FLOAT", InstructionType::TYPE1, reinterpret_cast<RawHandler>(float_handler)};
|
||||||
instructions[HIO] = {"HIO", InstructionType::TYPE1, nullptr};
|
instructions[HIO] = {"HIO", InstructionType::TYPE1, nullptr};
|
||||||
instructions[J] = {"J", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(j_handler)};
|
instructions[J] = {"J", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(j_handler)};
|
||||||
instructions[JEQ] = {"JEQ", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(jeq_handler)};
|
instructions[JEQ] = {"JEQ", InstructionType::TYPE3_4, reinterpret_cast<RawHandler>(jeq_handler)};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue