[spi_device] Add tpm_all test

This test has the following sequence
- Configure `TPM_CFG.EN` to On and fully randomize other TPM configuration.
- Run these 3 threads to randomly access TPM HW registers and other addresses.
- Host issues random TPM reads/writes to spi_device.
- SW polls the TPM interrupt `tpm_header_not_empty`, then read command/address and
the corresponding FIFO.
 - SW randomly updates TPM HW registers.
- Ensure all the data is correct in the scoreboard.

Also fix some small issues in the scb

Signed-off-by: Weicai Yang <weicai@google.com>
diff --git a/hw/ip/spi_device/data/spi_device_testplan.hjson b/hw/ip/spi_device/data/spi_device_testplan.hjson
index 15519f3..c453e10 100644
--- a/hw/ip/spi_device/data/spi_device_testplan.hjson
+++ b/hw/ip/spi_device/data/spi_device_testplan.hjson
@@ -195,15 +195,34 @@
       tests: ["spi_device_tpm_rw"]
     }
     {
-      name: tpm_locality
+      name: tpm_hw_reg
       desc: '''
-            - Make transactions of varying locality to the tpm submodule.
-            - Ensure that the data returned is correct for the given locality.
-            - Randomise TPM_CFG.invalid_locality and confirm response.'''
+            - Configure `TPM_CFG` as follows to have DUT directly respond for the access to the HW
+              registers.
+              - Set `tpm_mode` to fifo mode.
+              - Set `hw_reg_dis` to 0.
+              - Set `tpm_reg_chk_dis` to 0.
+              - Set `invalid_locality` to 1.
+            - Send SPI transactions of varying HW registers. In the meanwhile, SW updates the HW
+              registers.
+            - Ensure that the data returned is correct for the given address and active locality.'''
       stage: V2
       tests: ["spi_device_tpm_sts_read", "spi_device_tpm_read_hw_reg"]
     }
     {
+      name: tpm_fully_random_case
+      desc: '''
+            - Configure `TPM_CFG.EN` to On and fully randomize other TPM configuration.
+            - Run these 3 threads to randomly access TPM HW registers and other addresses.
+              - Host issues random TPM reads/writes to spi_device.
+              - SW polls the TPM interrupt `tpm_header_not_empty`, then read command/address and
+                the corresponding FIFO.
+              - SW randomly updates TPM HW registers.
+            - Ensure all the data is correct in the scoreboard.'''
+      stage: V2
+      tests: ["spi_device_tpm_all"]
+    }
+    {
       name: pass_cmd_filtering
       desc: '''
             - Randomize command opcode.
diff --git a/hw/ip/spi_device/dv/env/seq_lib/spi_device_tpm_all_vseq.sv b/hw/ip/spi_device/dv/env/seq_lib/spi_device_tpm_all_vseq.sv
new file mode 100644
index 0000000..7faf1cc
--- /dev/null
+++ b/hw/ip/spi_device/dv/env/seq_lib/spi_device_tpm_all_vseq.sv
@@ -0,0 +1,77 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+// A full random test to verify TPM mode
+// on the top of spi_device_tpm_read_hw_reg_vseq, override the constraint to enable following
+// 1. Enable TPM write
+// 2. Full randomization on TPM_CFG, except TPM_CFG.en is fixed to 1
+// Add a SW thread to read TPM write data or prepare data for TPM to read
+class spi_device_tpm_all_vseq extends spi_device_tpm_read_hw_reg_vseq;
+  `uvm_object_utils(spi_device_tpm_all_vseq)
+  `uvm_object_new
+
+  // Override this to test more in the extended test
+  constraint tpm_addition_for_read_hw_reg_c {
+    tpm_write dist {
+      0 :/ 2,
+      1 :/ 1
+    };
+    // this removed the constraint on setting TPM_CFG
+    direct_return_for_hw_reg == 0;
+  }
+
+  rand uint sw_to_poll_intr_cyc_dly;
+
+  constraint sw_to_poll_intr_cyc_dly_c {
+    sw_to_poll_intr_cyc_dly dist {
+      [1:10]     :/ 5,
+      [11:100]   :/ 2,
+      [101:1000] :/ 1
+    };
+  }
+
+  virtual task body();
+    bit main_body_done;
+    fork
+      begin
+        super.body();
+        main_body_done = 1;
+      end
+      begin : sw_process_tpm_fifo_thread
+        bit tpm_intr;
+        while (1) begin
+          bit cmdaddr_notempty_val;
+          `DV_CHECK_MEMBER_RANDOMIZE_FATAL(sw_to_poll_intr_cyc_dly)
+          cfg.clk_rst_vif.wait_clks(sw_to_poll_intr_cyc_dly);
+
+          csr_rd(.ptr(ral.intr_state.tpm_header_not_empty), .value(tpm_intr));
+          if (tpm_intr) begin
+            csr_wr(.ptr(ral.intr_state.tpm_header_not_empty), .value(tpm_intr));
+            while (1) begin
+              csr_rd(.ptr(ral.tpm_status.cmdaddr_notempty), .value(cmdaddr_notempty_val));
+              if (!cmdaddr_notempty_val) break;
+              process_tpm_fifo();
+            end;
+          end else if (main_body_done) begin
+            break;
+          end
+        end
+      end : sw_process_tpm_fifo_thread
+    join
+  endtask : body
+
+  virtual task process_tpm_fifo();
+    bit [TL_DW-1:0] cmd_addr_data;
+    bit [7:0] cmd_val;
+    bit write;
+    uint size;
+    bit [7:0] sw_byte_q[$]; // returned data is checked in scb
+
+    csr_rd(.ptr(ral.tpm_cmd_addr), .value(cmd_addr_data));
+
+    cmd_val = get_field_val(ral.tpm_cmd_addr.cmd, cmd_addr_data);
+    decode_tpm_cmd(cmd_val, write, size);
+    wait_and_process_tpm_fifo(write, size, sw_byte_q);
+  endtask : process_tpm_fifo
+endclass : spi_device_tpm_all_vseq
diff --git a/hw/ip/spi_device/dv/env/seq_lib/spi_device_tpm_base_vseq.sv b/hw/ip/spi_device/dv/env/seq_lib/spi_device_tpm_base_vseq.sv
index b574bf2..4d00598 100644
--- a/hw/ip/spi_device/dv/env/seq_lib/spi_device_tpm_base_vseq.sv
+++ b/hw/ip/spi_device/dv/env/seq_lib/spi_device_tpm_base_vseq.sv
@@ -96,10 +96,9 @@
   endtask : wait_and_check_tpm_cmd_addr
 
   virtual task wait_and_process_tpm_fifo(bit write,
-                                         bit [TPM_ADDR_WIDTH-1:0] exp_addr,
                                          uint exp_num_bytes,
                                          output bit [7:0] byte_q[$]);
-    wait_and_check_tpm_cmd_addr(get_tpm_cmd(write, exp_num_bytes), exp_addr);
+
     // Upon receiving read command, set read fifo contents
     if (write) begin
       bit [7:0] wrfifo_byte;
diff --git a/hw/ip/spi_device/dv/env/seq_lib/spi_device_tpm_read_hw_reg_vseq.sv b/hw/ip/spi_device/dv/env/seq_lib/spi_device_tpm_read_hw_reg_vseq.sv
index fb83238..8d84655 100644
--- a/hw/ip/spi_device/dv/env/seq_lib/spi_device_tpm_read_hw_reg_vseq.sv
+++ b/hw/ip/spi_device/dv/env/seq_lib/spi_device_tpm_read_hw_reg_vseq.sv
@@ -21,9 +21,13 @@
     };
   }
 
+  rand bit direct_return_for_hw_reg;
+
   // Override this to test more in the extended test
   constraint tpm_addition_for_read_hw_reg_c {
     tpm_mode == TpmFifoMode;
+    // have it always return by HW, so that this seq doesn't need to have SW to read/prepare data
+    direct_return_for_hw_reg == 1;
     is_hw_reg_region == 1;
     is_hw_reg_offset == 1;
     tpm_write == 0;
@@ -42,7 +46,7 @@
       bit upstream_spi_done;
       bit [7:0] returned_bytes[$]; // this is checked in scb
       `uvm_info(`gfn, $sformatf("starting sequence %0d/%0d", i, num_trans), UVM_LOW)
-      tpm_init(.mode(tpm_mode), .is_hw_return(1));
+      tpm_init(.mode(tpm_mode), .is_hw_return(direct_return_for_hw_reg));
 
       fork
         while (!upstream_spi_done) begin
diff --git a/hw/ip/spi_device/dv/env/seq_lib/spi_device_tpm_rw_vseq.sv b/hw/ip/spi_device/dv/env/seq_lib/spi_device_tpm_rw_vseq.sv
index 24ac1e1..81db17d 100644
--- a/hw/ip/spi_device/dv/env/seq_lib/spi_device_tpm_rw_vseq.sv
+++ b/hw/ip/spi_device/dv/env/seq_lib/spi_device_tpm_rw_vseq.sv
@@ -23,7 +23,8 @@
           spi_host_xfer_tpm_item(write, tpm_size, tpm_addr, spi_byte_q);
         end
         begin
-          wait_and_process_tpm_fifo(write, tpm_addr, tpm_size, sw_byte_q);
+          wait_and_check_tpm_cmd_addr(get_tpm_cmd(write, tpm_size), tpm_addr);
+          wait_and_process_tpm_fifo(write, tpm_size, sw_byte_q);
         end
       join
       `DV_CHECK_Q_EQ(spi_byte_q, sw_byte_q)
diff --git a/hw/ip/spi_device/dv/env/seq_lib/spi_device_vseq_list.sv b/hw/ip/spi_device/dv/env/seq_lib/spi_device_vseq_list.sv
index 18894b6..04c3177 100644
--- a/hw/ip/spi_device/dv/env/seq_lib/spi_device_vseq_list.sv
+++ b/hw/ip/spi_device/dv/env/seq_lib/spi_device_vseq_list.sv
@@ -16,6 +16,7 @@
 `include "spi_device_byte_transfer_vseq.sv"
 `include "spi_device_tpm_base_vseq.sv"
 `include "spi_device_tpm_read_hw_reg_vseq.sv"
+`include "spi_device_tpm_all_vseq.sv"
 `include "spi_device_bit_transfer_vseq.sv"
 `include "spi_device_tx_async_fifo_reset_vseq.sv"
 `include "spi_device_rx_async_fifo_reset_vseq.sv"
diff --git a/hw/ip/spi_device/dv/env/spi_device_env.core b/hw/ip/spi_device/dv/env/spi_device_env.core
index 66243bb..b45f1f9 100644
--- a/hw/ip/spi_device/dv/env/spi_device_env.core
+++ b/hw/ip/spi_device/dv/env/spi_device_env.core
@@ -32,6 +32,7 @@
       - seq_lib/spi_device_rx_timeout_vseq.sv: {is_include_file: true}
       - seq_lib/spi_device_tpm_base_vseq.sv: {is_include_file: true}
       - seq_lib/spi_device_tpm_read_hw_reg_vseq.sv: {is_include_file: true}
+      - seq_lib/spi_device_tpm_all_vseq.sv: {is_include_file: true}
       - seq_lib/spi_device_bit_transfer_vseq.sv: {is_include_file: true}
       - seq_lib/spi_device_tx_async_fifo_reset_vseq.sv: {is_include_file: true}
       - seq_lib/spi_device_rx_async_fifo_reset_vseq.sv: {is_include_file: true}
diff --git a/hw/ip/spi_device/dv/env/spi_device_scoreboard.sv b/hw/ip/spi_device/dv/env/spi_device_scoreboard.sv
index 193e1eb..ae6c2c6 100644
--- a/hw/ip/spi_device/dv/env/spi_device_scoreboard.sv
+++ b/hw/ip/spi_device/dv/env/spi_device_scoreboard.sv
@@ -180,13 +180,8 @@
         SpiModeTpm: begin
           bit [TPM_ADDR_WIDTH-1:0] addr = convert_addr_from_byte_queue(item.address_q);
           if (item.write_command) begin
-            if (is_invalid_locality_hw_rsp(addr)) begin
-              `uvm_info(`gfn, $sformatf("drop this item due to writing to invalid locality\n%s",
-                                        item.sprint()), UVM_MEDIUM)
-            end else begin
-              `DV_CHECK_EQ(tpm_write_spi_q.size, 0)
-              tpm_write_spi_q.push_back(item);
-            end
+            `DV_CHECK_EQ(tpm_write_spi_q.size, 0)
+            tpm_write_spi_q.push_back(item);
           end else begin
             bit [TL_DW-1:0] exp_q[$];
 
@@ -221,20 +216,6 @@
     return (base_addr == TPM_BASE_ADDR);
   endfunction
 
-  // return true when it's bigger than max locality and invalid locality check is enabled
-  // if true, the access to this addr is reponsed by HW
-  //  - for read, return 'hff
-  //  - for write, drop
-  function bit is_invalid_locality_hw_rsp(bit[TPM_ADDR_WIDTH-1:0] addr);
-    if (get_locality_from_addr(addr) >= MAX_TPM_LOCALITY &&
-        !`gmv(ral.tpm_cfg.tpm_reg_chk_dis) &&
-        `gmv(ral.tpm_cfg.invalid_locality) &&
-        is_match_to_tpm_base_addr(addr)) begin
-      return 1;
-    end
-    return 0;
-  endfunction
-
   `define CREATE_TPM_CASE_STMT(TPM_NAME, CSR_NAME) \
     ``TPM_NAME``_OFFSET: begin \
       exp_value_q.push_back(get_reg_val_with_all_1s_padding(`gmv(ral.``CSR_NAME``), \
@@ -264,7 +245,7 @@
 
     // handle invalid locality
     if (locality >= MAX_TPM_LOCALITY) begin
-      if (is_invalid_locality_hw_rsp(addr)) begin
+      if (`gmv(ral.tpm_cfg.invalid_locality)) begin
         exp_value_q = {'1};
         `uvm_info(`gfn, "return 'hff due to invalid locality", UVM_MEDIUM)
         return 1;
@@ -272,9 +253,11 @@
       return 0;
     end
 
+    // if hw_reg is disabled, return 0 and the request will be uploaded
+    if (`gmv(ral.tpm_cfg.hw_reg_dis)) return 0;
+
     aligned_offset = {addr[TPM_OFFSET_WIDTH-1:2], 2'd0};
     // if locality is inactive, return 'hff for TPM_STS
-    foreach (tpm_hw_reg_pre_val_aa[i]) $display("aa %s, %h", i, tpm_hw_reg_pre_val_aa[i]);
     if (aligned_offset == TPM_STS_OFFSET) begin
       bit cur_locality_active = cfg.get_locality_active(locality);
       bit pre_locality_active = cur_locality_active;
diff --git a/hw/ip/spi_device/dv/spi_device_sim_cfg.hjson b/hw/ip/spi_device/dv/spi_device_sim_cfg.hjson
index fe31bf8..b59456f 100644
--- a/hw/ip/spi_device/dv/spi_device_sim_cfg.hjson
+++ b/hw/ip/spi_device/dv/spi_device_sim_cfg.hjson
@@ -111,6 +111,11 @@
     }
 
     {
+      name: spi_device_tpm_all
+      uvm_test_seq: spi_device_tpm_all_vseq
+    }
+
+    {
       name: spi_device_bit_transfer
       uvm_test_seq: spi_device_bit_transfer_vseq
     }