194 lines
6.9 KiB
C++
194 lines
6.9 KiB
C++
//
|
|
// Created by black on 12.06.25.
|
|
//
|
|
|
|
#include "Manager.h"
|
|
|
|
#include <iostream>
|
|
#include <filesystem>
|
|
|
|
#include "components/Alu.h"
|
|
#include "components/Memory.h"
|
|
#include "components/Register.h"
|
|
namespace fs = std::filesystem;
|
|
|
|
Manager::~Manager() {
|
|
std::cout << "Schließe Quellcode Datei: '" << m_path << "'" << "\n" << std::flush;
|
|
m_programFile.close();
|
|
}
|
|
|
|
Manager &Manager::getInstance() {
|
|
static Manager instance;
|
|
return instance;
|
|
}
|
|
|
|
[[noreturn]] void Manager::run() {
|
|
if (!m_programFile.is_open()) {
|
|
std::cerr << "Bitte zuerst die init() Methode aufrufen!" << "\n" << std::flush;
|
|
return;
|
|
}
|
|
ProgramLoader::getInstance().indexFile(m_programFile);
|
|
// Die Position des Streams (virtueller Lesekopf) muss nach dem Indexen wieder zurückgesetzt werden
|
|
m_programFile.clear();
|
|
m_programFile.seekg(0);
|
|
|
|
bool runAll = false;
|
|
|
|
// Bearbeite jede Zeile des Quellcodes in der ALU
|
|
std::string line;
|
|
while (std::getline(m_programFile, line)) {
|
|
auto lineVector = ProgramLoader::parseLine(line);
|
|
// Sollte die aktuelle Zeile leer sein, überspringe die ALU
|
|
if (lineVector.empty()) continue;
|
|
Alu::calculate(lineVector);
|
|
|
|
// Frage nach und reagiere auf Nutzereingaben
|
|
if (!runAll) {
|
|
std::cout << "\n" << "Bearbeitete Codezeile: \033[34m" << line << "\033[0m";
|
|
runAll = handleUserInput();
|
|
}
|
|
}
|
|
|
|
// Beende das Program erst, wenn der Nutzer das tut
|
|
std::cout <<
|
|
"\nDer Quellcode ist nun \033[33mfertig\033[0m bearbeitet. Sie können noch auf den RAM und die Register zugreifen.";
|
|
while (true) handleExitInput();
|
|
}
|
|
|
|
void Manager::setStreamPosition(const std::streampos pos) {
|
|
m_programFile.seekg(pos);
|
|
}
|
|
|
|
std::streampos Manager::getStreamPosition() {
|
|
return m_programFile.tellg();
|
|
}
|
|
|
|
void Manager::init(const std::string &program_path) {
|
|
m_path = program_path;
|
|
std::cout << "Öffne Quellcode Datei: '" << m_path << "'" << "\n" << std::flush;
|
|
|
|
//Überprüfe, ob die Datei existiert
|
|
if (!fs::exists(m_path)) {
|
|
std::cerr << "Datei existiert nicht: " << m_path << "\n" << std::flush;
|
|
return;
|
|
}
|
|
m_programFile.open(m_path);
|
|
|
|
// Sollte die Datei nicht geöffnet worden sein, gib den Fehler aus
|
|
if (!m_programFile.is_open()) {
|
|
std::cerr << "Datei konnte nicht geöffnet werden: " << m_path << "\n" << std::flush;
|
|
std::cerr << "fail (z.B. Zugriffsrechte): " << m_programFile.fail() << "\n" << std::flush;
|
|
std::cerr << "bad (schwerwiegender Fehler): " << m_programFile.bad() << "\n" << std::flush;
|
|
return;
|
|
}
|
|
|
|
constexpr auto COLOR_GREEN = "\033[32m";
|
|
constexpr auto COLOR_YELLOW = "\033[33m";
|
|
constexpr auto COLOR_BLUE = "\033[34m";
|
|
constexpr auto COLOR_RESET = "\033[0m";
|
|
|
|
std::cout << COLOR_GREEN << "=== Herzlich willkommen beim RISC-V Emulator! ===" << COLOR_RESET << "\n";
|
|
std::cout << "Nachfolgend wird nun die angegebene Quellcodedatei eingelesen und von der ALU bearbeitet.\n"
|
|
<< COLOR_YELLOW << "Nach" << COLOR_RESET << " jeder bearbeiteten Codezeile wird "
|
|
<< COLOR_BLUE << "diese" << COLOR_RESET << " ausgegeben und Sie werden "
|
|
<< "nach dem " << COLOR_GREEN << "nächsten Schritt" << COLOR_RESET <<
|
|
" gefragt. Tätigen Sie Ihre Eingabe und bestätigen Sie mit "
|
|
<< COLOR_GREEN << "ENTER" << COLOR_RESET <<
|
|
".\nAnforderungen und Hinweise entnehmen Sie bitte der README.\n\n";
|
|
}
|
|
|
|
std::streampos Manager::getNextStreamLineOffset() {
|
|
// Speichert das aktuelle stream offset
|
|
const auto positionBefore = m_programFile.tellg();
|
|
|
|
// Geht eine Zeile nach vorne zum nächsten Befehl (PC+4) und speichert den offset
|
|
gotoNextStreamLine();
|
|
const auto positionAfter = m_programFile.tellg();
|
|
|
|
// Geht zum offset vom Anfang zurück und gibt die nächste Adresse (PC+4) zurück
|
|
m_programFile.seekg(positionBefore);
|
|
return positionAfter;
|
|
}
|
|
|
|
std::string Manager::gotoNextStreamLine() {
|
|
std::string line;
|
|
do {
|
|
getline(m_programFile, line);
|
|
} while (line.empty());
|
|
return line;
|
|
}
|
|
|
|
bool Manager::handleUserInput() {
|
|
constexpr auto COLOR_GREEN = "\033[32m";
|
|
constexpr auto COLOR_RESET = "\033[0m";
|
|
|
|
std::cout << "\nOptionen: ("
|
|
<< COLOR_GREEN << "s" << COLOR_RESET << ") Programm durchlaufen lassen, ("
|
|
<< COLOR_GREEN << "l" << COLOR_RESET << ") nächste Zeile, ("
|
|
<< COLOR_GREEN << "e" << COLOR_RESET << ") beenden, ("
|
|
<< COLOR_GREEN << "m" << COLOR_RESET << ") Memory Dump, ("
|
|
<< COLOR_GREEN << "r" << COLOR_RESET << ") Register Dump\n";
|
|
char input = '\0';
|
|
while (true) {
|
|
std::cout << "Eingabe: ";
|
|
std::cin >> input;
|
|
// ignoriere die Groß- und Kleinschreibung
|
|
input = std::tolower(input);
|
|
|
|
if (input == 's') {
|
|
return true;
|
|
} else if (input == 'l') {
|
|
return false;
|
|
} else if (input == 'e') {
|
|
std::cout << "Programm wird beendet.\n";
|
|
exit(0);
|
|
} else if (input == 'm') {
|
|
std::cout << "Wie viele Speicherzellen sollen gedumpt werden? ";
|
|
int dumpSize = 0;
|
|
while (!(std::cin >> dumpSize) || dumpSize == 0) {
|
|
std::cout << "Ungültige Eingabe. Bitte eine positive Zahl eingeben: ";
|
|
std::cin.clear();
|
|
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
|
|
}
|
|
Memory::getInstance().dump(dumpSize);
|
|
} else if (input == 'r') {
|
|
Register::getInstance().dump();
|
|
} else {
|
|
std::cout << "Ungültige Eingabe. Bitte erneut versuchen.\n";
|
|
}
|
|
}
|
|
}
|
|
|
|
void Manager::handleExitInput() {
|
|
constexpr auto COLOR_GREEN = "\033[32m";
|
|
constexpr auto COLOR_RESET = "\033[0m";
|
|
std::cout << "\nOptionen: ("
|
|
<< COLOR_GREEN << "e" << COLOR_RESET << ") beenden, ("
|
|
<< COLOR_GREEN << "m" << COLOR_RESET << ") Memory Dump, ("
|
|
<< COLOR_GREEN << "r" << COLOR_RESET << ") Register Dump\n";
|
|
char input = '\0';
|
|
while (true) {
|
|
std::cout << "Eingabe: ";
|
|
std::cin >> input;
|
|
input = std::tolower(input);
|
|
|
|
if (input == 'e') {
|
|
std::cout << "Programm wird beendet. :pepeExit:\n";
|
|
exit(0); // oder andere Beendigung
|
|
} else if (input == 'm') {
|
|
std::cout << "Wie viele Speicherzellen sollen gedumpt werden? ";
|
|
int dumpSize = 0;
|
|
while (!(std::cin >> dumpSize) || dumpSize == 0) {
|
|
std::cout << "Ungültige Eingabe. Bitte eine positive Zahl eingeben: ";
|
|
std::cin.clear();
|
|
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
|
|
}
|
|
Memory::getInstance().dump(dumpSize);
|
|
} else if (input == 'r') {
|
|
Register::getInstance().dump();
|
|
} else {
|
|
std::cout << "Ungültige Eingabe. Bitte erneut versuchen.\n";
|
|
}
|
|
}
|
|
}
|