This commit is contained in:
Timon 2025-12-10 18:28:54 +01:00
parent 705c7bcb58
commit d50c62106e
14 changed files with 344 additions and 156 deletions

View file

@ -1,4 +1,5 @@
#include "../headers/cpu.h"
#include <iostream>
void cpu::start() {
if (running) return;
@ -27,20 +28,24 @@ void cpu::setSpeed(int speedKhz) {
void cpu::zankaUre() {
while (running) {
// 1. Izvedemo določeno št. ukazov na tick
for (int i = 0; i < operacijeNaTick; i++) {
cpu::m->execute();
bool ok = cpu::m->execute();
if (!ok) {
running = false;
//std::cout << i << std::endl;
break;
}
}
// 2. Izračunamo kolikokrat mora "tikati" na sekundo
// speed_kHz = n tisoč ukazov / sekundo
// operacijeNaTick = koliko ukazov na en tik
// ticksPerSecond = (hitrostKhz * 1000) / operacijeNaTick
if (!running) break;
double ticksPerSecond = (hitrostKhz * 1000.0) / operacijeNaTick;
double sleepTimeSec = 1.0 / ticksPerSecond;
// 3. Ustavimo nit za izračunani čas
std::this_thread::sleep_for(std::chrono::duration<double>(sleepTimeSec));
}
}
void cpu::step() {
cpu::m->execute();
}

View file

@ -63,48 +63,48 @@ machine::machine() {
{"LDX", [&](int m){setX(getWord(m)); return true;}},
{"LDS", [&](int m){setS(getWord(m)); return true;}},
{"LDL", [&](int m){setL(getWord(m)); return true;}},
{"LDCH", [&](int m){setA(getByte(m)); return true;}}, //POPRAVIT
{"STA", [&](int m){setWord(m, getA()); return true;}},
{"LDCH", [&](int m){setA(getByte(m)&0xFF); return true;}},
{"STA", [&](int m){writeWord(m, getA()); return true;}},
{"STB", [&](int m){setWord(m, getB()); return true;}},
{"STT", [&](int m){setWord(m, getT()); return true;}},
{"STX", [&](int m){setWord(m, getX()); return true;}},
{"STL", [&](int m){setWord(m, getL()); return true;}},
{"STS", [&](int m){setWord(m, getS()); return true;}},
{"STCH", [&](int m){setByte(m, getA()); return true;}}, //POPRAVIT
{"STCH", [&](int m){setByte(m, getA()&0xFF); return true;}},
{"TIX", [&](int m){setX(getX()+1);
if (getX() < getWord(m)) setSW(CC_LT);
else if (getX() == getWord(m)) setSW(CC_EQ);
else setSW(CC_GT);
return true;}},
{"WD", [&](int m){return true;}},//POPRAVIT
{"RD", [&](int m){return true;}},//POPRAVIT
{"WD", [&](int m){getDevice(m).write(getA()&0xFF); return true;}},
{"RD", [&](int m){uint8_t c = getDevice(m).read()&0xFF; setA(c); return true;}},
};
}
//machine::getterji, setterji
int machine::getA() {return registri[A];}
void machine::setA(int a) {registri[A] = a;}
void machine::setA(int a) {registri[A] = a & 0xFFFFFF;}
int machine::getX() {return registri[X];}
void machine::setX(int x) {registri[X] = x;}
void machine::setX(int x) {registri[X] = x & 0xFFFFFF;}
int machine::getL() {return registri[L];}
void machine::setL(int l) {registri[L] = l;}
void machine::setL(int l) {registri[L] = l & 0xFFFFFF;}
int machine::getB() {return registri[B];}
void machine::setB(int b) {registri[B] = b;}
void machine::setB(int b) {registri[B] = b & 0xFFFFFF;}
int machine::getS() {return registri[S];}
void machine::setS(int s) {registri[S] = s;}
void machine::setS(int s) {registri[S] = s & 0xFFFFFF;}
int machine::getT() {return registri[T];}
void machine::setT(int t) {registri[T] = t;}
void machine::setT(int t) {registri[T] = t & 0xFFFFFF;}
double machine::getF() {return F_val;}
void machine::setF(double f) {F_val = f;}
int machine::getPC() {return registri[PC];}
void machine::setPC(int pc) {registri[PC] = pc;}
void machine::setPC(int pc) {registri[PC] = pc & 0xFFFFF;}
int machine::getSW() {return registri[SW];}
void machine::setSW(int sw) {registri[SW] = sw;}
@ -142,13 +142,31 @@ machine::machine() {
void machine::setWord(int adr, int val) {
if (adr < 0 || adr + 2 > MAX_ADRESS) outOfMemoryRange(adr+2);
if (val < 0 || val > 0xFFFFFF) throw invalid_argument("Beseda mora imeti vrednost med 0 in 0xFFFFFF.");
if (val < 0 || val > 0xFFFFFF) throw invalid_argument("Beseda mora imeti vrednost med 0 in 0xFFFFFF." + to_string(val));
pomnilnik[adr] = (val >> 16) & 0xFF; //val = 0x00123456 -> hočemo 12, val >> 16 -> 0x00000012 & 0x000000ff = 0x12
pomnilnik[adr+1] = (val >> 8) & 0xFF;
pomnilnik[adr+2] = (val) & 0xFF;
}
int machine::readWord(int addr) {
uint8_t b1 = getByte(addr);
uint8_t b2 = getByte(addr + 1);
uint8_t b3 = getByte(addr + 2);
int value = (b1 << 16) | (b2 << 8) | b3;
return value & 0xFFFFFF;
}
void machine::writeWord(int addr, int value) {
// tukaj NE mečemo invalid_argument, ampak odrežemo na 24 bitov
int v = value & 0xFFFFFF;
setByte(addr, (v >> 16) & 0xFF);
setByte(addr + 1, (v >> 8) & 0xFF);
setByte(addr + 2, v & 0xFF);
}
Device& machine::getDevice(uint8_t dev) {
if (dev > 255)
throw out_of_range("Naprava ne obstaja, izberite napravo med 0 in 255");
@ -156,10 +174,9 @@ machine::machine() {
if (!naprave[dev])
throw runtime_error("Naprava ni inicializirana");
return *naprave[dev]; //rabmo returnat pointer, ker nase naprave so shranjene kakor unique pointerji
return *naprave[dev]; //rabmo returnat pointer, ker naprave so shranjene kakor unique pointerji
}
void machine::setDevice(uint8_t num, unique_ptr<Device> dev) {
if (num > 255)
throw out_of_range("Naprava ne obstaja, izberite napravo med 0 in 255");
@ -174,39 +191,109 @@ machine::machine() {
naprave[num] = make_unique<fileDevice>(filename);
}
int machine::getUN(int n, int i, int x, int b, int p, int e, int operand){
int UN;
/*Ha_rel 000000 00004D
T 000000(zacetek) 1E(dolzina) 6F(byte) 20 44 77 20 44 90 40 90 50 0F 20 2B 01 00 00 90 40 94 50 0F 20 24 01 00 00 90 40 98 50
T 00001E 1A 0F202001000090409C500F20136B2010985394347F200F3F2FFD
T 000047 06 00001400000A
E 000000 <- zacetek programa
*/
if (e == 1) {
UN = operand;
void machine::loadObj(const string& path) {
ifstream file(path);
if (!file.is_open()) {
throw runtime_error("Ne morem odpreti OBJ datoteke: " + path);
}
else if (n == 0 && i == 0) {
// SIC format
UN = operand;
}
else {
if (p == 1)//PC relativno
UN = PC + operand;
else if (b == 1)//Bazno relativno
UN = B + operand;
else
UN = operand;
}
//indeksno
if (x == 1)
UN += X;
//takojsnje
if (n == 0 && i == 1)
return UN;
//posredno
if (n == 1 && i == 0)
return getWord(UN);
string line;
program_end = 0; // reset
program_start = 0;
//enostavno n=i=1
return UN;
cout << "Nalagam OBJ: " << path << endl;
while (getline(file, line)) {
if (line.empty()) continue;
char type = line[0];
if (type == 'H') {
string startHex = line.substr(7, 6);
string lenHex = line.substr(13, 6);
int start = stoi(startHex, nullptr, 16);
int len = stoi(lenHex, nullptr, 16);
program_start = start;
program_end = start;
} else if (type == 'T') {
string startHex = line.substr(1, 6);
string lenHex = line.substr(7, 2);
string data = line.substr(9);
int start = stoi(startHex, nullptr, 16);
int len = stoi(lenHex, nullptr, 16);
cout << "Nalozil " << len << " bajtou na " << hex << start << dec << endl;
for (int i = 0; i < len; i++) {
string byteHex = data.substr(i * 2, 2);
uint8_t value = stoi(byteHex, nullptr, 16);
setByte(start + i, value);
}
program_end = max(program_end, start + len);
} else if (type == 'E') {
if (line.size() > 1) {
string entryHex = line.substr(1);
program_start = stoi(entryHex, nullptr, 16);
}
setPC(program_start);
cout << "Zacetek programa = 0x" << hex << program_start << dec << endl;
}
}
file.close();
}
int machine::getUN(int n, int i, int x, int b, int p, int e, int disp) {
int UN;
//F4 20b
if (e == 1) {
UN = disp & 0xFFFFF;
}
//SIC 15b
else if (n == 0 && i == 0) {
UN = disp & 0x7FFF;
}
//F3
else {
if (p == 1) {
UN = (getPC() + disp) & 0xFFFFF;
} else if (b == 1) {
UN = (getB() + disp) & 0xFFFFF;
} else {
UN = disp & 0xFFFFF;
}
}
//indeksno se lahko povsod pojavi
if (x == 1) {
UN = (UN + getX()) & 0xFFFFF;
}
//immediate -> vrnemo kr vrednost npr #0xb000
if (n == 0 && i == 1) {
return disp;
}
//UN je pointer na uporabni naslov
if (n == 1 && i == 0) {
return readWord(UN);
}
//enostavnu
return UN;
}
void machine::outOfMemoryRange(int memory) {
throw out_of_range("Naslov je izven pomnilniškega obmocja: " + to_string(memory));
@ -236,14 +323,22 @@ machine::machine() {
return machine::getByte(registri[PC]++);
}
void machine::execute() {
uint8_t opcode8 = fetch();
uint8_t opcode6 = opcode8 & 0xFC;
bool machine::execute() {
//cout << "[EXECUTE] PC = " << hex << getPC() << endl;
int oldPC = getPC(); // PC pred fetchom
uint8_t opcode8 = fetch();
uint8_t opcode6 = opcode8 & 0xFC;
//cout << "Fetched opcode8=" << hex << int(opcode8)
// << " opcode6=" << int(opcode6) << dec << endl;
auto it = Opcode::OPCODES.find(opcode6);
if (it == Opcode::OPCODES.end()) {
invalidOpcode(opcode6);
return;
cout << "Narobe opcode\n";
return false;
}
InstructionInfo ii = it->second;
@ -267,15 +362,25 @@ machine::machine() {
break;
}
default:
break;
cout << "format not found\n";
return false;
}
if (uspesno) return;
else {
throw runtime_error("Izvajanje ukaza je bilo neuspešno");
if (!uspesno) {
cout << "[EXEC] STOP at PC=" << hex << getPC() << " opcode=" << int(opcode8) << dec << endl;
return false;
}
//konec programa
if (getPC() >= program_end || getPC() == oldPC) {
cout << "END OF PROGRAM at PC=0x" << hex << getPC() << dec << endl;
return false;
}
return true;
}
bool machine::execF1(uint8_t opcode, const string& mnemonic){
//FIX, FLOAT, HIO, TIO, SIO, NORM
auto it = Opcode::OPCODES.find(opcode);
@ -301,7 +406,8 @@ machine::machine() {
//normalizirej (F)
return true;
} else {
return true;
cout << "Izvajanje F1 neuspesno" + mnemonic + "\n";
return false;
}
}
@ -310,44 +416,84 @@ machine::machine() {
bool machine::execF2(uint8_t opcode, uint8_t operand, const string& mnemonic){
uint8_t r1 = (operand & 0xF0) >> 4;
uint8_t r2 = (operand & 0x0F);
auto it = ukaziF2.find(mnemonic);
if (it == ukaziF2.end()) {
notImplemented(mnemonic);
return false;
}
if (r1 > 9 || r2 > 9) { // r1<0, r2<0 pri uint8_t itak nista možna
invalidRegister(mnemonic, r1, r2);
return false;
}
bool ok = it->second(r1, r2);
if (it == ukaziF2.end()) notImplemented(mnemonic); return false;
if (r1 > 9 || r2 > 9 || r1 < 0 || r2 < 0) invalidRegister(mnemonic, r1, r2); return false;
return it->second(r1, r2);
if (!ok) {
cout << "Izvajanje F2 neuspesno, ukaz: " << mnemonic << "\n";
return false;
}
return true;
}
bool machine::execSIC_F3_F4(uint8_t byte1, uint8_t byte2, uint8_t byte3, const string& mnemonic) {
uint8_t n = (byte1 >> 7) & 1;
uint8_t i = (byte1 >> 6) & 1;
uint8_t n = (byte1 >> 1) & 1;
uint8_t i = byte1 & 1;
uint8_t x = (byte2 >> 7) & 1;
uint8_t b = (byte2 >> 6) & 1;
uint8_t p = (byte2 >> 5) & 1;
uint8_t e = (byte2 >> 4) & 1;
int operand = 0; int UN = 0;
auto it = ukaziSICF3F4.find(mnemonic); //najdemo pripadajoc ukaz
if (it == ukaziSICF3F4.end()) notImplemented(mnemonic); return false;
if (n == 0 && i == 0) {
//imamo format SIC
operand = ((byte2 & 0x7F) << 8) | byte3;
UN = getUN(0, 0, x, 0, 0, 0, operand); //sicer ni res da so bpe nujno 0, ampak dobim cel operand ki ga rabim že z bitnimi operacijami
} else if (e == 1) {
//imamo format 4
uint8_t byte4 = fetch();
operand = ((byte2 & 0x0F) << 16) | (byte3 << 8) | byte4;
UN = getUN(n, i, x, b, p, 1, operand);
} else {
//imamo format 3
operand = ((byte2 & 0x0F) << 8) | byte3;
if (operand & 0x800) { // če je bit 11 = 1
operand |= 0xFFFFF000; // napolni višje bite z 1
}
UN = getUN(n, i, x, b, p, 0, operand);
int disp = 0;
int UN = 0;
auto it = ukaziSICF3F4.find(mnemonic);
if (it == ukaziSICF3F4.end()) {
notImplemented(mnemonic);
return false;
}
return it->second(UN); // tukaj dejansko pozenemo ukaz z uporabnim naslovom
/*cout << "EXEC: " << mnemonic
<< " n=" << int(n)
<< " i=" << int(i)
<< " x=" << int(x)
<< " b=" << int(b)
<< " p=" << int(p)
<< " e=" << int(e)
<< " byte2=" << hex << int(byte2)
<< " byte3=" << hex << int(byte3)
<< dec << "\n";*/
//SIC
if (n == 0 && i == 0) {
disp = ((byte2 & 0x7F) << 8) | byte3;
UN = getUN(0, 0, x, 0, 0, 0, disp);
}
//F4
else if (e == 1) {
uint8_t byte4 = fetch();
disp = ((byte2 & 0x0F) << 16) | (byte3 << 8) | byte4;
UN = getUN(n, i, x, b, p, 1, disp);
}
//F3
else {
disp = ((byte2 & 0x0F) << 8) | byte3;
//sign extension
if (disp & 0x800) {
disp |= 0xFFFFF000;
}
UN = getUN(n, i, x, b, p, 0, disp);
}
//cout << "operand=" << disp << " UN=" << hex << UN << dec << "\n";
bool ok = it->second(UN);
if (!ok) {
cout << "Izvajanje SIC/F3/F4 neuspesno, ukaz: " << mnemonic << "\n";
return false;
}
return true;
}