[dv/kmac] kmac_burst_write test

This PR implements the kmac_burst_wr test as described in the testplan.

Signed-off-by: Udi Jonnalagadda <udij@google.com>
diff --git a/hw/ip/kmac/data/kmac_base_testplan.hjson b/hw/ip/kmac/data/kmac_base_testplan.hjson
index 0caa858..02b16e8 100644
--- a/hw/ip/kmac/data/kmac_base_testplan.hjson
+++ b/hw/ip/kmac/data/kmac_base_testplan.hjson
@@ -54,13 +54,13 @@
       tests: ["{name}_long_msg_and_output"]
     }
     {
-      name: burst_wr
+      name: burst_write
       desc: '''
             This is the same as the long_message test, except we burst-write chunks of the message
             into the msg_fifo, and disable intermediate status/CSR checks.
             '''
       milestone: V2
-      tests: ["{name}_burst_wr"]
+      tests: ["{name}_burst_write"]
     }
     {
       name: test_vectors
diff --git a/hw/ip/kmac/dv/env/kmac_env.core b/hw/ip/kmac/dv/env/kmac_env.core
index ff99fc8..65dcb11 100644
--- a/hw/ip/kmac/dv/env/kmac_env.core
+++ b/hw/ip/kmac/dv/env/kmac_env.core
@@ -33,6 +33,7 @@
       - seq_lib/kmac_test_vectors_shake_vseq.sv: {is_include_file: true}
       - seq_lib/kmac_test_vectors_kmac_vseq.sv: {is_include_file: true}
       - seq_lib/kmac_test_vectors_kmac_xof_vseq.sv: {is_include_file: true}
+      - seq_lib/kmac_burst_write_vseq.sv: {is_include_file: true}
     file_type: systemVerilogSource
 
 generate:
diff --git a/hw/ip/kmac/dv/env/kmac_env_pkg.sv b/hw/ip/kmac/dv/env/kmac_env_pkg.sv
index e44e5e7..aebe938 100644
--- a/hw/ip/kmac/dv/env/kmac_env_pkg.sv
+++ b/hw/ip/kmac/dv/env/kmac_env_pkg.sv
@@ -45,6 +45,16 @@
   parameter bit [TL_AW-1:0] KMAC_FIFO_BASE = 32'h800;
   parameter bit [TL_AW-1:0] KMAC_FIFO_END = 32'hFFC;
 
+  // width and depth of the msgfifo
+  parameter int KMAC_FIFO_DEPTH = kmac_pkg::MsgFifoDepth;
+  parameter int KMAC_FIFO_WIDTH = kmac_pkg::MsgWidth;
+
+  parameter int KMAC_FIFO_WORDS_PER_ENTRY = KMAC_FIFO_WIDTH / TL_DW;
+
+  parameter int KMAC_FIFO_NUM_WORDS = KMAC_FIFO_DEPTH * KMAC_FIFO_WORDS_PER_ENTRY;
+
+  parameter int KMAC_FIFO_NUM_BYTES = KMAC_FIFO_NUM_WORDS * 4;
+
   // Represents the max bit-width of some value to be encoded with either
   // `right_encode()` or `left_encode()`.
   parameter int MAX_ENCODE_WIDTH = 2040;
diff --git a/hw/ip/kmac/dv/env/seq_lib/kmac_base_vseq.sv b/hw/ip/kmac/dv/env/seq_lib/kmac_base_vseq.sv
index b721030..3563484 100644
--- a/hw/ip/kmac/dv/env/seq_lib/kmac_base_vseq.sv
+++ b/hw/ip/kmac/dv/env/seq_lib/kmac_base_vseq.sv
@@ -241,7 +241,9 @@
   endtask
 
   virtual function string convert2string();
-    return {$sformatf("enable_intr: %0p\n", enable_intr),
+    return {$sformatf("intr_en[KmacDone]: %0b\n", enable_intr[KmacDone]),
+            $sformatf("intr_en[KmacFifoEmpty]: %0b\n", enable_intr[KmacFifoEmpty]),
+            $sformatf("intr_en[KmacErr]: %0b\n", enable_intr[KmacErr]),
             $sformatf("kmac_en: %0b\n", kmac_en),
             $sformatf("xof_en: %0b\n", xof_en),
             $sformatf("hash_mode: %0s\n", hash_mode.name()),
@@ -511,6 +513,60 @@
     // TODO: final csr checks might be needed
   endtask
 
+  // This task burst writes 32-bit chunks of the message into the msgfifo
+  virtual task burst_write_msg(bit [7:0] msg_arr[]);
+    bit [TL_DW-1:0] data_word;
+    bit [7:0] msg_q[$];
+
+    if (msg_endian) dv_utils_pkg::endian_swap_byte_arr(msg_arr);
+
+    msg_q = msg_arr;
+
+    `uvm_info(`gfn, $sformatf("initial msg: %0p", msg_q), UVM_HIGH)
+
+    while (msg_q.size() > 0) begin
+      `uvm_info(`gfn, $sformatf("msg size: %0d", msg_q.size()), UVM_HIGH)
+
+      if (msg_q.size() >= KMAC_FIFO_NUM_BYTES) begin
+        repeat (KMAC_FIFO_NUM_WORDS) begin
+          `DV_CHECK_MEMBER_RANDOMIZE_FATAL(fifo_addr)
+          `DV_CHECK_MEMBER_RANDOMIZE_WITH_FATAL(data_mask, data_mask == '1;)
+
+          for (int i = 0; i < TL_DBW; i++) begin
+            data_word[i*8 +: 8] = msg_q.pop_front();
+            `uvm_info(`gfn, $sformatf("intermediate data_word: 0x%0x", data_word), UVM_HIGH)
+          end
+
+          // print some debug info before performing the TLUL write
+          `uvm_info(`gfn, $sformatf("msg_size: %0d", msg_q.size()), UVM_HIGH)
+          `uvm_info(`gfn, $sformatf("fifo_addr = 0x%0x", fifo_addr), UVM_HIGH)
+          `uvm_info(`gfn, $sformatf("data_word = 0x%0x", data_word), UVM_HIGH)
+          `uvm_info(`gfn, $sformatf("data_mask = 0x%0x", data_mask), UVM_HIGH)
+
+          tl_access(.addr(ral.get_addr_from_offset(fifo_addr)),
+                    .write(1),
+                    .data(data_word),
+                    .mask(data_mask),
+                    .blocking($urandom_range(0, 1)));
+        end
+        // wait for the fifo to be empty before writing more msg
+        //
+        // spinwait instead of checking the interrupt because it's not guaranteed
+        // that the interrupt will remain high after writing the last word,
+        // depending on how long the input message is.
+        csr_spinwait(.ptr(ral.status.fifo_empty), .exp_data(1));
+      end else begin
+        // if we reach this case, means that the remaining message
+        // is smaller in size than the fifo, so we can just write it normally
+        // using `write_msg()`.
+        write_msg(msg_q);
+        break;
+      end
+    end
+    // wait for all fifo accesses to complete
+    wait_no_outstanding_access();
+  endtask
+
   // This task checks the fifo_empty interrupt (if enabled) and clears it,
   // then waits for STATUS.fifo_full to be 0.
   virtual task wait_fifo_has_capacity();
