[xbar/dv] Support unmapped addr and add tests 1. update random seq framework 2. update scb to support unmapped addr 3. add tests - xbar_access_same_device - xbar_same_source - xbar_error_test: test d_error from device and disable protocol related constraint - xbar_unmapped_addr
diff --git a/hw/ip/tlul/dv/Makefile b/hw/ip/tlul/dv/Makefile index c29b52b..3780a80 100644 --- a/hw/ip/tlul/dv/Makefile +++ b/hw/ip/tlul/dv/Makefile
@@ -35,20 +35,21 @@ RUN_OPTS += +zero_delays=1 endif +# max outstanding 64, max 1000 cycle seems big enough ifeq (${TEST_NAME},xbar_sanity_large_delays) UVM_TEST_SEQ = xbar_sanity_vseq - RUN_OPTS += +min_req_delay=0 - RUN_OPTS += +max_req_delay=1000 - RUN_OPTS += +min_rsp_delay=0 - RUN_OPTS += +max_rsp_delay=1000 + RUN_OPTS += +max_host_req_delay=1000 + RUN_OPTS += +max_host_rsp_delay=1000 + RUN_OPTS += +max_device_req_delay=1000 + RUN_OPTS += +max_device_rsp_delay=1000 endif ifeq (${TEST_NAME},xbar_sanity_slow_rsp) UVM_TEST_SEQ = xbar_sanity_vseq - RUN_OPTS += +min_req_delay=0 - RUN_OPTS += +max_req_delay=10 - RUN_OPTS += +min_rsp_delay=0 - RUN_OPTS += +max_rsp_delay=1000 + RUN_OPTS += +max_host_req_delay=10 + RUN_OPTS += +max_host_rsp_delay=1000 + RUN_OPTS += +max_device_req_delay=10 + RUN_OPTS += +max_device_rsp_delay=1000 endif ifeq (${TEST_NAME},xbar_random) @@ -62,18 +63,48 @@ ifeq (${TEST_NAME},xbar_random_large_delays) UVM_TEST_SEQ = xbar_random_vseq - RUN_OPTS += +min_req_delay=0 - RUN_OPTS += +max_req_delay=1000 - RUN_OPTS += +min_rsp_delay=0 - RUN_OPTS += +max_rsp_delay=1000 + RUN_OPTS += +max_host_req_delay=1000 + RUN_OPTS += +max_host_rsp_delay=1000 + RUN_OPTS += +max_device_req_delay=1000 + RUN_OPTS += +max_device_rsp_delay=1000 endif ifeq (${TEST_NAME},xbar_random_slow_rsp) UVM_TEST_SEQ = xbar_random_vseq - RUN_OPTS += +min_req_delay=0 - RUN_OPTS += +max_req_delay=10 - RUN_OPTS += +min_rsp_delay=0 - RUN_OPTS += +max_rsp_delay=1000 + RUN_OPTS += +max_host_req_delay=10 + RUN_OPTS += +max_host_rsp_delay=1000 + RUN_OPTS += +max_device_req_delay=10 + RUN_OPTS += +max_device_rsp_delay=1000 +endif + +ifeq (${TEST_NAME},xbar_access_same_device) + UVM_TEST_SEQ = xbar_access_same_device_vseq +endif + +ifeq (${TEST_NAME},xbar_access_same_device_slow_rsp) + UVM_TEST_SEQ = xbar_access_same_device_vseq + RUN_OPTS += +max_host_req_delay=10 + RUN_OPTS += +max_host_rsp_delay=1000 + RUN_OPTS += +max_device_req_delay=10 + RUN_OPTS += +max_device_rsp_delay=1000 +endif + +ifeq (${TEST_NAME},xbar_same_source) + UVM_TEST_SEQ = xbar_same_source_vseq +endif + +ifeq (${TEST_NAME},xbar_error_random) + UVM_TEST = xbar_error_test + UVM_TEST_SEQ = xbar_random_vseq +endif + +ifeq (${TEST_NAME},xbar_unmapped_addr) + UVM_TEST_SEQ = xbar_unmapped_addr_vseq +endif + +ifeq (${TEST_NAME},xbar_error_and_unmapped_addr) + UVM_TEST = xbar_error_test + UVM_TEST_SEQ = xbar_unmapped_addr_vseq endif ####################################################################################################
diff --git a/hw/ip/tlul/dv/env/seq_lib/xbar_access_same_device_vseq.sv b/hw/ip/tlul/dv/env/seq_lib/xbar_access_same_device_vseq.sv new file mode 100644 index 0000000..0fbe1fb --- /dev/null +++ b/hw/ip/tlul/dv/env/seq_lib/xbar_access_same_device_vseq.sv
@@ -0,0 +1,32 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// test all hosts to access same device +// randomly pick one device, if host can acess this device, change it to only access this device +// repeat above for a few times +class xbar_access_same_device_vseq extends xbar_random_vseq; + + `uvm_object_utils(xbar_access_same_device_vseq) + `uvm_object_new + + virtual function void update_host_seq(); + int device_id = $urandom_range(0, xbar_devices.size - 1); + + if (cfg.en_cov) cov.same_device_access_cg.sample(device_id); + `uvm_info(`gfn, $sformatf("Picked device (%0s) for all hosts to access", + xbar_devices[device_id].device_name), UVM_HIGH) + + // change host to only access the picked device + foreach (host_seq[i]) begin + // if the selected device_id is a valid ID for this host, only store this id to use + if (device_id inside {host_seq[i].valid_device_id}) begin + host_seq[i].valid_device_id.delete(); + host_seq[i].valid_device_id.push_back(device_id); + `uvm_info(`gfn, $sformatf("Host (%0s) only accesses device (%0s)", + host_seq[i].get_name(), xbar_devices[device_id].device_name), UVM_HIGH) + end + end + endfunction + +endclass
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 637f520..2b89c52 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
@@ -25,14 +25,18 @@ `uvm_object_utils(xbar_base_vseq) `uvm_object_new + // call seq_init to create and configure host/device seq + // seq_init needs to be called before randomize as host_seq/device_seq are rand function void pre_randomize(); + seq_init(); + endfunction : pre_randomize + + virtual function void seq_init(); host_seq = new[xbar_hosts.size()]; device_seq = new[xbar_devices.size()]; 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].min_req_delay = p_sequencer.cfg.min_req_delay; - host_seq[i].max_req_delay = p_sequencer.cfg.max_req_delay; // 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 @@ -45,12 +49,10 @@ foreach (device_seq[i]) begin device_seq[i] = tl_device_seq::type_id::create( $sformatf("%0s_seq", xbar_devices[i].device_name)); - device_seq[i].min_rsp_delay = p_sequencer.cfg.min_rsp_delay; - device_seq[i].max_rsp_delay = p_sequencer.cfg.max_rsp_delay; end - endfunction : pre_randomize + endfunction : seq_init - virtual task run_device_seq_nonblocking(bit out_of_order_rsp = 1); + virtual task run_all_device_seq_nonblocking(bit out_of_order_rsp = 1); foreach (device_seq[i]) begin fork automatic int device_id = i; @@ -66,4 +68,29 @@ host_seq[host_id].get_full_name(), host_seq[host_id].req_cnt), UVM_LOW) endtask + + // run host seq in parallel and use num_enabled_hosts to decide how many hosts to run + virtual task run_all_host_seq_in_parallel(); + int completed_seq_cnt; + int host_cnt; + int host_id_q[$]; + + // make host_id_q store all host_id in random order + foreach (host_seq[i]) host_id_q.push_back(i); + host_id_q.shuffle(); + + foreach (host_id_q[i]) begin + fork + automatic int host_id = host_id_q[i]; + begin + run_host_seq(host_id); + completed_seq_cnt += 1; + end + join_none + host_cnt++; + if (host_cnt >= cfg.num_enabled_hosts) break; + end + wait(completed_seq_cnt == cfg.num_enabled_hosts); + endtask + endclass
diff --git a/hw/ip/tlul/dv/env/seq_lib/xbar_random_vseq.sv b/hw/ip/tlul/dv/env/seq_lib/xbar_random_vseq.sv index a2f5cf2..e38aec9 100644 --- a/hw/ip/tlul/dv/env/seq_lib/xbar_random_vseq.sv +++ b/hw/ip/tlul/dv/env/seq_lib/xbar_random_vseq.sv
@@ -2,28 +2,25 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 -// --------------------------------------------- -// Xbar environment virtual sequence -// --------------------------------------------- +// base random seq, most of xbar vseq will extend from this class xbar_random_vseq extends xbar_base_vseq; `uvm_object_utils(xbar_random_vseq) `uvm_object_new - virtual task body(); - int completed_seq_cnt; + // override it to control host seq in extended classes + virtual function void update_host_seq(); + endfunction - run_device_seq_nonblocking(); - foreach (host_seq[i]) begin - fork - automatic int host_id = i; - begin - run_host_seq(host_id); - completed_seq_cnt += 1; - end - join_none + virtual task body(); + run_all_device_seq_nonblocking(); + for (int i = 1; i <= num_trans; i++) begin + update_host_seq(); + run_all_host_seq_in_parallel(); + `uvm_info(`gfn, $sformatf("finished run %0d/%0d", i, num_trans), UVM_LOW) + // re-randomize for next loop + if (i <= num_trans) `DV_CHECK_RANDOMIZE_FATAL(this) end - wait (completed_seq_cnt == host_seq.size()); endtask endclass
diff --git a/hw/ip/tlul/dv/env/seq_lib/xbar_same_source_vseq.sv b/hw/ip/tlul/dv/env/seq_lib/xbar_same_source_vseq.sv new file mode 100644 index 0000000..121cb9f --- /dev/null +++ b/hw/ip/tlul/dv/env/seq_lib/xbar_same_source_vseq.sv
@@ -0,0 +1,32 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// test all hosts use same source id for each iteration +// reduce to 1-10 trans per iteration and increase interation number by x10 +class xbar_same_source_vseq extends xbar_random_vseq; + + `uvm_object_utils(xbar_same_source_vseq) + `uvm_object_new + + // reduce to 1-10 trans per iteration + function void seq_init(); + min_req_cnt = 1; + max_req_cnt = 10; + super.seq_init(); + endfunction + + virtual function void update_host_seq(); + int source = $urandom_range(0, (1 << VALID_HOST_ID_WIDTH) - 1); + + if (cfg.en_cov) cov.same_source_access_cg.sample(source); + `uvm_info(`gfn, $sformatf("Picked source (%0d) for all hosts", source), UVM_HIGH) + + // change host to only access the picked device + foreach (host_seq[i]) begin + host_seq[i].is_to_control_a_source = 1; + host_seq[i].controlled_a_source_val = source; + end + endfunction + +endclass
diff --git a/hw/ip/tlul/dv/env/seq_lib/xbar_sanity_vseq.sv b/hw/ip/tlul/dv/env/seq_lib/xbar_sanity_vseq.sv index 53ad5ae..2a8b4fc 100644 --- a/hw/ip/tlul/dv/env/seq_lib/xbar_sanity_vseq.sv +++ b/hw/ip/tlul/dv/env/seq_lib/xbar_sanity_vseq.sv
@@ -10,7 +10,7 @@ `uvm_object_new virtual task body(); - run_device_seq_nonblocking(.out_of_order_rsp(0)); + run_all_device_seq_nonblocking(.out_of_order_rsp(0)); foreach (host_seq[i]) begin run_host_seq(i); end
diff --git a/hw/ip/tlul/dv/env/seq_lib/xbar_seq_err_item.sv b/hw/ip/tlul/dv/env/seq_lib/xbar_seq_err_item.sv new file mode 100644 index 0000000..6d4b08b --- /dev/null +++ b/hw/ip/tlul/dv/env/seq_lib/xbar_seq_err_item.sv
@@ -0,0 +1,19 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// --------------------------------------------- +// TileLink sequence item with all protocol related constraint disabled +// --------------------------------------------- +class xbar_seq_err_item extends tl_seq_item; + + `uvm_object_utils(xbar_seq_err_item) + `uvm_object_new + + function void pre_randomize(); + disable_a_chan_protocol_constraint(); + no_d_error_c.constraint_mode(0); + endfunction + +endclass +
diff --git a/hw/ip/tlul/dv/env/seq_lib/xbar_seq_lib.sv b/hw/ip/tlul/dv/env/seq_lib/xbar_seq_lib.sv deleted file mode 100644 index 3ab47d1..0000000 --- a/hw/ip/tlul/dv/env/seq_lib/xbar_seq_lib.sv +++ /dev/null
@@ -1,38 +0,0 @@ -// Copyright lowRISC contributors. -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 - -// --------------------------------------------- -// TileLink agent sequence library -// --------------------------------------------- - -// Basic xbar TL host sequence -// TODO(taliu): Support illegal a_opcode -class xbar_tl_host_seq extends tl_host_seq; - - bit access_unclaimed_addr; - int valid_device_id[$]; - - `uvm_object_utils(xbar_tl_host_seq) - `uvm_object_new - - virtual function void randomize_req(tl_seq_item req, int idx); - int unsigned device_id; - if (valid_device_id.size() > 0) begin - device_id = $urandom_range(0, valid_device_id.size() - 1); - device_id = valid_device_id[device_id]; - end else begin - device_id = $urandom_range(0, xbar_devices.size() - 1); - end - if (!(req.randomize() with {a_valid_delay inside {[min_req_delay:max_req_delay]}; - // Keep msb to zero as it's reserved to add host ID - a_source[(SourceWidth - 1):VALID_HOST_ID_WIDTH] == 0; - if (!access_unclaimed_addr) { - a_addr inside {[xbar_devices[device_id].start_address : - xbar_devices[device_id].end_address]}; - }})) begin - `uvm_fatal(get_full_name(), "Cannot randomize req") - end - endfunction - -endclass
diff --git a/hw/ip/tlul/dv/env/seq_lib/xbar_tl_host_seq.sv b/hw/ip/tlul/dv/env/seq_lib/xbar_tl_host_seq.sv new file mode 100644 index 0000000..56d4ff7 --- /dev/null +++ b/hw/ip/tlul/dv/env/seq_lib/xbar_tl_host_seq.sv
@@ -0,0 +1,55 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// --------------------------------------------- +// TileLink agent sequence library +// --------------------------------------------- + +// Basic xbar TL host sequence +class xbar_tl_host_seq extends tl_host_seq; + + // if enabled, will allow to access both mapped and unmapped addr + bit en_unmapped_addr = 0; + + int valid_device_id[$]; + + // use below knob to control value of a_source in upper seq + bit is_to_control_a_source = 0; + int controlled_a_source_val; + + `uvm_object_utils(xbar_tl_host_seq) + `uvm_object_new + + virtual function void randomize_req(tl_seq_item req, int idx); + int unsigned device_id; + if (valid_device_id.size() > 0) begin + device_id = $urandom_range(0, valid_device_id.size() - 1); + device_id = valid_device_id[device_id]; + end else begin + device_id = $urandom_range(0, xbar_devices.size() - 1); + end + if (!(req.randomize() with {a_valid_delay inside {[min_req_delay:max_req_delay]}; + // Keep msb to zero as it's reserved to add host ID + a_source[(SourceWidth - 1):VALID_HOST_ID_WIDTH] == 0; + if (is_to_control_a_source) { + a_source == controlled_a_source_val; + } else { + // keep a_source unique + foreach (pending_req[i]) { + a_source != pending_req[i].a_source; + } + } + if (en_unmapped_addr) { + a_addr inside {[xbar_devices[device_id].start_address : + xbar_devices[device_id].end_address]} + dist {0 :/ 2, 1 :/ 1}; // 2/3 is unmapped + } else { + a_addr inside {[xbar_devices[device_id].start_address : + xbar_devices[device_id].end_address]}; + }})) begin + `uvm_fatal(get_full_name(), "Cannot randomize req") + end + endfunction + +endclass
diff --git a/hw/ip/tlul/dv/env/seq_lib/xbar_unmapped_addr_vseq.sv b/hw/ip/tlul/dv/env/seq_lib/xbar_unmapped_addr_vseq.sv new file mode 100644 index 0000000..a8214ec --- /dev/null +++ b/hw/ip/tlul/dv/env/seq_lib/xbar_unmapped_addr_vseq.sv
@@ -0,0 +1,19 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// allow host to drive unmapped addr +// expect xbar will return d_error=1 and won't pass it to any device +class xbar_unmapped_addr_vseq extends xbar_random_vseq; + + `uvm_object_utils(xbar_unmapped_addr_vseq) + `uvm_object_new + + // allow host to driver unmapped addr + virtual function void update_host_seq(); + foreach (host_seq[i]) begin + host_seq[i].en_unmapped_addr = 1; + end + endfunction + +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 5494be2..420c052 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
@@ -2,7 +2,11 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 -`include "xbar_seq_lib.sv" +`include "xbar_seq_err_item.sv" +`include "xbar_tl_host_seq.sv" `include "xbar_base_vseq.sv" `include "xbar_sanity_vseq.sv" `include "xbar_random_vseq.sv" +`include "xbar_access_same_device_vseq.sv" +`include "xbar_same_source_vseq.sv" +`include "xbar_unmapped_addr_vseq.sv"
diff --git a/hw/ip/tlul/dv/env/xbar_env.sv b/hw/ip/tlul/dv/env/xbar_env.sv index bb25d92..26fabda 100644 --- a/hw/ip/tlul/dv/env/xbar_env.sv +++ b/hw/ip/tlul/dv/env/xbar_env.sv
@@ -22,14 +22,14 @@ function void build_phase(uvm_phase phase); super.build_phase(phase); // Connect TileLink host and device agents - host_agent = new[cfg.num_of_hosts]; + host_agent = new[cfg.num_hosts]; foreach (host_agent[i]) begin host_agent[i] = tl_agent::type_id::create( $sformatf("%0s_agent", xbar_hosts[i].host_name), this); uvm_config_db#(tl_agent_cfg)::set(this, $sformatf("*%0s*", xbar_hosts[i].host_name),"cfg", cfg.host_agent_cfg[i]); end - device_agent = new[cfg.num_of_devices]; + device_agent = new[cfg.num_devices]; foreach (device_agent[i]) begin device_agent[i] = tl_agent::type_id::create( $sformatf("%0s_agent", xbar_devices[i].device_name), this); @@ -41,6 +41,9 @@ foreach (xbar_hosts[i]) begin scoreboard.add_item_port({"a_chan_", xbar_hosts[i].host_name}, scoreboard_pkg::kSrcPort); scoreboard.add_item_port({"d_chan_", xbar_hosts[i].host_name}, scoreboard_pkg::kDstPort); + // this queue is used to store expected rsp in d channel for unmapped address + scoreboard.add_item_queue({"host_unmapped_addr_", xbar_hosts[i].host_name}, + scoreboard_pkg::kInOrderCheck); end foreach (xbar_devices[i]) begin scoreboard.add_item_port({"a_chan_", xbar_devices[i].device_name}, scoreboard_pkg::kDstPort); @@ -57,8 +60,8 @@ super.connect_phase(phase); // Connect virtual sequencer if (cfg.is_active) begin - virtual_sequencer.host_seqr = new[cfg.num_of_hosts]; - virtual_sequencer.device_seqr = new[cfg.num_of_devices]; + virtual_sequencer.host_seqr = new[cfg.num_hosts]; + virtual_sequencer.device_seqr = new[cfg.num_devices]; foreach (host_agent[i]) begin virtual_sequencer.host_seqr[i] = host_agent[i].seqr; end
diff --git a/hw/ip/tlul/dv/env/xbar_env_cfg.sv b/hw/ip/tlul/dv/env/xbar_env_cfg.sv index 2ca7a9b..ad85e3e 100644 --- a/hw/ip/tlul/dv/env/xbar_env_cfg.sv +++ b/hw/ip/tlul/dv/env/xbar_env_cfg.sv
@@ -9,18 +9,23 @@ rand tl_agent_cfg host_agent_cfg[]; rand tl_agent_cfg device_agent_cfg[]; - int num_of_hosts; - int num_of_devices; - uint min_req_delay = 0; - uint max_req_delay = 20; - uint min_rsp_delay = 0; - uint max_rsp_delay = 20; + uint num_hosts; + uint num_devices; + uint num_enabled_hosts; + uint min_host_req_delay = 0; + uint max_host_req_delay = 20; + uint min_host_rsp_delay = 0; + uint max_host_rsp_delay = 20; + uint min_device_req_delay = 0; + uint max_device_req_delay = 20; + uint min_device_rsp_delay = 0; + uint max_device_rsp_delay = 20; `uvm_object_utils_begin(xbar_env_cfg) `uvm_field_array_object(host_agent_cfg, UVM_DEFAULT) `uvm_field_array_object(device_agent_cfg, UVM_DEFAULT) - `uvm_field_int(num_of_hosts, UVM_DEFAULT) - `uvm_field_int(num_of_devices, UVM_DEFAULT) + `uvm_field_int(num_hosts, UVM_DEFAULT) + `uvm_field_int(num_devices, UVM_DEFAULT) `uvm_object_utils_end `uvm_object_new @@ -29,22 +34,21 @@ bit [TL_AW-1:0] csr_addr_map_size = 2048); has_ral = 0; // no csr in xbar // Host TL agent cfg - num_of_hosts = xbar_hosts.size(); - host_agent_cfg = new[num_of_hosts]; + num_hosts = xbar_hosts.size(); + num_enabled_hosts = xbar_hosts.size(); + host_agent_cfg = new[num_hosts]; foreach (host_agent_cfg[i]) begin host_agent_cfg[i] = tl_agent_cfg::type_id:: create($sformatf("%0s_agent_cfg", xbar_hosts[i].host_name)); host_agent_cfg[i].is_host = 1; - host_agent_cfg[i].use_seq_item_a_valid_delay = 1; end // Device TL agent cfg - num_of_devices = xbar_devices.size(); - device_agent_cfg = new[num_of_devices]; + num_devices = xbar_devices.size(); + device_agent_cfg = new[num_devices]; foreach (device_agent_cfg[i]) begin device_agent_cfg[i] = tl_agent_cfg::type_id:: create($sformatf("%0s_agent_cfg", xbar_devices[i].device_name)); device_agent_cfg[i].is_host = 0; - device_agent_cfg[i].use_seq_item_d_valid_delay = 1; end endfunction endclass
diff --git a/hw/ip/tlul/dv/env/xbar_env_cov.sv b/hw/ip/tlul/dv/env/xbar_env_cov.sv index 60784bf..292b9de 100644 --- a/hw/ip/tlul/dv/env/xbar_env_cov.sv +++ b/hw/ip/tlul/dv/env/xbar_env_cov.sv
@@ -2,11 +2,40 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 +// sample at xbar_access_same_device_vseq +covergroup same_device_access_cg (uint num_dev) with function sample(uint dev_id); + cp_dev: coverpoint dev_id { + bins all_values[] = {[0:num_dev-1]}; + illegal_bins bin_others = default; + } +endgroup + +// sample at xbar_same_source_vseq +covergroup same_source_access_cg (uint num_source) with function sample(uint source); + cp_dev: coverpoint source { + bins all_values[] = {[0:num_source-1]}; + illegal_bins bin_others = default; + } +endgroup + class xbar_env_cov extends dv_base_env_cov #(.CFG_T(xbar_env_cfg)); + same_device_access_cg same_device_access_cg; + same_source_access_cg same_source_access_cg; + // cover mapped/unmapped addr per host + dv_base_generic_cov_obj host_access_mapped_addr_cg[string]; `uvm_component_utils(xbar_env_cov) function new(string name, uvm_component parent); super.new(name, parent); endfunction : new + virtual function void build_phase(uvm_phase phase); + super.build_phase(phase); + same_device_access_cg = new(cfg.num_devices); + same_source_access_cg = new(1 << VALID_HOST_ID_WIDTH); + foreach (xbar_hosts[i]) begin + host_access_mapped_addr_cg[xbar_hosts[i].host_name] = new(xbar_hosts[i].host_name); + end + endfunction + endclass
diff --git a/hw/ip/tlul/dv/env/xbar_params.svh b/hw/ip/tlul/dv/env/xbar_params.svh index e1eec35..d6c71b1 100644 --- a/hw/ip/tlul/dv/env/xbar_params.svh +++ b/hw/ip/tlul/dv/env/xbar_params.svh
@@ -24,6 +24,6 @@ tl_host_t xbar_hosts[$] = '{ '{"TlCorei", 0, '{"TlRom", "TlDebugMem", "TlRamMain", "TlEflash"}}, '{"TlCored", 1, '{"TlRom", "TlDebugMem", "TlRamMain", "TlEflash", "TlUart", "TlGpio", - "TlFlashCtrl", "TlRvTimer", "TlRvPlic"}}, + "TlSpiDevice", "TlFlashCtrl", "TlRvTimer", "TlHmac", "TlRvPlic"}}, '{"TlDmSba", 2, '{"TlRom", "TlRamMain", "TlEflash", "TlUart", "TlGpio", - "TlFlashCtrl", "TlRvTimer", "TlRvPlic"}}}; + "TlSpiDevice", "TlFlashCtrl", "TlRvTimer", "TlHmac", "TlRvPlic"}}};
diff --git a/hw/ip/tlul/dv/env/xbar_scoreboard.sv b/hw/ip/tlul/dv/env/xbar_scoreboard.sv index e973799..25b989e 100644 --- a/hw/ip/tlul/dv/env/xbar_scoreboard.sv +++ b/hw/ip/tlul/dv/env/xbar_scoreboard.sv
@@ -20,41 +20,51 @@ endfunction : new // Customize the get_queue_name function + // port_name is {"a/d_chan_", host/devce name} + // tl_channel is "a/d_chan_" + // tl_port is host/devce name virtual function string get_queue_name(tl_seq_item tr, string port_name); string queue_name; string tl_channel; string tl_port; tl_channel = port_name.substr(0, chan_prefix_len-1); - tl_port = port_name.substr(chan_prefix_len, port_name.len()-1); + tl_port = port_name.substr(chan_prefix_len, port_name.len() - 1); if (!port_dir.exists(port_name)) begin - `uvm_fatal(get_full_name(), $sformatf("Unexpected port name %0s", tl_port)) + `uvm_fatal(`gfn, $sformatf("Unexpected port name %0s", tl_port)) end begin - queue_name = {tl_channel, get_queue_suffix_name(tr, tl_port)}; + queue_name = get_queue_full_name(tr, tl_port, tl_channel); end - `uvm_info(get_full_name(), $sformatf("Scoreboard queue name : %0s", queue_name), UVM_HIGH) + `uvm_info(`gfn, $sformatf("Scoreboard queue name : %0s", queue_name), UVM_HIGH) return queue_name; endfunction // queue name is a_chan_``device_name`` or d_chan_``device_name``, device name is its suffix - // if port is a device, return device name - // if port is a host, need to find the pair device_name - virtual function string get_queue_suffix_name(tl_seq_item tr, string port_name); + // a_chan_/d_chan_ is prefix, which is from input queue_prefix + // if port is a device, return {queue_prefix, device_name} + // if port is a host, need to find the pair device_name, then return {queue_prefix, device_name} + // if unmapped addr, src is host a_chan, dst is host d_chan, so, + // use another prefix and return {"host_unmapped_addr_", host_name} + virtual function string get_queue_full_name(tl_seq_item tr, + string tl_port, + string queue_prefix); foreach (xbar_devices[i]) begin - if (xbar_devices[i].device_name == port_name) return port_name; + if (xbar_devices[i].device_name == tl_port) return {queue_prefix, tl_port}; end foreach (xbar_hosts[i]) begin - if (xbar_hosts[i].host_name == port_name) begin + if (xbar_hosts[i].host_name == tl_port) begin // Current port is a host port, get pair device port from the address foreach (xbar_devices[j]) begin if (tr.a_addr inside {[xbar_devices[j].start_address : xbar_devices[j].end_address]}) - return xbar_devices[j].device_name; + return {queue_prefix, xbar_devices[j].device_name}; end + // it's unmapped address + `uvm_info(`gfn, $sformatf("Unmapped addr: 0x%0h at %0s", tr.a_addr, tl_port), UVM_HIGH) + return {"host_unmapped_addr_", tl_port}; end end - // TODO(taliu) Determine how to handle unclaimed access - `uvm_error(get_full_name(), $sformatf("Found unclaimed access[%0s]: %0s", - port_name, tr.convert2string())) + `uvm_error(`gfn, $sformatf("Found unexpected item at[%0s]: %0s", + tl_port, tr.convert2string())) endfunction // from host to device, source ID may be changed and set all source ID to 0 @@ -66,16 +76,51 @@ return tr_modified; endfunction + // check if the item is from host and it has mapped address + function bit is_access_to_mapped_addr(tl_seq_item tr, string port_name); + string tl_port; + tl_port = port_name.substr(chan_prefix_len, port_name.len() - 1); + foreach (xbar_hosts[i]) begin + if (xbar_hosts[i].host_name == tl_port) begin + foreach (xbar_devices[j]) begin + if (tr.a_addr inside {[xbar_devices[j].start_address : + xbar_devices[j].end_address]}) begin + if (cfg.en_cov) cov.host_access_mapped_addr_cg[tl_port].sample(1); + return 1; // host port and mapped address + end + end + if (cfg.en_cov) cov.host_access_mapped_addr_cg[tl_port].sample(0); + return 0; // host port, but unmapped address + end + end + return 1; // not host port + endfunction + virtual function void process_src_packet(input tl_seq_item tr, input string port_name, output tl_seq_item transformed_tr[$]); - transformed_tr = {modify_source_id(tr)}; + if (is_access_to_mapped_addr(tr, port_name)) begin + transformed_tr = {modify_source_id(tr)}; + end else begin + tl_seq_item rsp; + `downcast(rsp, tr.clone()); + rsp.d_source = tr.a_source; + rsp.d_error = 1; + rsp.d_data = '1; + rsp.d_opcode = rsp.a_opcode == tlul_pkg::Get ? + tlul_pkg::AccessAckData : tlul_pkg::AccessAck; + transformed_tr = {rsp}; + end endfunction virtual function void process_dst_packet(input tl_seq_item tr, input string port_name, output tl_seq_item transformed_tr); - transformed_tr = modify_source_id(tr); + // if item is mapped, item will pass from h2d or d2h, source id may be changed and we don't + // predict it, modify all source_id to 0. + // if unmapped, item isn't passed down. source id shouldn't be changed. Check it + if (is_access_to_mapped_addr(tr, port_name)) transformed_tr = modify_source_id(tr); + else transformed_tr = tr; endfunction function string get_tl_port(string port_name);
diff --git a/hw/ip/tlul/dv/tests/xbar_base_test.sv b/hw/ip/tlul/dv/tests/xbar_base_test.sv index b71d163..87452f4 100644 --- a/hw/ip/tlul/dv/tests/xbar_base_test.sv +++ b/hw/ip/tlul/dv/tests/xbar_base_test.sv
@@ -11,15 +11,36 @@ test_timeout_ns = 600_000_000; // 600ms super.build_phase(phase); - void'($value$plusargs("min_req_delay=%d", cfg.min_req_delay)); - void'($value$plusargs("max_req_delay=%d", cfg.max_req_delay)); - void'($value$plusargs("min_rsp_delay=%d", cfg.min_rsp_delay)); - void'($value$plusargs("max_rsp_delay=%d", cfg.max_rsp_delay)); if (cfg.zero_delays) begin - cfg.min_req_delay = 0; - cfg.max_req_delay = 0; - cfg.min_rsp_delay = 0; - cfg.max_rsp_delay = 0; + cfg.min_host_req_delay = 0; + cfg.max_host_req_delay = 0; + cfg.min_host_rsp_delay = 0; + cfg.max_host_rsp_delay = 0; + cfg.min_device_req_delay = 0; + cfg.max_device_req_delay = 0; + cfg.min_device_rsp_delay = 0; + cfg.max_device_rsp_delay = 0; + end + void'($value$plusargs("min_host_req_delay=%d", cfg.min_host_req_delay)); + void'($value$plusargs("max_host_req_delay=%d", cfg.max_host_req_delay)); + void'($value$plusargs("min_host_rsp_delay=%d", cfg.min_host_rsp_delay)); + void'($value$plusargs("max_host_rsp_delay=%d", cfg.max_host_rsp_delay)); + void'($value$plusargs("min_device_req_delay=%d", cfg.min_device_req_delay)); + void'($value$plusargs("max_device_req_delay=%d", cfg.max_device_req_delay)); + void'($value$plusargs("min_device_rsp_delay=%d", cfg.min_device_rsp_delay)); + void'($value$plusargs("max_device_rsp_delay=%d", cfg.max_device_rsp_delay)); + void'($value$plusargs("num_enabled_hosts=%d", cfg.num_enabled_hosts)); + foreach (cfg.host_agent_cfg[i]) begin + cfg.host_agent_cfg[i].a_valid_delay_min = cfg.min_host_req_delay; + cfg.host_agent_cfg[i].a_valid_delay_max = cfg.max_host_req_delay; + cfg.host_agent_cfg[i].d_ready_delay_min = cfg.min_host_rsp_delay; + cfg.host_agent_cfg[i].d_ready_delay_max = cfg.max_host_rsp_delay; + end + foreach (cfg.device_agent_cfg[i]) begin + cfg.device_agent_cfg[i].d_valid_delay_min = cfg.min_device_req_delay; + cfg.device_agent_cfg[i].d_valid_delay_max = cfg.max_device_req_delay; + cfg.device_agent_cfg[i].a_ready_delay_min = cfg.min_device_rsp_delay; + cfg.device_agent_cfg[i].a_ready_delay_max = cfg.max_device_rsp_delay; end endfunction : build_phase
diff --git a/hw/ip/tlul/dv/tests/xbar_error_test.sv b/hw/ip/tlul/dv/tests/xbar_error_test.sv new file mode 100644 index 0000000..396ce54 --- /dev/null +++ b/hw/ip/tlul/dv/tests/xbar_error_test.sv
@@ -0,0 +1,15 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// override tl_seq_item with xbar_seq_err_item to disable TL protocol related constraint +class xbar_error_test extends xbar_base_test; + `uvm_component_utils(xbar_error_test) + `uvm_component_new + + virtual function void build_phase(uvm_phase phase); + super.build_phase(phase); + tl_seq_item::type_id::set_type_override(xbar_seq_err_item::get_type()); + endfunction : build_phase + +endclass : xbar_error_test
diff --git a/hw/ip/tlul/dv/tests/xbar_test.core b/hw/ip/tlul/dv/tests/xbar_test.core index 85cbb09..fe51c66 100644 --- a/hw/ip/tlul/dv/tests/xbar_test.core +++ b/hw/ip/tlul/dv/tests/xbar_test.core
@@ -11,6 +11,7 @@ files: - xbar_test_pkg.sv - xbar_base_test.sv: {is_include_file: true} + - xbar_error_test.sv: {is_include_file: true} file_type: systemVerilogSource targets:
diff --git a/hw/ip/tlul/dv/tests/xbar_test_pkg.sv b/hw/ip/tlul/dv/tests/xbar_test_pkg.sv index 5ee8488..927e4eb 100644 --- a/hw/ip/tlul/dv/tests/xbar_test_pkg.sv +++ b/hw/ip/tlul/dv/tests/xbar_test_pkg.sv
@@ -14,5 +14,6 @@ import dv_lib_pkg::*; `include "xbar_base_test.sv" + `include "xbar_error_test.sv" endpackage