fixed bugs
This commit is contained in:
@@ -13,7 +13,7 @@
|
|||||||
Es gibt folgende Anweisungen:
|
Es gibt folgende Anweisungen:
|
||||||
|
|
||||||
| Befehl | Abkürzung für | Aktion |
|
| Befehl | Abkürzung für | Aktion |
|
||||||
|:------:|:-------------:|:-------------------------------------------:|
|
|:------:|:-------------:|:-------------------------------------------:|
|
||||||
| s | sprint | Führt den Sourcecode bis zum Ende aus |
|
| s | sprint | Führt den Sourcecode bis zum Ende aus |
|
||||||
| l | line | Führe die nächste Zeile des Sourcecodes aus |
|
| l | line | Führe die nächste Zeile des Sourcecodes aus |
|
||||||
| e | end | Beende den Emulator direkt |
|
| e | end | Beende den Emulator direkt |
|
||||||
@@ -62,6 +62,10 @@
|
|||||||
- Leerzeilen sind erlaubt.
|
- Leerzeilen sind erlaubt.
|
||||||
- Kommentare sind mit `#` beginnend, auch inline, erlaubt.
|
- Kommentare sind mit `#` beginnend, auch inline, erlaubt.
|
||||||
- Der Assemblycode muss in einer `.txt` Datei gespeichert werden.
|
- Der Assemblycode muss in einer `.txt` Datei gespeichert werden.
|
||||||
|
- Speziell für Beispielprogramm 8: In diesem wird in Zeile 12 der Wert des Pointers auf das Array um 4 erhöht, um somit
|
||||||
|
zum nächsten Element zu springen. Aufgrund der Funktionsweise dieses Emulators ist das nicht nötig und der Wert
|
||||||
|
braucht
|
||||||
|
lediglich um 1 erhöht zu werden. In den beigefügten Beispielprogrammen ist das bereits berücksichtigt.
|
||||||
|
|
||||||
## Funktionsweise
|
## Funktionsweise
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ addi x4, x1, 0 # x4 = Laufender Zeiger (ptr) ins Array
|
|||||||
lw x3, 0(x4) # x3 = erstes Element (initiales Maximum)
|
lw x3, 0(x4) # x3 = erstes Element (initiales Maximum)
|
||||||
addi x2, x2, −1 # x2 = verbleibende Elemente
|
addi x2, x2, −1 # x2 = verbleibende Elemente
|
||||||
loop_max:
|
loop_max:
|
||||||
addi x4, x4, 4 # ptr += 4 (naechstes Element )
|
addi x4, x4, 1 # ptr += 4 (naechstes Element )
|
||||||
lw x5, 0(x4) # x5 = aktuelles Element
|
lw x5, 0(x4) # x5 = aktuelles Element
|
||||||
slt x6, x3, x5 # x6 = 1 , wenn x3 < x5
|
slt x6, x3, x5 # x6 = 1 , wenn x3 < x5
|
||||||
bne x6, x0, update # falls neues Element groesser: update
|
bne x6, x0, update # falls neues Element groesser: update
|
||||||
|
|||||||
@@ -28,7 +28,8 @@ void Alu::calculate(const std::vector<std::string> &commandVector) {
|
|||||||
const std::string &command = commandVector.at(0);
|
const std::string &command = commandVector.at(0);
|
||||||
|
|
||||||
// Extrahiere die Argumente des Befehls
|
// Extrahiere die Argumente des Befehls
|
||||||
const auto arg1 = parseArgument(commandVector.at(1));
|
int arg1 = 0;
|
||||||
|
if (isRegister(commandVector.at(1))) arg1 = parseArgument(commandVector.at(1));
|
||||||
|
|
||||||
// Wandle Vektor[2] (das zweite Argument) in eine Adresse um, falls es ein SW/LW Argument ist
|
// Wandle Vektor[2] (das zweite Argument) in eine Adresse um, falls es ein SW/LW Argument ist
|
||||||
int arg2 = 0;
|
int arg2 = 0;
|
||||||
@@ -44,7 +45,8 @@ void Alu::calculate(const std::vector<std::string> &commandVector) {
|
|||||||
// Wandle Vektor[3] (das dritte Argument) nur um, falls dieser existiert und kein immediate Wert ist
|
// Wandle Vektor[3] (das dritte Argument) nur um, falls dieser existiert und kein immediate Wert ist
|
||||||
int arg3 = 0;
|
int arg3 = 0;
|
||||||
if (commandVector.size() > 3) {
|
if (commandVector.size() > 3) {
|
||||||
if (const std::string &arg = commandVector.at(3); isRegister(arg) || isImmediate(arg)) {
|
const std::string &arg = commandVector.at(3);
|
||||||
|
if (isRegister(arg) || isImmediate(arg)) {
|
||||||
arg3 = parseArgument(arg);
|
arg3 = parseArgument(arg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -118,6 +120,13 @@ void Alu::calculate(const std::vector<std::string> &commandVector) {
|
|||||||
// Hole die Adresse aus dem Befehlsargument und die dazugehörigen Daten aus dem RAM
|
// Hole die Adresse aus dem Befehlsargument und die dazugehörigen Daten aus dem RAM
|
||||||
const auto address = arg2;
|
const auto address = arg2;
|
||||||
const auto data = mem.load(address);
|
const auto data = mem.load(address);
|
||||||
|
if (data == -1) {
|
||||||
|
std::cerr << "Es wurde ein Speicherzugriff außerhalb des maximal erlaubten Speicherbereiches versucht: "
|
||||||
|
<< address << "\nDer Fehler ist in folgender Zeile aufgetreten: " << commandVector.at(0) << " "
|
||||||
|
<< commandVector.at(1) << " " << commandVector.at(2) << "\nDer Emulator beendet nun!\n" <<
|
||||||
|
std::flush;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
// Speichere die Daten im angegeben Register
|
// Speichere die Daten im angegeben Register
|
||||||
reg.setRegister(arg1, data);
|
reg.setRegister(arg1, data);
|
||||||
} else if (command == "sw") {
|
} else if (command == "sw") {
|
||||||
@@ -148,7 +157,7 @@ void Alu::calculate(const std::vector<std::string> &commandVector) {
|
|||||||
// !!! Aufgrund des casts des stream offsets zu int funktioniert das nicht bei großen Quellcode Dateien
|
// !!! Aufgrund des casts des stream offsets zu int funktioniert das nicht bei großen Quellcode Dateien
|
||||||
// und führt zu undefiniertem Verhalten !!!
|
// und führt zu undefiniertem Verhalten !!!
|
||||||
// Speichert die Position des nächsten Befehls im angegebenen Register
|
// Speichert die Position des nächsten Befehls im angegebenen Register
|
||||||
const auto pos = static_cast<int>(man.getNextStreamLineOffset().operator std::streamoff());
|
const auto pos = static_cast<int>(man.getStreamPosition().operator std::streamoff());
|
||||||
reg.setRegister(arg1, pos);
|
reg.setRegister(arg1, pos);
|
||||||
// Holt sich die Position des angegebenen labels und die stream Position auf diese
|
// Holt sich die Position des angegebenen labels und die stream Position auf diese
|
||||||
const auto &label = commandVector.at(2);
|
const auto &label = commandVector.at(2);
|
||||||
@@ -159,12 +168,10 @@ void Alu::calculate(const std::vector<std::string> &commandVector) {
|
|||||||
// !!! Aufgrund des casts des stream offsets zu int funktioniert das nicht bei großen Quellcode Dateien
|
// !!! Aufgrund des casts des stream offsets zu int funktioniert das nicht bei großen Quellcode Dateien
|
||||||
// und führt zu undefiniertem Verhalten !!!
|
// und führt zu undefiniertem Verhalten !!!
|
||||||
// Speichert die Position des nächsten Befehls im angegebenen Register
|
// Speichert die Position des nächsten Befehls im angegebenen Register
|
||||||
const auto nextStreamLine = static_cast<int>(man.getNextStreamLineOffset().operator std::streamoff());
|
const auto currentStreamLine = static_cast<int>(man.getStreamPosition().operator std::streamoff());
|
||||||
reg.setRegister(arg1, nextStreamLine);
|
reg.setRegister(arg1, currentStreamLine);
|
||||||
// Erhöht die stream position (PC) um den angegebenen Wert
|
// Erhöht die stream position (PC) um den angegebenen Wert
|
||||||
for (int i = 1; i < arg2; ++i) {
|
man.setStreamPosition(arg2);
|
||||||
man.gotoNextStreamLine();
|
|
||||||
}
|
|
||||||
} else if (command == "j") {
|
} else if (command == "j") {
|
||||||
// Jump Befehl
|
// Jump Befehl
|
||||||
// Springe zum angegebenen Label
|
// Springe zum angegebenen Label
|
||||||
@@ -192,6 +199,18 @@ int Alu::parseArgument(std::string argument) {
|
|||||||
// Falls das erste Argument ein Register ist, entferne das führende "x"
|
// Falls das erste Argument ein Register ist, entferne das führende "x"
|
||||||
if (argument.at(0) == 'x') argument = argument.substr(1);
|
if (argument.at(0) == 'x') argument = argument.substr(1);
|
||||||
// Da das Argument noch als String vorliegt, muss es in ein int umgewandelt werden
|
// Da das Argument noch als String vorliegt, muss es in ein int umgewandelt werden
|
||||||
|
// Falls das '-' noch in Unicode ist, wandle es in ASCII um
|
||||||
|
if (argument.size() >= 3) {
|
||||||
|
const auto b0 = static_cast<unsigned char>(argument[0]);
|
||||||
|
const auto b1 = static_cast<unsigned char>(argument[1]);
|
||||||
|
const auto b2 = static_cast<unsigned char>(argument[2]);
|
||||||
|
if (b0 == 226 && b1 == 136 && b2 == 146) {
|
||||||
|
if (argument.size() == 3) return false; // Nur Minuszeichen, keine Zahl
|
||||||
|
// Ersetze Unicode-Minus durch ASCII-Minus und wandle den Rest um
|
||||||
|
const std::string fixedArg = "-" + argument.substr(3);
|
||||||
|
return std::stoi(fixedArg);
|
||||||
|
}
|
||||||
|
}
|
||||||
return std::stoi(argument);
|
return std::stoi(argument);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,10 +247,30 @@ bool Alu::isRegister(const std::string &argument) {
|
|||||||
bool Alu::isImmediate(const std::string &argument) {
|
bool Alu::isImmediate(const std::string &argument) {
|
||||||
if (argument.empty()) return false;
|
if (argument.empty()) return false;
|
||||||
|
|
||||||
constexpr size_t start = 0;
|
size_t start = 0;
|
||||||
// Überprüfe, ob jedes Zeichen im Argument eine Nummer ista
|
|
||||||
|
// Erlaube optional ein Minuszeichen am Anfang
|
||||||
|
// In Beispielcode 8 wird ein Unicode-Minus verwendet. Daher wird sicherheitshalber für beide Versionen gecheckt
|
||||||
|
// Prüfe auf ASCII-Minus
|
||||||
|
if (argument[0] == '-') {
|
||||||
|
if (argument.size() == 1) return false;
|
||||||
|
start = 1;
|
||||||
|
}
|
||||||
|
// Prüfe auf Unicode-Minus (dreibyte UTF-8)
|
||||||
|
else if (argument.size() >= 3) {
|
||||||
|
const auto b0 = static_cast<unsigned char>(argument[0]);
|
||||||
|
const auto b1 = static_cast<unsigned char>(argument[1]);
|
||||||
|
const auto b2 = static_cast<unsigned char>(argument[2]);
|
||||||
|
if (b0 == 226 && b1 == 136 && b2 == 146) {
|
||||||
|
if (argument.size() == 3) return false;
|
||||||
|
// Minuszeichen belegt dann 3 Bytes
|
||||||
|
start = 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prüfe, ob jedes Zeichen ab start eine Ziffer ist
|
||||||
for (size_t i = start; i < argument.size(); ++i) {
|
for (size_t i = start; i < argument.size(); ++i) {
|
||||||
if (!std::isdigit(argument.at(i))) return false;
|
if (!std::isdigit(argument[i])) return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,9 @@ void Memory::store(const int address, const int value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int Memory::load(const int address) const {
|
int Memory::load(const int address) const {
|
||||||
|
if (address >= m_memory.size()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
return m_memory.at(address);
|
return m_memory.at(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ void Register::setRegister(const int reg, const int value) {
|
|||||||
std::cerr << "\nRegister 0 darf nicht beschrieben werden! Das geschriebene Register wird "
|
std::cerr << "\nRegister 0 darf nicht beschrieben werden! Das geschriebene Register wird "
|
||||||
"auf 0 gesetzt. Dabei handelt es sich nicht unbedingt um einen Assembly "
|
"auf 0 gesetzt. Dabei handelt es sich nicht unbedingt um einen Assembly "
|
||||||
"Fehler, \nes ist in den meisten Fällen nur dem Emulator Aufbau geschuldet. (Für den Beispielcode "
|
"Fehler, \nes ist in den meisten Fällen nur dem Emulator Aufbau geschuldet. (Für den Beispielcode "
|
||||||
"4 z.B. ist dieser Fehler unbedenklich, es kann fortgefahren werden."
|
"4 z.B. ist dieser Fehler unbedenklich, es kann fortgefahren werden.)"
|
||||||
"\n" << std::flush;
|
"\n" << std::flush;
|
||||||
m_registers[reg] = 0;
|
m_registers[reg] = 0;
|
||||||
return;
|
return;
|
||||||
|
|||||||
Reference in New Issue
Block a user