[otbn] Implement RND/URND CSR/WSR and RND_PREFETCH CSR

This adds logic to read RND values from the EDN, removing the test RND
dummy value. A small cache to hold a single 256-bit random number from
an EDN request is provided. A RND_PREFETCH CSR is introduced which
prefetches to the cache when any value is written to it. Any RND read
will take the value from the cache, emptying it. If a value isn't
available in the cache the RND read will stall until one is available,
starting a new EDN request to fetch one if required.

An LFSR is added to supply values to URND. This is seeded via a request
to the EDN that occurs when OTBN starts. Execution cannot proceed until
the LFSR has been seeded.

Two dummy EDNs are provided in `otbn_top_sim.sv`. These provides the
existing test RND dummy value on every request after a fixed delay.

The ISS has been altered to support the new stalling behaviour for RND
reads. In a testbench the EDN interface is monitored and the ISS is
provided with RND values as they appear on the interface.

ISS support for URND has not yet been implemented, though it does
implement the stall at the beginning of execution whilst OTBN awaits a
URND reseed.

Signed-off-by: Greg Chadwick <gac@lowrisc.org>
diff --git a/hw/ip/otbn/rtl/otbn_controller.sv b/hw/ip/otbn/rtl/otbn_controller.sv
index 536807b..95144a0 100644
--- a/hw/ip/otbn/rtl/otbn_controller.sv
+++ b/hw/ip/otbn/rtl/otbn_controller.sv
@@ -107,8 +107,11 @@
   output logic [BaseWordsPerWLEN-1:0] ispr_base_wr_en_o,
   output logic [WLEN-1:0]             ispr_bignum_wdata_o,
   output logic                        ispr_bignum_wr_en_o,
-  output logic                        ispr_init_o,
-  input  logic [WLEN-1:0]             ispr_rdata_i
+  input  logic [WLEN-1:0]             ispr_rdata_i,
+
+  output logic rnd_req_o,
+  output logic rnd_prefetch_req_o,
+  input  logic rnd_valid_i
 );
   otbn_state_e state_q, state_d, state_raw;
 
@@ -118,6 +121,7 @@
   logic insn_fetch_req_valid_raw;
 
   logic stall;
+  logic ispr_stall;
   logic mem_stall;
   logic branch_taken;
   logic insn_executing;
@@ -143,7 +147,7 @@
 
   ispr_e                               ispr_addr_bignum;
 
-  logic                                ispr_wr_insn;
+  logic                                ispr_wr_insn, ispr_rd_insn;
   logic                                ispr_wr_base_insn;
   logic                                ispr_wr_bignum_insn;
 
@@ -185,7 +189,10 @@
   // just ensure incoming store error stops anything else happening.
   assign mem_stall = lsu_load_req_raw;
 
-  assign stall = mem_stall;
+  // Reads to RND must stall until data is available
+  assign ispr_stall = rnd_req_o & ~rnd_valid_i;
+
+  assign stall = mem_stall | ispr_stall;
 
   // OTBN is done (raising the 'done' interrupt) either when it executes an ecall or an error
   // occurs. The ecall triggered done is factored out as `done_complete` to avoid logic loops in the
@@ -211,7 +218,6 @@
     state_raw                = state_q;
     insn_fetch_req_valid_raw = 1'b0;
     insn_fetch_req_addr_o    = start_addr_i;
-    ispr_init_o              = 1'b0;
 
     // TODO: Harden state machine
     // TODO: Jumps/branches
@@ -222,8 +228,6 @@
 
           insn_fetch_req_addr_o    = start_addr_i;
           insn_fetch_req_valid_raw = 1'b1;
-
-          ispr_init_o = 1'b1;
         end
       end
       OtbnStateRun: begin
