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

@ -7,28 +7,29 @@ program
ADDR S, A
ADDR T, A
STA sum
WD #1
. Odstejemo x in y
LDA S
LDA x
SUBR T, A
STA diff
WD #1
. Zmnozimo x in y
LDA S
LDA x
MULR T, A
STA prod
WD #1
. Zdelimo x in y
LDA S
LDA x
DIVR T, A
STA quot
WD #1
. Ostanek pri deljenju x z y
LDA quot
MULR T, A
SUBR A, S
STS mod
#WD 1
halt J halt
sum RESW 1
@ -37,7 +38,7 @@ quot RESW 1
prod RESW 1
mod RESW 1
x WORD 20
y WORD 10
x WORD 15
y WORD 5
END program

View file

@ -1,20 +1,20 @@
***** Section <default> *****
Stats: size=77 blocks=77 symbols=10 literals=0 relocations=0
Stats: size=83 blocks=83 symbols=10 literals=0 relocations=0
Blocks
name start size #ins #dir #sto
<default> 00000 0004D 22 4 5
<default> 00000 00053 23 4 5
Symbols
name hex dec scope kind type description
a_rel 000000 0 exported relative code label
diff 00003B 59 local relative data label
halt 000035 53 local relative code label
mod 000044 68 local relative data label
prod 000041 65 local relative data label
diff 000041 65 local relative data label
halt 00003B 59 local relative code label
mod 00004A 74 local relative data label
prod 000047 71 local relative data label
program 000000 0 local relative code label
quot 00003E 62 local relative data label
sum 000038 56 local relative data label
x 000047 71 local relative data label
y 00004A 74 local relative data label
quot 000044 68 local relative data label
sum 00003E 62 local relative data label
x 00004D 77 local relative data label
y 000050 80 local relative data label
Literals
label definition
Relocations

View file

@ -1,44 +1,42 @@
00000 a_rel START 0
00000 6F2044 program LDS x
00003 772044 LDT y
00000 6F204A program LDS x
00003 77204A LDT y
00006 9040 ADDR S,A
00008 9050 ADDR T,A
0000A 0F202B STA sum
0000D 010000 LDA #0 . Reset A-ja
0000A 0F2031 STA sum
0000D DD0001 WD #1
. Odstejemo x in y
00010 9040 ADDR S,A
00012 9450 SUBR T,A
00014 0F2024 STA diff
00017 010000 LDA #0
00010 03203A LDA x
00013 9450 SUBR T,A
00015 0F2029 STA diff
00018 DD0001 WD #1
. Zmnozimo x in y
0001A 9040 ADDR S,A
0001C 9850 MULR T,A
0001E 0F2020 STA prod
00021 010000 LDA #0
0001B 03202F LDA x
0001E 9850 MULR T,A
00020 0F2024 STA prod
00023 DD0001 WD #1
. Zdelimo x in y
00024 9040 ADDR S,A
00026 9C50 DIVR T,A
00028 0F2013 STA quot
00026 032024 LDA x
00029 9C50 DIVR T,A
0002B 0F2016 STA quot
0002E DD0001 WD #1
. Ostanek pri deljenju x z y
0002B 6B2010 LDB quot
0002E 9853 MULR T,B
00030 9434 SUBR B,S
00032 7F200F STS mod
00031 032010 LDA quot
00034 9850 MULR T,A
00036 9404 SUBR A,S
00038 7F200F STS mod
. #WD 1
0003B 3F2FFD halt J halt
00035 3F2FFD halt J halt
0003E 000000 sum RESW 1
00041 000000 diff RESW 1
00044 000000 quot RESW 1
00047 000000 prod RESW 1
0004A 000000 mod RESW 1
00038 000000 sum RESW 1
0003B 000000 diff RESW 1
0003E 000000 quot RESW 1
00041 000000 prod RESW 1
00044 000000 mod RESW 1
0004D 00000F x WORD 15
00050 000005 y WORD 5
00047 000014 x WORD 20
0004A 00000A y WORD 10
0004D END program
00053 END program

View file

@ -1,5 +0,0 @@
Ha_rel 00000000004D
T0000001E6F2044772044904090500F202B010000904094500F202401000090409850
T00001E1A0F202001000090409C500F20136B2010985394347F200F3F2FFD
T0000470600001400000A
E000000

13
ass1/vhod_izhod/cat.log Normal file
View file

@ -0,0 +1,13 @@
***** Section <default> *****
Stats: size=9 blocks=9 symbols=2 literals=0 relocations=0
Blocks
name start size #ins #dir #sto
<default> 00000 00009 3 2 0
Symbols
name hex dec scope kind type description
cat 000000 0 exported relative code label
loop 000000 0 local relative code label
Literals
label definition
Relocations
address length flag symbol

