[otbn,rtl] Separate wipe value of last WDR and ACC register

Prior to this commit, WDR[31] and the ACC register had the same value
after secure wipe (#14324).  This commit fixes #14324 by extending the
secure wipe by one cycle, so that WDR[31] is now wiped in the cycle
before the ACC register is wiped.

Signed-off-by: Andreas Kurth <adk@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 52d4ab8..1ab4902 100644
--- a/hw/ip/otbn/dv/model/otbn_core_model.sv
+++ b/hw/ip/otbn/dv/model/otbn_core_model.sv
@@ -145,7 +145,7 @@
   } urnd_state_e;
   urnd_state_e urnd_state_q, urnd_state_d;
 
-  localparam int unsigned WIPE_CYCLES = 66;
+  localparam int unsigned WIPE_CYCLES = 67;
   typedef logic [$clog2(WIPE_CYCLES+1)-1:0] wipe_cyc_cnt_t;
   wipe_cyc_cnt_t wipe_cyc_cnt_q, wipe_cyc_cnt_d;
 
diff --git a/hw/ip/otbn/dv/otbnsim/sim/state.py b/hw/ip/otbn/dv/otbnsim/sim/state.py
index 20d378b..f125dcf 100644
--- a/hw/ip/otbn/dv/otbnsim/sim/state.py
+++ b/hw/ip/otbn/dv/otbnsim/sim/state.py
@@ -21,7 +21,7 @@
 
 # The number of cycles spent per round of a secure wipe. This takes constant
 # time in the RTL, mirrored here.
-_WIPE_CYCLES = 67
+_WIPE_CYCLES = 68
 
 
 class FsmState(IntEnum):
diff --git a/hw/ip/otbn/rtl/otbn_start_stop_control.sv b/hw/ip/otbn/rtl/otbn_start_stop_control.sv
index 718f753..47a716a 100644
--- a/hw/ip/otbn/rtl/otbn_start_stop_control.sv
+++ b/hw/ip/otbn/rtl/otbn_start_stop_control.sv
@@ -73,7 +73,7 @@
   logic secure_wipe_error_q, secure_wipe_error_d;
 
   logic addr_cnt_inc;
-  logic [4:0] addr_cnt_q, addr_cnt_d;
+  logic [5:0] addr_cnt_q, addr_cnt_d;
 
   logic spurious_urnd_ack_error;
   logic spurious_secure_wipe_req, dropped_secure_wipe_req;
@@ -220,7 +220,18 @@
         expect_secure_wipe    = 1'b1;
         secure_wipe_running_o = 1'b1;
 
-        if (addr_cnt_q == 5'b11111) begin
+        // Count one extra cycle when wiping the WDR, because the wipe signals to the WDR
+        // (`sec_wipe_wdr_o` and `sec_wipe_wdr_urnd_o`) are flopped once but the wipe signals to the
+        // ACC register, which is wiped directly after the last WDR, are not.  If we would not count
+        // this extra cycle, the last WDR and the ACC register would be wiped simultaneously and
+        // thus with the same random value.
+        if (addr_cnt_q == 6'b100000) begin
+          // Reset `addr_cnt` on the transition out of this state.
+          addr_cnt_inc = 1'b0;
+          // The following two signals are flopped once before they reach the FSM, so clear them one
+          // cycle early here.
+          sec_wipe_wdr_o      = 1'b0;
+          sec_wipe_wdr_urnd_o = 1'b0;
           state_d = OtbnStartStopSecureWipeAccModBaseUrnd;
         end
       end
@@ -234,12 +245,12 @@
         expect_secure_wipe    = 1'b1;
         secure_wipe_running_o = 1'b1;
         // The first two clock cycles are used to write random data to accumulator and modulus.
-        sec_wipe_acc_urnd_o   = (addr_cnt_q == 5'b00000);
-        sec_wipe_mod_urnd_o   = (addr_cnt_q == 5'b00001);
+        sec_wipe_acc_urnd_o   = (addr_cnt_q == 6'b000000);
+        sec_wipe_mod_urnd_o   = (addr_cnt_q == 6'b000001);
         // Supress writes to the zero register and the call stack.
-        sec_wipe_base_o       = (addr_cnt_q > 5'b00001);
-        sec_wipe_base_urnd_o  = (addr_cnt_q > 5'b00001);
-        if (addr_cnt_q == 5'b11111) begin
+        sec_wipe_base_o       = (addr_cnt_q > 6'b000001);
+        sec_wipe_base_urnd_o  = (addr_cnt_q > 6'b000001);
+        if (addr_cnt_q == 6'b011111) begin
           state_d = OtbnStartStopSecureWipeAllZero;
         end
       end
@@ -332,11 +343,11 @@
                                                                  OtbnStartStopStateLocked}) &&
                     init_sec_wipe_done_q));
 
-  assign addr_cnt_d = addr_cnt_inc ? (addr_cnt_q + 5'd1) : 5'd0;
+  assign addr_cnt_d = addr_cnt_inc ? (addr_cnt_q + 6'd1) : 6'd0;
 
   always_ff @(posedge clk_i or negedge rst_ni) begin
     if (!rst_ni) begin
-      addr_cnt_q           <= 5'd0;
+      addr_cnt_q           <= 6'd0;
       init_sec_wipe_done_q <= 1'b0;
     end else begin
       addr_cnt_q           <= addr_cnt_d;
@@ -354,7 +365,10 @@
     .mubi_o(wipe_after_urnd_refresh_q)
   );
 
-  assign sec_wipe_addr_o = addr_cnt_q;
+  // Clip the secure wipe address to [0..31].  This is safe because the wipe enable signals are
+  // never set when the counter exceeds 5 bit, which we assert below.
+  assign sec_wipe_addr_o = addr_cnt_q[4:0];
+  `ASSERT(NoSecWipeAbove32Bit_A, addr_cnt_q[5] |-> (!sec_wipe_wdr_o && !sec_wipe_acc_urnd_o))
 
   // A check for spurious or dropped secure wipe requests.
   // We only expect to start a secure wipe when running.