1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
#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");
p.addHelpOption();
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) {
QStringList pa = p.positionalArguments();
if (pa.size() != 1) {
std::cerr << "Single ELF file has to be specified" << std::endl;
exit(1);
}
cc.set_elf(pa[0]);
// TODO
}
void configure_tracer(QCommandLineParser &p, Tracer &tr) {
if (p.isSet("trace-fetch"))
tr.fetch();
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
}
int main(int argc, char *argv[]) {
QCoreApplication app(argc, argv);
app.setApplicationName("qtmips_cli");
app.setApplicationVersion("0.1");
QCommandLineParser p;
create_parser(p);
p.process(app);
MachineConfig cc;
configure_machine(p, cc);
QtMipsMachine machine(cc);
Tracer tr(&machine);
configure_tracer(p, tr);
Reporter r(&app, &machine);
configure_reporter(p, r);
machine.play();
return app.exec();
}
|