Add unit testing application
Whilst rudimentary and reliant on the GUI, this commit introduces a unit
test executable.
Unit tests may be specified in RISC-V assembly language, with a verification
string as a header. The test will be assembled, executed and the register
state is compared to the verification string.
MODIFY
.gitignore
.gitignore
@@ -7,8 +7,11 @@ Makefile
# Qt generated files
moc_*
+*.moc
ui_*
qrc_*
-# Executable
+# Executables & libraries
Ripes
+RipesTest
+libRipesLib.a
\ No newline at end of file

MODIFY
Ripes.pro
Ripes.pro
TEMPLATE = subdirs
CONFIG += ordered
-SUBDIRS = src app # test
-# test.depends = src
+SUBDIRS = src app test
+test.depends = src
app.depends = src

ADD
test/mulh.s
+# 5:0x80000000 6:0xffff8000 7:0x00004000
+li t0, 0x80000000
+li t1, 0xffff8000
+mulh t2, t0, t1
\ No newline at end of file

ADD
test/mulhsu.s
+# 5:0x80000000 6:0xffff8000 7:0x80004000
+li t0, 0x80000000
+li t1, 0xffff8000
+mulhsu t2, t0, t1
\ No newline at end of file

ADD
test/mulhu.s
+# 5:0x80000000 6:0xffff8000 7:0x7fffc000
+li t0, 0x80000000
+li t1, 0xffff8000
+mulhu t2, t0, t1
\ No newline at end of file

ADD
test/test.cpp
+#include <QtTest/QtTest>
+
+#include "mainwindow.h"
+#include "pipeline.h"
+
+#include <map>
+
+class TestRipes : public QObject {
+ Q_OBJECT
+private slots:
+ void runTests();
+
+private:
+ void executeTest(const QString& testcase);
+ void executeTest(const QString& testcase, const std::map<int, uint32_t>& verificationMap);
+};
+
+std::map<int, uint32_t> parseVerificationString(const QString& testcase) {
+ QString verificationString;
+ QFile file(testcase);
+ if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ verificationString = file.readAll();
+ file.close();
+ } else {
+ Q_ASSERT(false);
+ }
+
+ std::map<int, uint32_t> vparms;
+ verificationString.truncate(verificationString.indexOf('\n'));
+
+ // Test case must start with a verification string
+ Q_ASSERT(verificationString.startsWith('#'));
+ verificationString = verificationString.remove(0, 1).trimmed();
+
+ auto parms = verificationString.split(' ');
+ for (const auto& parm : parms) {
+ const auto& kv = parm.split(':');
+ Q_ASSERT(kv.size() == 2);
+ int key = kv[0].toInt();
+ uint32_t value = kv[1].toUInt(nullptr, 16);
+ vparms[key] = value;
+ }
+ return vparms;
+}
+
+void TestRipes::executeTest(const QString& testcase) {
+ const auto& verificationMap = parseVerificationString(testcase);
+ executeTest(testcase, verificationMap);
+}
+
+void TestRipes::executeTest(const QString& testcase, const std::map<int, uint32_t>& verificationMap) {
+ MainWindow w;
+ w.loadAssemblyFile(testcase);
+
+ // After loading an assembly file, the gui will await for no further changes by the user, and then start assembling.
+ // Sleep, allowing the event loop to be processed
+ QTest::qWait(1000);
+
+ auto pipeline = Pipeline::getPipeline();
+
+ pipeline->run();
+
+ const auto& regs = *pipeline->getRegPtr();
+ for (const auto& v : verificationMap) {
+ QVERIFY(regs[v.first] == v.second);
+ }
+}
+
+void TestRipes::runTests() {
+ // Avoid some warnings related to missing icons in the linked Ripes library
+ Q_INIT_RESOURCE(images);
+ Q_INIT_RESOURCE(examples);
+
+ executeTest(":/tests/mulh.s");
+ executeTest(":/tests/mulhu.s");
+ executeTest(":/tests/mulhsu.s");
+}
+
+QTEST_MAIN(TestRipes)
+#include "test.moc"

ADD
test/test.pro
+TARGET = RipesTest
+
+QT += testlib widgets
+
+CONFIG += c++14
+
+INCLUDEPATH += ../src/
+SOURCES += test.cpp
+RESOURCES += tests.qrc
+
+LIBS += -L$${DESTDIR}../src/ -lRipesLib

ADD
test/tests.qrc
+<RCC>
+ <qresource prefix="/tests">
+ <file>mulhu.s</file>
+ <file>mulhsu.s</file>
+ <file>mulh.s</file>
+ </qresource>
+</RCC>

Add unit testing application #34

Whilst rudimentary and reliant on the GUI, this commit introduces a unit
test executable.
Unit tests may be specified in RISC-V assembly language, with a verification
string as a header. The test will be assembled, executed and the register
state is compared to the verification string.