aboutsummaryrefslogtreecommitdiff
path: root/qtmips_cli/main.cpp
blob: 4fd6ce5b6bcb6c2d01d6111e8b16f1e8c6be0bfa (plain)
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();
}