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
|
||||
|
||||
// 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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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)};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue