implemented timer, opcode decoding
This commit is contained in:
parent
5a06b2bc0b
commit
76b2c711ef
2 changed files with 384 additions and 1 deletions
357
ass2/Machine.cpp
357
ass2/Machine.cpp
|
|
@ -1,10 +1,12 @@
|
||||||
#include "Machine.h"
|
#include "Machine.h"
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include "FileDevice.h"
|
#include "FileDevice.h"
|
||||||
#include "InputDevice.h"
|
#include "InputDevice.h"
|
||||||
|
#include "Opcode.h"
|
||||||
#include "OutputDevice.h"
|
#include "OutputDevice.h"
|
||||||
|
|
||||||
Machine::Machine() {
|
Machine::Machine() {
|
||||||
|
|
@ -18,6 +20,10 @@ Machine::Machine() {
|
||||||
PC = 0;
|
PC = 0;
|
||||||
SW = 0;
|
SW = 0;
|
||||||
|
|
||||||
|
running = false;
|
||||||
|
timerThread = nullptr;
|
||||||
|
speed = 1000; // default 1000 kHz = 1 MHz
|
||||||
|
|
||||||
for (int i = 0; i <= MAX_ADDRESS; i++) {
|
for (int i = 0; i <= MAX_ADDRESS; i++) {
|
||||||
memory[i] = 0;
|
memory[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
@ -32,6 +38,8 @@ Machine::Machine() {
|
||||||
}
|
}
|
||||||
|
|
||||||
Machine::~Machine() {
|
Machine::~Machine() {
|
||||||
|
stop();
|
||||||
|
|
||||||
for (int i = 0; i < MAX_DEVICES; i++) {
|
for (int i = 0; i < MAX_DEVICES; i++) {
|
||||||
if (devices[i] != nullptr) {
|
if (devices[i] != nullptr) {
|
||||||
delete devices[i];
|
delete devices[i];
|
||||||
|
|
@ -232,3 +240,352 @@ void Machine::setDevice(int num, Device* device) {
|
||||||
devices[num] = device;
|
devices[num] = device;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Machine::notImplemented(const char* mnemonic) {
|
||||||
|
std::cerr << "Error: instruction " << mnemonic << " not implemented" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Machine::invalidOpcode(int opcode) {
|
||||||
|
std::cerr << "Error: invalid opcode 0x" << std::hex << opcode << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Machine::invalidAddressing() {
|
||||||
|
std::cerr << "Error: invalid addressing mode" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Machine::fetch() {
|
||||||
|
int byte = getByte(PC);
|
||||||
|
PC = (PC + 1) & 0xFFFFFF;
|
||||||
|
return byte;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Machine::execute() {
|
||||||
|
int byte1 = fetch();
|
||||||
|
int opcode = byte1 & 0xFC;
|
||||||
|
int ni = byte1 & 0x03;
|
||||||
|
|
||||||
|
// format 1 (no operand)
|
||||||
|
if (execF1(opcode)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int byte2 = fetch();
|
||||||
|
|
||||||
|
// format 2 (register operand)
|
||||||
|
if (execF2(opcode, byte2)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// format 3 or 4
|
||||||
|
int xbpe = (byte2 >> 4) & 0x0F;
|
||||||
|
int disp = byte2 & 0x0F;
|
||||||
|
|
||||||
|
int byte3 = fetch();
|
||||||
|
disp = (disp << 8) | byte3;
|
||||||
|
|
||||||
|
// format 4 (extended)
|
||||||
|
if (xbpe & 0x01) {
|
||||||
|
int byte4 = fetch();
|
||||||
|
disp = (disp << 8) | byte4;
|
||||||
|
}
|
||||||
|
|
||||||
|
int addr = disp;
|
||||||
|
|
||||||
|
// base relative
|
||||||
|
if (xbpe & 0x04) {
|
||||||
|
addr = B + disp;
|
||||||
|
}
|
||||||
|
// pc relative
|
||||||
|
else if (xbpe & 0x02) {
|
||||||
|
// sign extend 12-bit displacement for format 3
|
||||||
|
if (!(xbpe & 0x01) && (disp & 0x800)) {
|
||||||
|
disp = disp | 0xFFFFF000;
|
||||||
|
}
|
||||||
|
addr = PC + disp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// indexed
|
||||||
|
if (xbpe & 0x08) {
|
||||||
|
addr = addr + X;
|
||||||
|
}
|
||||||
|
|
||||||
|
addr = addr & 0xFFFFFF;
|
||||||
|
|
||||||
|
execSICF3F4(opcode, ni, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Machine::execF1(int opcode) {
|
||||||
|
switch (opcode) {
|
||||||
|
case Opcode::FIX:
|
||||||
|
A = (int)F;
|
||||||
|
return true;
|
||||||
|
case Opcode::FLOAT:
|
||||||
|
F = (double)A;
|
||||||
|
return true;
|
||||||
|
case Opcode::NORM:
|
||||||
|
notImplemented("NORM");
|
||||||
|
return true;
|
||||||
|
case Opcode::SIO:
|
||||||
|
case Opcode::HIO:
|
||||||
|
case Opcode::TIO:
|
||||||
|
notImplemented("SIO/HIO/TIO");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Machine::execF2(int opcode, int operand) {
|
||||||
|
int r1 = (operand >> 4) & 0x0F;
|
||||||
|
int r2 = operand & 0x0F;
|
||||||
|
|
||||||
|
switch (opcode) {
|
||||||
|
case Opcode::ADDR:
|
||||||
|
setReg(r2, getReg(r1) + getReg(r2));
|
||||||
|
return true;
|
||||||
|
case Opcode::SUBR:
|
||||||
|
setReg(r2, getReg(r2) - getReg(r1));
|
||||||
|
return true;
|
||||||
|
case Opcode::MULR:
|
||||||
|
setReg(r2, getReg(r1) * getReg(r2));
|
||||||
|
return true;
|
||||||
|
case Opcode::DIVR:
|
||||||
|
setReg(r2, getReg(r2) / getReg(r1));
|
||||||
|
return true;
|
||||||
|
case Opcode::COMPR: {
|
||||||
|
int val1 = getReg(r1);
|
||||||
|
int val2 = getReg(r2);
|
||||||
|
if (val1 < val2)
|
||||||
|
setCC_less();
|
||||||
|
else if (val1 == val2)
|
||||||
|
setCC_equal();
|
||||||
|
else
|
||||||
|
setCC_greater();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case Opcode::SHIFTL:
|
||||||
|
setReg(r1, getReg(r1) << (r2 + 1));
|
||||||
|
return true;
|
||||||
|
case Opcode::SHIFTR:
|
||||||
|
setReg(r1, getReg(r1) >> (r2 + 1));
|
||||||
|
return true;
|
||||||
|
case Opcode::RMO:
|
||||||
|
setReg(r2, getReg(r1));
|
||||||
|
return true;
|
||||||
|
case Opcode::CLEAR:
|
||||||
|
setReg(r1, 0);
|
||||||
|
return true;
|
||||||
|
case Opcode::TIXR: {
|
||||||
|
X = X + 1;
|
||||||
|
int val = getReg(r1);
|
||||||
|
if (X < val)
|
||||||
|
setCC_less();
|
||||||
|
else if (X == val)
|
||||||
|
setCC_equal();
|
||||||
|
else
|
||||||
|
setCC_greater();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case Opcode::SVC:
|
||||||
|
notImplemented("SVC");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Machine::execSICF3F4(int opcode, int ni, int operand) {
|
||||||
|
int addr = operand;
|
||||||
|
int value;
|
||||||
|
|
||||||
|
// get value based on addressing mode
|
||||||
|
if (ni == 0x00) {
|
||||||
|
// SIC format (simple)
|
||||||
|
value = getWord(addr);
|
||||||
|
} else if (ni == 0x01) {
|
||||||
|
// immediate
|
||||||
|
value = addr;
|
||||||
|
} else if (ni == 0x02) {
|
||||||
|
// indirect
|
||||||
|
addr = getWord(addr);
|
||||||
|
value = getWord(addr);
|
||||||
|
} else {
|
||||||
|
// simple (ni == 0x03)
|
||||||
|
value = getWord(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (opcode) {
|
||||||
|
case Opcode::LDA:
|
||||||
|
A = value;
|
||||||
|
return true;
|
||||||
|
case Opcode::LDX:
|
||||||
|
X = value;
|
||||||
|
return true;
|
||||||
|
case Opcode::LDL:
|
||||||
|
L = value;
|
||||||
|
return true;
|
||||||
|
case Opcode::LDB:
|
||||||
|
B = value;
|
||||||
|
return true;
|
||||||
|
case Opcode::LDS:
|
||||||
|
S = value;
|
||||||
|
return true;
|
||||||
|
case Opcode::LDT:
|
||||||
|
T = value;
|
||||||
|
return true;
|
||||||
|
case Opcode::LDCH:
|
||||||
|
if (ni == 0x01) {
|
||||||
|
A = (A & 0xFFFF00) | (addr & 0xFF);
|
||||||
|
} else {
|
||||||
|
A = (A & 0xFFFF00) | getByte(addr);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case Opcode::STA:
|
||||||
|
setWord(addr, A);
|
||||||
|
return true;
|
||||||
|
case Opcode::STX:
|
||||||
|
setWord(addr, X);
|
||||||
|
return true;
|
||||||
|
case Opcode::STL:
|
||||||
|
setWord(addr, L);
|
||||||
|
return true;
|
||||||
|
case Opcode::STB:
|
||||||
|
setWord(addr, B);
|
||||||
|
return true;
|
||||||
|
case Opcode::STS:
|
||||||
|
setWord(addr, S);
|
||||||
|
return true;
|
||||||
|
case Opcode::STT:
|
||||||
|
setWord(addr, T);
|
||||||
|
return true;
|
||||||
|
case Opcode::STSW:
|
||||||
|
setWord(addr, SW);
|
||||||
|
return true;
|
||||||
|
case Opcode::STCH:
|
||||||
|
setByte(addr, A & 0xFF);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case Opcode::ADD:
|
||||||
|
A = A + value;
|
||||||
|
return true;
|
||||||
|
case Opcode::SUB:
|
||||||
|
A = A - value;
|
||||||
|
return true;
|
||||||
|
case Opcode::MUL:
|
||||||
|
A = A * value;
|
||||||
|
return true;
|
||||||
|
case Opcode::DIV:
|
||||||
|
A = A / value;
|
||||||
|
return true;
|
||||||
|
case Opcode::AND:
|
||||||
|
A = A & value;
|
||||||
|
return true;
|
||||||
|
case Opcode::OR:
|
||||||
|
A = A | value;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case Opcode::COMP:
|
||||||
|
if (A < value)
|
||||||
|
setCC_less();
|
||||||
|
else if (A == value)
|
||||||
|
setCC_equal();
|
||||||
|
else
|
||||||
|
setCC_greater();
|
||||||
|
return true;
|
||||||
|
case Opcode::TIX:
|
||||||
|
X = X + 1;
|
||||||
|
if (X < value)
|
||||||
|
setCC_less();
|
||||||
|
else if (X == value)
|
||||||
|
setCC_equal();
|
||||||
|
else
|
||||||
|
setCC_greater();
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case Opcode::J:
|
||||||
|
PC = addr;
|
||||||
|
return true;
|
||||||
|
case Opcode::JEQ:
|
||||||
|
if (getCC() == 0x40) PC = addr;
|
||||||
|
return true;
|
||||||
|
case Opcode::JGT:
|
||||||
|
if (getCC() == 0x80) PC = addr;
|
||||||
|
return true;
|
||||||
|
case Opcode::JLT:
|
||||||
|
if (getCC() == 0x00) PC = addr;
|
||||||
|
return true;
|
||||||
|
case Opcode::JSUB:
|
||||||
|
L = PC;
|
||||||
|
PC = addr;
|
||||||
|
return true;
|
||||||
|
case Opcode::RSUB:
|
||||||
|
PC = L;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case Opcode::TD: {
|
||||||
|
Device* dev = getDevice(getByte(addr));
|
||||||
|
if (dev != nullptr && dev->test()) {
|
||||||
|
setCC_less();
|
||||||
|
} else {
|
||||||
|
setCC_equal();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case Opcode::RD: {
|
||||||
|
Device* dev = getDevice(getByte(addr));
|
||||||
|
if (dev != nullptr) {
|
||||||
|
A = (A & 0xFFFF00) | dev->read();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case Opcode::WD: {
|
||||||
|
Device* dev = getDevice(getByte(addr));
|
||||||
|
if (dev != nullptr) {
|
||||||
|
dev->write(A & 0xFF);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
invalidOpcode(opcode);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Machine::start() {
|
||||||
|
if (running) return;
|
||||||
|
|
||||||
|
running = true;
|
||||||
|
timerThread = new std::thread([this]() {
|
||||||
|
while (running) {
|
||||||
|
int instructionsPerTick = speed / 1000;
|
||||||
|
if (instructionsPerTick < 1) instructionsPerTick = 1;
|
||||||
|
|
||||||
|
for (int i = 0; i < instructionsPerTick && running; i++) {
|
||||||
|
execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void Machine::stop() {
|
||||||
|
running = false;
|
||||||
|
if (timerThread != nullptr) {
|
||||||
|
timerThread->join();
|
||||||
|
delete timerThread;
|
||||||
|
timerThread = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Machine::isRunning() const {
|
||||||
|
return running;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Machine::getSpeed() const {
|
||||||
|
return speed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Machine::setSpeed(int kHz) {
|
||||||
|
speed = kHz;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@
|
||||||
#define MACHINE_H
|
#define MACHINE_H
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <thread>
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
#include "Device.h"
|
#include "Device.h"
|
||||||
|
|
||||||
|
|
@ -24,6 +26,11 @@ class Machine {
|
||||||
int PC; // Program Counter (24-bit)
|
int PC; // Program Counter (24-bit)
|
||||||
int SW; // Status Word (24-bit)
|
int SW; // Status Word (24-bit)
|
||||||
|
|
||||||
|
// timer simulation
|
||||||
|
std::atomic<bool> running;
|
||||||
|
std::thread* timerThread;
|
||||||
|
int speed; // kHz
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Machine();
|
Machine();
|
||||||
~Machine();
|
~Machine();
|
||||||
|
|
@ -62,12 +69,31 @@ class Machine {
|
||||||
|
|
||||||
int getByte(int addr) const;
|
int getByte(int addr) const;
|
||||||
void setByte(int addr, int val);
|
void setByte(int addr, int val);
|
||||||
|
|
||||||
int getWord(int addr) const;
|
int getWord(int addr) const;
|
||||||
void setWord(int addr, int val);
|
void setWord(int addr, int val);
|
||||||
|
|
||||||
Device* getDevice(int num) const;
|
Device* getDevice(int num) const;
|
||||||
void setDevice(int num, Device* device);
|
void setDevice(int num, Device* device);
|
||||||
|
|
||||||
|
// error handling
|
||||||
|
void notImplemented(const char* mnemonic);
|
||||||
|
void invalidOpcode(int opcode);
|
||||||
|
void invalidAddressing();
|
||||||
|
|
||||||
|
// execution
|
||||||
|
int fetch();
|
||||||
|
void execute();
|
||||||
|
bool execF1(int opcode);
|
||||||
|
bool execF2(int opcode, int operand);
|
||||||
|
bool execSICF3F4(int opcode, int ni, int operand);
|
||||||
|
|
||||||
|
// timer simulation
|
||||||
|
void start();
|
||||||
|
void stop();
|
||||||
|
bool isRunning() const;
|
||||||
|
int getSpeed() const;
|
||||||
|
void setSpeed(int kHz);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // MACHINE_H
|
#endif // MACHINE_H
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue