created sicxe emulator project

This commit is contained in:
zanostro 2025-11-11 11:03:25 +01:00
parent cb38efe586
commit 3332b2971b
18 changed files with 1051 additions and 0 deletions

View file

@ -0,0 +1,261 @@
#include "machine.h"
#include <memory>
#include "opcode.h"
#include "instructions.h"
using std::make_shared;
string prefix = "Machine error: ";
Machine::Machine()
{
devices.resize(NUM_DEVICES);
// device 0: standard input
devices[0] = make_shared<InputDevice>(std::cin);
// device 1: standard output
devices[1] = make_shared<OutputDevice>(std::cout);
// device 2: standard error
devices[2] = make_shared<OutputDevice>(std::cerr);
}
Machine::~Machine()
{
for (auto& device : devices) {
device.reset();
}
}
void Machine::notImplemented(string mnemonic)
{
cout << prefix << "Not implemented: " << mnemonic << endl;
}
void Machine::invalidOpcode(int opcode)
{
cout << prefix << "Invalid opcode: " << opcode << endl;
}
void Machine::invalidAddressing()
{
cout << prefix << "Invalid addressing mode" << endl;
}
void Machine::divisionByZero(int opcode)
{
cout << prefix << "Division by zero error in opcode: " << opcode << endl;
}
void Machine::undefinedHandler(int opcode)
{
cout << prefix << "Undefined handler for opcode: " << opcode << endl;
}
int Machine::getReg(int regNum) const
{
switch (regNum) {
case 0: return A;
case 1: return X;
case 2: return L;
case 3: return B;
case 4: return S;
case 5: return T;
case 6: return F;
case 8: return PC;
case 9: return SW;
default:
cerr << prefix << "Invalid register number: " << regNum << endl;
return -1;
}
}
// TODO: handle double for F register
void Machine::setReg(int regNum, int value)
{
value = toSIC24(value);
switch (regNum) {
case 0: A = value; break;
case 1: X = value; break;
case 2: L = value; break;
case 3: B = value; break;
case 4: S = value; break;
case 5: T = value; break;
case 6: F = value; break;
case 8: PC = value; break;
case 9: SW = value; break;
default:
cerr << prefix << "Invalid register number: " << regNum << endl;
break;
}
}
int Machine::getByte(int address)
{
if (address < 0 || address >= MEMORY_SIZE) {
cerr << prefix << "Invalid memory address: " << address << endl;
return -1;
}
return static_cast<int>(memory[address]);
}
void Machine::setByte(int address, int value)
{
if(address < 0 || address >= MEMORY_SIZE) {
cerr << prefix << "Invalid memory address: " << address << endl;
return;
}
memory[address] = static_cast<unsigned char>(value);
}
// Assuming word is 3 bytes
int Machine::getWord(int address)
{
if (address < 0 || address + 2 >= MEMORY_SIZE) {
cerr << prefix << "Invalid memory address: " << address << endl;
return -1;
}
return static_cast<int>(memory[address]) | (static_cast<int>(memory[address + 1]) << 8) | (static_cast<int>(memory[address + 2]) << 16);
}
// Assuming word is 3 bytes
void Machine::setWord(int address, int value)
{
if(address < 0 || address + 2 >= MEMORY_SIZE) {
cerr << prefix << "Invalid memory address: " << address << endl;
return;
}
memory[address] = static_cast<unsigned char>(value & 0xFF);
memory[address + 1] = static_cast<unsigned char>((value >> 8) & 0xFF);
memory[address + 2] = static_cast<unsigned char>((value >> 16) & 0xFF);
}
// TODO: implement proper float storage and retrieval
double Machine::getFloat(int address)
{
return 0.0;
}
void Machine::setFloat(int address, double value)
{
// TODO: implement proper float storage
}
Device &Machine::getDevice(int num)
{
if(num < 0 || num >= static_cast<int>(devices.size()) || !devices[num]) {
cerr << prefix << "Invalid device number: " << num << endl;
return fallbackDevice;
}
return *devices[num];
}
void Machine::setDevice(int num, std::shared_ptr<Device> device)
{
if(num < 0 || num >= NUM_DEVICES) {
cerr << prefix << "Invalid device number: " << num << endl;
return;
}
if(static_cast<int>(devices.size()) != NUM_DEVICES) {
devices.resize(NUM_DEVICES);
}
// Enforce: devices with index >= 2 must be FileDevice instances
if (num >= 2) {
// try dynamic cast
if (std::dynamic_pointer_cast<FileDevice>(device) == nullptr) {
cerr << prefix << "Device at index " << num << " must be a FileDevice." << endl;
return;
}
}
devices[num] = device;
}
void Machine::setFileDevice(int num, const std::string &filename)
{
if(num < 0 || num >= NUM_DEVICES) {
cerr << prefix << "Invalid device number: " << num << endl;
return;
}
if(static_cast<int>(devices.size()) != NUM_DEVICES) {
devices.resize(NUM_DEVICES);
}
try {
devices[num] = std::make_shared<FileDevice>(filename);
} catch (const std::exception &e) {
cerr << prefix << "Failed to create FileDevice for index " << num << ": " << e.what() << endl;
}
}
int Machine::fetch()
{
return getByte(PC++);
}
void Machine::execute()
{
int opcode = fetch();
InstructionType type = instructions[opcode].type;
switch (type) {
case InstructionType::TYPE1: execF1(opcode);break;
case InstructionType::TYPE2: execF2(opcode, fetch());break;
case InstructionType::TYPE3_4: // extract n and i bits
{
int ni = opcode & 0x3;
int operand = fetch();
execSICF3F4(opcode, ni, operand);
}
break;
default: invalidOpcode(opcode); break;
}
}
bool Machine::execF1(int opcode)
{
switch (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;
}
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);
handler(*this, r1, r2);
return true;
}
undefinedHandler(opcode);
return false;
}
bool Machine::execSICF3F4(int opcode, int ni, int operand)
{
return false;
}