aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--qtmips_cli/main.cpp98
-rw-r--r--qtmips_cli/reporter.cpp19
-rw-r--r--qtmips_cli/reporter.h11
3 files changed, 121 insertions, 7 deletions
diff --git a/qtmips_cli/main.cpp b/qtmips_cli/main.cpp
index 14c818f..1a742e3 100644
--- a/qtmips_cli/main.cpp
+++ b/qtmips_cli/main.cpp
@@ -37,6 +37,7 @@
#include <QCommandLineParser>
#include <cctype>
#include <iostream>
+#include <fstream>
#include "tracer.h"
#include "reporter.h"
@@ -64,13 +65,15 @@ void create_parser(QCommandLineParser &p) {
p.addOption({{"trace-hi", "tr-hi"}, "Print HI register changes."});
p.addOption({{"dump-registers", "d-regs"}, "Dump registers state at program exit."});
p.addOption({"dump-cache-stats", "Dump cache statistics at program exit."});
+ p.addOption({"dump-range", "Dump memory range.", "START,LENGTH,FNAME"});
+ p.addOption({"load-range", "Load memory range.", "START,FNAME"});
p.addOption({"expect-fail", "Expect that program causes CPU trap and fail if it doesn't."});
p.addOption({"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"});
p.addOption({"d-cache", "Data cache. Format policy,sets,words_in_blocks,associativity where policy is random/lru/lfu", "DCACHE"});
p.addOption({"i-cache", "Instruction cache. Format policy,sets,words_in_blocks,associativity where policy is random/lru/lfu", "ICACHE"});
- p.addOption({"read-time", "memory read access time (cycles).", "RTIME"});
- p.addOption({"write-time", "memory read access time (cycles).", "WTIME"});
- p.addOption({"burst-time", "memory read access time (cycles).", "BTIME"});
+ p.addOption({"read-time", "Memory read access time (cycles).", "RTIME"});
+ p.addOption({"write-time", "Memory read access time (cycles).", "WTIME"});
+ p.addOption({"burst-time", "Memory read access time (cycles).", "BTIME"});
}
void configure_cache(MachineConfigCache &cacheconf, QStringList cachearg, QString which) {
@@ -192,7 +195,7 @@ void configure_tracer(QCommandLineParser &p, Tracer &tr) {
// TODO
}
-void configure_reporter(QCommandLineParser &p, Reporter &r) {
+void configure_reporter(QCommandLineParser &p, Reporter &r, const SymbolTable *symtab) {
if (p.isSet("dump-registers"))
r.regs();
if (p.isSet("dump-cache-stats"))
@@ -225,9 +228,90 @@ void configure_reporter(QCommandLineParser &p, Reporter &r) {
if (p.isSet("expect-fail") && !p.isSet("fail-match"))
r.expect_fail(Reporter::FailAny);
+ foreach (QString range_arg, p.values("dump-range")) {
+ std::uint32_t start;
+ std::uint32_t len;
+ bool ok1 = true;
+ bool ok2 = true;
+ QString str;
+ int comma1 = range_arg.indexOf(",");
+ if (comma1 < 0) {
+ cout << "Range start missing" << endl;
+ exit(1);
+ }
+ int comma2 = range_arg.indexOf(",", comma1 + 1);
+ if (comma2 < 0) {
+ cout << "Range lengt/name missing" << endl;
+ exit(1);
+ }
+ str = range_arg.mid(0, comma1);
+ if (str.size() >= 1 && !str.at(0).isDigit() && symtab != nullptr) {
+ ok1 = symtab->name_to_value(start, str);
+ } else {
+ start = str.toULong(&ok1, 0);
+ }
+ str = range_arg.mid(comma1 + 1, comma2 - comma1 - 1);
+ if (str.size() >= 1 && !str.at(0).isDigit() && symtab != nullptr) {
+ ok2 = symtab->name_to_value(len, str);
+ } else {
+ len = str.toULong(&ok2, 0);
+ }
+ if (!ok1 || !ok2) {
+ cout << "Range start/length specification error." << endl;
+ exit(1);
+ }
+ r.add_dump_range(start, len, range_arg.mid(comma2 + 1));
+ }
+
// TODO
}
+void load_ranges(QtMipsMachine &machine, const QStringList &ranges) {
+ foreach (QString range_arg, ranges) {
+ std::uint32_t start;
+ bool ok = true;
+ QString str;
+ int comma1 = range_arg.indexOf(",");
+ if (comma1 < 0) {
+ cout << "Range start missing" << endl;
+ exit(1);
+ }
+ str = range_arg.mid(0, comma1);
+ if (str.size() >= 1 && !str.at(0).isDigit() && machine.symbol_table() != nullptr) {
+ ok = machine.symbol_table()->name_to_value(start, str);
+ } else {
+ start = str.toULong(&ok, 0);
+ }
+ if (!ok) {
+ cout << "Range start/length specification error." << endl;
+ exit(1);
+ }
+ ifstream in;
+ std::uint32_t val;
+ std::uint32_t addr = start;
+ in.open(range_arg.mid(comma1 + 1).toLocal8Bit().data(), ios::in);
+ start = start & ~3;
+ for (std::string line; getline(in, line); )
+ {
+ size_t endpos = line.find_last_not_of(" \t\n");
+ size_t startpos = line.find_first_not_of(" \t\n");
+ size_t idx;
+ if (std::string::npos == endpos)
+ continue;
+ line = line.substr(0, endpos + 1);
+ line = line.substr(startpos);
+ val = stoul(line, &idx, 0);
+ if (idx != line.size()) {
+ cout << "cannot parse load range data." << endl;
+ exit(1);
+ }
+ machine.memory_rw()->write_word(addr, val);
+ addr += 4;
+ }
+ in.close();
+ }
+}
+
int main(int argc, char *argv[]) {
QCoreApplication app(argc, argv);
app.setApplicationName("qtmips_cli");
@@ -239,13 +323,15 @@ int main(int argc, char *argv[]) {
MachineConfig cc;
configure_machine(p, cc);
- QtMipsMachine machine(cc);
+ QtMipsMachine machine(cc, true);
Tracer tr(&machine);
configure_tracer(p, tr);
Reporter r(&app, &machine);
- configure_reporter(p, r);
+ configure_reporter(p, r, machine.symbol_table());
+
+ load_ranges(machine, p.values("load-range"));
machine.play();
return app.exec();
diff --git a/qtmips_cli/reporter.cpp b/qtmips_cli/reporter.cpp
index 70803a8..4f9a8cb 100644
--- a/qtmips_cli/reporter.cpp
+++ b/qtmips_cli/reporter.cpp
@@ -35,6 +35,7 @@
#include "reporter.h"
#include <iostream>
+#include <fstream>
#include <iomanip>
#include <typeinfo>
#include <qtmipsexception.h>
@@ -67,6 +68,10 @@ void Reporter::expect_fail(enum FailReason reason) {
e_fail = (enum FailReason)(e_fail | reason);
}
+void Reporter::add_dump_range(std::uint32_t start, std::uint32_t len, QString fname) {
+ dump_ranges.append({start, len, fname});
+}
+
void Reporter::machine_exit() {
report();
if (e_fail != 0) {
@@ -188,4 +193,18 @@ void Reporter::report() {
cout << "d-cache:stalled-cycles:" << machine->cache_data()->stalled_cycles() << endl;
cout << "d-cache:improved-speed:" << machine->cache_data()->speed_improvement() << endl;
}
+ foreach (DumpRange range, dump_ranges) {
+ ofstream out;
+ out.open(range.fname.toLocal8Bit().data(), ios::out | ios::trunc);
+ std::int32_t start = range.start & ~3;
+ std::int32_t end = range.start + range.len;
+ if (end < start)
+ end = 0xffffffff;
+ for (std::int32_t addr = start; addr < end; addr += 4) {
+ out << "0x";
+ out_hex(out, machine->memory()->read_word(addr), 8);
+ out << endl;
+ }
+ out.close();
+ }
}
diff --git a/qtmips_cli/reporter.h b/qtmips_cli/reporter.h
index 2dfaea9..5359908 100644
--- a/qtmips_cli/reporter.h
+++ b/qtmips_cli/reporter.h
@@ -37,6 +37,8 @@
#define REPORTER_H
#include <QObject>
+#include <QVector>
+#include <QString>
#include <QCoreApplication>
#include "qtmipsmachine.h"
@@ -55,9 +57,15 @@ public:
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);
+ struct DumpRange {
+ std::uint32_t start;
+ std::uint32_t len;
+ QString fname;
+ };
+ void add_dump_range(std::uint32_t start, std::uint32_t len, QString fname);
+
private slots:
void machine_exit();
void machine_trap(machine::QtMipsException &e);
@@ -66,6 +74,7 @@ private slots:
private:
QCoreApplication *app;
machine::QtMipsMachine *machine;
+ QVector<DumpRange> dump_ranges;
bool e_regs;
bool e_cache_stats;