diff --git a/test/tb_axi_mcast_xbar.sv b/test/tb_axi_mcast_xbar.sv index 26446f29e..ae1b1daa2 100644 --- a/test/tb_axi_mcast_xbar.sv +++ b/test/tb_axi_mcast_xbar.sv @@ -75,8 +75,8 @@ module tb_axi_mcast_xbar #( UniqueIds: TbUniqueIds, AxiAddrWidth: TbAxiAddrWidth, AxiDataWidth: TbAxiDataWidth, - NoAddrRules: TbNumSlaves, - NoMulticastRules: TbNumSlaves, + NoAddrRules: TbNumSlaves * 2, + NoMulticastRules: TbNumSlaves * 2, NoMulticastPorts: TbNumSlaves }; typedef logic [TbAxiIdWidthMasters-1:0] id_mst_t; @@ -108,14 +108,15 @@ module tb_axi_mcast_xbar #( `AXI_TYPEDEF_RESP_T(slv_resp_t, b_chan_slv_t, r_chan_slv_t) // Each slave has its own address range: - localparam rule_t [xbar_cfg.NoAddrRules-1:0] AddrMap = addr_map_gen(); + localparam rule_t [xbar_cfg.NoAddrRules-1:0] AddrMap = {addr_map_gen(32'h1000_0000, 32'h10_0000), + addr_map_gen(32'h0b00_0000, 32'h1_0000)}; - function rule_t [xbar_cfg.NoAddrRules-1:0] addr_map_gen (); - for (int unsigned i = 0; i < xbar_cfg.NoAddrRules; i++) begin + function rule_t [xbar_cfg.NoMstPorts-1:0] addr_map_gen (addr_t base, addr_t offset); + for (int unsigned i = 0; i < xbar_cfg.NoMstPorts; i++) begin addr_map_gen[i] = rule_t'{ idx: unsigned'(i), - start_addr: i * 32'h0000_2000, - end_addr: (i+1) * 32'h0000_2000, + start_addr: base + offset * i, + end_addr: base + offset * (i + 1), default: '0 }; end @@ -225,9 +226,12 @@ module tb_axi_mcast_xbar #( axi_rand_master[i] = new( master_dv[i] ); end_of_sim[i] <= 1'b0; axi_rand_master[i].add_memory_region(AddrMap[0].start_addr, + AddrMap[xbar_cfg.NoMstPorts-1].end_addr, + axi_pkg::DEVICE_NONBUFFERABLE); + axi_rand_master[i].add_memory_region(AddrMap[xbar_cfg.NoMstPorts].start_addr, AddrMap[xbar_cfg.NoAddrRules-1].end_addr, axi_pkg::DEVICE_NONBUFFERABLE); - axi_rand_master[i].set_multicast_probability(0.5); + axi_rand_master[i].set_multicast_probability(50); axi_rand_master[i].reset(); @(posedge rst_n); axi_rand_master[i].run(TbNumReads, TbNumWrites); diff --git a/test/tb_axi_mcast_xbar_pkg.sv b/test/tb_axi_mcast_xbar_pkg.sv index 36cfe489b..406faffa6 100644 --- a/test/tb_axi_mcast_xbar_pkg.sv +++ b/test/tb_axi_mcast_xbar_pkg.sv @@ -155,20 +155,21 @@ package tb_axi_mcast_xbar_pkg; // populates the expected b response in its own id_queue and in case the atomic bit [5] // is set it also injects an expected response in the R channel. task automatic monitor_mst_aw(input int unsigned i); - axi_addr_t aw_addr; - axi_addr_t aw_mcast; - axi_addr_t rule_addr; - axi_addr_t rule_mask; - axi_addr_t aw_addr_masked; - axi_addr_t addrmap_masked; - idx_slv_t to_slave_idx[$]; - int unsigned num_slaves_matched; - axi_addr_t addr_to_slave[$]; - axi_addr_t mask_to_slave[$]; - bit decerr; - exp_ax_t exp_aw; - slv_axi_id_t exp_aw_id; - string slaves_str; + axi_addr_t aw_addr; + axi_addr_t aw_mcast; + axi_addr_t rule_addr; + axi_addr_t rule_mask; + axi_addr_t aw_addr_masked; + axi_addr_t addrmap_masked; + idx_slv_t to_slave_idx[$]; + axi_addr_t addr_to_slave[$]; + axi_addr_t mask_to_slave[$]; + bit [NoSlaves-1:0] matched_slaves; + int unsigned num_slaves_matched; + bit decerr; + exp_ax_t exp_aw; + slv_axi_id_t exp_aw_id; + string slaves_str; master_exp_t exp_b; @@ -180,29 +181,45 @@ package tb_axi_mcast_xbar_pkg; // Check to which slaves the transaction is directed or if it should go to a decerror. // Store the indices of the selected slaves (to_slave_idx) and the filtered address - // sets {addr, mask} to be forwarded to each slave (addr_to_slave, mask_to_slave). + // sets {addr, mask} to be forwarded to each slave (addr_queue, mask_queue). + + // Get address information from request aw_addr = masters_axi[i].aw_addr; aw_mcast = masters_axi[i].aw_user[AxiAddrWidth-1:0]; for (int k = 0; k < AxiAddrWidth; k++) aw_addr_masked[k] = aw_mcast[k] ? 1'bx : aw_addr[k]; $display("Trying to match: %b", aw_addr_masked); - for (int unsigned j = 0; j < NoAddrRules; j++) begin - // convert rule to mask (NAPOT) form - rule_mask = {'0, {$clog2(AddrMap[j].end_addr - AddrMap[j].start_addr){1'b1}}}; + + // Compare request against each address rule. We look at the rules starting from the + // last ones. In case of multiple rules matching for the same slave, we want only + // the last rule to have effect + for (int j = (NoAddrRules - 1); j >= 0; j--) begin + + // Convert address rule to mask (NAPOT) form + rule_mask = AddrMap[j].end_addr - AddrMap[j].start_addr - 1; rule_addr = AddrMap[j].start_addr; - // request goes to the slave if all bits match, out of those which are neither masked - // in the request nor in the addrmap rule for (int k = 0; k < AxiAddrWidth; k++) addrmap_masked[k] = rule_mask[k] ? 1'bx : rule_addr[k]; $display("With slave %3d : %b", AddrMap[j].idx, addrmap_masked); + + // Request goes to the slave if all bits match, out of those which are neither masked + // in the request nor in the addrmap rule if (&(~(aw_addr ^ rule_addr) | rule_mask | aw_mcast)) begin - to_slave_idx.push_back(AddrMap[j].idx); - mask_to_slave.push_back(aw_mcast & rule_mask); - addr_to_slave.push_back((~aw_mcast & aw_addr) | (aw_mcast & rule_addr)); - $display(" Push mask : %b", aw_mcast & rule_mask); - $display(" Push address : %b", (~aw_mcast & aw_addr) | (aw_mcast & rule_addr)); + int unsigned slave_idx = AddrMap[j].idx; + + // Only push the request if we haven't already matched it with a previous rule + // for the same slave + if (!matched_slaves[slave_idx]) begin + matched_slaves[slave_idx] = 1'b1; + to_slave_idx.push_back(slave_idx); + mask_to_slave.push_back(aw_mcast & rule_mask); + addr_to_slave.push_back((~aw_mcast & aw_addr) | (aw_mcast & rule_addr)); + $display(" Push mask : %32b", aw_mcast & rule_mask); + $display(" Push address : %32b", (~aw_mcast & aw_addr) | (aw_mcast & rule_addr)); + end end end + num_slaves_matched = to_slave_idx.size(); decerr = num_slaves_matched == 0;