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; +}