[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