fixed bugs

This commit is contained in:
black
2025-07-10 18:27:14 +02:00
parent e1dcd693bd
commit ddace01d82
5 changed files with 60 additions and 14 deletions

View File

@@ -13,7 +13,7 @@
Es gibt folgende Anweisungen:
| Befehl | Abkürzung für | Aktion |
|:------:|:-------------:|:-------------------------------------------:|
|:------:|:-------------:|:-------------------------------------------:|
| s | sprint | Führt den Sourcecode bis zum Ende aus |
| l | line | Führe die nächste Zeile des Sourcecodes aus |
| e | end | Beende den Emulator direkt |
@@ -62,6 +62,10 @@
- Leerzeilen sind erlaubt.
- Kommentare sind mit `#` beginnend, auch inline, erlaubt.
- 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

View File

@@ -9,7 +9,7 @@ addi x4, x1, 0 # x4 = Laufender Zeiger (ptr) ins Array
lw x3, 0(x4) # x3 = erstes Element (initiales Maximum)
addi x2, x2, 1 # x2 = verbleibende Elemente
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
slt x6, x3, x5 # x6 = 1 , wenn x3 < x5
bne x6, x0, update # falls neues Element groesser: update

View File

@@ -28,7 +28,8 @@ void Alu::calculate(const std::vector<std::string> &commandVector) {
const std::string &command = commandVector.at(0);
// 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
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
int arg3 = 0;
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);
}
}
@@ -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
const auto address = arg2;
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
reg.setRegister(arg1, data);
} 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
// und führt zu undefiniertem Verhalten !!!
// 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);
// Holt sich die Position des angegebenen labels und die stream Position auf diese
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
// und führt zu undefiniertem Verhalten !!!
// Speichert die Position des nächsten Befehls im angegebenen Register
const auto nextStreamLine = static_cast<int>(man.getNextStreamLineOffset().operator std::streamoff());
reg.setRegister(arg1, nextStreamLine);
const auto currentStreamLine = static_cast<int>(man.getStreamPosition().operator std::streamoff());
reg.setRegister(arg1, currentStreamLine);
// Erhöht die stream position (PC) um den angegebenen Wert
for (int i = 1; i < arg2; ++i) {
man.gotoNextStreamLine();
}
man.setStreamPosition(arg2);
} else if (command == "j") {
// Jump Befehl
// 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"
if (argument.at(0) == 'x') argument = argument.substr(1);
// 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);
}
@@ -228,10 +247,30 @@ bool Alu::isRegister(const std::string &argument) {
bool Alu::isImmediate(const std::string &argument) {
if (argument.empty()) return false;
constexpr size_t start = 0;
// Überprüfe, ob jedes Zeichen im Argument eine Nummer ista
size_t start = 0;
// 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) {
if (!std::isdigit(argument.at(i))) return false;
if (!std::isdigit(argument[i])) return false;
}
return true;
}

View File

@@ -21,6 +21,9 @@ void Memory::store(const int address, const int value) {
}
int Memory::load(const int address) const {
if (address >= m_memory.size()) {
return -1;
}
return m_memory.at(address);
}

View File

@@ -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 "
"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 "
"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;
m_registers[reg] = 0;
return;