[top_earlgrey/dv] Add filtering variant of SPI passthrough test
Add variant of SPI passthrough test that incorporates the use of
filtered opcodes.
Signed-off-by: Alexander Williams <awill@google.com>
diff --git a/hw/top_earlgrey/dv/env/seq_lib/chip_sw_spi_passthrough_vseq.sv b/hw/top_earlgrey/dv/env/seq_lib/chip_sw_spi_passthrough_vseq.sv
index a4cb170..fe1169b 100644
--- a/hw/top_earlgrey/dv/env/seq_lib/chip_sw_spi_passthrough_vseq.sv
+++ b/hw/top_earlgrey/dv/env/seq_lib/chip_sw_spi_passthrough_vseq.sv
@@ -17,6 +17,8 @@
33_000, // 30 MHz
167_000 // 6 MHz
};
+ // A bit map of command slots that will have passthrough filters enabled.
+ rand bit [spi_device_pkg::NumTotalCmdInfo-1:0] passthrough_filters;
// Generate a random permutation of the following opcodes, and place them in
// the test_opcodes queue:
@@ -47,6 +49,30 @@
"Observed SPI transaction on spi_host1, which should be inactive"));
endtask
+ task get_filtered_commands(output bit [255:0] filter_map);
+ filter_map = '0;
+ for (int i = 0; i < spi_device_pkg::NumTotalCmdInfo; i++) begin
+ uvm_object csr;
+ uvm_reg_data_t opcode;
+ case (spi_device_pkg::cmd_info_index_e'(i))
+ spi_device_pkg::CmdInfoEn4B:
+ csr = ral.spi_device.cmd_info_en4b.opcode;
+ spi_device_pkg::CmdInfoEx4B:
+ csr = ral.spi_device.cmd_info_ex4b.opcode;
+ spi_device_pkg::CmdInfoWrEn:
+ csr = ral.spi_device.cmd_info_wren.opcode;
+ spi_device_pkg::CmdInfoWrDi:
+ csr = ral.spi_device.cmd_info_wrdi.opcode;
+ default:
+ csr = ral.spi_device.cmd_info[i].opcode;
+ endcase
+ if (passthrough_filters[i]) begin
+ csr_rd(.ptr(csr), .value(opcode), .backdoor(1));
+ filter_map[opcode] = 1'b1;
+ end
+ end
+ endtask
+
// Send the sequence of commands indicated by the `test_opcodes` member.
// These commands must be registered with the host and device agents, as the
// command info determines the actions takes for each opcode. Random data of
@@ -56,38 +82,60 @@
spi_device_flash_seq m_spi_device_seq;
spi_host_flash_seq m_spi_host_seq;
spi_item host_rsp, device_rsp;
+ spi_item device_rsp_q[$];
spi_agent_cfg agent_cfg = cfg.m_spi_host_agent_cfg;
+ bit [255:0] filter_map;
+ get_filtered_commands(filter_map);
- while (test_opcodes.size() > 0) begin
- bit [7:0] opcode = test_opcodes.pop_front();
-
- `uvm_create_on(m_spi_device_seq, p_sequencer.spi_device_sequencer_hs[0]);
- `uvm_create_on(m_spi_host_seq, p_sequencer.spi_host_sequencer_h);
- // Prepare for specific opcode. The address_q is kept empty, which will
- // trigger m_spi_host_seq to do the lookup and supply a random value.
- `DV_CHECK_RANDOMIZE_WITH_FATAL(m_spi_host_seq,
- opcode == local::opcode;
- address_q.size() == 0;
- payload_q.size() <= local::max_payload_size;
- read_size == payload_q.size(););
+ fork begin : isolation_fork
+ // The device agent handles the incoming command, if it is not filtered.
fork
- begin
+ forever begin
+ `uvm_create_on(m_spi_device_seq, p_sequencer.spi_device_sequencer_hs[0]);
`uvm_send(m_spi_device_seq);
+ device_rsp_q.push_back(m_spi_device_seq.rsp);
end
- begin
- `uvm_send(m_spi_host_seq);
- end
- join
+ join_none
- // Check that the command, address, and data sent matches on both sides.
- host_rsp = m_spi_host_seq.rsp;
- device_rsp = m_spi_device_seq.rsp;
- `DV_CHECK_EQ(host_rsp.opcode, device_rsp.opcode);
- `DV_CHECK_Q_EQ(host_rsp.address_q, device_rsp.address_q);
- `DV_CHECK_EQ(host_rsp.dummy_cycles, device_rsp.dummy_cycles);
- `DV_CHECK_EQ(host_rsp.num_lanes, device_rsp.num_lanes);
- `DV_CHECK_Q_EQ(host_rsp.payload_q, device_rsp.payload_q);
- end
+ while (test_opcodes.size() > 0) begin
+ bit [7:0] opcode = test_opcodes.pop_front();
+
+ `uvm_create_on(m_spi_host_seq, p_sequencer.spi_host_sequencer_h);
+ // Prepare for specific opcode. The address_q is kept empty, which will
+ // trigger m_spi_host_seq to do the lookup and supply a random value.
+ `DV_CHECK_RANDOMIZE_WITH_FATAL(m_spi_host_seq,
+ opcode == local::opcode;
+ address_q.size() == 0;
+ payload_q.size() <= local::max_payload_size;
+ read_size == payload_q.size(););
+ `uvm_send(m_spi_host_seq);
+ // Wait for a small delay to allow the device agent to push the response
+ // into the queue.
+ #1ps;
+ if (!filter_map[opcode]) begin
+ // Check that the command, address, and data sent matches on both sides.
+ `DV_CHECK_EQ(device_rsp_q.size(), 1);
+ host_rsp = m_spi_host_seq.rsp;
+ device_rsp = device_rsp_q.pop_front();
+ `DV_CHECK_EQ(host_rsp.opcode, device_rsp.opcode);
+ `DV_CHECK_Q_EQ(host_rsp.address_q, device_rsp.address_q);
+ `DV_CHECK_EQ(host_rsp.dummy_cycles, device_rsp.dummy_cycles);
+ `DV_CHECK_EQ(host_rsp.num_lanes, device_rsp.num_lanes);
+ `DV_CHECK_Q_EQ(host_rsp.payload_q, device_rsp.payload_q);
+ end else begin
+ `DV_CHECK_EQ(device_rsp_q.size(), 0);
+ end
+ end
+ disable fork;
+ end join
+ endtask
+
+ virtual task cpu_init();
+ bit [7:0] sw_filter_config[4];
+ super.cpu_init();
+ `DV_CHECK_MEMBER_RANDOMIZE_FATAL(passthrough_filters);
+ sw_filter_config = {<<byte{passthrough_filters}};
+ sw_symbol_backdoor_overwrite("kFilteredCommands", sw_filter_config);
endtask
virtual task body();
diff --git a/sw/device/tests/sim_dv/BUILD b/sw/device/tests/sim_dv/BUILD
index e5bf5b6..fd790ce 100644
--- a/sw/device/tests/sim_dv/BUILD
+++ b/sw/device/tests/sim_dv/BUILD
@@ -825,6 +825,7 @@
deps = [
"//hw/top_earlgrey/sw/autogen:top_earlgrey",
"//sw/device/lib/arch:device",
+ "//sw/device/lib/base:bitfield",
"//sw/device/lib/base:mmio",
"//sw/device/lib/dif:pinmux",
"//sw/device/lib/dif:spi_device",
diff --git a/sw/device/tests/sim_dv/spi_passthrough_test.c b/sw/device/tests/sim_dv/spi_passthrough_test.c
index c5c66c3..fcaa45e 100644
--- a/sw/device/tests/sim_dv/spi_passthrough_test.c
+++ b/sw/device/tests/sim_dv/spi_passthrough_test.c
@@ -6,6 +6,7 @@
#include <stdbool.h>
#include "sw/device/lib/arch/device.h"
+#include "sw/device/lib/base/bitfield.h"
#include "sw/device/lib/base/mmio.h"
#include "sw/device/lib/dif/dif_pinmux.h"
#include "sw/device/lib/dif/dif_spi_device.h"
@@ -21,6 +22,10 @@
OTTF_DEFINE_TEST_CONFIG();
+// Bit map of command slots to be filtered. This is supplied by the DV
+// environment.
+const volatile uint32_t kFilteredCommands;
+
static dif_pinmux_t pinmux;
static dif_spi_device_handle_t spi_device;
static dif_spi_host_t spi_host0;
@@ -219,10 +224,11 @@
CHECK_DIF_OK(dif_spi_device_set_passthrough_intercept_config(
&spi_device, intercept_config));
- // Set up passthrough filter to allow all commands.
+ // Set up passthrough filter to allow all commands, initially.
CHECK_DIF_OK(dif_spi_device_set_all_passthrough_command_filters(
&spi_device, kDifToggleDisabled));
+ uint32_t filters = kFilteredCommands;
dif_spi_device_flash_command_t read_commands[] = {
{
// Slot 0: ReadStatus1
@@ -303,6 +309,10 @@
};
for (int i = 0; i < ARRAYSIZE(read_commands); ++i) {
uint8_t slot = i + kSpiDeviceReadCommandSlotBase;
+ if (bitfield_bit32_read(filters, slot)) {
+ CHECK_DIF_OK(dif_spi_device_set_passthrough_command_filter(
+ &spi_device, read_commands[i].opcode, kDifToggleEnabled));
+ }
CHECK_DIF_OK(dif_spi_device_set_flash_command_slot(
&spi_device, slot, kDifToggleEnabled, read_commands[i]));
}
@@ -350,6 +360,10 @@
};
for (int i = 0; i < ARRAYSIZE(write_commands); ++i) {
uint8_t slot = i + kSpiDeviceWriteCommandSlotBase;
+ if (bitfield_bit32_read(filters, slot)) {
+ CHECK_DIF_OK(dif_spi_device_set_passthrough_command_filter(
+ &spi_device, write_commands[i].opcode, kDifToggleEnabled));
+ }
CHECK_DIF_OK(dif_spi_device_set_flash_command_slot(
&spi_device, slot, kDifToggleEnabled, write_commands[i]));
}