updated simulator
This commit is contained in:
parent
76b2c711ef
commit
8ddd71cf69
7 changed files with 305 additions and 14 deletions
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
76
ass2/README.md
Normal 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
40
ass2/Utils.cpp
Normal 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
14
ass2/Utils.h
Normal 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
|
||||
|
|
@ -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);
|
||||
|
||||
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 (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;
|
||||
|
||||
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
33
ass2/run.sh
Executable 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
|
||||
Loading…
Add table
Add a link
Reference in a new issue