@@ -309,7 +313,8 @@
 
   `ASSERT(ErrBitSetOnErr, err |-> |err_bits_o)
 
-  `ASSERT(ControllerStateValid, state_q inside {OtbnStateHalt, OtbnStateRun, OtbnStateStall})
+  `ASSERT(ControllerStateValid, state_q inside {OtbnStateHalt, OtbnStateRun,
+                                                OtbnStateStall})
   // Branch only takes effect in OtbnStateRun so must not go into stall state for branch
   // instructions.
   `ASSERT(NoStallOnBranch,
@@ -579,6 +584,14 @@
         ispr_addr_base      = IsprRnd;
         ispr_word_addr_base = '0;
       end
+      CsrRndPrefetch: begin
+        // Reading from RND_PREFETCH results in 0, there is no ISPR to read so no address is set.
+        // The csr_rdata mux logic takes care of producing the 0.
+      end
+      CsrUrnd: begin
+        ispr_addr_base      = IsprUrnd;
+        ispr_word_addr_base = '0;
+      end
       default: csr_illegal_addr = 1'b1;
     endcase
   end
@@ -600,10 +613,11 @@
   always_comb begin
     csr_rdata = csr_rdata_raw;
 
-    unique case(csr_addr)
+    unique case (csr_addr)
       // For FG0/FG1 select out appropriate bits from FLAGS ISPR and pad the rest with zeros.
-      CsrFg0: csr_rdata = {28'b0, csr_rdata_raw[3:0]};
-      CsrFg1: csr_rdata = {28'b0, csr_rdata_raw[7:4]};
+      CsrFg0:         csr_rdata = {28'b0, csr_rdata_raw[3:0]};
+      CsrFg1:         csr_rdata = {28'b0, csr_rdata_raw[7:4]};
+      CsrRndPrefetch: csr_rdata = '0;
       default: ;
     endcase
   end
@@ -615,7 +629,7 @@
   always_comb begin
     csr_wdata = csr_wdata_raw;
 
-    unique case(csr_addr)
+    unique case (csr_addr)
       // For FG0/FG1 only modify relevant part of FLAGS ISPR.
       CsrFg0: csr_wdata = {24'b0, csr_rdata_raw[7:4], csr_wdata_raw[3:0]};
       CsrFg1: csr_wdata = {24'b0, csr_wdata_raw[3:0], csr_rdata_raw[3:0]};
@@ -637,9 +651,10 @@
     wsr_illegal_addr = 1'b0;
 
     unique case (wsr_addr)
-      WsrMod: ispr_addr_bignum = IsprMod;
-      WsrRnd: ispr_addr_bignum = IsprRnd;
-      WsrAcc: ispr_addr_bignum = IsprAcc;
+      WsrMod:  ispr_addr_bignum = IsprMod;
+      WsrRnd:  ispr_addr_bignum = IsprRnd;
+      WsrAcc:  ispr_addr_bignum = IsprAcc;
+      WsrUrnd: ispr_addr_bignum = IsprUrnd;
       default: wsr_illegal_addr = 1'b1;
     endcase
   end
@@ -655,7 +670,12 @@
                                                         insn_dec_shared_i.ispr_rs_insn);
 
   assign ispr_wr_insn = insn_dec_shared_i.ispr_wr_insn | insn_dec_shared_i.ispr_rs_insn;
-  assign ispr_wr_base_insn   = ispr_wr_insn & (insn_dec_shared_i.subset == InsnSubsetBase);
+  assign ispr_rd_insn = insn_dec_shared_i.ispr_rd_insn | insn_dec_shared_i.ispr_rs_insn;
+
+  // Write to RND_PREFETCH must not produce ISR write
+  assign ispr_wr_base_insn =
+    ispr_wr_insn & (insn_dec_shared_i.subset == InsnSubsetBase) & (csr_addr != CsrRndPrefetch);
+
   assign ispr_wr_bignum_insn = ispr_wr_insn & (insn_dec_shared_i.subset == InsnSubsetBignum);
 
   assign ispr_addr_o         = insn_dec_shared_i.subset == InsnSubsetBase ? ispr_addr_base :
@@ -693,6 +713,11 @@
                                                                dmem_addr_unaligned_bignum |
                                                                dmem_addr_unaligned_base);
 
+  assign rnd_req_o = insn_valid_i & ispr_rd_insn & (ispr_addr_o == IsprRnd);
+
+  assign rnd_prefetch_req_o = insn_valid_i & ispr_wr_insn &
+      (insn_dec_shared_i.subset == InsnSubsetBase) & (csr_addr == CsrRndPrefetch);
+
   // RF Read enables for bignum RF are unused for now. Future security hardening work may make use
   // of them.
   logic unused_rf_ren_a_bignum;