[dv/kmac] initial covergroup implementation

this PR adds the initial implementation of covergroups to KMAC.

Signed-off-by: Udi Jonnalagadda <udij@google.com>
diff --git a/hw/ip/kmac/dv/env/kmac_env_cov.sv b/hw/ip/kmac/dv/env/kmac_env_cov.sv
index bebab8d..e56da96 100644
--- a/hw/ip/kmac/dv/env/kmac_env_cov.sv
+++ b/hw/ip/kmac/dv/env/kmac_env_cov.sv
@@ -8,6 +8,185 @@
  * Covergroups may also be wrapped inside helper classes if needed.
  */
 
+// Covers various configuration combinations for the masked version of KMAC.
+//
+// Declare this outside of `kmac_env_cov` so that we can conditionally instantiate this in the
+// `build_phase` depending on a value in the env_cfg object.
+
+// macro for the common KMAC configuration fields
+`define COMMON_CFG_CGS \
+    kmac_en:      coverpoint kmac; \
+    xof_en:       coverpoint xof; \
+    strength:     coverpoint kstrength; \
+    mode:         coverpoint kmode; \
+    key_len:      coverpoint key; \
+    msg_endian:   coverpoint msg_endianness; \
+    state_endian: coverpoint state_endianness; \
+    sideload:     coverpoint en_sideload;
+
+// creates the cross bins for all XOF functions
+`define XOF_CROSS_CG(strength_cg, valid_mode_expr) \
+      bins valid = ``valid_mode_expr`` && binsof(``strength_cg``) intersect {sha3_pkg::L128, sha3_pkg::L256}; \
+      ignore_bins invalid_mode = !``valid_mode_expr``; \
+      ignore_bins invalid_strength = !binsof(``strength_cg``) intersect {sha3_pkg::L128, sha3_pkg::L256};
+
+// creates the cross bins for SHA3 functions
+`define SHA3_CROSS_CG(mode_cg, strength_cg) \
+    bins valid = binsof(``mode_cg``) intersect {sha3_pkg::Sha3}; \
+    ignore_bins invalid_mode = !binsof(``mode_cg``) intersect {sha3_pkg::Sha3}; \
+    ignore_bins invalid_strength = binsof(``strength_cg``) intersect {sha3_pkg::L128};
+
+// creates a coverpoint to cover different TLUL access granularities
+`define MASK_CP(name, mask) \
+    ``name``: coverpoint ``mask`` { \
+      bins byte_access        = {'b0001, 'b0010, 'b0100, 'b1000}; \
+      bins halfword_access    = {'b0011, 'b0110, 'b1100}; \
+      bins triple_byte_access = {'b0111, 'b1110}; \
+      bins word_access        = {'b1111}; \
+    }
+
+
+covergroup config_masked_cg with function sample(bit kmac, bit xof,
+                                                 sha3_pkg::keccak_strength_e kstrength,
+                                                 sha3_pkg::sha3_mode_e kmode,
+                                                 kmac_pkg::key_len_e key,
+                                                 bit msg_endianness,
+                                                 bit state_endianness,
+                                                 bit en_sideload,
+                                                 kmac_pkg::entropy_mode_e entr_mode,
+                                                 bit fast_entropy);
+  `COMMON_CFG_CGS
+
+  entropy_mode: coverpoint entr_mode;
+
+  entropy_fast_process: coverpoint fast_entropy;
+
+  // cross the various configuration settings
+
+  kmac_cross: cross kmac_en, xof_en, strength, key_len, msg_endian,
+                    state_endian, entropy_mode, entropy_fast_process {
+    `XOF_CROSS_CG(strength, binsof(kmac_en) intersect {1})
+  }
+
+  cshake_cross: cross mode, strength, msg_endian, state_endian,
+                               entropy_mode, entropy_fast_process {
+    `XOF_CROSS_CG(strength, binsof(mode) intersect {sha3_pkg::CShake})
+  }
+
+  shake_cross: cross mode, strength, msg_endian, state_endian,
+                              entropy_mode, entropy_fast_process {
+    `XOF_CROSS_CG(strength, binsof(mode) intersect {sha3_pkg::Shake})
+  }
+
+  sha3_cross: cross mode, strength, msg_endian, state_endian,
+                    entropy_mode, entropy_fast_process {
+    `SHA3_CROSS_CG(mode, strength)
+  }
+endgroup
+
+
+// Covers various configuration combinations for the unmasked version of KMAC.
+//
+// Declare this outside of `kmac_env_cov` so that we can conditionally instantiate this in the
+// `build_phase` depending on a value in the env_cfg object.
+covergroup config_unmasked_cg with function sample(bit kmac, bit xof,
+                                                   sha3_pkg::keccak_strength_e kstrength,
+                                                   sha3_pkg::sha3_mode_e kmode,
+                                                   kmac_pkg::key_len_e key,
+                                                   bit msg_endianness,
+                                                   bit state_endianness,
+                                                   bit en_sideload);
+  `COMMON_CFG_CGS
+
+  // cross the various configuration settings
+
+  kmac_cross: cross kmac_en, xof_en, strength, key_len, msg_endian, state_endian {
+    `XOF_CROSS_CG(strength, binsof(kmac_en) intersect {1})
+  }
+
+  cshake_cross: cross mode, strength, msg_endian, state_endian {
+    `XOF_CROSS_CG(strength, binsof(mode) intersect {sha3_pkg::CShake})
+  }
+
+  shake_cross: cross mode, strength, msg_endian, state_endian {
+    `XOF_CROSS_CG(strength, binsof(mode) intersect {sha3_pkg::Shake})
+  }
+
+  sha3_cross: cross mode, strength, msg_endian, state_endian {
+    `SHA3_CROSS_CG(mode, strength)
+  }
+
+endgroup
+
+// Wrapper class for the covergroup for the application interface.
+//
+// We do this so that we can create an array of these covergroups for each app interface
+// present in the testbench environment.
+class app_cg_wrap;
+  // done signal is sent while kecak rounds are running
+  covergroup app_cg(string name) with function sample(bit single_beat,
+                                                      bit [keymgr_pkg::KmacDataIfWidth/8-1:0] strb,
+                                                      bit err,
+                                                      bit is_done,
+                                                      bit in_keccak);
+    option.per_instance = 1;
+    option.name = name;
+
+    single_data_beat: coverpoint single_beat;
+
+    data_strb: coverpoint strb {
+      bins one_byte         = {'b0000_0001};
+      bins two_bytes        = {'b0000_0011};
+      bins three_bytes      = {'b0000_0111};
+      bins four_bytes       = {'b0000_1111};
+      bins five_bytes       = {'b0001_1111};
+      bins six_bytes        = {'b0011_1111};
+      bins seven_bytes      = {'b0111_1111};
+      bins full_data_beat   = {'1};
+      illegal_bins invalid  = default;
+    }
+
+    app_err: coverpoint err;
+
+    done: coverpoint is_done;
+
+    in_keccak_rounds: coverpoint in_keccak;
+
+    partial_data_on_last_beat: cross done, data_strb {
+      bins valid = binsof(done) intersect {1};
+
+      ignore_bins invalid = !binsof(done) intersect {1};
+    }
+
+    done_in_keccak_rounds: cross done, in_keccak_rounds {
+      bins valid = binsof(done) intersect {1};
+
+      ignore_bins invalid = !binsof(done) intersect {1};
+    }
+  endgroup
+
+  function new(string name = "app_cg");
+    app_cg = new(name);
+  endfunction
+
+  function void sample(bit single_beat,
+                       bit [keymgr_pkg::KmacDataIfWidth/8-1:0] strb,
+                       bit err,
+                       bit is_done,
+                       bit in_keccak);
+    app_cg.sample(single_beat, strb, err, is_done, in_keccak);
+  endfunction
+endclass
+
+
+// Covers whether we see an EDN response while keccak rounds are active/inactive.
+// Create this covergroup outside of the class as its instantiation relies on a field in the
+// env.cfg.
+covergroup edn_cg with function sample(bit in_keccak_rounds);
+  edn_in_keccak: coverpoint in_keccak_rounds;
+endgroup
+
+
 class kmac_env_cov extends cip_base_env_cov #(.CFG_T(kmac_env_cfg));
   `uvm_component_utils(kmac_env_cov)
 
@@ -15,11 +194,176 @@
   // kmac_env_cfg: cfg
 
   // covergroups
-  // [add covergroups here]
+
+  config_masked_cg config_masked_cg;
+  config_unmasked_cg config_unmasked_cg;
+
+  edn_cg edn_cg;
+
+  app_cg_wrap app_cg_wrappers[kmac_pkg::NumAppIntf];
+
+  covergroup msg_len_cg with function sample(int len);
+    msg_len: coverpoint len {
+      bins len_0                    = {0};
+      bins len_1                    = {1};
+      bins len_keccak_block_sizes[] = {72, 104, 136, 144, 168};
+      bins len_0_256                = {[0 : 256]};
+      bins len_257_512              = {[257 : 512]};
+      bins len_513_768              = {[513 : 768]};
+      bins len_769_1024             = {[769 : 1024]};
+      bins len_1025_2500            = {[1025 : 2500]};
+      bins len_2501_5000            = {[2501 : 5000]};
+      bins len_5001_7500            = {[5001 : 7500]};
+      bins len_7501_10000           = {[7501 : 10_000]};
+      bins remainder                = default;
+    }
+  endgroup
+
+  covergroup output_digest_len_cg with function sample(int len);
+    output_digest_len: coverpoint len {
+      bins len_1                            = {1};
+      bins len_2_63                         = {[2 : 63]};
+      bins len_datapath_width               = {64};
+      bins len_keccak_block_sizes[]         = {72, 104, 136, 144, 168};
+      bins len_min_for_xof_require_squeeze  = {137, 169};
+      bins len_65_200                       = {[65  : 200]};
+      bins len_201_400                      = {[201 : 400]};
+      bins len_401_600                      = {[401 : 600]};
+      bins len_601_800                      = {[601 : 800]};
+      bins len_801_1000                     = {[801 : 1_000]};
+      bins remainder                        = default;
+    }
+  endgroup
+
+  covergroup prefix_range_cg with function sample(byte b);
+    prefix_range: coverpoint b {
+      bins space              = {32};
+      bins capital_letters    = {[65 : 90]};
+      bins lowercase_letters  = {[97 : 122]};
+      bins rest               = default;
+    }
+  endgroup
+
+  covergroup msgfifo_write_mask_cg with function sample(bit [TL_DBW-1:0] mask);
+    `MASK_CP(msgfifo_write_mask, mask)
+  endgroup
+
+  covergroup msgfifo_level_cg with function sample(bit fifo_empty, bit fifo_full, bit [4:0] fifo_depth,
+                                                   sha3_pkg::sha3_mode_e mode, bit kmac_en);
+    kmac_mode: coverpoint kmac_en;
+    hash_mode: coverpoint mode {
+      bins sha3   = {sha3_pkg::Sha3};
+      bins shake  = {sha3_pkg::Shake};
+      bins cshake = {sha3_pkg::CShake};
+    }
+    msgfifo_empty:  coverpoint fifo_empty;
+    msgfifo_full:   coverpoint fifo_full;
+    msgfifo_depth:  coverpoint fifo_depth {
+      bins depth[] = {[0 : KMAC_FIFO_DEPTH]};
+      bins invalid = default;
+    }
+  endgroup
+
+  covergroup sha3_status_cg with function sample(bit sha3_idle, bit sha3_absorb, bit sha3_squeeze);
+    idle:     coverpoint sha3_idle;
+    absorb:   coverpoint sha3_absorb;
+    squeeze:  coverpoint sha3_squeeze;
+  endgroup
+
+  covergroup state_read_mask_cg with function sample(bit [TL_DBW-1:0] mask, bit share_num);
+    share: coverpoint share_num;
+    `MASK_CP(state_read_mask, mask)
+    state_mask_share_cross: cross share, state_read_mask;
+  endgroup
+
+  covergroup cmd_process_cg with function sample(bit in_keccak_rounds, bit keccak_complete_cycle);
+    in_keccak: coverpoint in_keccak_rounds;
+
+    in_keccak_complete_cycle: coverpoint keccak_complete_cycle;
+  endgroup
+
+  covergroup sideload_cg with function sample(bit en_sideload, bit in_kmac, bit app_keymgr);
+    sideload:       coverpoint en_sideload;
+    kmac_mode:      coverpoint in_kmac;
+    in_app_keymgr:  coverpoint app_keymgr;
+
+    sideload_cross: cross sideload, kmac_mode, in_app_keymgr {
+      bins sw_kmac_valid_sideload   = binsof(sideload) intersect {1} && binsof(kmac_mode);
+      bins sw_kmac_invalid_sideload = binsof(sideload) intersect {1} && binsof(kmac_mode);
+      bins app_valid_sideload       = binsof(sideload) intersect {1} && binsof(in_app_keymgr);
+      bins app_invalid_sideload     = binsof(sideload) intersect {1} && binsof(in_app_keymgr);
+
+      ignore_bins invalid = !binsof(sideload) intersect {1};
+    }
+  endgroup
+
+  covergroup app_cg with function sample();
+
+  endgroup
+
+  covergroup error_cg with function sample(kmac_pkg::err_code_e kmac_err,
+                                           sha3_pkg::err_code_e sha3_err);
+    // placeholder comment
+    kmac_err_code: coverpoint kmac_err {
+      bins err_none = {kmac_pkg::ErrNone};
+      bins err_key_not_valid = {kmac_pkg::ErrKeyNotValid};
+      bins err_sw_pushed_msg_fifo = {kmac_pkg::ErrSwPushedMsgFifo};
+      bins err_sw_pushed_wrong_cmd = {kmac_pkg::ErrSwPushedWrongCmd};
+      bins err_wait_timer_expired = {kmac_pkg::ErrWaitTimerExpired};
+      bins err_incorrect_entropy_mode = {kmac_pkg::ErrIncorrectEntropyMode};
+
+      bins invalid = default;
+    }
+
+    sha3_err_code: coverpoint sha3_err {
+      bins err_none            = {sha3_pkg::ErrNone};
+      bins err_sha3_sw_control = {sha3_pkg::ErrSha3SwControl};
+
+      bins invalid = default;
+    }
+  endgroup
+
+  function sample_cfg(bit kmac,
+                      bit xof,
+                      sha3_pkg::keccak_strength_e kstrength,
+                      sha3_pkg::sha3_mode_e kmode,
+                      kmac_pkg::key_len_e key_len,
+                      bit msg_endianness,
+                      bit state_endianness,
+                      bit en_sideload,
+                      kmac_pkg::entropy_mode_e entropy_mode,
+                      bit fast_entropy);
+
+    if (cfg.enable_masking) begin
+      config_masked_cg.sample(kmac, xof, kstrength, kmode, key_len, msg_endianness,
+                              state_endianness, en_sideload, entropy_mode,
+                              fast_entropy);
+    end else begin
+      config_unmasked_cg.sample(kmac, xof, kstrength, kmode, key_len,
+                                msg_endianness, state_endianness,
+                                en_sideload);
+    end
+  endfunction
+
 
   function new(string name, uvm_component parent);
+    kmac_app_e app_name = app_name.first;
     super.new(name, parent);
     // [instantiate covergroups here]
+    msg_len_cg = new();
+    output_digest_len_cg = new();
+    prefix_range_cg = new();
+    msgfifo_write_mask_cg = new();
+    msgfifo_level_cg = new();
+    sha3_status_cg = new();
+    state_read_mask_cg = new();
+    cmd_process_cg = new();
+    sideload_cg = new();
+    error_cg = new(); // TODO sample this in scb
+    do begin
+      app_cg_wrappers[app_name] = new({app_name.name(), "_cg"});
+      app_name = app_name.next;
+    end while (app_name != app_name.first);
   endfunction : new
 
   virtual function void build_phase(uvm_phase phase);
@@ -27,6 +371,17 @@
     // [or instantiate covergroups here]
     // Please instantiate sticky_intr_cov array of objects for all interrupts that are sticky
     // See cip_base_env_cov for details
+    if (cfg.enable_masking) begin
+      config_masked_cg = new();
+      edn_cg = new();
+    end else begin
+      config_unmasked_cg = new();
+    end
   endfunction
 
 endclass
+
+`undef MASK_CP
+`undef SHA3_CROSS_CG
+`undef XOF_CROSS_CG
+`undef COMMON_CFG_CGS
diff --git a/hw/ip/kmac/dv/env/kmac_scoreboard.sv b/hw/ip/kmac/dv/env/kmac_scoreboard.sv
index 1b90529..5fa4db5 100644
--- a/hw/ip/kmac/dv/env/kmac_scoreboard.sv
+++ b/hw/ip/kmac/dv/env/kmac_scoreboard.sv
@@ -24,6 +24,9 @@
   // Represents the number of blocks that have been filled in sha3pad
   int num_blocks_filled = 0;
 
+  // used solely for coverage sampling, indicates that keccak rounds are currently running
+  bit in_keccak_rounds = 0;
+
   // Whenever the keccak rounds are running, the `complete` signal is raised at the end
   // for a single cycle to signal to sha3 control logic that the keccak engine is completed.
   //
@@ -192,6 +195,7 @@
       process_sha3_idle();
       process_sha3_absorb();
       process_sha3_squeeze();
+      if (cfg.en_cov) sample_sha3_status();
       process_initial_digest();
       process_manual_digest_squeeze();
       process_intr_kmac_done();
@@ -303,6 +307,25 @@
             end else if (`KMAC_APP_VALID_TRANS(AppRom)) begin
               app_mode = AppRom;
             end
+
+            // sample sideload-related coverage
+            if (cfg.en_cov) begin
+              // Note that all arguments to the covergroup sample() function are the same,
+              // this is due to the nature of the arguments that this function takes:
+              //
+              // - `en_sideload`: this bit indicates whether sideloading mode is active
+              // - `in_kmac`    : this bit indicates whether we are operating in KMAC mode
+              // - `app_keymgr` : this bit indicates whether we are using the Keymgr-specific App
+              //                  interface
+              //
+              // Checking whether the current application mode is the AppKeymgr mode gives us
+              // sufficient information for all three of these arguments due to the nature of this
+              // particular interface.
+              cov.sideload_cg.sample(app_mode == AppKeymgr,
+                                     app_mode == AppKeymgr,
+                                     app_mode == AppKeymgr);
+            end
+
             @(posedge sha3_idle);
           end
           ,
@@ -311,6 +334,7 @@
       if (cfg.under_reset) begin
         @(negedge cfg.under_reset);
       end
+
     end
   endtask
 
@@ -333,6 +357,16 @@
                         UVM_HIGH)
               {kmac_app_block_data, kmac_app_block_strb, kmac_app_last} = kmac_app_block_item.h_data;
               kmac_app_block_strb_size = $countones(kmac_app_block_strb);
+
+              // sample coverage
+              if (cfg.en_cov) begin
+                cov.app_cg_wrappers[app_mode].sample(0,
+                                                    kmac_app_block_strb,
+                                                    0,
+                                                    kmac_app_last,
+                                                    in_keccak_rounds);
+              end
+
               got_data_from_kmac_app = 1;
               while (kmac_app_block_strb > 0) begin
                 if (kmac_app_block_strb[0]) begin
@@ -382,6 +416,17 @@
                                         kmac_app_rsp.sprint()),
                               UVM_HIGH)
 
+                    // sample coverage
+                    if (cfg.en_cov) begin
+                      cov.app_cg_wrappers[app_mode].sample(
+                        kmac_app_rsp.byte_data_q.size() <= keymgr_pkg::KmacDataIfWidth/8,
+                        '0,
+                        kmac_app_rsp.rsp_error,
+                        1,
+                        0
+                      );
+                    end
+
                     // safety check that things are working properly and
                     // no random KMAC_APP operations are seen
                     `DV_CHECK_FATAL(in_kmac_app == 1,
@@ -514,6 +559,22 @@
     end
   endtask
 
+  // This is a simple task that just polls for any changes in the SHA3 status bits and samples them
+  virtual task sample_sha3_status();
+    forever begin
+      @(negedge cfg.under_reset);
+      `DV_SPINWAIT_EXIT(
+          forever begin
+            @(sha3_idle or sha3_absorb or sha3_squeeze);
+            #0;
+            cov.sha3_status_cg.sample(sha3_idle, sha3_absorb, sha3_squeeze);
+          end
+          ,
+          @(posedge cfg.under_reset);
+      )
+    end
+  endtask
+
   // This task handles asserting the `kmac_done` interrupt bit
   virtual task process_intr_kmac_done();
     @(negedge cfg.under_reset);
@@ -686,6 +747,8 @@
     // processing is enabled).
     bit full_entropy_expansion = 0;
 
+    in_keccak_rounds = 1;
+
     // insert zero delay to ensure all entropy-related updates have settled
     //
     // this also helps catch an edge case where EDN returns valid entropy
@@ -790,6 +853,8 @@
     cfg.clk_rst_vif.wait_clks(1);
     keccak_complete_cycle = 0;
 
+    in_keccak_rounds = 0;
+
     `uvm_info(`gfn, "finished waiting for keccak", UVM_HIGH)
   endtask
 
@@ -1569,6 +1634,12 @@
               fifo_empty = (fifo_depth == 0);
               fifo_full  = fifo_depth == KMAC_FIFO_DEPTH;
 
+              // sample coverage on the fifo status
+              if (cfg.en_cov) begin
+                cov.msgfifo_level_cg.sample(fifo_empty, fifo_full, fifo_depth,
+                                            hash_mode, kmac_en);
+              end
+
               `uvm_info(`gfn, $sformatf("fifo_depth: %0d", fifo_depth), UVM_HIGH)
               `uvm_info(`gfn, $sformatf("fifo_empty: %0d", fifo_empty), UVM_HIGH)
               `uvm_info(`gfn, $sformatf("fifo_full: %0d", fifo_full), UVM_HIGH)
@@ -1739,6 +1810,11 @@
 
           entropy_mode = entropy_mode_e'(item.a_data[KmacEntropyModeMSB:KmacEntropyModeLSB]);
 
+          // sample sideload-related coverage
+          if (cfg.en_cov) begin
+            cov.sideload_cg.sample(item.a_data[KmacSideload], kmac_en, 0);
+          end
+
           if (entropy_mode == EntropyModeEdn &&
               item.a_data[KmacEntropyReady] &&
               first_op_after_rst) begin
@@ -1751,8 +1827,6 @@
             in_edn_fetch = 1;
             `uvm_info(`gfn, "raised in_edn_fetch after reset", UVM_HIGH)
           end
