Implement system call handling
MODIFY
CMakeLists.txt
CMakeLists.txt
@@ -35,6 +35,7 @@ qt5_add_resources(EXAMPLES_SRC ${CMAKE_SOURCE_DIR}/examples/examples.qrc)
# hack hack hack - the cereal headers within VSRTL expects the cereal include directory to be in the path.
# This requirement propagates onto inclusions from here, so we have to make this available aswell.
include_directories(${RIPES_LIB} PUBLIC external/VSRTL/external/cereal/include)
+include_directories(${RIPES_LIB} PUBLIC external/VSRTL/external)
include_directories(external)
# Platform specific pre-target setup(s)

MODIFY
src/mainwindow.cpp
src/mainwindow.cpp
@@ -72,8 +72,10 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), m_ui(new Ui::Main
connect(this, &MainWindow::updateMemoryTab, m_memoryTab, &MemoryTab::update);
connect(m_stackedTabs, &QStackedWidget::currentChanged, m_memoryTab, &MemoryTab::update);
connect(m_editTab, &EditTab::programChanged, m_processorHandler, &ProcessorHandler::loadProgram);
+
connect(m_processorHandler, &ProcessorHandler::reqProcessorReset, m_processorTab, &ProcessorTab::reset);
connect(m_processorHandler, &ProcessorHandler::reqReloadProgram, m_editTab, &EditTab::emitProgramChanged);
+ connect(m_processorHandler, &ProcessorHandler::print, m_processorTab, &ProcessorTab::printToLog);
connect(m_ui->actionAbout, &QAction::triggered, this, &MainWindow::about);
connect(m_ui->actionOpen_wiki, &QAction::triggered, this, &MainWindow::wiki);

MODIFY
src/processorhandler.cpp
src/processorhandler.cpp
#include "processorregistry.h"
+#include <QMessageBox>
+
ProcessorHandler::ProcessorHandler() {
// Contruct the default processor
selectProcessor(m_currentProcessorID);
@@ -21,5 +23,44 @@ void ProcessorHandler::loadProgram(const std::map<uint32_t, QByteArray*>& segmen
void ProcessorHandler::selectProcessor(ProcessorID id) {
m_currentProcessorID = id;
m_currentProcessor = ProcessorRegistry::constructProcessor(m_currentProcessorID);
+ m_currentProcessor->handleSysCall.Connect(this, &ProcessorHandler::handleSysCall);
emit reqReloadProgram();
}
+
+void ProcessorHandler::handleSysCall() {
+ const unsigned int arg = m_currentProcessor->getRegister(10);
+ switch (arg) {
+ case Ripes::SysCall::None:
+ return;
+ case Ripes::SysCall::PrintStr: {
+ QByteArray string;
+ char byte;
+ unsigned int address = m_currentProcessor->getRegister(11);
+ do {
+ byte = m_currentProcessor->getMemory().readMem(address++) & 0xFF;
+ string.append(byte);
+ } while (byte != '\0');
+ emit print(QString::fromUtf8(string));
+ return;
+ }
+ case Ripes::SysCall::PrintInt: {
+ emit print(QString::number(static_cast<int>(m_currentProcessor->getRegister(11))));
+ return;
+ }
+ case Ripes::SysCall::PrintChar: {
+ QString val = QChar(m_currentProcessor->getRegister(11));
+ emit print(val);
+ break;
+ }
+ case Ripes::SysCall::Exit: {
+ emit exit();
+ return;
+ }
+ default: {
+ QString title = "Error";
+ QString text = "Unknown system call argument in register a0: " + QString::number(arg);
+ QMessageBox::warning(nullptr, title, text);
+ return;
+ }
+ }
+}

MODIFY
src/processorhandler.h
src/processorhandler.h
@@ -33,8 +33,21 @@ signals:
*/
void reqReloadProgram();
+ /**
+ * @brief print
+ * Print string to log
+ */
+ void print(const QString&);
+
+ /**
+ * @brief exit
+ * end the current simulation, disallowing further clocking of the processor unless the processor is reset.
+ */
+ void exit();
+
public slots:
void loadProgram(const std::map<uint32_t, QByteArray*>& segments);
+ void handleSysCall();
private:
static constexpr ProcessorID defaultProcessor = ProcessorID::RISCV_SS;

MODIFY
src/processors/ripesprocessor.h
src/processors/ripesprocessor.h
#include <QString>
#include <map>
+#include "Signals/Signal.h"
#include "VSRTL/core/vsrtl_design.h"
namespace Ripes {
+enum SysCall { None = 0, PrintInt = 1, PrintChar = 2, PrintStr = 4, Exit = 10 };
+
enum class SupportedISA { RISCV };
struct StageInfo {
@@ -58,6 +61,12 @@ public:
*/
virtual vsrtl::SparseArray& getMemory() = 0;
+ /**
+ * @brief getRegister
+ * @return value currently present in register @p i
+ */
+ virtual unsigned int getRegister(unsigned i) = 0;
+
/**
* @brief setProgramCounter
* Sets the program counter of the processor to @param address
@@ -69,6 +78,8 @@ public:
m_instructionsRetired = 0;
}
+ Gallant::Signal0<> handleSysCall;
+
private:
// Statistics
unsigned int m_instructionsRetired = 0;

ADD
src/processors/ss/ecallchecker.h
+#pragma once
+
+#include "VSRTL/core/vsrtl_component.h"
+#include "Signals/Signal.h"
+
+#include "riscv.h"
+
+namespace vsrtl {
+using namespace core;
+namespace RISCV {
+
+class EcallChecker : public Component {
+public:
+ EcallChecker(std::string name, SimComponent* parent) : Component(name, parent) {
+ dummy << [=] {
+ if(opcode.uValue() == RVInstr::ECALL){
+ m_signal->Emit();
+ }
+ return 0;
+ };
+ }
+
+ void setSysCallSignal(Gallant::Signal0<>* sig){
+ m_signal = sig;
+ }
+
+ Gallant::Signal0<>* m_signal;
+
+
+ INPUTPORT_ENUM(opcode, RVInstr);
+ OUTPUTPORT(dummy, 1);
+};
+
+}
+}

MODIFY
src/processors/ss/riscv_ss.h
src/processors/ss/riscv_ss.h
#include "branch.h"
#include "control.h"
#include "decode.h"
+#include "ecallchecker.h"
#include "immediate.h"
#include "registerfile.h"
#include "riscv.h"
@@ -104,6 +105,11 @@ public:
registerFile->r2_out >> data_mem->data_in;
control->mem_ctrl >> data_mem->op;
data_mem->mem->setMemory(m_memory);
+
+ // -----------------------------------------------------------------------
+ // Ecall checker
+ decode->opcode >> ecallChecker->opcode;
+ ecallChecker->setSysCallSignal(&handleSysCall);
}
// Design subcomponents
@@ -136,6 +142,8 @@ public:
ADDRESSSPACE(m_memory);
ADDRESSSPACE(m_regMem);
+ SUBCOMPONENT(ecallChecker, EcallChecker);
+
// Ripes interface compliance
virtual Ripes::SupportedISA implementsISA() const override { return Ripes::SupportedISA::RISCV; }
unsigned int stageCount() const override { return 1; }
@@ -147,6 +155,7 @@ public:
propagateDesign();
}
SparseArray& getMemory() override { return *m_memory; }
+ unsigned int getRegister(unsigned i) override { return registerFile->getRegister(i); }
};
} // namespace RISCV
} // namespace vsrtl

MODIFY
src/processortab.cpp
src/processortab.cpp
@@ -54,6 +54,11 @@ ProcessorTab::ProcessorTab(ProcessorHandler& handler, QToolBar* toolbar, QWidget
updateActionState();
}
+void ProcessorTab::printToLog(const QString& text) {
+ m_ui->console->insertPlainText(text);
+ m_ui->console->verticalScrollBar()->setValue(m_ui->console->verticalScrollBar()->maximum());
+}
+
void ProcessorTab::setupSimulatorActions() {
const QIcon processorIcon = QIcon(":/icons/cpu.svg");
m_selectProcessorAction = new QAction(processorIcon, "Select processor", this);
@@ -267,15 +272,15 @@ bool ProcessorTab::handleEcall(const std::pair<Pipeline::ECALL, int32_t>& ecall_
case Pipeline::ECALL::none:
break;
case Pipeline::ECALL::print_string: {
- emit appendToLog(Parser::getParser()->getStringAt(static_cast<uint32_t>(ecall_val.second)));
+ // emit appendToLog(Parser::getParser()->getStringAt(static_cast<uint32_t>(ecall_val.second)));
break;
}
case Pipeline::ECALL::print_int: {
- emit appendToLog(QString::number(ecall_val.second));
+ // emit appendToLog(QString::number(ecall_val.second));
break;
}
case Pipeline::ECALL::print_char: {
- emit appendToLog(QChar(ecall_val.second));
+ // emit appendToLog(QChar(ecall_val.second));
break;
}
case Pipeline::ECALL::exit: {

MODIFY
src/processortab.h
src/processortab.h
@@ -46,6 +46,7 @@ public slots:
void restart();
void reset();
void run();
+ void printToLog(const QString&);
void processorSelection();

Implement system call handling