added new instructions and new test

This commit is contained in:
zanostro 2025-11-12 12:13:26 +01:00
parent d4754a048d
commit 6b3f4989ae
6 changed files with 142 additions and 38 deletions

View file

@ -5,8 +5,16 @@
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
void addr_handler(Machine& m, int r1, int r2);

View file

@ -5,6 +5,9 @@
#include <iostream>
#include <vector>
#include <memory>
#include <atomic>
#include <mutex>
#include "constants.h"
#include "device.h"
@ -23,6 +26,7 @@ using std::cout;
class Machine {
public:
Machine();
Machine(int speedkHz) : Machine() { this->speedkHz = speedkHz; }
~Machine();
int getA() const { return A; }
@ -74,7 +78,6 @@ public:
// Set a file device at index `num` using the provided filename.
void setFileDevice(int num, const std::string &filename);
// Fetch and execute instructions
int fetch();
void execute();
@ -83,6 +86,12 @@ public:
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();
// error handling methods
void notImplemented(string mnemonic);
void invalidOpcode(int opcode);
@ -102,6 +111,11 @@ private:
std::vector<std::shared_ptr<Device>> devices;
// fallback device returned when device slot is empty/invalid
Device fallbackDevice;
// Execution control
std::atomic<bool> running{false};
std::atomic<int> speedkHz{1}; // Default 1 kHz
void tick(); // simulate a clock tick
};

View file

@ -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));
}

View file

@ -5,6 +5,7 @@
#include "opcode.h"
#include "instructions.h"
#include <cmath>
#include <thread>
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)
{
cout << prefix << "Not implemented: " << mnemonic << endl;
@ -39,6 +51,7 @@ void Machine::invalidOpcode(int opcode)
cout << prefix << "Invalid opcode: " << opcode << endl;
}
void Machine::invalidAddressing()
{
cout << prefix << "Invalid addressing mode" << endl;
@ -54,6 +67,15 @@ void Machine::undefinedHandler(int opcode)
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
{
switch (regNum) {
@ -307,6 +329,11 @@ void Machine::execute() {
bool Machine::execF1(int opcode)
{
if (instructions[opcode].handler) {
auto handler = reinterpret_cast<void(*)(Machine&)>(instructions[opcode].handler);
handler(*this);
return true;
}
undefinedHandler(opcode);
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;
}
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);
}

View file

@ -1,4 +1,6 @@
#include <iostream>
#include <thread>
#include <chrono>
#include "machine.h"
#include "file_device.h"
#include "opcode.h"
@ -12,42 +14,69 @@ int main()
loadInstructionSet();
Machine machine;
cout << "Machine initialized successfully." << endl;
cout << "SIC/XE Program: Accumulator Loop" << endl;
// Test 1: ADD immediate 0x0030 (ADD #48)
machine.setA(10);
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;
const int TEMP_ADDR = 0x50;
const int LOOP_ADDR = 0x03;
// 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;
// clear TEMP
machine.setByte(TEMP_ADDR, 0);
// 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;
// Program (addresses):
// 0x00 LDA #1
// 0x03 LDB TEMP
// 0x06 ADDR A,B
// 0x08 RMO B,A
// 0x0A STA TEMP
// 0x0D J LOOP
// LDA #1
machine.setByte(0x00, 0x01);
machine.setByte(0x01, 0x00);
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;
}

View file

@ -18,8 +18,8 @@ void loadInstructionSet()
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, nullptr};
instructions[FLOAT] = {"FLOAT", InstructionType::TYPE1, nullptr};
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)};