|
|
|
|
@@ -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;
|
|
|
|
|
}
|
|
|
|
|
|