[otbn] Run checks a cycle after model has finished
Otherwise, you end up racing with the final cycle in the RTL. This
hasn't been a problem until now (especially because the last
instruction is usually ECALL, which has no other side-effects), but
matters when with the trace comparison code, which needs to check
we've seen every trace entry.
Signed-off-by: Rupert Swarbrick <rswarbrick@lowrisc.org>
diff --git a/hw/ip/otbn/dv/model/otbn_core_model.sv b/hw/ip/otbn/dv/model/otbn_core_model.sv
index fcfafdc..cb5736f 100644
--- a/hw/ip/otbn/dv/model/otbn_core_model.sv
+++ b/hw/ip/otbn/dv/model/otbn_core_model.sv
@@ -104,14 +104,15 @@
// Extract particular bits of the status value.
//
// [0] running: The ISS is currently running
- // [1] failed_step: Something went wrong when trying to start or step the ISS.
- // [2] failed_cmp: The consistency check at the end of run failed.
+ // [1] check_due: The ISS just finished but still needs to check results
+ // [2] failed_step: Something went wrong when trying to start or step the ISS.
+ // [3] failed_cmp: The consistency check at the end of run failed.
// [31:16] raw_err_code: The code to expose as the ERR_CODE register
//
- bit failed_cmp, failed_step, running;
+ bit failed_cmp, failed_step, check_due, running;
bit [15:0] raw_err_code;
- assign {failed_cmp, failed_step, running} = status[2:0];
+ assign {failed_cmp, failed_step, check_due, running} = status[3:0];
assign raw_err_code = status[31:16];
assign err_code_o = err_code_e'(raw_err_code);
@@ -120,7 +121,7 @@
// Clear status (stop running, and forget any errors)
status <= 0;
end else begin
- if (start_i | running) begin
+ if (start_i | running | check_due) begin
status <= otbn_model_step(model_handle,
ImemScope, ImemSizeWords,
DmemScope, DmemSizeWords,
diff --git a/hw/ip/otbn/dv/model/otbn_model.cc b/hw/ip/otbn/dv/model/otbn_model.cc
index 77f62ed..c14ddd8 100644
--- a/hw/ip/otbn/dv/model/otbn_model.cc
+++ b/hw/ip/otbn/dv/model/otbn_model.cc
@@ -29,9 +29,10 @@
}
#define RUNNING_BIT (1U << 0)
-#define FAILED_STEP_BIT (1U << 1)
-#define FAILED_CMP_BIT (1U << 2)
-#define STATUS_MASK ((1U << 3) - 1)
+#define CHECK_DUE_BIT (1U << 1)
+#define FAILED_STEP_BIT (1U << 2)
+#define FAILED_CMP_BIT (1U << 3)
+#define STATUS_MASK ((1U << 4) - 1)
// The main entry point to the OTBN model, exported from here and used in
// otbn_core_model.sv.
@@ -40,13 +41,15 @@
// parameter, which has the following bits:
//
// Bit 0: running True if the model is currently running
-// Bit 1: failed_step Something failed when trying to start/step ISS
-// Bit 2: failed_cmp Consistency check at end of run failed
+// Bit 1: check_due True if the model finished running last cycle
+// Bit 2: failed_step Something failed when trying to start/step ISS
+// Bit 3: failed_cmp Consistency check at end of run failed
// Bits 31:16: err_code Error code to report on negedge of running
//
// The otbn_model_step function should only be called when either the model is
-// running (bit 0 of status) or when start_i is asserted. At other times, it
-// will return immediately (but wastes a DPI call).
+// running (bit 0 of status), has a check due (bit 1 of status), or when
+// start_i is asserted. At other times, it will return immediately (but wastes
+// a DPI call).
//
// If the model is running and start_i is false, otbn_model_step steps the ISS
// by a single cycle. If something goes wrong, it will set failed_step to true
@@ -530,6 +533,27 @@
// Clear out any ERR_CODE from a previous cycle
status &= STATUS_MASK;
+ // Run model checks if needed. This usually happens just after an operation
+ // has finished.
+ bool check_rtl = (design_scope[0] != '\0');
+ if (check_rtl && (status & CHECK_DUE_BIT)) {
+ switch (check_model(model, dmem_scope, dmem_words, design_scope)) {
+ case 1:
+ // Match (success)
+ break;
+
+ case 0:
+ // Mismatch
+ status |= FAILED_CMP_BIT;
+ break;
+
+ default:
+ // Something went wrong
+ return (status & ~RUNNING_BIT) | FAILED_STEP_BIT;
+ }
+ status &= ~CHECK_DUE_BIT;
+ }
+
// Start the model if requested
if (start_i) {
switch (start_model(model, imem_scope, imem_words, dmem_scope, dmem_words,
@@ -558,7 +582,7 @@
case 1:
// Finished
- status = (status & ~RUNNING_BIT) | (err_code << 16);
+ status = (status & ~RUNNING_BIT) | CHECK_DUE_BIT | (err_code << 16);
break;
default:
@@ -570,8 +594,9 @@
if (status & RUNNING_BIT)
return status;
- // If we've stopped running, either load DMEM or check against the RTL.
- if (design_scope[0] == '\0') {
+ // If we've just stopped running and there's no RTL, load the contents of
+ // DMEM back from the ISS
+ if (!check_rtl) {
switch (load_dmem(model, dmem_scope, dmem_words)) {
case 0:
// Success
@@ -581,21 +606,6 @@
// Failed to load DMEM
return (status & ~RUNNING_BIT) | FAILED_STEP_BIT;
}
- } else {
- switch (check_model(model, dmem_scope, dmem_words, design_scope)) {
- case 1:
- // Match (success)
- break;
-
- case 0:
- // Mismatch
- status |= FAILED_CMP_BIT;
- break;
-
- default:
- // Something went wrong
- return (status & ~RUNNING_BIT) | FAILED_STEP_BIT;
- }
}
return status;