diff options
-rw-r--r-- | qtmips_cli/main.cpp | 98 | ||||
-rw-r--r-- | qtmips_cli/reporter.cpp | 19 | ||||
-rw-r--r-- | qtmips_cli/reporter.h | 11 |
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; |