[otbn,dv] Teach ISS wrapper to handle resets Without this, you get weird errors where OTBN gets resets half-way through a stall and a consistency check in the OtbnTraceChecker gets confused because it sees a stall at one address, followed by an execution at another. Signed-off-by: Rupert Swarbrick <rswarbrick@lowrisc.org>
diff --git a/hw/ip/otbn/dv/model/iss_wrapper.cc b/hw/ip/otbn/dv/model/iss_wrapper.cc index b32504e..14542d0 100644 --- a/hw/ip/otbn/dv/model/iss_wrapper.cc +++ b/hw/ip/otbn/dv/model/iss_wrapper.cc
@@ -381,6 +381,11 @@ return mismatch ? -1 : (done ? 1 : 0); } +void ISSWrapper::reset(bool gen_trace) { + if (gen_trace) + OtbnTraceChecker::get().Flush(); +} + void ISSWrapper::get_regs(std::array<uint32_t, 32> *gprs, std::array<u256_t, 32> *wdrs) { assert(gprs && wdrs);
diff --git a/hw/ip/otbn/dv/model/iss_wrapper.h b/hw/ip/otbn/dv/model/iss_wrapper.h index 8cacc9a..b9b3f82 100644 --- a/hw/ip/otbn/dv/model/iss_wrapper.h +++ b/hw/ip/otbn/dv/model/iss_wrapper.h
@@ -57,6 +57,12 @@ // it's the value of the ERR_BITS register. int step(bool gen_trace); + // Reset simulation + // + // This doesn't actually send anything to the ISS, but instead tells + // the OtbnTraceChecker to clear out any partial instructions + void reset(bool gen_trace); + // Get the current value of otbn.INSN_CNT. This should be called just after // step (but doesn't necessarily need to wait until the run has finished). uint32_t get_insn_cnt() const { return insn_cnt_; }
diff --git a/hw/ip/otbn/dv/model/otbn_core_model.sv b/hw/ip/otbn/dv/model/otbn_core_model.sv index 0fbaaf7..e0311b1 100644 --- a/hw/ip/otbn/dv/model/otbn_core_model.sv +++ b/hw/ip/otbn/dv/model/otbn_core_model.sv
@@ -52,7 +52,7 @@ string design_scope, int unsigned imem_words, int unsigned dmem_words); - import "DPI-C" function void otbn_model_destroy(chandle handle); + import "DPI-C" function void otbn_model_destroy(chandle model); import "DPI-C" context function int unsigned otbn_model_step(chandle model, logic start, @@ -64,6 +64,7 @@ inout bit [31:0] insn_cnt, inout bit [31:0] err_bits, inout bit [31:0] stop_pc); + import "DPI-C" function void otbn_model_reset(chandle model); localparam int ImemSizeWords = ImemSizeByte / 4; @@ -116,7 +117,9 @@ always_ff @(posedge clk_i or negedge rst_ni) begin if (!rst_ni) begin - // Clear status (stop running, and forget any errors and final PC) + if (status != 0) begin + otbn_model_reset(model_handle); + end status <= 0; raw_err_bits_q <= 0; stop_pc_q <= 0;
diff --git a/hw/ip/otbn/dv/model/otbn_model.cc b/hw/ip/otbn/dv/model/otbn_model.cc index e6301a2..11b267a 100644 --- a/hw/ip/otbn/dv/model/otbn_model.cc +++ b/hw/ip/otbn/dv/model/otbn_model.cc
@@ -660,3 +660,14 @@ return status; } + +// Flush any information in the model +extern "C" void otbn_model_reset(OtbnModel *model) { + assert(model); + + ISSWrapper *iss = model->get_wrapper(false); + if (iss) { + bool check_rtl = (model->design_scope_.size() > 0); + iss->reset(check_rtl); + } +}
diff --git a/hw/ip/otbn/dv/model/otbn_trace_checker.cc b/hw/ip/otbn/dv/model/otbn_trace_checker.cc index 60b8fa8..7f6d8a1 100644 --- a/hw/ip/otbn/dv/model/otbn_trace_checker.cc +++ b/hw/ip/otbn/dv/model/otbn_trace_checker.cc
@@ -176,6 +176,12 @@ return MatchPair(); } +void OtbnTraceChecker::Flush() { + rtl_pending_ = false; + rtl_stall_ = false; + iss_pending_ = false; +} + bool OtbnTraceChecker::Finish() { assert(!(rtl_pending_ && iss_pending_)); done_ = true;
diff --git a/hw/ip/otbn/dv/model/otbn_trace_checker.h b/hw/ip/otbn/dv/model/otbn_trace_checker.h index 886c933..eed21f4 100644 --- a/hw/ip/otbn/dv/model/otbn_trace_checker.h +++ b/hw/ip/otbn/dv/model/otbn_trace_checker.h
@@ -60,6 +60,10 @@ // Prints an error message to stderr and returns false on mismatch. bool OnIssTrace(const std::vector<std::string> &lines); + // Flush any pending entries. We need to do this on reset, to handle + // the case where we reset the processor in the middle of a stall. + void Flush(); + // Call this when the ISS simulation completes an operation (on ECALL or // error). //