7
ass1/vhod_izhod/cat.lst Normal file
View file

@ -0,0 +1,7 @@
00000 cat START 0
00000 D90000 loop RD #0
00003 DD0001 WD #1
00006 3F2FF7 J loop
00009 END cat

6
ass2/files/arithr.obj Normal file
View file

@ -0,0 +1,6 @@
Ha_rel 000000000053
T0000001E6F204A77204A904090500F2031DD000103203A94500F2029DD000103202F
T00001E1E98500F2024DD00010320249C500F2016DD0001032010985094047F200F3F
T00003C022FFD
T00004D0600000F000005
E000000

3
ass2/files/cat.obj Normal file
View file

@ -0,0 +1,3 @@
Hcat 000000000009
T00000009D90000DD00013F2FF7
E000000

View file

@ -0,0 +1 @@
2

View file

@ -19,6 +19,7 @@ class cpu {
bool isRunning();
void setSpeed(int kHz);
int getSpeed();
void step();
private:
void zankaUre();
};

View file

@ -18,7 +18,6 @@
class machine {
public:
// Register indices
static const int A = 0;
static const int X = 1;
static const int L = 2;
@ -29,7 +28,6 @@ public:
static const int PC = 8;
static const int SW = 9;
// Condition codes
static const int CC_LT = 0x00;
static const int CC_EQ = 0x40;
static const int CC_GT = 0x80;
@ -39,7 +37,8 @@ public:
private:
std::array<int, 10> registri{};
double F_val = 0.0;
int program_end = 0;
int program_start = 0;
std::array<uint8_t, MAX_ADRESS> pomnilnik{};
std::array<std::unique_ptr<Device>, 256> naprave{};
std::unordered_map<std::string, std::function<bool(int,int)>> ukaziF2;
@ -47,8 +46,7 @@ private:
public:
machine();
// getters-setters
//getterji, setterji
int getA(); void setA(int a);
int getX(); void setX(int x);
int getL(); void setL(int l);
@ -63,19 +61,21 @@ public:
int getReg(int r);
void setReg(int r, int val);
// memory
int getByte(int adr);
void setByte(int adr, int val);
int getWord(int adr);
void setWord(int adr, int val);
void writeWord(int addr, int value);
int readWord(int addr);
int getUN(int n, int i, int x, int b, int p, int e, int operand);
// devices
//naprave
Device& getDevice(uint8_t dev);
void setDevice(uint8_t num, std::unique_ptr<Device> dev);
void setFileDevice(uint8_t num, const std::string& filename);
void loadObj(const std::string &path);
// error helpers
// errorji
void notImplemented(const std::string& mnemonic);
void invalidOpcode(int opcode);
void invalidAdressing();
@ -83,9 +83,9 @@ public:
void outOfMemoryRange(int mem);
void divisionByZero();
// execution
//execution
uint8_t fetch();
void execute();
bool execute();
bool execF1(uint8_t opcode, const std::string& mnemonic);
bool execF2(uint8_t opcode, uint8_t operand, const std::string& mnemonic);
bool execSIC_F3_F4(uint8_t b1, uint8_t b2, uint8_t b3, const std::string& mnemonic);

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;
}
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;
void machine::loadObj(const string& path) {
ifstream file(path);
//posredno
if (n == 1 && i == 0)
return getWord(UN);
if (!file.is_open()) {
throw runtime_error("Ne morem odpreti OBJ datoteke: " + path);
}
//enostavno n=i=1
return UN;
string line;
program_end = 0; // reset
program_start = 0;
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() {
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 (it == ukaziF2.end()) notImplemented(mnemonic); return false;
if (r1 > 9 || r2 > 9 || r1 < 0 || r2 < 0) invalidRegister(mnemonic, r1, r2); return false;
if (r1 > 9 || r2 > 9) { // r1<0, r2<0 pri uint8_t itak nista možna
invalidRegister(mnemonic, r1, r2);
return false;
}
return it->second(r1, r2);
bool ok = 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;
int disp = 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);
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;
}

View file

@ -1,12 +1,24 @@
#include "../headers/machine.h"
#include "../headers/cpu.h"
#include <iostream>
int main(int argc, char const *argv[]){
machine m;
cpu procesor(&m);
m.loadObj("files/arithr.obj");
//m.loadObj("files/cat.obj");
procesor.setSpeed(100);
procesor.start();
//stuff
procesor.stop();
/*stuff
m.setA(50); //dela
m.getDevice(1).write(m.getA()); //dela->izpis na std izhod
m.getDevice(1).write(10); //izpis newlinea
m.getDevice(4).write(m.getA()); //dela->izpis v datoteko
*/
while (procesor.isRunning()) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
std::cout << "Program končan.\n";
return 0;
}