updated simulator

This commit is contained in:
privsk 2025-12-05 13:27:40 +01:00
parent 76b2c711ef
commit 8ddd71cf69
7 changed files with 305 additions and 14 deletions

View file

@ -2,12 +2,15 @@
#include <chrono>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <sstream>
#include "FileDevice.h"
#include "InputDevice.h"
#include "Opcode.h"
#include "OutputDevice.h"
#include "Utils.h"
Machine::Machine() {
A = 0;
@ -228,10 +231,19 @@ void Machine::setWord(int addr, int val) {
}
}
Device* Machine::getDevice(int num) const {
Device* Machine::getDevice(int num) {
if (num < 0 || num >= MAX_DEVICES) {
return nullptr;
}
// lazy init for file devices (3-255)
if (devices[num] == nullptr && num >= 3) {
std::stringstream ss;
ss << std::setw(2) << std::setfill('0') << std::hex << std::uppercase << num;
std::string filename = ss.str() + ".dev";
devices[num] = new FileDevice(filename);
}
return devices[num];
}
@ -578,6 +590,10 @@ void Machine::stop() {
}
}
void Machine::step() {
execute();
}
bool Machine::isRunning() const {
return running;
}
@ -589,3 +605,54 @@ int Machine::getSpeed() const {
void Machine::setSpeed(int kHz) {
speed = kHz;
}
bool Machine::loadSection(std::istream& r) {
int startAddr = 0;
int execAddr = 0;
char recordType;
while (r.get(recordType)) {
if (recordType == '\n' || recordType == '\r') {
continue;
}
if (recordType == 'H') {
// header: H^name(6)^startAddr(6)^length(6)
std::string name = Utils::readString(r, 6);
startAddr = Utils::readWord(r);
int length = Utils::readWord(r);
(void)name;
(void)length;
} else if (recordType == 'T') {
// text: T^addr(6)^length(2)^data
int addr = Utils::readWord(r);
int len = Utils::readByte(r);
for (int i = 0; i < len; i++) {
int byte = Utils::readByte(r);
setByte(addr + i, byte);
}
} else if (recordType == 'M') {
// modification: M^addr(6)^length(2)
// skip for absolute loader
Utils::readWord(r);
Utils::readByte(r);
} else if (recordType == 'E') {
// end: E^execAddr(6) or E alone
execAddr = Utils::readWord(r);
if (execAddr == 0) {
execAddr = startAddr;
}
PC = execAddr;
return true;
}
// skip to end of line
char c;
while (r.get(c) && c != '\n') {
// skip
}
}
return false;
}

View file

@ -1,9 +1,10 @@
#ifndef MACHINE_H
#define MACHINE_H
#include <cstdint>
#include <thread>
#include <atomic>
#include <cstdint>
#include <istream>
#include <thread>
#include "Device.h"
@ -73,7 +74,7 @@ class Machine {
int getWord(int addr) const;
void setWord(int addr, int val);
Device* getDevice(int num) const;
Device* getDevice(int num);
void setDevice(int num, Device* device);
// error handling
@ -91,9 +92,13 @@ class Machine {
// timer simulation
void start();
void stop();
void step();
bool isRunning() const;
int getSpeed() const;
void setSpeed(int kHz);
// loader
bool loadSection(std::istream& r);
};
#endif // MACHINE_H

76
ass2/README.md Normal file
View file

@ -0,0 +1,76 @@
# SIC/XE Simulator
C++ implementacija SIC/XE simulatorja
## Prevajanje
```bash
./run.sh
```
ali ročno:
```bash
g++ -std=c++11 -pthread -c *.cpp
g++ -std=c++11 -pthread -o simulator *.o
```
## Uporaba
```bash
./simulator <pot/do/datoteka.obj>
```
```bash
./simulator /obj/poly.obj
```
ali z run.sh:
```bash
./run.sh /obj/poly.obj
```
## Funkcionalnosti
### Registri
- **A** - Accumulator (24-bit)
- **X** - Index register (24-bit)
- **L** - Linkage register (24-bit)
- **B** - Base register (24-bit)
- **S, T** - General purpose (24-bit)
- **F** - Floating point (48-bit)
- **PC** - Program Counter (24-bit)
- **SW** - Status Word (24-bit)
### Pomnilnik
- 1 MB (naslovi 0x00000 - 0xFFFFF)
- Big-endian zapis
### Naprave
- **0** - standardni vhod (stdin)
- **1** - standardni izhod (stdout)
- **2** - standardni izhod za napake (stderr)
- **3–255** - leno se ustvarijo datoteke `XX.dev` (hex), branje/pisanje prek TD/RD/WD
### Podprti ukazi
| Format | Ukazi |
|--------|-------|
| F1 | FIX, FLOAT (float aritmetike ni implementirane) |
| F2 | ADDR, SUBR, MULR, DIVR, COMPR, SHIFTL, SHIFTR, RMO, CLEAR, TIXR |
| F3/F4 | LDA, LDX, LDL, LDB, LDS, LDT, LDCH, STA, STX, STL, STB, STS, STT, STCH, STSW, ADD, SUB, MUL, DIV, AND, OR, COMP, TIX, J, JEQ, JGT, JLT, JSUB, RSUB, TD, RD, WD |
**Ni** implementirano: ADDF, SUBF, MULF, DIVF, COMPF, LDF, STF, SIO/HIO/TIO, SSK, LPS.
### Načini naslavljanja
- Neposredno (immediate)
- Posredno (indirect)
- Preprosto (simple)
- Indeksirano (indexed)
- Bazno relativno (base relative)
- PC relativno (PC relative)
### Izvajanje
- `step()` – izvede en ukaz
- `start()` / `stop()` – samodejno izvajanje s časovnikom (privzeto 1000 kHz)
- Zaščita pred neskončno zanko: ustavi po 100000 ukazih v glavnem programu

40
ass2/Utils.cpp Normal file
View file

@ -0,0 +1,40 @@
#include "Utils.h"
std::string Utils::readString(std::istream& r, int len) {
std::string result;
for (int i = 0; i < len; i++) {
char c;
if (r.get(c)) {
result += c;
}
}
return result;
}
int Utils::readByte(std::istream& r) {
char hex[3];
hex[0] = r.get();
hex[1] = r.get();
hex[2] = '\0';
int value = 0;
for (int i = 0; i < 2; i++) {
value <<= 4;
char c = hex[i];
if (c >= '0' && c <= '9') {
value += c - '0';
} else if (c >= 'A' && c <= 'F') {
value += c - 'A' + 10;
} else if (c >= 'a' && c <= 'f') {
value += c - 'a' + 10;
}
}
return value;
}
int Utils::readWord(std::istream& r) {
int b1 = readByte(r);
int b2 = readByte(r);
int b3 = readByte(r);
return (b1 << 16) | (b2 << 8) | b3;
}

14
ass2/Utils.h Normal file
View file

@ -0,0 +1,14 @@
#ifndef UTILS_H
#define UTILS_H
#include <istream>
#include <string>
class Utils {
public:
static std::string readString(std::istream& r, int len);
static int readByte(std::istream& r);
static int readWord(std::istream& r);
};
#endif

View file

@ -1,16 +1,72 @@
#include <fstream>
#include <iomanip>
#include <iostream>
#include "Machine.h"
int main() {
void printReg(const char* name, int value) {
std::cout << name << " = " << std::setw(8) << std::dec << value
<< " (0x" << std::hex << std::setw(6) << std::setfill('0')
<< value << ")" << std::setfill(' ') << std::endl;
}
void printRegisters(Machine& machine) {
std::cout << "\n=== Registers ===" << std::endl;
printReg("A ", machine.getA());
printReg("X ", machine.getX());
printReg("L ", machine.getL());
printReg("B ", machine.getB());
printReg("S ", machine.getS());
printReg("T ", machine.getT());
printReg("F ", machine.getF());
printReg("PC", machine.getPC());
printReg("SW", machine.getSW());
}
int main(int argc, char* argv[]) {
Machine machine;
machine.setA(0x123456);
machine.setX(0xABCDEF);
machine.setPC(0x1000);
if (argc > 1) {
std::ifstream file(argv[1]);
if (file.is_open()) {
std::cout << "=== SIC/XE Simulator ===" << std::endl;
std::cout << "Loading: " << argv[1] << std::endl;
std::cout << "Register A: 0x" << std::hex << machine.getA() << std::endl;
std::cout << "Register X: 0x" << std::hex << machine.getX() << std::endl;
std::cout << "Program Counter: 0x" << std::hex << machine.getPC() << std::endl;
if (machine.loadSection(file)) {
std::cout << "Start address: 0x" << std::hex << std::setw(6) << std::setfill('0') << machine.getPC() << std::dec << std::setfill(' ') << std::endl;
std::cout << "\nExecuting..." << std::endl;
int prevPC = -1;
int instrCount = 0;
int maxInstr = 100000; // stop after too many instructions
while (machine.getPC() != prevPC && instrCount < maxInstr) {
prevPC = machine.getPC();
machine.execute();
instrCount++;
}
if (instrCount >= maxInstr) {
std::cout << "\nwarning: stopped after " << maxInstr << " instructions (infinite loop?)" << std::endl;
} else {
std::cout << "Halted after " << instrCount << " instructions" << std::endl;
}
printRegisters(machine);
} else {
std::cerr << "ERROR: Failed to load " << argv[1] << std::endl;
return 1;
}
file.close();
} else {
std::cerr << "ERROR: Cannot open " << argv[1] << std::endl;
return 1;
}
} else {
std::cout << "SIC/XE Simulator" << std::endl;
std::cout << "Usage: " << argv[0] << " <file.obj>" << std::endl;
}
return 0;
}

33
ass2/run.sh Executable file
View file

@ -0,0 +1,33 @@
#!/bin/bash
# SIC/XE Simulator - build and run script
# compile source files
echo "Compiling..."
g++ -std=c++11 -pthread -c Device.cpp InputDevice.cpp OutputDevice.cpp FileDevice.cpp Utils.cpp Machine.cpp main.cpp
if [ $? -ne 0 ]; then
echo "Compilation failed!"
exit 1
fi
# link
g++ -std=c++11 -pthread -o simulator *.o
if [ $? -ne 0 ]; then
echo "Linking failed!"
exit 1
fi
echo "Build successful!"
# run with argument if provided
if [ $# -gt 0 ]; then
echo ""
./simulator "$1"
else
echo "Usage: ./run.sh <file.obj>"
echo ""
echo "Available .obj files:"
ls -1 *.obj 2>/dev/null || echo " (none found)"
fi