Use protobuf to store simulation trace
PiperOrigin-RevId: 567391644
diff --git a/sim/BUILD b/sim/BUILD
index 8ea30ec..3ced2fe 100644
--- a/sim/BUILD
+++ b/sim/BUILD
@@ -131,6 +131,7 @@
":kelvin_decoder",
":kelvin_isa",
":kelvin_state",
+ "//sim/proto:trace_cc_proto",
"//sim/renode:kelvin_renode_memory",
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/flags:flag",
diff --git a/sim/kelvin_top.cc b/sim/kelvin_top.cc
index 0862639..445df59 100644
--- a/sim/kelvin_top.cc
+++ b/sim/kelvin_top.cc
@@ -8,7 +8,6 @@
#include <cstdint>
#include <cstring>
#include <fstream>
-#include <iomanip>
#include <ios>
#include <iostream>
#include <string>
@@ -18,6 +17,7 @@
#include "sim/decoder.h"
#include "sim/kelvin_enums.h"
#include "sim/kelvin_state.h"
+#include "sim/proto/kelvin_trace.pb.h"
#include "sim/renode/kelvin_renode_memory.h"
#include "absl/flags/flag.h"
#include "absl/functional/bind_front.h"
@@ -41,8 +41,12 @@
#include "mpact/sim/util/memory/flat_demand_memory.h"
ABSL_FLAG(bool, use_semihost, false, "Use semihost in the simulation");
-ABSL_FLAG(bool, trace, false, "Dump executed instruction trace");
-ABSL_FLAG(std::string, trace_path, "/tmp/kelvin_trace.txt",
+ABSL_FLAG(bool, trace, false,
+ "Dump executed instruction trace as Google Protobuf binary file. The "
+ "output can be decoded with protoc");
+ABSL_FLAG(bool, trace_disasm, false,
+ "Dump the disassembled opcode string with the trace");
+ABSL_FLAG(std::string, trace_path, "/tmp/kelvin_trace.pb",
"Path to save trace");
namespace kelvin::sim {
@@ -52,8 +56,7 @@
constexpr char kKelvinName[] = "Kelvin";
// Local helper function used to execute instructions.
-static inline bool ExecuteInstruction(mpact::sim::util::Instruction *inst,
- std::fstream *trace = nullptr) {
+static inline bool ExecuteInstruction(mpact::sim::util::Instruction *inst) {
for (auto *resource : inst->ResourceHold()) {
if (!resource->IsFree()) {
return false;
@@ -62,13 +65,6 @@
for (auto *resource : inst->ResourceAcquire()) {
resource->Acquire();
}
- if (trace != nullptr) {
- // TODO(hcindyl): Use protobuf to store the serialized trace.
- *trace << "["
- << "0x" << std::setfill('0') << std::setw(8) << std::hex
- << inst->address() << "] " << inst->AsString() << std::endl;
- }
-
inst->Execute(nullptr);
return true;
}
@@ -359,13 +355,16 @@
uint64_t next_seq_pc;
std::fstream trace_file;
+ proto::TraceData trace_data;
+ auto *inst_db = db_factory_.Allocate<uint32_t>(1);
if (absl::GetFlag(FLAGS_trace)) {
std::string trace_path = absl::GetFlag(FLAGS_trace_path);
std::string trace_dir =
trace_path.substr(0, trace_path.find_last_of('/'));
int res = mkdir(trace_dir.c_str(), 0777);
if (res == 0 || errno == EEXIST) {
- trace_file.open(absl::GetFlag(FLAGS_trace_path), std::ios_base::out);
+ trace_file.open(absl::GetFlag(FLAGS_trace_path),
+ std::ios_base::out | std::ios_base::binary);
std::cout << "Dump trace file at " << absl::GetFlag(FLAGS_trace_path)
<< std::endl;
} else {
@@ -381,9 +380,19 @@
// executed will overwrite this.
SetPc(next_seq_pc);
bool executed = false;
- std::fstream *trace_ptr = trace_file.is_open() ? &trace_file : nullptr;
do {
- executed = ExecuteInstruction(inst, trace_ptr);
+ executed = ExecuteInstruction(inst);
+ if (trace_file.is_open()) {
+ // Set trace entry {address, instruction}
+ memory_->Load(pc, inst_db, nullptr, nullptr);
+ auto inst_word = inst_db->Get<uint32_t>(0);
+ proto::TraceEntry *trace_entry = trace_data.add_entry();
+ trace_entry->set_address(pc);
+ trace_entry->set_opcode(inst_word);
+ if (absl::GetFlag(FLAGS_trace_disasm)) {
+ trace_entry->set_disasm(inst->AsString());
+ }
+ }
counter_num_cycles_.Increment(1);
state_->AdvanceDelayLines();
} while (!executed);
@@ -404,7 +413,9 @@
}
run_status_ = RunStatus::kHalted;
+ inst_db->DecRef();
if (trace_file.is_open()) {
+ trace_data.SerializeToOstream(&trace_file);
trace_file.close();
}
// Notify that the run has completed.
diff --git a/sim/proto/BUILD b/sim/proto/BUILD
new file mode 100644
index 0000000..17f0722
--- /dev/null
+++ b/sim/proto/BUILD
@@ -0,0 +1,19 @@
+# Protobuf for the kelvin sim trace file
+
+
+
+package(default_visibility = ["//visibility:public"])
+
+proto_library(
+ name = "trace_proto",
+ srcs = [
+ "kelvin_trace.proto",
+ ],
+)
+
+cc_proto_library(
+ name = "trace_cc_proto",
+ deps = [
+ ":trace_proto",
+ ],
+)
diff --git a/sim/proto/kelvin_trace.proto b/sim/proto/kelvin_trace.proto
new file mode 100644
index 0000000..2c060a3
--- /dev/null
+++ b/sim/proto/kelvin_trace.proto
@@ -0,0 +1,15 @@
+syntax = "proto2";
+
+package kelvin.sim.proto;
+
+option java_multiple_files = true;
+
+message TraceEntry {
+ optional uint32 address = 1;
+ optional uint32 opcode = 2;
+ optional string disasm = 3;
+}
+
+message TraceData {
+ repeated TraceEntry entry = 1;
+}