[xbar/dv] Add stress and reset tests
1. Add stress and stress with reset tests
2. change scb to extend dv_base_scoreboard in order to reuse reset
features
3. fix tl_host_driver for reset
diff --git a/hw/dv/sv/scoreboard/scoreboard.core b/hw/dv/sv/scoreboard/scoreboard.core
index c7ae67f..57ed585 100644
--- a/hw/dv/sv/scoreboard/scoreboard.core
+++ b/hw/dv/sv/scoreboard/scoreboard.core
@@ -7,6 +7,8 @@
filesets:
files_dv:
+ depend:
+ - lowrisc:dv:dv_lib
files:
- scoreboard_pkg.sv
- scoreboard_queue.sv: {is_include_file: true}
diff --git a/hw/dv/sv/scoreboard/scoreboard.sv b/hw/dv/sv/scoreboard/scoreboard.sv
index bca36db..4f26d18 100644
--- a/hw/dv/sv/scoreboard/scoreboard.sv
+++ b/hw/dv/sv/scoreboard/scoreboard.sv
@@ -10,20 +10,23 @@
// - Support multi-cast
// - Support data transform from source to destination
-class scoreboard#(type SEQ_ITEM = uvm_object) extends uvm_component;
+class scoreboard#(type ITEM_T = uvm_object,
+ type RAL_T = dv_base_reg_block,
+ type CFG_T = dv_base_env_cfg,
+ type COV_T = dv_base_env_cov) extends dv_base_scoreboard#(RAL_T, CFG_T, COV_T);
- uvm_tlm_analysis_fifo #(SEQ_ITEM) item_fifos[string];
+ uvm_tlm_analysis_fifo #(ITEM_T) item_fifos[string];
// Port direction
port_dir_e port_dir[string];
// Queues for pending items
- scoreboard_queue#(SEQ_ITEM) item_queues[string];
+ scoreboard_queue#(ITEM_T) item_queues[string];
int unsigned timeout_cycle_limit = 10000;
bit [63:0] ref_timer;
bit [63:0] last_activity_cycle;
int unsigned num_of_exp_item;
int unsigned num_of_act_item;
int unsigned timeout_check_cycle_interval = 100;
- bit enable_logging = 1'b1;
+ bit enable_logging = 1'b0;
uvm_phase run_phase_h;
bit objection_raised;
semaphore token;
@@ -33,7 +36,8 @@
bit allow_packet_drop;
bit disable_scoreboard;
- `uvm_component_param_utils(scoreboard#(SEQ_ITEM))
+ `uvm_component_param_utils(scoreboard#(ITEM_T, dv_base_reg_block,
+ dv_base_env_cfg, dv_base_env_cov))
function new (string name, uvm_component parent);
super.new(name, parent);
@@ -41,6 +45,7 @@
function void build_phase(uvm_phase phase);
super.build_phase(phase);
+ void'($value$plusargs("scb_logging=%d", enable_logging));
if (!uvm_config_db#(virtual clk_rst_if)::get(this, "", "clk_rst_vif", clk_vif)) begin
`uvm_fatal(get_full_name(), "Cannot get clk interface")
end
@@ -74,12 +79,13 @@
end
`uvm_info(get_full_name(), $sformatf(
"Adding queue :%0s(%0s)", queue_name, policy.name()), UVM_HIGH)
- item_queues[queue_name] = scoreboard_queue#(SEQ_ITEM)::type_id::
+ item_queues[queue_name] = scoreboard_queue#(ITEM_T)::type_id::
create($sformatf("%0s_%0s", get_full_name(), queue_name));
item_queues[queue_name].policy = policy;
endfunction
task run_phase(uvm_phase phase);
+ super.run_phase(phase);
run_phase_h = phase;
if (disable_scoreboard) return;
fork
@@ -97,8 +103,8 @@
// Collect items from analysis FIFO, send to corresponding queues
virtual task port_monitor(string port_name);
- SEQ_ITEM tr;
- SEQ_ITEM transformed_tr[$];
+ ITEM_T tr;
+ ITEM_T transformed_tr[$];
string queue_name;
while(1) begin
item_fifos[port_name].get(tr);
@@ -124,7 +130,7 @@
item_queues[queue_name].add_expected_item(transformed_tr[i], ref_timer);
end
end else begin
- SEQ_ITEM tr_modified;
+ ITEM_T tr_modified;
queue_name = get_queue_name(tr, port_name);
// destination ports
if (!item_queues.exists(queue_name)) begin
@@ -177,22 +183,22 @@
// - Support multi-cast original transaction to multiple destinations
// This step is optional, the default implementation is pass through the original
// transaction without any modification.
- virtual function void process_src_packet(input SEQ_ITEM tr,
- input string port_name,
- output SEQ_ITEM transformed_tr[$]);
+ virtual function void process_src_packet(input ITEM_T tr,
+ input string port_name,
+ output ITEM_T transformed_tr[$]);
transformed_tr = {tr};
endfunction
// Process the destination packet before comparing
- virtual function void process_dst_packet(input SEQ_ITEM tr,
- input string port_name,
- output SEQ_ITEM transformed_tr);
+ virtual function void process_dst_packet(input ITEM_T tr,
+ input string port_name,
+ output ITEM_T transformed_tr);
transformed_tr = tr;
endfunction
// Get scoreboard queue name based on the transaction and port name
// This function should be implemented with actual transaction to queue mapping
- virtual function string get_queue_name(SEQ_ITEM tr, string port_name);
+ virtual function string get_queue_name(ITEM_T tr, string port_name);
return "default";
endfunction
@@ -234,4 +240,13 @@
end
endtask
+ virtual function void reset(string kind = "HARD");
+ last_activity_cycle = ref_timer;
+ foreach (item_fifos[i]) item_fifos[i].flush();
+ foreach (item_queues[i]) item_queues[i].reset();
+ num_of_act_item = 0;
+ num_of_exp_item = 0;
+ handle_objection();
+ endfunction
+
endclass
diff --git a/hw/dv/sv/scoreboard/scoreboard_pkg.sv b/hw/dv/sv/scoreboard/scoreboard_pkg.sv
index ced853a..4614c94 100644
--- a/hw/dv/sv/scoreboard/scoreboard_pkg.sv
+++ b/hw/dv/sv/scoreboard/scoreboard_pkg.sv
@@ -5,6 +5,7 @@
package scoreboard_pkg;
import uvm_pkg::*;
+ import dv_lib_pkg::*;
typedef enum bit {
kSrcPort = 1'b0,
diff --git a/hw/dv/sv/scoreboard/scoreboard_queue.sv b/hw/dv/sv/scoreboard/scoreboard_queue.sv
index 454cfa0..f045671 100644
--- a/hw/dv/sv/scoreboard/scoreboard_queue.sv
+++ b/hw/dv/sv/scoreboard/scoreboard_queue.sv
@@ -126,4 +126,12 @@
`uvm_fatal(get_full_name(), "custom_check must be implemented for kCustomCheck policy")
endfunction
+ // delete all the queues once reset
+ virtual function void reset();
+ expected_items.delete();
+ actual_items.delete();
+ expected_items_timestamp.delete();
+ actual_items_timestamp.delete();
+ endfunction
+
endclass
diff --git a/hw/dv/sv/tl_agent/tl_host_driver.sv b/hw/dv/sv/tl_agent/tl_host_driver.sv
index 206ffd0..87a55e3 100644
--- a/hw/dv/sv/tl_agent/tl_host_driver.sv
+++ b/hw/dv/sv/tl_agent/tl_host_driver.sv
@@ -126,18 +126,20 @@
rsp = pending_a_req[i];
rsp.d_opcode = vif.host_cb.d2h.d_opcode;
rsp.d_data = vif.host_cb.d2h.d_data;
- rsp.d_source = vif.host_cb.d2h.d_source;
rsp.d_param = vif.host_cb.d2h.d_param;
rsp.d_error = vif.host_cb.d2h.d_error;
rsp.d_sink = vif.host_cb.d2h.d_sink;
rsp.d_size = vif.host_cb.d2h.d_size;
rsp.d_user = vif.host_cb.d2h.d_user;
+ // make sure every req has a rsp with same source even during reset
+ if (reset_asserted) rsp.d_source = rsp.a_source;
+ else rsp.d_source = vif.host_cb.d2h.d_source;
req_found = 1'b1;
seq_item_port.put_response(rsp);
pending_a_req.delete(i);
`uvm_info(get_full_name(), $sformatf("Got response %0s, pending req:%0d",
rsp.convert2string(), pending_a_req.size()), UVM_HIGH)
- if (!reset_asserted) break;
+ break;
end
end
diff --git a/hw/dv/sv/tl_agent/tl_seq_lib.sv b/hw/dv/sv/tl_agent/tl_seq_lib.sv
index d24c3bf..13605cc 100644
--- a/hw/dv/sv/tl_agent/tl_seq_lib.sv
+++ b/hw/dv/sv/tl_agent/tl_seq_lib.sv
@@ -15,6 +15,7 @@
tl_seq_item pending_req[$];
int min_req_delay = 0;
int max_req_delay = 10;
+ int max_outstanding = 8;
`uvm_object_utils(tl_host_seq)
`uvm_object_new
@@ -47,6 +48,7 @@
begin : request_thread
`uvm_info(`gfn, $sformatf("Start sending %0d host requests", req_cnt), UVM_HIGH)
for (int i = 0; i < req_cnt; i++) begin
+ wait(pending_req.size < max_outstanding);
req = tl_seq_item::type_id::create("req");
start_item(req);
randomize_req(req, i);
@@ -72,6 +74,12 @@
virtual function void process_response(tl_seq_item req, tl_seq_item rsp);
endfunction
+ virtual function void set_max_outstanding(int value);
+ max_outstanding = value;
+ set_response_queue_depth(value);
+ `uvm_info(`gfn, $sformatf("Max outstanding: %0d", value), UVM_HIGH)
+ endfunction
+
endclass : tl_host_seq
// extend host seq to send single specific item constructed by the caller
diff --git a/hw/ip/tlul/dv/Makefile b/hw/ip/tlul/dv/Makefile
index 3780a80..aa602de 100644
--- a/hw/ip/tlul/dv/Makefile
+++ b/hw/ip/tlul/dv/Makefile
@@ -107,6 +107,24 @@
UVM_TEST_SEQ = xbar_unmapped_addr_vseq
endif
+ifeq (${TEST_NAME},xbar_stress_all)
+ UVM_TEST_SEQ = xbar_stress_all_vseq
+endif
+
+ifeq (${TEST_NAME},xbar_stress_all_with_error)
+ UVM_TEST = xbar_error_test
+ UVM_TEST_SEQ = xbar_stress_all_vseq
+endif
+
+ifeq (${TEST_NAME},xbar_stress_all_with_reset)
+ UVM_TEST_SEQ = xbar_stress_all_with_reset_vseq
+endif
+
+ifeq (${TEST_NAME},xbar_stress_all_with_reset_error)
+ UVM_TEST = xbar_error_test
+ UVM_TEST_SEQ = xbar_stress_all_with_reset_vseq
+endif
+
####################################################################################################
## Include the tool Makefile below ##
## Dont add anything else below it! ##
diff --git a/hw/ip/tlul/dv/env/seq_lib/xbar_base_vseq.sv b/hw/ip/tlul/dv/env/seq_lib/xbar_base_vseq.sv
index 2b89c52..5709300 100644
--- a/hw/ip/tlul/dv/env/seq_lib/xbar_base_vseq.sv
+++ b/hw/ip/tlul/dv/env/seq_lib/xbar_base_vseq.sv
@@ -16,6 +16,9 @@
uint min_req_cnt = 100;
uint max_req_cnt = 200;
+ // if seq crosses with the other seq, only need to enable device rsp thread
+ bit do_device_rsp = 1;
+
constraint req_cnt_c {
foreach (host_seq[i]) {
host_seq[i].req_cnt inside {[min_req_cnt : max_req_cnt]};
@@ -37,6 +40,7 @@
foreach (host_seq[i]) begin
host_seq[i] = xbar_tl_host_seq::type_id::create(
$sformatf("%0s_seq", xbar_hosts[i].host_name));
+ host_seq[i].set_max_outstanding(1 << VALID_HOST_ID_WIDTH);
// Default only send request to valid devices that is accessible by the host
foreach (xbar_devices[j]) begin
if (is_valid_path(xbar_hosts[i].host_name, xbar_devices[j].device_name)) begin
@@ -53,12 +57,14 @@
endfunction : seq_init
virtual task run_all_device_seq_nonblocking(bit out_of_order_rsp = 1);
- foreach (device_seq[i]) begin
- fork
- automatic int device_id = i;
- device_seq[device_id].out_of_order_rsp = out_of_order_rsp;
- device_seq[device_id].start(p_sequencer.device_seqr[device_id]);
- join_none
+ if (do_device_rsp) begin
+ foreach (device_seq[i]) begin
+ fork
+ automatic int device_id = i;
+ device_seq[device_id].out_of_order_rsp = out_of_order_rsp;
+ device_seq[device_id].start(p_sequencer.device_seqr[device_id]);
+ join_none
+ end
end
endtask
diff --git a/hw/ip/tlul/dv/env/seq_lib/xbar_stress_all_vseq.sv b/hw/ip/tlul/dv/env/seq_lib/xbar_stress_all_vseq.sv
new file mode 100644
index 0000000..bf8a6b0
--- /dev/null
+++ b/hw/ip/tlul/dv/env/seq_lib/xbar_stress_all_vseq.sv
@@ -0,0 +1,61 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+// combine all xbar seqs in one seq to run in parallel for mutiply times
+class xbar_stress_all_vseq extends xbar_base_vseq;
+ `uvm_object_utils(xbar_stress_all_vseq)
+
+ // reduce num_trans
+ constraint num_trans_c {
+ num_trans inside {[1:5]};
+ }
+
+ `uvm_object_new
+
+ task body();
+ string seq_names[] = {"xbar_sanity_vseq",
+ "xbar_random_vseq",
+ "xbar_access_same_device_vseq",
+ "xbar_same_source_vseq",
+ "xbar_unmapped_addr_vseq"};
+ run_all_device_seq_nonblocking();
+ for (int i = 1; i <= num_trans; i++) fork
+ begin // isolation thread
+ foreach (seq_names[i]) begin
+ automatic int seq_idx = i;
+ fork
+ if ($urandom_range(0, 1)) begin
+ uvm_sequence seq;
+ xbar_base_vseq xbar_vseq;
+ uint dly_to_start_seq;
+
+ seq = create_seq_by_name(seq_names[seq_idx]);
+ `downcast(xbar_vseq, seq)
+
+ // dut_init (reset) is done in xbar_stress_all_vseq
+ xbar_vseq.do_dut_init = 0;
+ // rsp thread is created in xbar_stress_all_vseq at line 22
+ xbar_vseq.do_device_rsp = 0;
+
+ xbar_vseq.set_sequencer(p_sequencer);
+ `DV_CHECK_RANDOMIZE_FATAL(xbar_vseq)
+ `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(dly_to_start_seq,
+ dly_to_start_seq dist {
+ 0 :/ 1,
+ [1:100] :/ 1,
+ [101:1000] :/ 1
+ };)
+ cfg.clk_rst_vif.wait_clks(dly_to_start_seq);
+ xbar_vseq.start(p_sequencer);
+ end
+ join_none
+ end
+ wait fork;
+ if ($urandom_range(0, 1)) dut_init();
+ `uvm_info(`gfn, $sformatf("finished run %0d/%0d", i, num_trans), UVM_LOW)
+ end // isolation thread
+ join
+ endtask : body
+
+endclass
diff --git a/hw/ip/tlul/dv/env/seq_lib/xbar_stress_all_with_reset_vseq.sv b/hw/ip/tlul/dv/env/seq_lib/xbar_stress_all_with_reset_vseq.sv
new file mode 100644
index 0000000..1a3534d
--- /dev/null
+++ b/hw/ip/tlul/dv/env/seq_lib/xbar_stress_all_with_reset_vseq.sv
@@ -0,0 +1,62 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+// one thread running the hmac_stress_all sequence
+// another thread randomly insert reset
+class xbar_stress_all_with_reset_vseq extends xbar_base_vseq;
+ `uvm_object_utils(xbar_stress_all_with_reset_vseq)
+
+ rand uint delay;
+
+ `uvm_object_new
+
+ constraint delay_c {
+ delay dist {
+ 0 :/ 1,
+ [1 :100] :/ 1,
+ [101 :10_000] :/ 8,
+ [10_001 :1_000_000] :/ 1
+ };
+ }
+
+ task body();
+ for (int i = 1; i <= num_trans; i++) begin
+ bit reset_ongoing;
+ fork
+ begin : seq_wo_reset
+ xbar_stress_all_vseq xbar_vseq;
+ xbar_vseq = xbar_stress_all_vseq::type_id::create("xbar_stress_all_vseq");
+
+ xbar_vseq.do_dut_init = 0;
+ xbar_vseq.set_sequencer(p_sequencer);
+ `DV_CHECK_RANDOMIZE_FATAL(xbar_vseq)
+ xbar_vseq.start(p_sequencer);
+ // once reset starts, need to wait until reset is done
+ wait (reset_ongoing == 0);
+ `uvm_info(`gfn, $sformatf("Finished run %0d/%0d w/o reset", i, num_trans), UVM_LOW)
+ end
+
+ begin : reset
+ `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(delay,
+ delay dist {
+ 1 :/ 1,
+ [2 :100] :/ 1,
+ [101 :10_000] :/ 8,
+ [10_001 :1_000_000] :/ 1
+ };)
+ cfg.clk_rst_vif.wait_clks(delay);
+ reset_ongoing = 1;
+ apply_reset("HARD");
+ reset_ongoing = 0;
+ `uvm_info(`gfn, $sformatf("Reset is issued for run %0d/%0d", i, num_trans), UVM_LOW)
+ end
+ join_any
+ disable fork;
+ // delay to avoid race condition when sending item and checking no item after reset occur at
+ // the same time
+ #1ps;
+ end // end for loop
+ endtask : body
+
+endclass
diff --git a/hw/ip/tlul/dv/env/seq_lib/xbar_vseq_list.sv b/hw/ip/tlul/dv/env/seq_lib/xbar_vseq_list.sv
index 420c052..aef1331 100644
--- a/hw/ip/tlul/dv/env/seq_lib/xbar_vseq_list.sv
+++ b/hw/ip/tlul/dv/env/seq_lib/xbar_vseq_list.sv
@@ -10,3 +10,5 @@
`include "xbar_access_same_device_vseq.sv"
`include "xbar_same_source_vseq.sv"
`include "xbar_unmapped_addr_vseq.sv"
+`include "xbar_stress_all_vseq.sv"
+`include "xbar_stress_all_with_reset_vseq.sv"
diff --git a/hw/ip/tlul/dv/env/xbar_scoreboard.sv b/hw/ip/tlul/dv/env/xbar_scoreboard.sv
index 25b989e..bcf2ccd 100644
--- a/hw/ip/tlul/dv/env/xbar_scoreboard.sv
+++ b/hw/ip/tlul/dv/env/xbar_scoreboard.sv
@@ -7,10 +7,10 @@
// Extend from common multi-streams scoreboard
// Use the device address map to determine the queue ID
// ------------------------------------------------------------------------
-class xbar_scoreboard extends scoreboard_pkg::scoreboard#(tl_seq_item);
-
- xbar_env_cfg cfg;
- xbar_env_cov cov;
+class xbar_scoreboard extends scoreboard_pkg::scoreboard #(.ITEM_T(tl_seq_item),
+ .RAL_T (dv_base_reg_block),
+ .CFG_T (xbar_env_cfg),
+ .COV_T (xbar_env_cov));
int chan_prefix_len = 7;
`uvm_component_utils(xbar_scoreboard)