[entropy_src, dv] Add scoreboard support for accesses to ENTROPY_DATA

- Make use of the entropy_data_q to receive raw entropy for predicting accesses to ENTROPY_DATA
- Activate the scoreboard in the smoke test
- Miscellaneous debug comments, which can be activated with --run-mode set_verbosity_comp_a_uvm_debug

Signed-off-by: Martin Lueker-Boden <martin.lueker-boden@wdc.com>
diff --git a/hw/ip/entropy_src/dv/entropy_src_sim_cfg.hjson b/hw/ip/entropy_src/dv/entropy_src_sim_cfg.hjson
index 409da16..b396348 100644
--- a/hw/ip/entropy_src/dv/entropy_src_sim_cfg.hjson
+++ b/hw/ip/entropy_src/dv/entropy_src_sim_cfg.hjson
@@ -68,5 +68,17 @@
       tests: ["entropy_src_smoke"]
     }
   ]
+
+  component_a: "uvm_test_top.env.scoreboard"
+  id_a : _ALL_
+  verbosity_a: UVM_MEDIUM
+  phase_a: run
+
+  run_modes: [
+    {
+      name: set_verbosity_comp_a_uvm_debug
+      run_opts: ["+uvm_set_verbosity={component_a},{id_a},{verbosity_a},{phase_a}"]
+    }
+  ]
 }
 
diff --git a/hw/ip/entropy_src/dv/env/entropy_src_scoreboard.sv b/hw/ip/entropy_src/dv/env/entropy_src_scoreboard.sv
index 44c1206..c60e896 100644
--- a/hw/ip/entropy_src/dv/env/entropy_src_scoreboard.sv
+++ b/hw/ip/entropy_src/dv/env/entropy_src_scoreboard.sv
@@ -2,22 +2,27 @@
 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
 // SPDX-License-Identifier: Apache-2.0
 
-class entropy_src_scoreboard extends cip_base_scoreboard #(
+class entropy_src_scoreboard extends cip_base_scoreboard
+  #(
     .CFG_T(entropy_src_env_cfg),
     .RAL_T(entropy_src_reg_block),
     .COV_T(entropy_src_env_cov)
   );
+  import entropy_src_pkg::*;
+
   `uvm_component_utils(entropy_src_scoreboard)
 
+  int entropy_data_reads = 0;
+
   // local variables
-  push_pull_item#(.HostDataWidth(entropy_src_pkg::RNG_BUS_WIDTH))  rng_item;
-  bit [31:0]                                                       entropy_data_q[$];
-  bit [entropy_src_pkg::FIPS_CSRNG_BUS_WIDTH-1:0]                  fips_csrng_q[$];
+  push_pull_item#(.HostDataWidth(RNG_BUS_WIDTH))  rng_item;
+  bit [31:0]                       entropy_data_q[$];
+  bit [FIPS_CSRNG_BUS_WIDTH - 1:0] fips_csrng_q[$];
 
   // TLM agent fifos
-  uvm_tlm_analysis_fifo#(push_pull_item#(.HostDataWidth(entropy_src_pkg::FIPS_CSRNG_BUS_WIDTH)))
+  uvm_tlm_analysis_fifo#(push_pull_item#(.HostDataWidth(FIPS_CSRNG_BUS_WIDTH)))
       csrng_fifo;
-  uvm_tlm_analysis_fifo#(push_pull_item#(.HostDataWidth(entropy_src_pkg::RNG_BUS_WIDTH)))
+  uvm_tlm_analysis_fifo#(push_pull_item#(.HostDataWidth(RNG_BUS_WIDTH)))
       rng_fifo;
 
   `uvm_component_new
@@ -35,26 +40,26 @@
 
   task run_phase(uvm_phase phase);
     super.run_phase(phase);
-
-    fork
-      collect_entropy();
-      process_csrng();
-    join_none
+    if (cfg.en_scb) begin
+      fork
+        collect_entropy();
+        process_csrng();
+      join_none
+    end
   endtask
 
   virtual task process_tl_access(tl_seq_item item, tl_channels_e channel, string ral_name);
     uvm_reg csr;
     // TODO: Add conditioning prediction, still TBD in design
