aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKarel Kočí <cynerd@email.cz>2018-01-01 20:43:42 +0100
committerKarel Kočí <cynerd@email.cz>2018-01-01 20:47:36 +0100
commit128ce1ee2115b54d43db1334e12410b1cc216f10 (patch)
tree10593231884a85966f38ac1fff9d139ae75e1bbb
parent92b6d05aed7cbfa7ddb0c5dcc61318c69c03bc97 (diff)
downloadqtmips-128ce1ee2115b54d43db1334e12410b1cc216f10.tar.gz
qtmips-128ce1ee2115b54d43db1334e12410b1cc216f10.tar.bz2
qtmips-128ce1ee2115b54d43db1334e12410b1cc216f10.zip
cli: extend tracer and implement reporter
-rw-r--r--qtmips_cli/main.cpp83
-rw-r--r--qtmips_cli/qtmips_cli.pro6
-rw-r--r--qtmips_cli/reporter.cpp59
-rw-r--r--qtmips_cli/reporter.h40
-rw-r--r--qtmips_cli/tracer.cpp46
-rw-r--r--qtmips_cli/tracer.h10
6 files changed, 237 insertions, 7 deletions
diff --git a/qtmips_cli/main.cpp b/qtmips_cli/main.cpp
index 4c4652b..2260ea5 100644
--- a/qtmips_cli/main.cpp
+++ b/qtmips_cli/main.cpp
@@ -1,9 +1,12 @@
#include <QCoreApplication>
#include <QCommandLineParser>
+#include <cctype>
#include <iostream>
#include "tracer.h"
+#include "reporter.h"
using namespace machine;
+using namespace std;
void create_parser(QCommandLineParser &p) {
p.setApplicationDescription("QtMips CLI machine simulator");
@@ -11,6 +14,17 @@ void create_parser(QCommandLineParser &p) {
p.addVersionOption();
p.addPositionalArgument("FILE", "Input ELF executable file");
+
+ p.addOptions({
+ {{"trace-fetch", "tr-fetch"}, "Trace fetched instruction."},
+ {{"trace-pc", "tr-pc"}, "Print program counter register changes."},
+ {{"trace-gp", "tr-gp"}, "Print general purpose register changes. You can use * for all registers.", "REG"},
+ {{"trace-lo", "tr-lo"}, "Print LO register changes."},
+ {{"trace-hi", "tr-hi"}, "Print HI register changes."},
+ {{"dump-registers", "d-regs"}, "Dump registers state at program exit."},
+ {"expect-fail", "Expect that program causes CPU trap and fail if it doesn't."},
+ {"fail-match", "Program should exit with exactly this CPU TRAP. Possible values are I(unsupported Instruction), A(Unsupported ALU operation), O(Overflow/underflow) and J(Unaligned Jump). You can freely combine them. Using this implies expect-fail option.", "TRAP"},
+ });
}
void configure_machine(QCommandLineParser &p, MachineConfig &cc) {
@@ -25,8 +39,68 @@ void configure_machine(QCommandLineParser &p, MachineConfig &cc) {
}
void configure_tracer(QCommandLineParser &p, Tracer &tr) {
+ // TODO trace fetched instruction
+
+ if (p.isSet("trace-pc"))
+ tr.reg_pc();
+
+ QStringList gps = p.values("trace-gp");
+ for (int i = 0; i < gps.size(); i++) {
+ if (gps[i] == "*") {
+ for (int y = 0; y < 32; y++)
+ tr.reg_gp(y);
+ } else {
+ bool res;
+ int num = gps[i].toInt(&res);
+ if (res && num <= 32) {
+ tr.reg_gp(num);
+ } else {
+ cout << "Unknown register number given for trace-gp: " << gps[i].toStdString() << endl;
+ exit(1);
+ }
+ }
+ }
+
+ if (p.isSet("trace-lo"))
+ tr.reg_lo();
+ if (p.isSet("trace-hi"))
+ tr.reg_hi();
+
+ // TODO
+}
+
+void configure_reporter(QCommandLineParser &p, Reporter &r) {
+ if (p.isSet("dump-registers"))
+ r.regs();
+
+ QStringList fail = p.values("fail-match");
+ for (int i = 0; i < fail.size(); i++) {
+ for (int y = 0; y < fail[i].length(); y++) {
+ enum Reporter::FailReason reason;
+ switch (tolower(fail[i].toStdString()[y])) {
+ case 'i':
+ reason = Reporter::FR_I;
+ break;
+ case 'a':
+ reason = Reporter::FR_A;
+ break;
+ case 'o':
+ reason = Reporter::FR_O;
+ break;
+ case 'j':
+ reason = Reporter::FR_J;
+ break;
+ default:
+ cout << "Unknown fail condition: " << fail[i].toStdString()[y] << endl;
+ exit(1);
+ }
+ r.expect_fail(reason);
+ }
+ }
+ if (p.isSet("expect-fail") && !p.isSet("fail-match"))
+ r.expect_fail(Reporter::FailAny);
+
// TODO
- tr.reg_pc();
}
int main(int argc, char *argv[]) {
@@ -42,11 +116,12 @@ int main(int argc, char *argv[]) {
configure_machine(p, cc);
QtMipsMachine machine(cc);
- app.connect(&machine, SIGNAL(program_exit()), &app, SLOT(quit()));
-
Tracer tr(&machine);
configure_tracer(p, tr);
- machine.play(); // Run machine
+ Reporter r(&app, &machine);
+ configure_reporter(p, r);
+
+ machine.play();
return app.exec();
}
diff --git a/qtmips_cli/qtmips_cli.pro b/qtmips_cli/qtmips_cli.pro
index 088a015..d9100f8 100644
--- a/qtmips_cli/qtmips_cli.pro
+++ b/qtmips_cli/qtmips_cli.pro
@@ -18,7 +18,9 @@ DEFINES += QT_DEPRECATED_WARNINGS
SOURCES += \
main.cpp \
- tracer.cpp
+ tracer.cpp \
+ reporter.cpp
HEADERS += \
- tracer.h
+ tracer.h \
+ reporter.h
diff --git a/qtmips_cli/reporter.cpp b/qtmips_cli/reporter.cpp
new file mode 100644
index 0000000..70d1d27
--- /dev/null
+++ b/qtmips_cli/reporter.cpp
@@ -0,0 +1,59 @@
+#include "reporter.h"
+#include <iostream>
+#include <typeinfo>
+#include <qtmipsexception.h>
+
+using namespace machine;
+using namespace std;
+
+Reporter::Reporter(QCoreApplication *app, QtMipsMachine *machine) : QObject() {
+ this->app = app;
+ this->machine = machine;
+
+ connect(machine, SIGNAL(program_exit()), this, SLOT(machine_exit()));
+ connect(machine, SIGNAL(program_trap(machine::QtMipsException&)), this, SLOT(machine_trap(machine::QtMipsException&)));
+
+ e_regs = false;
+ e_fail = (enum FailReason)0;
+}
+
+void Reporter::regs() {
+ e_regs = true;
+}
+
+void Reporter::expect_fail(enum FailReason reason) {
+ e_fail = (enum FailReason)(e_fail | reason);
+}
+
+void Reporter::machine_exit() {
+ report();
+ if (e_fail != 0) {
+ cout << "Machine was expected to fail but it didn't." << endl;
+ app->exit(1);
+ } else
+ app->exit();
+}
+
+void Reporter::machine_trap(QtMipsException &e) {
+ report();
+
+ bool expected = false;
+ auto& etype = typeid(e);
+ if (etype == typeid(QtMipsExceptionUnsupportedInstruction))
+ expected = e_fail & FR_I;
+ else if (etype == typeid(QtMipsExceptionUnsupportedAluOperation))
+ expected = e_fail & FR_A;
+ else if (etype == typeid(QtMipsExceptionOverflow))
+ expected = e_fail & FR_O;
+ else if (etype == typeid(QtMipsExceptionUnalignedJump))
+ expected = e_fail & FR_J;
+
+ cout << "Machine trapped: " << e.what() << endl;
+ app->exit(expected ? 0 : 1);
+}
+
+void Reporter::report() {
+ if (e_regs) {
+ // TODO
+ }
+}
diff --git a/qtmips_cli/reporter.h b/qtmips_cli/reporter.h
new file mode 100644
index 0000000..8dcc5f1
--- /dev/null
+++ b/qtmips_cli/reporter.h
@@ -0,0 +1,40 @@
+#ifndef REPORTER_H
+#define REPORTER_H
+
+#include <QObject>
+#include <QCoreApplication>
+#include "qtmipsmachine.h"
+
+class Reporter : QObject {
+ Q_OBJECT
+public:
+ Reporter(QCoreApplication *app, machine::QtMipsMachine *machine);
+
+ void regs(); // Report status of registers
+ // TODO
+
+ enum FailReason {
+ FR_I = (1<<0), // Unsupported Instruction
+ FR_A = (1<<1), // Unsupported ALU operation
+ FR_O = (1<<2), // Overflow/underflow of numerical operation
+ FR_J = (1<<3), // Unaligned jump
+ };
+ static const enum FailReason FailAny = (enum FailReason)(FR_I | FR_A | FR_O | FR_J);
+
+ void expect_fail(enum FailReason reason);
+
+private slots:
+ void machine_exit();
+ void machine_trap(machine::QtMipsException &e);
+
+private:
+ QCoreApplication *app;
+ machine::QtMipsMachine *machine;
+
+ bool e_regs;
+ enum FailReason e_fail;
+
+ void report();
+};
+
+#endif // REPORTER_H
diff --git a/qtmips_cli/tracer.cpp b/qtmips_cli/tracer.cpp
index 2969112..55dc3e3 100644
--- a/qtmips_cli/tracer.cpp
+++ b/qtmips_cli/tracer.cpp
@@ -1,17 +1,61 @@
#include "tracer.h"
#include <iostream>
+#include <qtmipsexception.h>
using namespace std;
using namespace machine;
Tracer::Tracer(QtMipsMachine *machine) {
this->machine = machine;
+ for (unsigned i = 0; i < 32; i++)
+ gp_regs[i] = false;
+ r_hi = false;
+ r_lo = false;
+
+ con_regs_pc = false;
+ con_regs_gp = false;
+ con_regs_hi_lo = false;
}
+#define CON(VAR, SIG, SLT) do { \
+ if (!VAR) { \
+ connect(machine->registers(), SIGNAL(SIG), this, SLOT(SLT)); \
+ VAR = true;\
+ }\
+ } while(false)
+
void Tracer::reg_pc() {
- connect(machine->registers(), SIGNAL(pc_update(std::uint32_t)), this, SLOT(regs_pc_update(std::uint32_t)));
+ CON(con_regs_pc, pc_update(std::uint32_t), regs_pc_update(std::uint32_t));
+}
+
+void Tracer::reg_gp(std::uint8_t i) {
+ SANITY_ASSERT(i <= 32, "Trying to trace invalid gp.");
+ CON(con_regs_gp, gp_update(std::uint8_t,std::uint32_t), regs_gp_update(std::uint8_t,std::uint32_t));
+ gp_regs[i] = true;
+}
+
+void Tracer::reg_lo() {
+ CON(con_regs_hi_lo, hi_lo_update(bool hi, std::uint32_t val), regs_hi_lo_update(bool hi, std::uint32_t val));
+ r_lo = true;
+}
+
+void Tracer::reg_hi() {
+ CON(con_regs_hi_lo, hi_lo_update(bool hi, std::uint32_t val), regs_hi_lo_update(bool hi, std::uint32_t val));
+ r_hi = true;
}
void Tracer::regs_pc_update(std::uint32_t val) {
cout << "PC:" << hex << val << endl;
}
+
+void Tracer::regs_gp_update(std::uint8_t i, std::uint32_t val) {
+ if (gp_regs[i])
+ cout << "GP" << dec << (unsigned)i << ":" << hex << val << endl;
+}
+
+void Tracer::regs_hi_lo_update(bool hi, std::uint32_t val) {
+ if (hi && r_hi)
+ cout << "HI:" << hex << val << endl;
+ else if (!hi && r_lo)
+ cout << "LO:" << hex << val << endl;
+}
diff --git a/qtmips_cli/tracer.h b/qtmips_cli/tracer.h
index d5a476b..245f418 100644
--- a/qtmips_cli/tracer.h
+++ b/qtmips_cli/tracer.h
@@ -11,12 +11,22 @@ public:
// Trace registers
void reg_pc();
+ void reg_gp(std::uint8_t i);
+ void reg_lo();
+ void reg_hi();
private slots:
void regs_pc_update(std::uint32_t val);
+ void regs_gp_update(std::uint8_t i, std::uint32_t val);
+ void regs_hi_lo_update(bool hi, std::uint32_t val);
private:
machine::QtMipsMachine *machine;
+
+ bool gp_regs[32];
+ bool r_hi, r_lo;
+
+ bool con_regs_pc, con_regs_gp, con_regs_hi_lo;
};
#endif // TRACER_H