diff --git a/hw/ip/kmac/dv/env/seq_lib/kmac_burst_write_vseq.sv b/hw/ip/kmac/dv/env/seq_lib/kmac_burst_write_vseq.sv
new file mode 100644
index 0000000..aa31a51
--- /dev/null
+++ b/hw/ip/kmac/dv/env/seq_lib/kmac_burst_write_vseq.sv
@@ -0,0 +1,15 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+class kmac_burst_write_vseq extends kmac_long_msg_and_output_vseq;
+
+  `uvm_object_utils(kmac_burst_write_vseq)
+  `uvm_object_new
+
+  virtual task pre_start();
+    burst_write = 1;
+    super.pre_start();
+  endtask
+
+endclass
diff --git a/hw/ip/kmac/dv/env/seq_lib/kmac_smoke_vseq.sv b/hw/ip/kmac/dv/env/seq_lib/kmac_smoke_vseq.sv
index 761da6a..1fd6e20 100644
--- a/hw/ip/kmac/dv/env/seq_lib/kmac_smoke_vseq.sv
+++ b/hw/ip/kmac/dv/env/seq_lib/kmac_smoke_vseq.sv
@@ -8,6 +8,9 @@
   `uvm_object_utils(kmac_smoke_vseq)
   `uvm_object_new
 
+  // Set this bit if we want to burst write the message into the msgfifo
+  bit burst_write = 0;
+
   // TODO: 200 is chosen as upper bound due to large configuration space for KMAC.
   //       If this large range causes noticeable simulation slowdown, reduce it.
   constraint num_trans_c {
@@ -117,7 +120,11 @@
 
       // write the message into msgfifo
       `uvm_info(`gfn, $sformatf("msg: %0p", msg), UVM_HIGH)
-      write_msg(msg);
+      if (burst_write) begin
+        burst_write_msg(msg);
+      end else begin
+        write_msg(msg);
+      end
 
       // if using KMAC, need to write either encoded output length or 0 to msgfifo
       if (kmac_en) begin
diff --git a/hw/ip/kmac/dv/env/seq_lib/kmac_vseq_list.sv b/hw/ip/kmac/dv/env/seq_lib/kmac_vseq_list.sv
index 6580c48..4da7714 100644
--- a/hw/ip/kmac/dv/env/seq_lib/kmac_vseq_list.sv
+++ b/hw/ip/kmac/dv/env/seq_lib/kmac_vseq_list.sv
@@ -12,3 +12,4 @@
 `include "kmac_test_vectors_shake_vseq.sv"
 `include "kmac_test_vectors_kmac_vseq.sv"
 `include "kmac_test_vectors_kmac_xof_vseq.sv"
+`include "kmac_burst_write_vseq.sv"
diff --git a/hw/ip/kmac/dv/kmac_base_sim_cfg.hjson b/hw/ip/kmac/dv/kmac_base_sim_cfg.hjson
index 3a33da6..1fd24c0 100644
--- a/hw/ip/kmac/dv/kmac_base_sim_cfg.hjson
+++ b/hw/ip/kmac/dv/kmac_base_sim_cfg.hjson
@@ -81,6 +81,10 @@
       uvm_test_seq: kmac_sideload_vseq
     }
     {
+      name: "{variant}_burst_write"
+      uvm_test_seq: kmac_burst_write_vseq
+    }
+    {
       name: "{variant}_test_vectors_sha3_224"
       uvm_test_seq: kmac_test_vectors_sha3_vseq
       run_opts: ["+test_vectors_dir={build_dir}/src/lowrisc_dv_test_vectors_0",