-
-          // TODO - sample coverage
         end
       end
       "cmd": begin
@@ -1769,6 +1843,10 @@
               // kmac will now compute the digest
               kmac_cmd = CmdProcess;
 
+              if (cfg.en_cov) begin
+                cov.cmd_process_cg.sample(in_keccak_rounds, keccak_complete_cycle);
+              end
+
               // Raise this bit after a small delay to handle an edge case where
               // fifo_wr_ptr and fifo_rd_ptr both increment on same cycle that CmdProcess
               // is latched by internal scoreboard logic
@@ -1784,6 +1862,11 @@
             CmdDone: begin
               kmac_cmd = CmdDone;
 
+              // sample coverage of message length
+              if (cfg.en_cov) begin
+                cov.msg_len_cg.sample(msg.size());
+              end
+
               // Calculate the digest using DPI and check for correctness
               check_digest();
 
@@ -1912,6 +1995,11 @@
           `uvm_info(`gfn, $sformatf("item.a_mask: 0b%0b", item.a_mask), UVM_HIGH)
           `uvm_info(`gfn, $sformatf("full_data: %0p", full_data), UVM_HIGH)
 
+          // sample coverage on the write mask
+          if (cfg.en_cov) begin
+            cov.msgfifo_write_mask_cg.sample(item.a_mask);
+          end
+
           // All writes in big-endian order will be full-word,
           // so we can generalize this to a for-loop that reverses the byte order of each word.
           // This way we can also preserve little-endian ordering.
