[spi_device/dv] Test flash mode read buffer
1. add `spi_device_flash_mode_vseq` to enable flash_mode
2. update scb
1. add upstream_spi_req_fifo to get the item when opcode and address
are collected
2. check read command on read buffer while payload is being collected
3. extract `compare_mem_byte` to convert addr and compare with exp mem
3. rename `spi_device_pass_all` to `spi_device_flash_all` as it randomly
test flash_mode and passthrough_mode
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 5e74d35..a467d84 100644
--- a/hw/ip/spi_device/data/spi_device_testplan.hjson
+++ b/hw/ip/spi_device/data/spi_device_testplan.hjson
@@ -215,7 +215,7 @@
- Check opcode and address are passing through again.
- Invalid opcode is also filtered'''
milestone: V2
- tests: ["spi_device_pass_cmd_filtering", "spi_device_pass_all"]
+ tests: ["spi_device_pass_cmd_filtering", "spi_device_flash_all"]
}
{
name: pass_addr_translation
@@ -228,7 +228,7 @@
- Disable address translation for given command.
- Check address is now passing unchanged.'''
milestone: V2
- tests: ["spi_device_pass_addr_payload_swap", "spi_device_pass_all"]
+ tests: ["spi_device_pass_addr_payload_swap", "spi_device_flash_all"]
}
{
name: pass_payload_translation
@@ -240,7 +240,7 @@
- Disable payload translation for given command.
- Check payload is now passing unchanged.'''
milestone: V2
- tests: ["spi_device_pass_addr_payload_swap", "spi_device_pass_all"]
+ tests: ["spi_device_pass_addr_payload_swap", "spi_device_flash_all"]
}
{
name: cmd_info_slots
@@ -253,7 +253,7 @@
- Disable some cmd info slots.
- Check no propagation of disabled commands.'''
milestone: V2
- tests: ["spi_device_pass_all"]
+ tests: ["spi_device_flash_all"]
}
{
name: cmd_read_status
@@ -264,7 +264,7 @@
- Initiate response to the read status.
- Check proper reception of response.'''
milestone: V2
- tests: ["spi_device_intercept", "spi_device_pass_all"]
+ tests: ["spi_device_intercept", "spi_device_flash_all"]
}
{
name: cmd_read_jedec
@@ -275,7 +275,7 @@
- Initiate response to the read jedec.
- Check proper reception of response.'''
milestone: V2
- tests: ["spi_device_intercept", "spi_device_pass_all"]
+ tests: ["spi_device_intercept", "spi_device_flash_all"]
}
{
name: cmd_read_sfdp
@@ -286,7 +286,7 @@
- Initiate response to the read sfdp.
- Check proper reception of response.'''
milestone: V2
- tests: ["spi_device_intercept", "spi_device_pass_all"]
+ tests: ["spi_device_intercept", "spi_device_flash_all"]
}
{
name: cmd_fast_read
@@ -297,7 +297,7 @@
- Initiate response to the fast read.
- Check proper reception of response.'''
milestone: V2
- tests: ["spi_device_intercept", "spi_device_pass_all"]
+ tests: ["spi_device_intercept", "spi_device_flash_all"]
}
{
name: flash_cmd_upload
@@ -346,15 +346,16 @@
{
name: cmd_read_buffer
desc: '''
- - Configure device in flash or passthrough mode.
- - SW updates read buffer contents.
- - Issue read command.
+ - Configure device in flash mode.
+ - Issue read commands.
+ - Create another parallel thread that SW updates read buffer contents after a watermark
+ or buffer flip event occurs.
- Check proper read data.
- - Issue new read command that crosses read buffer boundary.
- - Behavior on crossing uncertain //TODO Clarify spec on this
- - Check internal buffer index bit.'''
+ - Randomly issue read command that crosses read buffer boundary and switches back to
+ index 0.
+ - Check correctness of `last_read_addr`, `readbuf_watermark` and `readbuf_flip`.'''
milestone: V2
- tests: []
+ tests: ["spi_device_flash_mode"]
}
{
name: cmd_dummy_cycle
@@ -368,7 +369,7 @@
- Issue new read command that crosses read maibox boundary.
- Check internal buffer index bit.'''
milestone: V2
- tests: ["spi_device_mailbox", "spi_device_pass_all"]
+ tests: ["spi_device_mailbox", "spi_device_flash_all"]
}
{
name: quad_spi
@@ -379,7 +380,7 @@
- Issue supported command.
- Check data on all four lines.'''
milestone: V2
- tests: ["spi_device_pass_all"]
+ tests: ["spi_device_flash_all"]
}
{
name: dual_spi
@@ -390,7 +391,7 @@
- Issue supported command.
- Check data on both lines.'''
milestone: V2
- tests: ["spi_device_pass_all"]
+ tests: ["spi_device_flash_all"]
}
{
name: 4b_3b_feature
diff --git a/hw/ip/spi_device/dv/env/seq_lib/spi_device_flash_mode_vseq.sv b/hw/ip/spi_device/dv/env/seq_lib/spi_device_flash_mode_vseq.sv
new file mode 100644
index 0000000..5631cd6
--- /dev/null
+++ b/hw/ip/spi_device/dv/env/seq_lib/spi_device_flash_mode_vseq.sv
@@ -0,0 +1,13 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+// set mode to FlashMode to test read buffer along with other intercept commands
+class spi_device_flash_mode_vseq extends spi_device_intercept_vseq;
+ `uvm_object_utils(spi_device_flash_mode_vseq)
+ `uvm_object_new
+
+ constraint device_mode_c {
+ device_mode == FlashMode;
+ }
+endclass : spi_device_flash_mode_vseq
diff --git a/hw/ip/spi_device/dv/env/seq_lib/spi_device_pass_all_vseq.sv b/hw/ip/spi_device/dv/env/seq_lib/spi_device_pass_all_vseq.sv
deleted file mode 100644
index 4f53dd6..0000000
--- a/hw/ip/spi_device/dv/env/seq_lib/spi_device_pass_all_vseq.sv
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright lowRISC contributors.
-// Licensed under the Apache License, Version 2.0, see LICENSE for details.
-// SPDX-License-Identifier: Apache-2.0
-
-// Enable all passthrough related features during init, and then randomly send valid commands
-class spi_device_pass_all_vseq extends spi_device_pass_base_vseq;
- `uvm_object_utils(spi_device_pass_all_vseq)
- `uvm_object_new
-
- int write_flash_status_pct = 30;
-
- virtual task body();
- bit main_seq_done;
-
- allow_addr_swap = 1;
- allow_payload_swap = 1;
- allow_intercept = 1;
-
- // enable upload
- allow_upload = 1;
- always_set_busy_when_upload_contain_payload = 1;
-
- allow_write_enable_disable = 1;
- allow_addr_cfg_cmd = 1;
-
- fork
- // this thread runs until the main_seq completes
- while (!main_seq_done) upload_fifo_read_seq();
- // main seq that sends spi items
- begin
- main_seq();
- main_seq_done = 1;
- end
- join
- endtask : body
-
- virtual task upload_fifo_read_seq();
- int upload_read_dly;
- `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(upload_read_dly,
- upload_read_dly dist {
- [0:10] :/ 1,
- [11:100] :/ 2,
- [101:1000] :/ 2,
- [1000:5000] :/ 1};)
- cfg.clk_rst_vif.wait_clks(upload_read_dly);
- read_upload_fifos();
- endtask : upload_fifo_read_seq
-
- virtual task main_seq();
- for (int i = 0; i < num_trans; ++i) begin
- `uvm_info(`gfn, $sformatf("running iteration %0d/%0d", i, num_trans), UVM_LOW)
-
- spi_device_flash_pass_init(PassthroughMode);
- for (int j = 0; j < 20; ++j) begin
- if ($urandom_range(0, 99) < write_flash_status_pct) begin
- random_access_flash_status(.write(1), .busy(1));
- end else if ($urandom_range(0, 1)) begin
- random_access_flash_status(.write(0));
- end
-
- if ($urandom_range(0, 1)) read_and_check_4b_en();
-
- randomize_op_addr_size();
- `uvm_info(`gfn, $sformatf("Testing op_num %0d/20, op = 0x%0h", j, opcode), UVM_MEDIUM)
-
- spi_host_xfer_flash_item(opcode, payload_size, read_start_addr);
- cfg.clk_rst_vif.wait_clks(10);
- end
- end
- endtask : main_seq
-endclass : spi_device_pass_all_vseq
diff --git a/hw/ip/spi_device/dv/env/seq_lib/spi_device_pass_base_vseq.sv b/hw/ip/spi_device/dv/env/seq_lib/spi_device_pass_base_vseq.sv
index c7dd9ed..cc389f6 100644
--- a/hw/ip/spi_device/dv/env/seq_lib/spi_device_pass_base_vseq.sv
+++ b/hw/ip/spi_device/dv/env/seq_lib/spi_device_pass_base_vseq.sv
@@ -21,6 +21,13 @@
// we can only hold one payload, set it busy to avoid payload is overwritten before read out.
bit always_set_busy_when_upload_contain_payload;
+ rand device_mode_e device_mode;
+
+ // overide this to enable other modes
+ constraint device_mode_c {
+ device_mode == PassthroughMode;
+ }
+
bit [7:0] valid_opcode_q[$];
rand bit valid_op;
rand bit [7:0] opcode;
@@ -80,6 +87,12 @@
}
}
+ constraint addr_size_and_device_mode_c {
+ // flash mode doesn't support mailbox boundary crossing.
+ device_mode == FlashMode ->
+ read_addr_size_type inside {ReadAddrWithinMailbox, ReadAddrOutsideMailbox};
+ }
+
`uvm_object_utils(spi_device_pass_base_vseq)
`uvm_object_new
@@ -247,7 +260,7 @@
endfunction
// Task for flash or pass init
- virtual task spi_device_flash_pass_init(device_mode_e mode);
+ virtual task spi_device_flash_pass_init();
spi_device_init();
`uvm_info(`gfn, "Initialize flash/passthrough mode", UVM_MEDIUM)
// TODO, fixed config for now
@@ -277,13 +290,8 @@
ral.cfg.cpha.set(1'b0);
csr_update(.csr(ral.cfg)); // TODO check if randomization possible
// Set the passthrough or flash mode mode
- `DV_CHECK(mode inside {FlashMode, PassthroughMode});
- if (mode == FlashMode) begin
- ral.control.mode.set(FlashMode);
- end
- if (mode == PassthroughMode) begin
- ral.control.mode.set(PassthroughMode);
- end
+ `DV_CHECK(device_mode inside {FlashMode, PassthroughMode});
+ ral.control.mode.set(device_mode);
csr_update(.csr(ral.control));
// addr/payload swap settting
@@ -308,7 +316,8 @@
// in passthrough, if upload is enabled, need to enable status intercept, so that host side
// can know if spi_device is busy or not
- if (allow_upload && mode == PassthroughMode && (`gmv(ral.intercept_en.status) == 0)) begin
+ if (allow_upload && device_mode == PassthroughMode && (`gmv(ral.intercept_en.status) == 0))
+ begin
ral.intercept_en.status.set(1);
csr_update(ral.intercept_en);
end
@@ -502,7 +511,7 @@
if (payload_depth_val > PAYLOAD_FIFO_SIZE) payload_depth_val = PAYLOAD_FIFO_SIZE;
// need to shift by 2 for the offset used at mem_rd
- payload_base_offset = (READ_CMD_BUFFER_SIZE + MAILBOX_BUFFER_SIZE + SFDP_SIZE) / 4;
+ payload_base_offset = (READ_BUFFER_SIZE + MAILBOX_BUFFER_SIZE + SFDP_SIZE) / 4;
payload_depth_val = payload_depth_val / 4;
for (int i = 0; i < payload_depth_val; i++) begin
bit [TL_DW-1:0] val;
diff --git a/hw/ip/spi_device/dv/env/seq_lib/spi_device_pass_cmd_filtering_vseq.sv b/hw/ip/spi_device/dv/env/seq_lib/spi_device_pass_cmd_filtering_vseq.sv
index 3140847..dba4071 100644
--- a/hw/ip/spi_device/dv/env/seq_lib/spi_device_pass_cmd_filtering_vseq.sv
+++ b/hw/ip/spi_device/dv/env/seq_lib/spi_device_pass_cmd_filtering_vseq.sv
@@ -11,7 +11,7 @@
allow_set_cmd_info_invalid = 1;
allow_use_invalid_opcode = 1;
- spi_device_flash_pass_init(PassthroughMode);
+ spi_device_flash_pass_init();
for (int i = 0; i < num_trans; ++i) begin
randomize_op_addr_size();
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 d1ad720..c8400ce 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
@@ -29,4 +29,5 @@
`include "spi_device_mailbox_vseq.sv"
`include "spi_device_upload_vseq.sv"
`include "spi_device_cfg_cmd_vseq.sv"
-`include "spi_device_pass_all_vseq.sv"
+`include "spi_device_flash_mode_vseq.sv"
+`include "spi_device_flash_all_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 a1a78ee..cbe77aa 100644
--- a/hw/ip/spi_device/dv/env/spi_device_env.core
+++ b/hw/ip/spi_device/dv/env/spi_device_env.core
@@ -45,7 +45,8 @@
- seq_lib/spi_device_mailbox_vseq.sv: {is_include_file: true}
- seq_lib/spi_device_upload_vseq.sv: {is_include_file: true}
- seq_lib/spi_device_cfg_cmd_vseq.sv: {is_include_file: true}
- - seq_lib/spi_device_pass_all_vseq.sv: {is_include_file: true}
+ - seq_lib/spi_device_flash_mode_vseq.sv: {is_include_file: true}
+ - seq_lib/spi_device_flash_all_vseq.sv: {is_include_file: true}
file_type: systemVerilogSource
generate:
diff --git a/hw/ip/spi_device/dv/env/spi_device_env.sv b/hw/ip/spi_device/dv/env/spi_device_env.sv
index 60bc4bc..3a6fb80 100644
--- a/hw/ip/spi_device/dv/env/spi_device_env.sv
+++ b/hw/ip/spi_device/dv/env/spi_device_env.sv
@@ -33,6 +33,8 @@
scoreboard.upstream_spi_host_fifo.analysis_export);
spi_host_agent.monitor.device_analysis_port.connect(
scoreboard.upstream_spi_device_fifo.analysis_export);
+ spi_host_agent.monitor.req_analysis_port.connect(
+ scoreboard.upstream_spi_req_fifo.analysis_export);
spi_device_agent.monitor.host_analysis_port.connect(
scoreboard.downstream_spi_host_fifo.analysis_export);
end
diff --git a/hw/ip/spi_device/dv/env/spi_device_env_pkg.sv b/hw/ip/spi_device/dv/env/spi_device_env_pkg.sv
index 500521d..c096cf4 100644
--- a/hw/ip/spi_device/dv/env/spi_device_env_pkg.sv
+++ b/hw/ip/spi_device/dv/env/spi_device_env_pkg.sv
@@ -83,10 +83,10 @@
parameter uint SRAM_PTR_PHASE_BIT = SRAM_MSB + 1;
parameter uint SRAM_WORD_SIZE = 4;
parameter uint ASYNC_FIFO_SIZE = 8;
- parameter uint READ_CMD_START_ADDR = SRAM_OFFSET;
- parameter uint READ_CMD_BUFFER_SIZE = 2048;
+ parameter uint READ_BUFFER_START_ADDR = SRAM_OFFSET;
+ parameter uint READ_BUFFER_SIZE = 2048;
// MAILBOX_START_ADDR is 0x800
- parameter uint MAILBOX_START_ADDR = READ_CMD_START_ADDR + READ_CMD_BUFFER_SIZE;
+ parameter uint MAILBOX_START_ADDR = READ_BUFFER_START_ADDR + READ_BUFFER_SIZE;
parameter uint MAILBOX_BUFFER_SIZE = 1024;
// SFDP_START_ADDR is 0xc00
parameter uint SFDP_START_ADDR = MAILBOX_START_ADDR + MAILBOX_BUFFER_SIZE;
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 00a4083..7a78992 100644
--- a/hw/ip/spi_device/dv/env/spi_device_scoreboard.sv
+++ b/hw/ip/spi_device/dv/env/spi_device_scoreboard.sv
@@ -27,6 +27,8 @@
// TLM fifos to pick up the packets
uvm_tlm_analysis_fifo #(spi_item) upstream_spi_host_fifo;
uvm_tlm_analysis_fifo #(spi_item) upstream_spi_device_fifo;
+ // connect with req_analysis_port where it receives item when opcode and address are received
+ uvm_tlm_analysis_fifo #(spi_item) upstream_spi_req_fifo;
uvm_tlm_analysis_fifo #(spi_item) downstream_spi_host_fifo;
// mem model to save expected value
@@ -66,6 +68,7 @@
super.build_phase(phase);
upstream_spi_host_fifo = new("upstream_spi_host_fifo", this);
upstream_spi_device_fifo = new("upstream_spi_device_fifo", this);
+ upstream_spi_req_fifo = new("upstream_spi_req_fifo", this);
downstream_spi_host_fifo = new("downstream_spi_host_fifo", this);
tx_mem = mem_model#()::type_id::create("tx_mem", this);
rx_mem = mem_model#()::type_id::create("rx_mem", this);
@@ -80,6 +83,7 @@
process_upstream_spi_host_fifo();
process_upstream_spi_device_fifo();
process_downstream_spi_fifo();
+ process_read_buffer_cmd();
forever_latch_flash_status();
join_none
endtask
@@ -103,14 +107,17 @@
bit is_intercepted;
bit set_busy;
`DV_CHECK_EQ(item.item_type, SpiFlashTrans)
- // downstream item should be in the queue at the same time, add small delay
- #1ps;
- cmd_type = triage_flash_cmd(item.opcode, set_busy);
- `uvm_info(`gfn, $sformatf("Triage flash cmd: %s, set_busy: %0d", cmd_type, set_busy),
- UVM_MEDIUM)
- is_intercepted = 1;
- case (cmd_type)
+ // read buffer is handled at `process_read_buffer_cmd`
+ if (!is_read_buffer_cmd(item)) begin
+ // downstream item should be in the queue at the same time, add small delay
+ #1ps;
+ cmd_type = triage_flash_cmd(item.opcode, set_busy);
+ `uvm_info(`gfn, $sformatf("Triage flash cmd: %s, set_busy: %0d", cmd_type, set_busy),
+ UVM_MEDIUM)
+
+ is_intercepted = 1;
+ case (cmd_type)
NoInternalProcess: begin
is_intercepted = 0;
end
@@ -129,7 +136,7 @@
`DV_CHECK_EQ_FATAL(spi_passthrough_downstream_q.size, 1)
downstream_item = spi_passthrough_downstream_q[0];
end
- check_read_cmd_data(item, downstream_item);
+ check_read_cmd_data_for_non_read_buffer(item, downstream_item);
end
InternalProcessCfgCmd: begin
if (`GET_OPCODE_VALID_AND_MATCH(cmd_info_en4b, item.opcode)) begin
@@ -152,17 +159,18 @@
process_upload_cmd(item);
end
default: `uvm_fatal(`gfn, "can't get here")
- endcase
+ endcase
- // if busy, passthrough is blocked
- if (is_opcode_passthrough(item.opcode) && !`gmv(ral.flash_status.busy)) begin
- compare_passthru_item(.upstream_item(item), .is_intercepted(is_intercepted));
- end
+ // if busy, passthrough is blocked
+ if (is_opcode_passthrough(item.opcode) && !`gmv(ral.flash_status.busy)) begin
+ compare_passthru_item(.upstream_item(item), .is_intercepted(is_intercepted));
+ end
+ end // if (!is_read_buffer_cmd(item))
latch_flash_status(set_busy, update_wel, wel_val);
end
default: `uvm_fatal(`gfn, $sformatf("Unexpected mode: %0d", `gmv(ral.control.mode)))
- endcase
+ endcase // case (`gmv(ral.control.mode))
end // forever
endtask
@@ -250,6 +258,8 @@
end
endtask
+ // this only triages post-process cmd. read buffer cmd isn't handled here as it needs to be
+ // processed during transaction.
virtual function internal_process_cmd_e triage_flash_cmd(bit[7:0] opcode, output bit set_busy);
internal_process_cmd_e cmd_type;
bit is_status, is_jedec, is_sfdp;
@@ -366,29 +376,29 @@
`DV_CHECK_EQ(item.address_q.size, 3)
offset = (item.address_q[2] + i) % SFDP_SIZE;
- // get_normalized_addr makes it word-aligned, but we need byte offset
- addr = get_converted_addr(offset + SFDP_START_ADDR);
-
- `DV_CHECK(spi_mem.addr_exists(addr))
- spi_mem.compare_byte(addr, item.payload_q[i]);
- `uvm_info(`gfn, $sformatf("compare sfdp idx %0d, act: 0x%0x, mem addr 0x%0x, exp: 0x%0x",
- offset, item.payload_q[i], addr, spi_mem.read_byte(addr)), UVM_MEDIUM)
+ compare_mem_byte(SFDP_START_ADDR, offset, item.payload_q[i], i, "SFDP");
end
endfunction
+ virtual function void compare_mem_byte(bit [31:0] base_addr, bit [31:0] offset, bit[7:0] act_val,
+ // these 2 inputs are for log only
+ int payload_idx, string msg);
+ bit [31:0] addr = get_converted_addr(base_addr + offset);
+ `DV_CHECK(spi_mem.addr_exists(addr))
+ spi_mem.compare_byte(addr, act_val);
+ `uvm_info(`gfn, $sformatf(
+ "%s compare idx: %0d, offset %0d, mem addr 0x%0x, act: 0x%0x, exp: 0x%0x",
+ msg, payload_idx, offset, addr, act_val, spi_mem.read_byte(addr)), UVM_MEDIUM)
+ endfunction
+
// check read return data again exp_mem or downstream item
- virtual function void check_read_cmd_data(spi_item up_item, spi_item dn_item);
+ // this doesn't handle read cmd falling in read buffer
+ virtual function void check_read_cmd_data_for_non_read_buffer(spi_item up_item,
+ spi_item dn_item);
bit [31:0] start_addr, end_addr;
- bit [31:0] mbx_base_addr = get_mbx_base_addr(ral);
// TODO, sample this for coverage
read_addr_size_type_e read_addr_size_type;
bit is_passthru = `gmv(ral.control.mode) == PassthroughMode;
- bit mailbox_en;
-
- if (`gmv(ral.cfg.mailbox_en)) begin
- mailbox_en = 1;
- if (is_passthru) mailbox_en &= `gmv(ral.intercept_en.mbx);
- end
foreach (up_item.address_q[i]) begin
if (i > 0) start_addr = start_addr << 8;
@@ -400,34 +410,24 @@
foreach (up_item.payload_q[i]) begin
bit [31:0] cur_addr = start_addr + i;
- // out of mbx region
- if ((cur_addr < mbx_base_addr) || (cur_addr >= mbx_base_addr + MAILBOX_BUFFER_SIZE) ||
- !mailbox_en) begin
+ if (is_in_mailbox_region(cur_addr)) begin
+ bit [31:0] offset = cur_addr % MAILBOX_BUFFER_SIZE;
+ compare_mem_byte(MAILBOX_START_ADDR, offset, up_item.payload_q[i], i, "Mailbox");
+ end else begin // out of mbx region
string str;
- if (is_passthru) begin // passthrough mode
- if (dn_item != null) begin
- str = $sformatf("compare mbx data with downstread item. idx %0d, up: 0x%0x, dn: 0x%0x",
- i, up_item.payload_q[i], dn_item.payload_q[i]);
- `DV_CHECK_CASE_EQ(up_item.payload_q[i], dn_item.payload_q[i], str)
- end else begin // cmd is filtered
- str = $sformatf("compare mbx data. idx %0d, value 0x%0x != z",
- i, up_item.payload_q[i]);
- `DV_CHECK_CASE_EQ(up_item.payload_q[i], 8'dz, str)
- end
- end else begin // flash mode
- // TODO, support later, let it fail
- `DV_CHECK_EQ(0, 1)
+ `DV_CHECK_EQ_FATAL(is_passthru, 1)
+ if (dn_item != null) begin
+ str = $sformatf("compare mbx data with downstread item. idx %0d, up: 0x%0x, dn: 0x%0x",
+ i, up_item.payload_q[i], dn_item.payload_q[i]);
+ `DV_CHECK_CASE_EQ(up_item.payload_q[i], dn_item.payload_q[i], str)
+ end else begin // cmd is filtered
+ str = $sformatf("compare mbx data. idx %0d, value 0x%0x != z",
+ i, up_item.payload_q[i]);
+ `DV_CHECK_CASE_EQ(up_item.payload_q[i], 8'dz, str)
end
- `uvm_info(`gfn, str, UVM_MEDIUM)
- end else begin // in mbx region
- bit [31:0] offset = cur_addr % MAILBOX_BUFFER_SIZE + MAILBOX_START_ADDR;
- bit [31:0] addr = get_converted_addr(offset);
- `DV_CHECK(spi_mem.addr_exists(addr))
- spi_mem.compare_byte(addr, up_item.payload_q[i]);
- `uvm_info(`gfn, $sformatf("compare mbx idx %0d, act: 0x%0x, mem addr 0x%0x, exp: 0x%0x",
- i, up_item.payload_q[i], addr, spi_mem.read_byte(addr)), UVM_MEDIUM)
+ `uvm_info(`gfn, str, UVM_MEDIUM)
end
end
@@ -467,6 +467,32 @@
end
endfunction
+ virtual function bit is_read_buffer_cmd(spi_item item);
+ if (`gmv(ral.control.mode) != FlashMode ||
+ item.item_type != SpiFlashTrans ||
+ !(item.opcode inside {READ_CMD_LIST}) ||
+ !is_internal_recog_cmd(item.opcode)) begin
+ return 0;
+ end
+ if (is_in_mailbox_region(convert_addr_from_byte_queue(item.address_q))) return 0;
+ return 1;
+ endfunction
+
+ virtual function bit [31:0] is_in_mailbox_region(bit [31:0] addr);
+ bit [31:0] mbx_base_addr = get_mbx_base_addr(ral);
+ bit is_passthru = `gmv(ral.control.mode) == PassthroughMode;
+ bit mailbox_en;
+
+ if (`gmv(ral.cfg.mailbox_en)) begin
+ mailbox_en = 1;
+ if (is_passthru) mailbox_en &= `gmv(ral.intercept_en.mbx);
+ end
+ if (addr inside {[mbx_base_addr: mbx_base_addr + MAILBOX_BUFFER_SIZE - 1]} && mailbox_en) begin
+ return 1;
+ end
+ return 0;
+ endfunction
+
// convert offset to the mem address that is used to find the locaiton in exp_mem
// lsb 2 bit will be kept
virtual function bit [31:0] get_converted_addr(bit [31:0] offset);
@@ -518,7 +544,8 @@
downstream_item = spi_passthrough_downstream_q.pop_front();
if (is_intercepted) begin
- // compare opcode and address. data is ignored as data is checked in check_read_cmd_data
+ // compare opcode and address. data is ignored as data is checked in
+ // check_read_cmd_data_for_non_read_buffer
`DV_CHECK_EQ(upstream_item.opcode, downstream_item.opcode)
`DV_CHECK_EQ(upstream_item.address_q.size, downstream_item.address_q.size)
foreach (upstream_item.address_q[i]) begin
@@ -555,6 +582,35 @@
end
endtask
+ // read buffer cmd is handled separately as we can't wait until the item is completed.
+ // while upstream reads the buffer, SW may prepare the data on the other side of the buffer.
+ // when the item completes, the buffer may be overwritten with other data
+ virtual task process_read_buffer_cmd();
+ forever begin
+ spi_item item;
+ uint payload_idx;
+ bit [31:0] start_addr, offset;
+
+ upstream_spi_req_fifo.get(item);
+ if (!is_read_buffer_cmd(item)) continue;
+
+ start_addr = convert_addr_from_byte_queue(item.address_q);
+ `DV_SPINWAIT(
+ while (1) begin
+ `DV_WAIT(item.payload_q.size > payload_idx || item.mon_item_complete)
+ if (item.payload_q.size > payload_idx) begin
+ offset = (start_addr + payload_idx) % READ_BUFFER_SIZE;
+ compare_mem_byte(READ_BUFFER_START_ADDR, offset, item.payload_q[payload_idx],
+ payload_idx, "Read buffer");
+ payload_idx++;
+ `DV_CHECK_EQ(item.payload_q.size, payload_idx)
+ end
+ if (item.mon_item_complete) break;
+ end
+ )
+ end
+ endtask
+
// process_tl_access:this task processes incoming access into the IP over tl interface
// this is already called in cip_base_scoreboard::process_tl_a/d_chan_fifo tasks
virtual task process_tl_access(tl_seq_item item, tl_channels_e channel, string ral_name);
@@ -823,6 +879,7 @@
super.check_phase(phase);
`DV_EOT_PRINT_TLM_FIFO_CONTENTS(spi_item, upstream_spi_host_fifo)
`DV_EOT_PRINT_TLM_FIFO_CONTENTS(spi_item, upstream_spi_device_fifo)
+ `DV_EOT_PRINT_TLM_FIFO_CONTENTS(spi_item, upstream_spi_req_fifo)
`DV_EOT_PRINT_TLM_FIFO_CONTENTS(spi_item, downstream_spi_host_fifo)
`DV_CHECK_EQ(tx_word_q.size, 0)
`DV_CHECK_EQ(rx_word_q.size, 0)
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 cb0fcb3..841a13f 100644
--- a/hw/ip/spi_device/dv/spi_device_sim_cfg.hjson
+++ b/hw/ip/spi_device/dv/spi_device_sim_cfg.hjson
@@ -171,8 +171,13 @@
}
{
- name: spi_device_pass_all
- uvm_test_seq: spi_device_pass_all_vseq
+ name: spi_device_flash_mode
+ uvm_test_seq: spi_device_flash_mode_vseq
+ }
+
+ {
+ name: spi_device_flash_all
+ uvm_test_seq: spi_device_flash_all_vseq
}
]