added instruction functionality
This commit is contained in:
parent
483a16c194
commit
d4754a048d
9 changed files with 754 additions and 170 deletions
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include "opcode.h"
|
||||
#include "instructions.h"
|
||||
#include <cmath>
|
||||
|
||||
using std::make_shared;
|
||||
|
||||
|
|
@ -128,23 +129,93 @@ void Machine::setWord(int address, int value)
|
|||
cerr << prefix << "Invalid memory address: " << address << endl;
|
||||
return;
|
||||
}
|
||||
value &= 0xFFFFFF;
|
||||
|
||||
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;
|
||||
if (address < 0 || address + 5 >= MEMORY_SIZE) {
|
||||
cerr << prefix << "Invalid float address: " << address << endl;
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
// load 6 bytes, little-endian → 48-bit word
|
||||
unsigned long long raw =
|
||||
(unsigned long long)memory[address] |
|
||||
((unsigned long long)memory[address+1] << 8) |
|
||||
((unsigned long long)memory[address+2] << 16) |
|
||||
((unsigned long long)memory[address+3] << 24) |
|
||||
((unsigned long long)memory[address+4] << 32) |
|
||||
((unsigned long long)memory[address+5] << 40);
|
||||
|
||||
int sign = (raw >> 47) & 0x1;
|
||||
int exponent = (raw >> 40) & 0x7F;
|
||||
unsigned long long frac = raw & SICF_FRAC_MASK; // 40 bits
|
||||
|
||||
if (raw == 0) return 0.0;
|
||||
|
||||
// value = (1 + frac/2^40) * 2^(exp - 64)
|
||||
double mant = 1.0 + (double)frac / (double)(1ULL << SICF_FRAC_BITS);
|
||||
int e = exponent - SICF_EXP_BIAS;
|
||||
double val = std::ldexp(mant, e); // ldexp is fast enough here
|
||||
return sign ? -val : val;
|
||||
}
|
||||
|
||||
void Machine::setFloat(int address, double value)
|
||||
{
|
||||
// TODO: implement proper float storage
|
||||
if (address < 0 || address + 5 >= MEMORY_SIZE) {
|
||||
cerr << prefix << "Invalid float address: " << address << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
if (value == 0.0) {
|
||||
memory[address] = 0;
|
||||
memory[address+1] = 0;
|
||||
memory[address+2] = 0;
|
||||
memory[address+3] = 0;
|
||||
memory[address+4] = 0;
|
||||
memory[address+5] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
int sign = value < 0;
|
||||
double x = sign ? -value : value;
|
||||
|
||||
// normalize x to [1, 2)
|
||||
int exp2 = 0;
|
||||
x = std::frexp(x, &exp2);
|
||||
x *= 2.0;
|
||||
exp2 -= 1;
|
||||
|
||||
int exp_field = exp2 + SICF_EXP_BIAS;
|
||||
if (exp_field < 0) exp_field = 0;
|
||||
if (exp_field > 127) exp_field = 127;
|
||||
|
||||
// mantissa = (x - 1) * 2^40
|
||||
double frac_d = (x - 1.0) * (double)(1ULL << SICF_FRAC_BITS);
|
||||
unsigned long long frac = (unsigned long long)(frac_d + 0.5); // round
|
||||
frac &= SICF_FRAC_MASK;
|
||||
|
||||
unsigned long long raw =
|
||||
((unsigned long long)sign << 47) |
|
||||
((unsigned long long)exp_field << 40) |
|
||||
frac;
|
||||
|
||||
// store 6 bytes little-endian
|
||||
memory[address] = (unsigned char)( raw & 0xFF);
|
||||
memory[address+1] = (unsigned char)((raw >> 8) & 0xFF);
|
||||
memory[address+2] = (unsigned char)((raw >> 16) & 0xFF);
|
||||
memory[address+3] = (unsigned char)((raw >> 24) & 0xFF);
|
||||
memory[address+4] = (unsigned char)((raw >> 32) & 0xFF);
|
||||
memory[address+5] = (unsigned char)((raw >> 40) & 0xFF);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Device &Machine::getDevice(int num)
|
||||
{
|
||||
if(num < 0 || num >= static_cast<int>(devices.size()) || !devices[num]) {
|
||||
|
|
@ -195,49 +266,48 @@ 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;
|
||||
void Machine::execute() {
|
||||
int b1 = fetch();
|
||||
InstructionInfo &info = instructions[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];
|
||||
int ni = b1 & NI_MASK;
|
||||
|
||||
if (info34.type == InstructionType::TYPE3_4) {
|
||||
int b2 = fetch(), b3 = fetch();
|
||||
int x = (b2 & 0x80) ? 1 : 0;
|
||||
int b = (b2 & 0x40) ? 1 : 0;
|
||||
int p = (b2 & 0x20) ? 1 : 0;
|
||||
int e = (b2 & 0x10) ? 1 : 0;
|
||||
|
||||
int operand;
|
||||
if (ni == NI_SIC) {
|
||||
// PURE SIC
|
||||
operand = ((b2 & 0x7F) << 8) | b3;
|
||||
} else {
|
||||
// SIC/XE
|
||||
operand = e
|
||||
? (((b2 & 0x0F) << 16) | (b3 << 8) | fetch()) // F4: 20-bit
|
||||
: (((b2 & 0x0F) << 8) | b3); // F3: 12-bit
|
||||
}
|
||||
|
||||
execSICF3F4(opcode, ni, x, b, p, e, operand);
|
||||
return;
|
||||
}
|
||||
|
||||
invalidOpcode(b1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
undefinedHandler(opcode);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -255,7 +325,47 @@ bool Machine::execF2(int opcode, int operand)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool Machine::execSICF3F4(int opcode, int ni, int operand)
|
||||
|
||||
bool Machine::execSICF3F4(int opcode, int ni, int x, int b, int p, int e, int operand)
|
||||
{
|
||||
int ea_part = operand;
|
||||
int base = 0;
|
||||
AddressingMode mode = getAddressingMode(ni);
|
||||
|
||||
// --- 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);
|
||||
h(*this, ea, mode);
|
||||
return true;
|
||||
}
|
||||
undefinedHandler(opcode);
|
||||
return false;
|
||||
}
|
||||
|
||||
// --- SIC/XE EA calc ---
|
||||
|
||||
if (!e) { // format 3
|
||||
if (b && !p) {
|
||||
base = getB(); // base-relative, unsigned 12-bit
|
||||
} else if (p && !b) {
|
||||
// PC-relative, signed 12-bit
|
||||
if (ea_part & 0x800) // bit 11 set?
|
||||
ea_part |= 0xFFFFF000; // sign-extend
|
||||
base = getPC();
|
||||
}
|
||||
}
|
||||
// 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);
|
||||
h(*this, ea, mode);
|
||||
return true;
|
||||
}
|
||||
|
||||
undefinedHandler(opcode);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue