[dv/hmac] HMAC FIFOEmpty DV

This assumes tx_empty will trigger only during reg_hash_start and
reg_hash_process

Co-authored-by: Cindy Chen <chencindy@google.com>

Signed-off-by: Eunchan Kim <eunchan@opentitan.org>
Signed-off-by: Cindy Chen <chencindy@google.com>
diff --git a/hw/ip/hmac/dv/env/hmac_env_pkg.sv b/hw/ip/hmac/dv/env/hmac_env_pkg.sv
index 0896b86..55c34f2 100644
--- a/hw/ip/hmac/dv/env/hmac_env_pkg.sv
+++ b/hw/ip/hmac/dv/env/hmac_env_pkg.sv
@@ -38,7 +38,7 @@
 
   typedef enum {
     HmacDone,
-    HmacMsgFifoFull,
+    HmacMsgFifoEmpty,
     HmacErr
   } hmac_intr_e;
 
diff --git a/hw/ip/hmac/dv/env/hmac_scoreboard.sv b/hw/ip/hmac/dv/env/hmac_scoreboard.sv
index e626083..54dc5f6 100644
--- a/hw/ip/hmac/dv/env/hmac_scoreboard.sv
+++ b/hw/ip/hmac/dv/env/hmac_scoreboard.sv
@@ -8,7 +8,7 @@
   `uvm_component_utils(hmac_scoreboard)
   `uvm_component_new
 
-  bit             sha_en, fifo_full;
+  bit             sha_en, fifo_full, fifo_empty;
   bit [7:0]       msg_q[$];
   bit             hmac_start, hmac_process;
   int             hmac_wr_cnt, hmac_rd_cnt;
@@ -22,7 +22,7 @@
   task run_phase(uvm_phase phase);
     super.run_phase(phase);
     fork
-      hmac_process_fifo_full();
+      hmac_process_fifo_status();
       hmac_process_fifo_wr();
       hmac_process_fifo_rd();
     join_none
@@ -95,6 +95,9 @@
             void'(ral.intr_state.predict(.value(intr_state_exp), .kind(UVM_PREDICT_DIRECT)));
             intr_test = item.a_data;
           end
+          "intr_state": begin
+            if (item.a_data[HmacMsgFifoEmpty]) fifo_empty = 0;
+          end
           "cfg": begin
             if (hmac_start) return; // won't update configs if hash start
             if (cfg.en_cov) cov.cfg_cg.sample(item.a_data);
@@ -141,6 +144,11 @@
                                              (hmac_fifo_full  << HmacStaMsgFifoFull) |
                                              (hmac_fifo_depth << HmacStaMsgFifoDepth);
           void'(ral.status.predict(.value(hmac_status_data), .kind(UVM_PREDICT_READ)));
+        end else if (csr_name == "intr_state") begin
+          if (fifo_empty && ral.intr_state.fifo_empty.get_mirrored_value() != 1) begin
+            void'(ral.intr_state.fifo_empty.predict(.value(1), .kind(UVM_PREDICT_READ)));
+            `uvm_info(`gfn, "predict again", UVM_HIGH)
+          end
         end
       return;
     end
@@ -223,6 +231,7 @@
     hmac_rd_cnt = 0;
     intr_test   = 0;
     key         = '{default:0};
+    fifo_empty  = 0;
   endfunction
 
   // clear variables after expected digest is calculated
@@ -265,15 +274,19 @@
     join
   endtask
 
-  virtual task hmac_process_fifo_full();
+  virtual task hmac_process_fifo_status();
     forever @(hmac_wr_cnt, hmac_rd_cnt) begin
       // when hmac_wr_cnt and hmac_rd_cnt update at the same time, wait 1ps to guarantee
       // get both update
       #1ps;
-      if ((hmac_wr_cnt - hmac_rd_cnt) == HMAC_MSG_FIFO_DEPTH) begin
-        void'(ral.intr_state.fifo_full.predict(.value(1)));
-        `uvm_info(`gfn, "predict interrupt fifo full is set", UVM_HIGH)
-        fifo_full = 1;
+      if ((hmac_wr_cnt == hmac_rd_cnt) && (hmac_wr_cnt != 0)) begin
+        // after the rd wr pointers are equal, wait one clk cycle for the fifo_empty register
+        // update, wait another clk cycle for the register value to reflect
+        if (!fifo_empty) begin
+          cfg.clk_rst_vif.wait_clks(2);
+          `uvm_info(`gfn, "predict interrupt fifo empty is set", UVM_HIGH)
+          fifo_empty = 1;
+        end
       end
     end
   endtask
@@ -347,7 +360,7 @@
 
   function void check_phase(uvm_phase phase);
     super.check_phase(phase);
-    `DV_CHECK_EQ(cfg.intr_vif.pins[HmacMsgFifoFull], 1'b0)
+    `DV_CHECK_EQ(cfg.intr_vif.pins[HmacMsgFifoEmpty], 1'b0)
     `DV_CHECK_EQ(cfg.intr_vif.pins[HmacDone], 1'b0)
     `DV_CHECK_EQ(cfg.intr_vif.pins[HmacErr], 1'b0)
   endfunction
diff --git a/hw/ip/hmac/dv/env/seq_lib/hmac_base_vseq.sv b/hw/ip/hmac/dv/env/seq_lib/hmac_base_vseq.sv
index 2567e3c..51a743a 100644
--- a/hw/ip/hmac/dv/env/seq_lib/hmac_base_vseq.sv
+++ b/hw/ip/hmac/dv/env/seq_lib/hmac_base_vseq.sv
@@ -52,7 +52,7 @@
                          bit hmac_en = 1'b1,
                          bit endian_swap = 1'b1,
                          bit digest_swap = 1'b1,
-                         bit intr_fifo_full_en = 1'b1,
+                         bit intr_fifo_empty_en = 1'b1,
                          bit intr_hmac_done_en = 1'b1,
                          bit intr_hmac_err_en  = 1'b1);
     bit [TL_DW-1:0] interrupts;
@@ -65,7 +65,7 @@
 
     // enable interrupts
     interrupts = (intr_hmac_err_en << HmacErr) | (intr_hmac_done_en << HmacDone) |
-                 (intr_fifo_full_en << HmacMsgFifoFull);
+                 (intr_fifo_empty_en << HmacMsgFifoEmpty);
     cfg_interrupts(.interrupts(interrupts), .enable(1'b1));
   endtask
 
@@ -192,8 +192,8 @@
                 .blocking($urandom_range(0, 1)));
 
       if (ral.cfg.sha_en.get_mirrored_value()) begin
-        if (!do_back_pressure) check_status_intr_fifo_full();
-        else clear_intr_fifo_full();
+        //if (!do_back_pressure) check_status_intr_fifo_full();
+        //else clear_intr_fifo_full();
         // randomly change key, config regs during msg wr, should trigger error or be discarded
         write_discard_config_and_key($urandom_range(0, 20) == 0, $urandom_range(0, 20) == 0);
       end else begin
@@ -226,7 +226,7 @@
                     .blocking($urandom_range(0, 1)));
         end
         if (ral.cfg.sha_en.get_mirrored_value()) begin
-          clear_intr_fifo_full();
+          //clear_intr_fifo_full();
         end else begin
           check_error_code();
         end
@@ -248,33 +248,33 @@
 
   // read status FIFO FULL and check intr FIFO FULL
   // if intr_fifo_full_enable is disable, check intr_fifo_full_state and clear it
-  virtual task check_status_intr_fifo_full();
-    bit msg_fifo_full;
-    csr_utils_pkg::wait_no_outstanding_access();
-    csr_rd(ral.status.fifo_full, msg_fifo_full);
-    if (ral.intr_enable.fifo_full.get_mirrored_value()) begin
-      check_interrupts(.interrupts((1 << HmacMsgFifoFull)), .check_set(msg_fifo_full));
-    end else begin
-      csr_rd_check(.ptr(ral.intr_state), .compare_value(msg_fifo_full),
-                   .compare_mask(1 << HmacMsgFifoFull));
-      csr_wr(.csr(ral.intr_state), .value(1 << HmacMsgFifoFull));
-    end
-  endtask
+  //virtual task check_status_intr_fifo_full();
+  //  bit msg_fifo_full;
+  //  csr_utils_pkg::wait_no_outstanding_access();
+  //  csr_rd(ral.status.fifo_full, msg_fifo_full);
+  //  if (ral.intr_enable.fifo_full.get_mirrored_value()) begin
+  //    check_interrupts(.interrupts((1 << HmacMsgFifoFull)), .check_set(msg_fifo_full));
+  //  end else begin
+  //    csr_rd_check(.ptr(ral.intr_state), .compare_value(msg_fifo_full),
+  //                 .compare_mask(1 << HmacMsgFifoFull));
+  //    csr_wr(.csr(ral.intr_state), .value(1 << HmacMsgFifoFull));
+  //  end
+  //endtask
 
   // when msg fifo full interrupt is set, this task clears the interrupt
   // checking the correctness of the fifo full interrupt is done in scb
-  virtual task clear_intr_fifo_full();
-    csr_utils_pkg::wait_no_outstanding_access();
-    if (ral.intr_enable.fifo_full.get_mirrored_value()) begin
-      if (cfg.intr_vif.pins[HmacMsgFifoFull] === 1'b1) begin
-        check_interrupts(.interrupts((1 << HmacMsgFifoFull)), .check_set(1'b1));
-      end
-    end else begin
-      bit msg_fifo_full;
-      csr_rd(ral.intr_state.fifo_full, msg_fifo_full);
-      if (msg_fifo_full) csr_wr(.csr(ral.intr_state), .value(msg_fifo_full << HmacMsgFifoFull));
-    end
-  endtask
+  //virtual task clear_intr_fifo_full();
+  //  csr_utils_pkg::wait_no_outstanding_access();
+  //  if (ral.intr_enable.fifo_full.get_mirrored_value()) begin
+  //    if (cfg.intr_vif.pins[HmacMsgFifoFull] === 1'b1) begin
+  //      check_interrupts(.interrupts((1 << HmacMsgFifoFull)), .check_set(1'b1));
+  //    end
+  //  end else begin
+  //    bit msg_fifo_full;
+  //    csr_rd(ral.intr_state.fifo_full, msg_fifo_full);
+  //    if (msg_fifo_full) csr_wr(.csr(ral.intr_state), .value(msg_fifo_full << HmacMsgFifoFull));
+  //  end
+  //endtask
 
   // this task is called when sha_en=0 and sequence set hash_start, or streamed in msg
   // it will check intr_pin, intr_state, and error_code register
diff --git a/hw/ip/hmac/dv/env/seq_lib/hmac_sanity_vseq.sv b/hw/ip/hmac/dv/env/seq_lib/hmac_sanity_vseq.sv
index 7441614..0f28d33 100644
--- a/hw/ip/hmac/dv/env/seq_lib/hmac_sanity_vseq.sv
+++ b/hw/ip/hmac/dv/env/seq_lib/hmac_sanity_vseq.sv
@@ -14,7 +14,7 @@
   rand bit        sha_en;
   rand bit        endian_swap;
   rand bit        digest_swap;
-  rand bit        intr_fifo_full_en;
+  rand bit        intr_fifo_empty_en;
   rand bit        intr_hmac_done_en;
   rand bit        intr_hmac_err_en;
   rand bit [31:0] key[8];
@@ -42,7 +42,7 @@
   }
 
   constraint intr_enable_c {
-    intr_fifo_full_en dist {1'b1 := 8, 1'b0 := 2};
+    intr_fifo_empty_en dist {1'b1 := 8, 1'b0 := 2};
     intr_hmac_done_en dist {1'b1 := 8, 1'b0 := 2};
     intr_hmac_err_en  dist {1'b1 := 8, 1'b0 := 2};
   }
@@ -59,12 +59,12 @@
       `DV_CHECK_RANDOMIZE_FATAL(this)
       `uvm_info(`gfn, $sformatf("starting seq %0d/%0d, message size %0d, hmac=%0d, sha=%0d",
                                 i, num_trans, msg.size(), hmac_en, sha_en), UVM_LOW)
-      `uvm_info(`gfn, $sformatf("intr_fifo_full/hmac_done/hmac_err_en=%b, endian/digest_swap=%b",
-                                {intr_fifo_full_en, intr_hmac_done_en, intr_hmac_err_en},
+      `uvm_info(`gfn, $sformatf("intr_fifo_empty/hmac_done/hmac_err_en=%b, endian/digest_swap=%b",
+                                {intr_fifo_empty_en, intr_hmac_done_en, intr_hmac_err_en},
                                 {endian_swap, digest_swap}), UVM_HIGH)
       // initialize hmac configs
       hmac_init(.sha_en(sha_en), .hmac_en(hmac_en), .endian_swap(endian_swap),
-                .digest_swap(digest_swap), .intr_fifo_full_en(intr_fifo_full_en),
+                .digest_swap(digest_swap), .intr_fifo_empty_en(intr_fifo_empty_en),
                 .intr_hmac_done_en(intr_hmac_done_en), .intr_hmac_err_en(intr_hmac_err_en));
 
       // can randomly read previous digest
@@ -77,6 +77,7 @@
       if (i != 1 && $urandom_range(0, 1)) rd_digest();
 
       if (sha_en || $urandom_range(0, 1)) begin
+        bit [TL_DW-1:0] intr_state_val;
         // start stream in msg
         if (do_hash_start) trigger_hash();
 
@@ -101,22 +102,21 @@
         // msg stream in finished, start hash
         if (do_hash_start) trigger_process();
 
-        // fifo_full intr can be triggered at the latest two cycle after process
-        // example: current fifo_depth=(14 words + 2 bytes), then wr last 4 bytes, design will
-        // process the 15th word then trigger intr_fifo_full
-        cfg.clk_rst_vif.wait_clks(2);
-        clear_intr_fifo_full();
+        // TODO: temp solution as after hmac_process, scb hmac_empty has one cycle mismatch with
+        // RTL
+        if (hmac_en) cfg.clk_rst_vif.wait_clks(HMAC_KEY_PROCESS_CYCLES);
+        else cfg.clk_rst_vif.wait_clks(HMAC_MSG_PROCESS_CYCLES);
 
         if (do_hash_start) begin
           // wait for interrupt to assert, check status and clear it
           if (intr_hmac_done_en) begin
             wait(cfg.intr_vif.pins[HmacDone] === 1'b1);
-            check_interrupts(.interrupts((1 << HmacDone)), .check_set(1'b1));
           end else begin
             csr_spinwait(.ptr(ral.intr_state.hmac_done), .exp_data(1'b1));
-            csr_wr(.csr(ral.intr_state), .value(1 << HmacDone));
           end
         end
+        csr_rd(.ptr(ral.intr_state), .value(intr_state_val));
+        csr_wr(.csr(ral.intr_state), .value(intr_state_val));
       end
 
       // if disable sha, digest should be cleared
diff --git a/hw/ip/hmac/dv/env/seq_lib/hmac_test_vectors_sha_vseq.sv b/hw/ip/hmac/dv/env/seq_lib/hmac_test_vectors_sha_vseq.sv
index fee3868..5d28b2f 100644
--- a/hw/ip/hmac/dv/env/seq_lib/hmac_test_vectors_sha_vseq.sv
+++ b/hw/ip/hmac/dv/env/seq_lib/hmac_test_vectors_sha_vseq.sv
@@ -49,7 +49,7 @@
         // example: current fifo_depth=(14 words + 2 bytes), then wr last 4 bytes, design will
         // process the 15th word then trigger intr_fifo_full
         cfg.clk_rst_vif.wait_clks(2);
-        clear_intr_fifo_full();
+        //clear_intr_fifo_full();
 
         wait(cfg.intr_vif.pins[HmacDone] === 1'b1);
         check_interrupts(.interrupts((1 << HmacDone)), .check_set(1'b1));
diff --git a/hw/ip/hmac/dv/tb/tb.sv b/hw/ip/hmac/dv/tb/tb.sv
index 9ecf845..e6948d2 100644
--- a/hw/ip/hmac/dv/tb/tb.sv
+++ b/hw/ip/hmac/dv/tb/tb.sv
@@ -20,7 +20,7 @@
   wire [NUM_MAX_INTERRUPTS-1:0]  interrupts;
 
   wire intr_hmac_done;
-  wire intr_fifo_full;
+  wire intr_fifo_empty;
   wire intr_hmac_err;
 
   // parameters
@@ -42,16 +42,16 @@
     .tl_o               ( tl_if.d2h      ),
 
     .intr_hmac_done_o   ( intr_hmac_done ),
-    .intr_fifo_full_o   ( intr_fifo_full ),
+    .intr_fifo_empty_o  ( intr_fifo_empty ),
     .intr_hmac_err_o    ( intr_hmac_err  ),
 
     .alert_rx_i         ( alert_if_msg_push_sha_disabled.alert_rx ),
     .alert_tx_o         ( alert_if_msg_push_sha_disabled.alert_tx )
   );
 
-  assign interrupts[HmacDone]        = intr_hmac_done;
-  assign interrupts[HmacMsgFifoFull] = intr_fifo_full;
-  assign interrupts[HmacErr]         = intr_hmac_err;
+  assign interrupts[HmacDone]         = intr_hmac_done;
+  assign interrupts[HmacMsgFifoEmpty] = intr_fifo_empty;
+  assign interrupts[HmacErr]          = intr_hmac_err;
 
   initial begin
     // drive clk and rst_n from clk_if