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 <chrono>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <iomanip>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
#include "FileDevice.h"
|
#include "FileDevice.h"
|
||||||
#include "InputDevice.h"
|
#include "InputDevice.h"
|
||||||
#include "Opcode.h"
|
#include "Opcode.h"
|
||||||
#include "OutputDevice.h"
|
#include "OutputDevice.h"
|
||||||
|
#include "Utils.h"
|
||||||
|
|
||||||
Machine::Machine() {
|
Machine::Machine() {
|
||||||
A = 0;
|
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) {
|
if (num < 0 || num >= MAX_DEVICES) {
|
||||||
return nullptr;
|
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];
|
return devices[num];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -578,6 +590,10 @@ void Machine::stop() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Machine::step() {
|
||||||
|
execute();
|
||||||
|
}
|
||||||
|
|
||||||
bool Machine::isRunning() const {
|
bool Machine::isRunning() const {
|
||||||
return running;
|
return running;
|
||||||
}
|
}
|
||||||
|
|
@ -589,3 +605,54 @@ int Machine::getSpeed() const {
|
||||||
void Machine::setSpeed(int kHz) {
|
void Machine::setSpeed(int kHz) {
|
||||||
speed = 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
|
#ifndef MACHINE_H
|
||||||
#define MACHINE_H
|
#define MACHINE_H
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <thread>
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <istream>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
#include "Device.h"
|
#include "Device.h"
|
||||||
|
|
||||||
|
|
@ -73,7 +74,7 @@ class Machine {
|
||||||
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);
|
||||||
void setDevice(int num, Device* device);
|
void setDevice(int num, Device* device);
|
||||||
|
|
||||||
// error handling
|
// error handling
|
||||||
|
|
@ -91,9 +92,13 @@ class Machine {
|
||||||
// timer simulation
|
// timer simulation
|
||||||
void start();
|
void start();
|
||||||
void stop();
|
void stop();
|
||||||
|
void step();
|
||||||
bool isRunning() const;
|
bool isRunning() const;
|
||||||
int getSpeed() const;
|
int getSpeed() const;
|
||||||
void setSpeed(int kHz);
|
void setSpeed(int kHz);
|
||||||
|
|
||||||
|
// loader
|
||||||
|
bool loadSection(std::istream& r);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // MACHINE_H
|
#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 <iostream>
|
||||||
|
|
||||||
#include "Machine.h"
|
#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 machine;
|
||||||
|
|
||||||
machine.setA(0x123456);
|
if (argc > 1) {
|
||||||
machine.setX(0xABCDEF);
|
std::ifstream file(argv[1]);
|
||||||
machine.setPC(0x1000);
|
if (file.is_open()) {
|
||||||
|
std::cout << "=== SIC/XE Simulator ===" << std::endl;
|
||||||
std::cout << "Register A: 0x" << std::hex << machine.getA() << std::endl;
|
std::cout << "Loading: " << argv[1] << 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;
|
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