-    bit     do_read_check   = 1'b1;
-    bit     write           = item.is_write();
+    bit do_read_check       = 1'b1;
+    bit write               = item.is_write();
     uvm_reg_addr_t csr_addr = cfg.ral_models[ral_name].get_word_aligned_addr(item.a_addr);
 
     // if access was to a valid csr, get the csr handle
     if (csr_addr inside {cfg.ral_models[ral_name].csr_addrs}) begin
       csr = cfg.ral_models[ral_name].default_map.get_reg_by_offset(csr_addr);
       `DV_CHECK_NE_FATAL(csr, null)
-    end
-    else begin
+    end else begin
       `uvm_fatal(`gfn, $sformatf("Access unexpected addr 0x%0h", csr_addr))
     end
 
@@ -71,6 +76,7 @@
     case (csr.get_name())
       // add individual case item for each csr
       "intr_state": begin
+        // TODO
         do_read_check = 1'b0;
       end
       "intr_enable": begin
@@ -139,7 +145,11 @@
       if (do_read_check) begin
         case (csr.get_name())
           "entropy_data": begin
-            void'(csr.predict(.value(entropy_data_q.pop_front()), .kind(UVM_PREDICT_READ)));
+            bit [31:0] ed_pred_data = entropy_data_q.pop_front();
+            `uvm_info(`gfn, $sformatf("entropy_data_prediction: %08h\n", ed_pred_data), UVM_MEDIUM)
+            `DV_CHECK_FATAL(csr.predict(.value(ed_pred_data), .kind(UVM_PREDICT_READ)))
+            entropy_data_reads++;
+            `uvm_info(`gfn, $sformatf("entropy_data_reads: %3d\n", entropy_data_reads), UVM_MEDIUM);
           end
         endcase
 
@@ -149,37 +159,60 @@
     end
   endtask
 
-  function bit [entropy_src_pkg::FIPS_CSRNG_BUS_WIDTH-1:0] predict_fips_csrng (
-      bit [entropy_src_pkg::RNG_BUS_WIDTH-1:0] data_q[$]);
-    bit [entropy_src_pkg::FIPS_CSRNG_BUS_WIDTH - 1:0]   fips_csrng_data;
-    bit [entropy_src_pkg::CSRNG_BUS_WIDTH - 1:0]        csrng_data;
-    bit [entropy_src_pkg::FIPS_BUS_WIDTH - 1:0]         fips_data;
+  function bit [FIPS_BUS_WIDTH - 1:0] get_fips_compliance(
+      bit [FIPS_CSRNG_BUS_WIDTH - 1:0] fips_csrng);
+    return fips_csrng[CSRNG_BUS_WIDTH +: FIPS_BUS_WIDTH];
+  endfunction
 
-    // TODO: Add shah3 prediction
+  function bit [CSRNG_BUS_WIDTH - 1:0] get_csrng_seed(bit [FIPS_CSRNG_BUS_WIDTH - 1:0] fips_csrng);
+    return fips_csrng[0 +: CSRNG_BUS_WIDTH];
+  endfunction
+
+  function bit [FIPS_CSRNG_BUS_WIDTH - 1:0] predict_fips_csrng(
+      bit [RNG_BUS_WIDTH - 1:0] data_q[$]);
+    bit [FIPS_CSRNG_BUS_WIDTH - 1:0] fips_csrng_data;
+    bit [CSRNG_BUS_WIDTH - 1:0]      csrng_data;
+    bit [FIPS_BUS_WIDTH - 1:0]       fips_data;
+
+    // TODO: Add SHA3 prediction
     if (cfg.type_bypass) begin
       fips_data = '0;
+    end else begin
+      // TODO: support Boot mode entropy
+      // Will require some changes from #9451
+      fips_data = '1;
     end
+
     for (int i = data_q.size() - 1; i >= 0 ; i--) begin
+      // Since the queue is read from back to front
+      // earlier rng bits occupy the less significant bits of csrng_data
       csrng_data = (csrng_data << 4) + data_q[i];
     end
     fips_csrng_data = {fips_data, csrng_data};
 
-    return csrng_data;
+    return fips_csrng_data;
   endfunction
 
   task collect_entropy();
-    bit [15:0]   window_size;
-    bit [entropy_src_pkg::RNG_BUS_WIDTH-1:0]   rng_data, rng_data_q[$];
+    bit [15:0]              window_size;
+    bit [RNG_BUS_WIDTH - 1:0] rng_data, rng_data_q[$];
+    bit                     first_call;
+    int                     rng_frames_per_window;
+
+    first_call = 1'b1;
 
     // TODO: Read window size from register
-    if (cfg.type_bypass)
-      window_size = entropy_src_pkg::CSRNG_BUS_WIDTH;
+    if (cfg.type_bypass || first_call)
+      window_size = CSRNG_BUS_WIDTH;
     else
       window_size = 2048;
 
+    // TODO: RNG bit-select
+    rng_frames_per_window = window_size/RNG_BUS_WIDTH;
+
     forever begin
       if (cfg.rng_bit_enable == prim_mubi_pkg::MuBi4True) begin
-        for (int i = 0; i < entropy_src_pkg::RNG_BUS_WIDTH; i++) begin
+        for (int i = 0; i < RNG_BUS_WIDTH; i++) begin
           rng_fifo.get(rng_item);
           rng_data[i] = rng_item.h_data[cfg.rng_bit_sel];
         end
@@ -189,22 +222,39 @@
         rng_data = rng_item.h_data;
       end
       rng_data_q.push_back(rng_data);
-      if (rng_data_q.size() == entropy_src_pkg::CSRNG_BUS_WIDTH/entropy_src_pkg::RNG_BUS_WIDTH) begin
-        fips_csrng_q.push_back(predict_fips_csrng(rng_data_q[0:entropy_src_pkg::CSRNG_BUS_WIDTH-1]));
-        for (int i = 0; i < entropy_src_pkg::CSRNG_BUS_WIDTH/entropy_src_pkg::RNG_BUS_WIDTH; i++) begin
-          rng_data_q.delete(0);
+
+      if (rng_data_q.size() == rng_frames_per_window) begin
+        bit [FIPS_CSRNG_BUS_WIDTH - 1:0] fips_csrng;
+        fips_csrng = predict_fips_csrng(rng_data_q);
+        if (cfg.route_software == prim_mubi_pkg::MuBi4True) begin
+          bit [CSRNG_BUS_WIDTH - 1:0] csrng_seed = get_csrng_seed(fips_csrng);
+          for (int i = 0; i < CSRNG_BUS_WIDTH/TL_DW; i++) begin
+            bit [TL_DW - 1:0] entropy_slice = csrng_seed[i*TL_DW +: TL_DW];
+            entropy_data_q.push_back(entropy_slice);
+          end
+        end else if (cfg.route_software == prim_mubi_pkg::MuBi4False) begin
+          fips_csrng_q.push_back(fips_csrng);
+        end else begin
+          // TODO: invalid MuBi value for route_software: What where does data go?
+        end
+        for (int i = 0; i < rng_frames_per_window; i++) begin
+          rng_data_q.delete();
         end
       end
+      first_call = 1'b0;
     end
   endtask
 
   virtual task process_csrng();
-    push_pull_item#(.HostDataWidth(entropy_src_pkg::FIPS_CSRNG_BUS_WIDTH))  item;
-    bit [entropy_src_pkg::FIPS_CSRNG_BUS_WIDTH - 1:0]   fips_csrng_data;
+    push_pull_item#(.HostDataWidth(FIPS_CSRNG_BUS_WIDTH))  item;
+    bit [FIPS_CSRNG_BUS_WIDTH - 1:0]   fips_csrng_data;
+
+   `uvm_info(`gfn, "task \"process_csrng\" starting\n", UVM_FULL)
 
     forever begin
       csrng_fifo.get(item);
       fips_csrng_data = item.d_data;