@@ -1947,6 +2035,11 @@
         state_mask = item.a_mask;
         digest_word = item.d_data;
 
+        // sample coverage on state read mask
+        if (cfg.en_cov) begin
+          cov.state_read_mask_cg.sample(state_mask, share1_access);
+        end
+
         `uvm_info(`gfn, $sformatf("state read mask: 0b%0b", state_mask), UVM_HIGH)
         `uvm_info(`gfn, $sformatf("digest_word: 0x%0x", digest_word), UVM_HIGH)
 
@@ -2127,6 +2220,20 @@
           $sformatf("Calculated output length doesn't match actual output length!"))
     end
 
+    if (cfg.en_cov) begin
+      // sample configuration coverage, as only now do we know which KMAC variant is used
+      // (xof/non-xof)
+      cov.sample_cfg(kmac_en, xof_en, strength, hash_mode, key_len,
+                     `gmv(ral.cfg.msg_endianness), `gmv(ral.cfg.state_endianness),
+                     `gmv(ral.cfg.sideload), entropy_mode, entropy_fast_process);
+
+      // sample coverage on the digest length
+      if (cfg.en_cov) begin
+        cov.output_digest_len_cg.sample(output_len_bytes);
+      end
+    end
+
+
     `uvm_info(`gfn, $sformatf("output_len_bytes: %0d", output_len_bytes), UVM_HIGH)
     `uvm_info(`gfn, $sformatf("xof_en: %0d", xof_en), UVM_HIGH)
 
@@ -2376,6 +2483,13 @@
       prefix_bytes = {<< byte {prefix_bytes}};
     end
 
+    // sample coverage
+    if (cfg.en_cov) begin
+      foreach (prefix_bytes[i]) begin
+        cov.prefix_range_cg.sample(byte'(prefix_bytes[i]));
+      end
+    end
+
     `uvm_info(`gfn, $sformatf("prefix: %0p", prefix), UVM_HIGH)
     `uvm_info(`gfn, $sformatf("prefix_bytes: %0p", prefix_bytes), UVM_HIGH)