[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
}