+      `uvm_info(`gfn, "process_csrng: new item: %096h\n", UVM_MEDIUM)
       `DV_CHECK_EQ_FATAL(fips_csrng_data, fips_csrng_q[0])
       fips_csrng_q.pop_front();
     end
diff --git a/hw/ip/entropy_src/dv/env/seq_lib/entropy_src_smoke_vseq.sv b/hw/ip/entropy_src/dv/env/seq_lib/entropy_src_smoke_vseq.sv
index 5c24eee..1f37e9d 100644
--- a/hw/ip/entropy_src/dv/env/seq_lib/entropy_src_smoke_vseq.sv
+++ b/hw/ip/entropy_src/dv/env/seq_lib/entropy_src_smoke_vseq.sv
@@ -28,9 +28,9 @@
     csr_spinwait(.ptr(ral.intr_state.es_entropy_valid), .exp_data(1'b1));
 
     // Read and check entropy
-    for (int i = 0; i < entropy_src_pkg::CSRNG_BUS_WIDTH/TL_DW/2; i++) begin
-      csr_rd_check(.ptr(ral.entropy_data), .compare_value(INCR_ENTROPY_LO));
-      csr_rd_check(.ptr(ral.entropy_data), .compare_value(INCR_ENTROPY_HI));
+    for (int i = 0; i < entropy_src_pkg::CSRNG_BUS_WIDTH/TL_DW; i++) begin
+      bit [TL_DW-1:0] entropy_tlul;
+      csr_rd(.ptr(ral.entropy_data), .value(entropy_tlul));
     end
 
     // Ensure entropy_valid interrupt bit set
diff --git a/hw/ip/entropy_src/dv/tests/entropy_src_smoke_test.sv b/hw/ip/entropy_src/dv/tests/entropy_src_smoke_test.sv
index 341beda..9fe8c16 100644
--- a/hw/ip/entropy_src/dv/tests/entropy_src_smoke_test.sv
+++ b/hw/ip/entropy_src/dv/tests/entropy_src_smoke_test.sv
@@ -10,8 +10,7 @@
   function void configure_env();
     super.configure_env();
 
-    // TODO: Enable scoreboard
-    cfg.en_scb                      = 0;
+    cfg.en_scb                      = 1;
     cfg.fips_window_size            = 2048;
     cfg.bypass_window_size          = 384;
     cfg.boot_mode_retry_limit       = 10;