[otbn,dv] Be more descriptive when failing a trace comparison

Signed-off-by: Rupert Swarbrick <rswarbrick@lowrisc.org>
diff --git a/hw/ip/otbn/dv/model/otbn_trace_checker.cc b/hw/ip/otbn/dv/model/otbn_trace_checker.cc
index 484eb18..a060df5 100644
--- a/hw/ip/otbn/dv/model/otbn_trace_checker.cc
+++ b/hw/ip/otbn/dv/model/otbn_trace_checker.cc
@@ -238,11 +238,12 @@
   rtl_pending_ = false;
   iss_pending_ = false;
   iss_started_ = false;
-  if (!(rtl_entry_.compare_rtl_iss_entries(iss_entry_,
-                                           no_sec_wipe_data_chk_))) {
-    std::cerr
-        << ("ERROR: Mismatch between RTL and ISS trace entries.\n"
-            "  RTL entry is:\n");
+
+  std::string err_desc;
+  if (!(rtl_entry_.compare_rtl_iss_entries(iss_entry_, no_sec_wipe_data_chk_,
+                                           &err_desc))) {
+    std::cerr << "ERROR: Mismatch between RTL and ISS trace entries: "
+              << err_desc << "\n  RTL entry is:\n";
     rtl_entry_.print("    ", std::cerr);
     std::cerr << "  ISS entry is:\n";
     iss_entry_.print("    ", std::cerr);
diff --git a/hw/ip/otbn/dv/model/otbn_trace_entry.cc b/hw/ip/otbn/dv/model/otbn_trace_entry.cc
index 9a86bcc..f93aeec 100644
--- a/hw/ip/otbn/dv/model/otbn_trace_entry.cc
+++ b/hw/ip/otbn/dv/model/otbn_trace_entry.cc
@@ -60,43 +60,40 @@
 }
 
 bool OtbnTraceEntry::compare_rtl_iss_entries(const OtbnTraceEntry &other,
-                                             bool no_sec_wipe_data_chk) const {
-  if (hdr_ != other.hdr_)
+                                             bool no_sec_wipe_data_chk,
+                                             std::string *err_desc) const {
+  assert(err_desc);
+
+  if (hdr_ != other.hdr_) {
+    *err_desc = "Headers don't match.";
     return false;
+  }
 
   for (const auto &rtlptr : writes_) {
     auto isskey = other.writes_.find(rtlptr.first);
-    if (isskey == other.writes_.end())
+    if (isskey == other.writes_.end()) {
+      std::ostringstream oss;
+      oss << "RTL had a write to `" << rtlptr.first
+          << "', but the ISS doesn't have a write to that location.";
+      *err_desc = oss.str();
       return false;
+    }
     // compare rtlptr.second and isskey.second
     if (!check_entries_compatible(trace_type_, rtlptr.first, rtlptr.second,
-                                  isskey->second, no_sec_wipe_data_chk))
+                                  isskey->second, no_sec_wipe_data_chk,
+                                  err_desc))
       return false;
   }
 
-  if (writes_.size() != other.writes_.size())
+  if (writes_.size() != other.writes_.size()) {
+    std::ostringstream oss;
+    oss << "RTL wrote to " << writes_.size() << " locations; the ISS wrote to "
+        << other.writes_.size() << ".";
+    *err_desc = oss.str();
     return false;
-  return true;
-}
-
-bool OtbnTraceEntry::check_entries_compatible(
-    trace_type_t type, const std::string &key,
-    const std::vector<OtbnTraceBodyLine> &rtl_lines,
-    const std::vector<OtbnTraceBodyLine> &iss_lines,
-    bool no_sec_wipe_data_chk) {
-  assert(rtl_lines.size() && iss_lines.size());
-  assert(type == WipeComplete || type == Exec);
-
-  if (type == WipeComplete && key != "FLAGS0" && key != "FLAGS1") {
-    if (rtl_lines.size() != 2)
-      return false;
-    if (!no_sec_wipe_data_chk && type == WipeComplete) {
-      if (rtl_lines.front() == rtl_lines.back())
-        return false;
-    }
   }
 
-  return rtl_lines.back() == iss_lines.back();
+  return true;
 }
 
 void OtbnTraceEntry::print(const std::string &indent, std::ostream &os) const {
@@ -194,6 +191,41 @@
           (trace_type_ == OtbnTraceEntry::WipeComplete));
 }
 
+bool OtbnTraceEntry::check_entries_compatible(
+    trace_type_t type, const std::string &key,
+    const std::vector<OtbnTraceBodyLine> &rtl_lines,
+    const std::vector<OtbnTraceBodyLine> &iss_lines, bool no_sec_wipe_data_chk,
+    std::string *err_desc) {
+  assert(rtl_lines.size() && iss_lines.size());
+  assert(type == WipeComplete || type == Exec);
+  assert(err_desc);
+
+  if (type == WipeComplete && key != "FLAGS0" && key != "FLAGS1") {
+    if (rtl_lines.size() != 2) {
+      std::ostringstream oss;
+      oss << "There are " << rtl_lines.size() << "RTL lines for key `" << key
+          << "'; we expected 2.";
+      *err_desc = oss.str();
+      return false;
+    }
+    if (!no_sec_wipe_data_chk && rtl_lines.front() == rtl_lines.back()) {
+      std::ostringstream oss;
+      oss << "Repeated identical RTL lines for key `" << key << "'.";
+      *err_desc = oss.str();
+      return false;
+    }
+  }
+
+  if (!(rtl_lines.back() == iss_lines.back())) {
+    std::ostringstream oss;
+    oss << "Final values of ISS and RTL don't match for key `" << key << "'.";
+    *err_desc = oss.str();
+    return false;
+  }
+
+  return true;
+}
+
 OtbnTraceEntry::trace_type_t OtbnTraceEntry::hdr_to_trace_type(
     const std::string &hdr) {
   if (hdr.empty()) {
diff --git a/hw/ip/otbn/dv/model/otbn_trace_entry.h b/hw/ip/otbn/dv/model/otbn_trace_entry.h
index 995ab9e..6822095 100644
--- a/hw/ip/otbn/dv/model/otbn_trace_entry.h
+++ b/hw/ip/otbn/dv/model/otbn_trace_entry.h
@@ -55,7 +55,9 @@
   bool from_rtl_trace(const std::string &trace);
 
   bool compare_rtl_iss_entries(const OtbnTraceEntry &other,
-                               bool no_sec_wipe_data_chk) const;
+                               bool no_sec_wipe_data_chk,
+                               std::string *err_desc) const;
+
   void print(const std::string &indent, std::ostream &os) const;
 
   void take_writes(const OtbnTraceEntry &other, bool other_first);
@@ -72,13 +74,13 @@
   // True if this entry is "final" (Exec or WipeComplete)
   bool is_final() const;
 
+ protected:
   static bool check_entries_compatible(
       trace_type_t type, const std::string &key,
       const std::vector<OtbnTraceBodyLine> &rtl_lines,
       const std::vector<OtbnTraceBodyLine> &iss_lines,
-      bool no_sec_wipe_data_chk);
+      bool no_sec_wipe_data_chk, std::string *err_desc);
 
- protected:
   static trace_type_t hdr_to_trace_type(const std::string &hdr);
 
   trace_type_t trace_type_;