From 0c1f1b0e42481cd6c577ab7cf873b11b510cfe10 Mon Sep 17 00:00:00 2001 From: Luca Colagrande Date: Wed, 29 Jun 2022 18:19:13 +0200 Subject: [PATCH] axi_mcast_xbar: Replace demux select indices with select masks --- Bender.yml | 4 +- scripts/run_vsim.sh | 18 +-- src/axi_mcast_demux.sv | 275 +++++++++++++++++++++-------------------- src/axi_mcast_xbar.sv | 121 +++++------------- test/tb_axi_xbar.sv | 45 ++++--- 5 files changed, 215 insertions(+), 248 deletions(-) diff --git a/Bender.yml b/Bender.yml index e88148e32..54bc45a69 100644 --- a/Bender.yml +++ b/Bender.yml @@ -8,7 +8,7 @@ package: - "Wolfgang Roenninger " dependencies: - common_cells: { git: "https://github.com/pulp-platform/common_cells.git", version: 1.21.0 } + common_cells: { git: "git@github.com:pulp-platform/common_cells.git", rev: "new/multiaddr-decode" } common_verification: { git: "https://github.com/pulp-platform/common_verification.git", version: 0.2.0 } export_include_dirs: @@ -30,6 +30,7 @@ sources: - src/axi_cut.sv - src/axi_delayer.sv - src/axi_demux.sv + - src/axi_mcast_demux.sv - src/axi_dw_downsizer.sv - src/axi_dw_upsizer.sv - src/axi_id_remap.sv @@ -57,6 +58,7 @@ sources: - src/axi_iw_converter.sv - src/axi_lite_xbar.sv - src/axi_xbar.sv + - src/axi_mcast_xbar.sv - target: synth_test files: diff --git a/scripts/run_vsim.sh b/scripts/run_vsim.sh index c72be8e8d..5b279ddae 100755 --- a/scripts/run_vsim.sh +++ b/scripts/run_vsim.sh @@ -160,14 +160,16 @@ exec_test() { done ;; axi_xbar) - for NumMst in 1 6; do - for NumSlv in 1 8; do - for Atop in 0 1; do - for Exclusive in 0 1; do - for UniqueIds in 0 1; do - call_vsim tb_axi_xbar -gTbNumMst=$NumMst -gTbNumSlv=$NumSlv \ - -gTbEnAtop=$Atop -gTbEnExcl=$Exclusive \ - -gTbUniqueIds=$UniqueIds + for Multicast in 0 1; do + for NumMst in 1 6; do + for NumSlv in 1 8; do + for Atop in 0 1; do + for Exclusive in 0 1; do + for UniqueIds in 0 1; do + call_vsim tb_axi_xbar -gTbMulticast=$Multicast -gTbNumMst=$NumMst -gTbNumSlv=$NumSlv \ + -gTbEnAtop=$Atop -gTbEnExcl=$Exclusive \ + -gTbUniqueIds=$UniqueIds + done done done done diff --git a/src/axi_mcast_demux.sv b/src/axi_mcast_demux.sv index 7d15e57c2..464a9bfb3 100644 --- a/src/axi_mcast_demux.sv +++ b/src/axi_mcast_demux.sv @@ -24,7 +24,7 @@ // axi_demux: Demultiplex an AXI bus from one slave port to multiple master ports. // See `doc/axi_demux.md` for the documentation, including the definition of parameters and ports. -module axi_demux #( +module axi_mcast_demux #( parameter int unsigned AxiIdWidth = 32'd0, parameter bit AtopSupport = 1'b1, parameter type aw_chan_t = logic, @@ -45,8 +45,7 @@ module axi_demux #( parameter bit SpillAr = 1'b1, parameter bit SpillR = 1'b0, // Dependent parameters, DO NOT OVERRIDE! - parameter int unsigned SelectWidth = (NoMstPorts > 32'd1) ? $clog2(NoMstPorts) : 32'd1, - parameter type select_t = logic [SelectWidth-1:0] + parameter type select_t = logic [NoMstPorts-1:0] ) ( input logic clk_i, input logic rst_ni, @@ -159,6 +158,10 @@ module axi_demux #( aw_chan_select_t slv_aw_chan_select; logic slv_aw_valid, slv_aw_ready; + // AW/AR channels inputs to mux + logic [NoMstPorts-1:0] mst_aw_readies; + logic [NoMstPorts-1:0] mst_ar_readies; + // AW ID counter select_t lookup_aw_select; logic aw_select_occupied, aw_id_cnt_full; @@ -283,6 +286,7 @@ module axi_demux #( (!(ar_id_cnt_full && slv_aw_chan_select.aw_chan.atop[axi_pkg::ATOP_R_RESP]) || !AtopSupport)) begin // there is a valid AW vector make the id lookup and go further, if it passes + // TODO colluca change to |(slv_aw_chan_select.aw_select & lookup_aw_select) if (slv_aw_valid && (!aw_select_occupied || (slv_aw_chan_select.aw_select == lookup_aw_select))) begin // connect the handshake @@ -558,11 +562,12 @@ module axi_demux #( .idx_o ( ) ); - assign ar_ready = ar_valid & mst_resps_i[slv_ar_chan_select.ar_select].ar_ready; - assign aw_ready = aw_valid & mst_resps_i[slv_aw_chan_select.aw_select].aw_ready; + // TODO colluca adapt with state machines + assign ar_ready = ar_valid & |(mst_ar_readies & slv_ar_chan_select.ar_select); + assign aw_ready = aw_valid & |(mst_aw_readies & slv_aw_chan_select.aw_select); // process that defines the individual demuxes and assignments for the arbitration - // as mst_reqs_o has to be drivem from the same always comb block! + // as mst_reqs_o has to be driven from the same always comb block! always_comb begin // default assignments mst_reqs_o = '0; @@ -573,14 +578,14 @@ module axi_demux #( // AW channel mst_reqs_o[i].aw = slv_aw_chan_select.aw_chan; mst_reqs_o[i].aw_valid = 1'b0; - if (aw_valid && (slv_aw_chan_select.aw_select == i)) begin + if (aw_valid && slv_aw_chan_select.aw_select[i]) begin mst_reqs_o[i].aw_valid = 1'b1; end // W channel mst_reqs_o[i].w = slv_w_chan; mst_reqs_o[i].w_valid = 1'b0; - if (!w_fifo_empty && (w_select == i)) begin + if (!w_fifo_empty && w_select[i]) begin mst_reqs_o[i].w_valid = slv_w_valid; slv_w_ready = mst_resps_i[i].w_ready; w_fifo_pop = slv_w_valid & mst_resps_i[i].w_ready & slv_w_chan.last; @@ -592,7 +597,7 @@ module axi_demux #( // AR channel mst_reqs_o[i].ar = slv_ar_chan_select.ar_chan; mst_reqs_o[i].ar_valid = 1'b0; - if (ar_valid && (slv_ar_chan_select.ar_select == i)) begin + if (ar_valid && slv_ar_chan_select.ar_select[i]) begin mst_reqs_o[i].ar_valid = 1'b1; end @@ -600,12 +605,14 @@ module axi_demux #( mst_reqs_o[i].r_ready = mst_r_readies[i]; end end - // unpack the response B and R channels for the arbitration + // unpack the response AW, AR, B and R channels for the arbitration/muxes for (genvar i = 0; i < NoMstPorts; i++) begin : gen_b_channels assign mst_b_chans[i] = mst_resps_i[i].b; assign mst_b_valids[i] = mst_resps_i[i].b_valid; assign mst_r_chans[i] = mst_resps_i[i].r; assign mst_r_valids[i] = mst_resps_i[i].r_valid; + assign mst_aw_readies[i] = mst_resps_i[i].aw_ready; + assign mst_ar_readies[i] = mst_resps_i[i].ar_ready; end @@ -620,6 +627,7 @@ module axi_demux #( $fatal(1, "AxiIdBits has to be equal or smaller than AxiIdWidth."); end default disable iff (!rst_ni); + // TODO colluca adapt aw_select: assume property( @(posedge clk_i) (slv_req_i.aw_valid |-> (slv_aw_select_i < NoMstPorts))) else $fatal(1, "slv_aw_select_i is %d: AW has selected a slave that is not defined.\ @@ -652,131 +660,131 @@ module axi_demux #( end endmodule -module axi_demux_id_counters #( - // the lower bits of the AXI ID that should be considered, results in 2**AXI_ID_BITS counters - parameter int unsigned AxiIdBits = 2, - parameter int unsigned CounterWidth = 4, - parameter type mst_port_select_t = logic -) ( - input clk_i, // Clock - input rst_ni, // Asynchronous reset active low - // lookup - input logic [AxiIdBits-1:0] lookup_axi_id_i, - output mst_port_select_t lookup_mst_select_o, - output logic lookup_mst_select_occupied_o, - // push - output logic full_o, - input logic [AxiIdBits-1:0] push_axi_id_i, - input mst_port_select_t push_mst_select_i, - input logic push_i, - // inject ATOPs in AR channel - input logic [AxiIdBits-1:0] inject_axi_id_i, - input logic inject_i, - // pop - input logic [AxiIdBits-1:0] pop_axi_id_i, - input logic pop_i -); - localparam int unsigned NoCounters = 2**AxiIdBits; - typedef logic [CounterWidth-1:0] cnt_t; - - // registers, each gets loaded when push_en[i] - mst_port_select_t [NoCounters-1:0] mst_select_q; - - // counter signals - logic [NoCounters-1:0] push_en, inject_en, pop_en, occupied, cnt_full; - - //----------------------------------- - // Lookup - //----------------------------------- - assign lookup_mst_select_o = mst_select_q[lookup_axi_id_i]; - assign lookup_mst_select_occupied_o = occupied[lookup_axi_id_i]; - //----------------------------------- - // Push and Pop - //----------------------------------- - assign push_en = (push_i) ? (1 << push_axi_id_i) : '0; - assign inject_en = (inject_i) ? (1 << inject_axi_id_i) : '0; - assign pop_en = (pop_i) ? (1 << pop_axi_id_i) : '0; - assign full_o = |cnt_full; - // counters - for (genvar i = 0; i < NoCounters; i++) begin : gen_counters - logic cnt_en, cnt_down, overflow; - cnt_t cnt_delta, in_flight; - always_comb begin - unique case ({push_en[i], inject_en[i], pop_en[i]}) - 3'b001 : begin // pop_i = -1 - cnt_en = 1'b1; - cnt_down = 1'b1; - cnt_delta = cnt_t'(1); - end - 3'b010 : begin // inject_i = +1 - cnt_en = 1'b1; - cnt_down = 1'b0; - cnt_delta = cnt_t'(1); - end - // 3'b011, inject_i & pop_i = 0 --> use default - 3'b100 : begin // push_i = +1 - cnt_en = 1'b1; - cnt_down = 1'b0; - cnt_delta = cnt_t'(1); - end - // 3'b101, push_i & pop_i = 0 --> use default - 3'b110 : begin // push_i & inject_i = +2 - cnt_en = 1'b1; - cnt_down = 1'b0; - cnt_delta = cnt_t'(2); - end - 3'b111 : begin // push_i & inject_i & pop_i = +1 - cnt_en = 1'b1; - cnt_down = 1'b0; - cnt_delta = cnt_t'(1); - end - default : begin // do nothing to the counters - cnt_en = 1'b0; - cnt_down = 1'b0; - cnt_delta = cnt_t'(0); - end - endcase - end - - delta_counter #( - .WIDTH ( CounterWidth ), - .STICKY_OVERFLOW ( 1'b0 ) - ) i_in_flight_cnt ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .clear_i ( 1'b0 ), - .en_i ( cnt_en ), - .load_i ( 1'b0 ), - .down_i ( cnt_down ), - .delta_i ( cnt_delta ), - .d_i ( '0 ), - .q_o ( in_flight ), - .overflow_o ( overflow ) - ); - assign occupied[i] = |in_flight; - assign cnt_full[i] = overflow | (&in_flight); - - // holds the selection signal for this id - `FFLARN(mst_select_q[i], push_mst_select_i, push_en[i], '0, clk_i, rst_ni) - -// pragma translate_off -`ifndef VERILATOR -`ifndef XSIM - // Validate parameters. - cnt_underflow: assert property( - @(posedge clk_i) disable iff (~rst_ni) (pop_en[i] |=> !overflow)) else - $fatal(1, "axi_demux_id_counters > Counter: %0d underflowed.\ - The reason is probably a faulty AXI response.", i); -`endif -`endif -// pragma translate_on - end -endmodule +// module axi_demux_id_counters #( +// // the lower bits of the AXI ID that should be considered, results in 2**AXI_ID_BITS counters +// parameter int unsigned AxiIdBits = 2, +// parameter int unsigned CounterWidth = 4, +// parameter type mst_port_select_t = logic +// ) ( +// input clk_i, // Clock +// input rst_ni, // Asynchronous reset active low +// // lookup +// input logic [AxiIdBits-1:0] lookup_axi_id_i, +// output mst_port_select_t lookup_mst_select_o, +// output logic lookup_mst_select_occupied_o, +// // push +// output logic full_o, +// input logic [AxiIdBits-1:0] push_axi_id_i, +// input mst_port_select_t push_mst_select_i, +// input logic push_i, +// // inject ATOPs in AR channel +// input logic [AxiIdBits-1:0] inject_axi_id_i, +// input logic inject_i, +// // pop +// input logic [AxiIdBits-1:0] pop_axi_id_i, +// input logic pop_i +// ); +// localparam int unsigned NoCounters = 2**AxiIdBits; +// typedef logic [CounterWidth-1:0] cnt_t; + +// // registers, each gets loaded when push_en[i] +// mst_port_select_t [NoCounters-1:0] mst_select_q; + +// // counter signals +// logic [NoCounters-1:0] push_en, inject_en, pop_en, occupied, cnt_full; + +// //----------------------------------- +// // Lookup +// //----------------------------------- +// assign lookup_mst_select_o = mst_select_q[lookup_axi_id_i]; +// assign lookup_mst_select_occupied_o = occupied[lookup_axi_id_i]; +// //----------------------------------- +// // Push and Pop +// //----------------------------------- +// assign push_en = (push_i) ? (1 << push_axi_id_i) : '0; +// assign inject_en = (inject_i) ? (1 << inject_axi_id_i) : '0; +// assign pop_en = (pop_i) ? (1 << pop_axi_id_i) : '0; +// assign full_o = |cnt_full; +// // counters +// for (genvar i = 0; i < NoCounters; i++) begin : gen_counters +// logic cnt_en, cnt_down, overflow; +// cnt_t cnt_delta, in_flight; +// always_comb begin +// unique case ({push_en[i], inject_en[i], pop_en[i]}) +// 3'b001 : begin // pop_i = -1 +// cnt_en = 1'b1; +// cnt_down = 1'b1; +// cnt_delta = cnt_t'(1); +// end +// 3'b010 : begin // inject_i = +1 +// cnt_en = 1'b1; +// cnt_down = 1'b0; +// cnt_delta = cnt_t'(1); +// end +// // 3'b011, inject_i & pop_i = 0 --> use default +// 3'b100 : begin // push_i = +1 +// cnt_en = 1'b1; +// cnt_down = 1'b0; +// cnt_delta = cnt_t'(1); +// end +// // 3'b101, push_i & pop_i = 0 --> use default +// 3'b110 : begin // push_i & inject_i = +2 +// cnt_en = 1'b1; +// cnt_down = 1'b0; +// cnt_delta = cnt_t'(2); +// end +// 3'b111 : begin // push_i & inject_i & pop_i = +1 +// cnt_en = 1'b1; +// cnt_down = 1'b0; +// cnt_delta = cnt_t'(1); +// end +// default : begin // do nothing to the counters +// cnt_en = 1'b0; +// cnt_down = 1'b0; +// cnt_delta = cnt_t'(0); +// end +// endcase +// end + +// delta_counter #( +// .WIDTH ( CounterWidth ), +// .STICKY_OVERFLOW ( 1'b0 ) +// ) i_in_flight_cnt ( +// .clk_i ( clk_i ), +// .rst_ni ( rst_ni ), +// .clear_i ( 1'b0 ), +// .en_i ( cnt_en ), +// .load_i ( 1'b0 ), +// .down_i ( cnt_down ), +// .delta_i ( cnt_delta ), +// .d_i ( '0 ), +// .q_o ( in_flight ), +// .overflow_o ( overflow ) +// ); +// assign occupied[i] = |in_flight; +// assign cnt_full[i] = overflow | (&in_flight); + +// // holds the selection signal for this id +// `FFLARN(mst_select_q[i], push_mst_select_i, push_en[i], '0, clk_i, rst_ni) + +// // pragma translate_off +// `ifndef VERILATOR +// `ifndef XSIM +// // Validate parameters. +// cnt_underflow: assert property( +// @(posedge clk_i) disable iff (~rst_ni) (pop_en[i] |=> !overflow)) else +// $fatal(1, "axi_demux_id_counters > Counter: %0d underflowed.\ +// The reason is probably a faulty AXI response.", i); +// `endif +// `endif +// // pragma translate_on +// end +// endmodule // interface wrapper `include "axi/assign.svh" `include "axi/typedef.svh" -module axi_demux_intf #( +module axi_mcast_demux_intf #( parameter int unsigned AXI_ID_WIDTH = 32'd0, // Synopsys DC requires default value for params parameter bit ATOP_SUPPORT = 1'b1, parameter int unsigned AXI_ADDR_WIDTH = 32'd0, @@ -793,8 +801,7 @@ module axi_demux_intf #( parameter bit SPILL_AR = 1'b1, parameter bit SPILL_R = 1'b0, // Dependent parameters, DO NOT OVERRIDE! - parameter int unsigned SELECT_WIDTH = (NO_MST_PORTS > 32'd1) ? $clog2(NO_MST_PORTS) : 32'd1, - parameter type select_t = logic [SELECT_WIDTH-1:0] // MST port select type + parameter type select_t = logic [NO_MST_PORTS-1:0] ) ( input logic clk_i, // Clock input logic rst_ni, // Asynchronous reset active low @@ -831,7 +838,7 @@ module axi_demux_intf #( `AXI_ASSIGN_TO_RESP(mst_resp[i], mst[i]) end - axi_demux #( + axi_mcast_demux #( .AxiIdWidth ( AXI_ID_WIDTH ), // ID Width .AtopSupport ( ATOP_SUPPORT ), .aw_chan_t ( aw_chan_t ), // AW Channel Type diff --git a/src/axi_mcast_xbar.sv b/src/axi_mcast_xbar.sv index 764084619..203179270 100644 --- a/src/axi_mcast_xbar.sv +++ b/src/axi_mcast_xbar.sv @@ -12,10 +12,12 @@ // - Wolfgang Roenninger // - Andreas Kurth // - Florian Zaruba +// - Luca Colagrande -// axi_xbar: Fully-connected AXI4+ATOP crossbar with an arbitrary number of slave and master ports. +// axi_multicast_xbar: Multicast-enabled fully-connected AXI4+ATOP crossbar with an arbitrary number +// of slave and master ports. // See `doc/axi_xbar.md` for the documentation, including the definition of parameters and ports. -module axi_xbar +module axi_mcast_xbar import cf_math_pkg::idx_width; #( parameter axi_pkg::xbar_cfg_t Cfg = '0, @@ -35,36 +37,20 @@ import cf_math_pkg::idx_width; parameter type mst_req_t = logic, parameter type mst_resp_t = logic, parameter type rule_t = axi_pkg::xbar_rule_64_t -`ifdef VCS - , localparam int unsigned MstPortsIdxWidth = - (Cfg.NoMstPorts == 32'd1) ? 32'd1 : unsigned'($clog2(Cfg.NoMstPorts)) -`endif ) ( - input logic clk_i, - input logic rst_ni, - input logic test_i, - input slv_req_t [Cfg.NoSlvPorts-1:0] slv_ports_req_i, - output slv_resp_t [Cfg.NoSlvPorts-1:0] slv_ports_resp_o, - output mst_req_t [Cfg.NoMstPorts-1:0] mst_ports_req_o, - input mst_resp_t [Cfg.NoMstPorts-1:0] mst_ports_resp_i, - input rule_t [Cfg.NoAddrRules-1:0] addr_map_i, - input logic [Cfg.NoSlvPorts-1:0] en_default_mst_port_i, -`ifdef VCS - input logic [Cfg.NoSlvPorts-1:0][MstPortsIdxWidth-1:0] default_mst_port_i -`else - input logic [Cfg.NoSlvPorts-1:0][idx_width(Cfg.NoMstPorts)-1:0] default_mst_port_i -`endif + input logic clk_i, + input logic rst_ni, + input logic test_i, + input slv_req_t [Cfg.NoSlvPorts-1:0] slv_ports_req_i, + output slv_resp_t [Cfg.NoSlvPorts-1:0] slv_ports_resp_o, + output mst_req_t [Cfg.NoMstPorts-1:0] mst_ports_req_o, + input mst_resp_t [Cfg.NoMstPorts-1:0] mst_ports_resp_i, + input rule_t [Cfg.NoAddrRules-1:0] addr_map_i ); typedef logic [Cfg.AxiAddrWidth-1:0] addr_t; // to account for the decoding error slave -`ifdef VCS - localparam int unsigned MstPortsIdxWidthOne = - (Cfg.NoMstPorts == 32'd1) ? 32'd1 : unsigned'($clog2(Cfg.NoMstPorts + 1)); - typedef logic [MstPortsIdxWidthOne-1:0] mst_port_idx_t; -`else - typedef logic [idx_width(Cfg.NoMstPorts + 1)-1:0] mst_port_idx_t; -`endif + typedef logic [(Cfg.NoMstPorts+1)-1:0] mst_port_mask_t; // signals from the axi_demuxes, one index more for decode error slv_req_t [Cfg.NoSlvPorts-1:0][Cfg.NoMstPorts:0] slv_reqs; @@ -78,16 +64,12 @@ import cf_math_pkg::idx_width; slv_resp_t [Cfg.NoMstPorts-1:0][Cfg.NoSlvPorts-1:0] mst_resps; for (genvar i = 0; i < Cfg.NoSlvPorts; i++) begin : gen_slv_port_demux -`ifdef VCS - logic [MstPortsIdxWidth-1:0] dec_aw, dec_ar; -`else - logic [idx_width(Cfg.NoMstPorts)-1:0] dec_aw, dec_ar; -`endif - mst_port_idx_t slv_aw_select, slv_ar_select; - logic dec_aw_valid, dec_aw_error; - logic dec_ar_valid, dec_ar_error; + logic [Cfg.NoMstPorts-1:0] dec_aw, dec_ar; + mst_port_mask_t slv_aw_select, slv_ar_select; + logic dec_aw_valid, dec_aw_error; + logic dec_ar_valid, dec_ar_error; - addr_decode #( + multiaddr_decode #( .NoIndices ( Cfg.NoMstPorts ), .NoRules ( Cfg.NoAddrRules ), .addr_t ( addr_t ), @@ -95,14 +77,12 @@ import cf_math_pkg::idx_width; ) i_axi_aw_decode ( .addr_i ( slv_ports_req_i[i].aw.addr ), .addr_map_i ( addr_map_i ), - .idx_o ( dec_aw ), + .mask_o ( dec_aw ), .dec_valid_o ( dec_aw_valid ), - .dec_error_o ( dec_aw_error ), - .en_default_idx_i ( en_default_mst_port_i[i] ), - .default_idx_i ( default_mst_port_i[i] ) + .dec_error_o ( dec_aw_error ) ); - addr_decode #( + multiaddr_decode #( .NoIndices ( Cfg.NoMstPorts ), .addr_t ( addr_t ), .NoRules ( Cfg.NoAddrRules ), @@ -110,47 +90,18 @@ import cf_math_pkg::idx_width; ) i_axi_ar_decode ( .addr_i ( slv_ports_req_i[i].ar.addr ), .addr_map_i ( addr_map_i ), - .idx_o ( dec_ar ), + .mask_o ( dec_ar ), .dec_valid_o ( dec_ar_valid ), - .dec_error_o ( dec_ar_error ), - .en_default_idx_i ( en_default_mst_port_i[i] ), - .default_idx_i ( default_mst_port_i[i] ) + .dec_error_o ( dec_ar_error ) ); assign slv_aw_select = (dec_aw_error) ? - mst_port_idx_t'(Cfg.NoMstPorts) : mst_port_idx_t'(dec_aw); + {1'b1, {Cfg.NoMstPorts{1'b0}}} : {1'b0, dec_aw}; assign slv_ar_select = (dec_ar_error) ? - mst_port_idx_t'(Cfg.NoMstPorts) : mst_port_idx_t'(dec_ar); + {1'b1, {Cfg.NoMstPorts{1'b0}}} : {1'b0, dec_ar}; - // make sure that the default slave does not get changed, if there is an unserved Ax - // pragma translate_off - `ifndef VERILATOR - `ifndef XSIM - default disable iff (~rst_ni); - default_aw_mst_port_en: assert property( - @(posedge clk_i) (slv_ports_req_i[i].aw_valid && !slv_ports_resp_o[i].aw_ready) - |=> $stable(en_default_mst_port_i[i])) - else $fatal (1, $sformatf("It is not allowed to change the default mst port\ - enable, when there is an unserved Aw beat. Slave Port: %0d", i)); - default_aw_mst_port: assert property( - @(posedge clk_i) (slv_ports_req_i[i].aw_valid && !slv_ports_resp_o[i].aw_ready) - |=> $stable(default_mst_port_i[i])) - else $fatal (1, $sformatf("It is not allowed to change the default mst port\ - when there is an unserved Aw beat. Slave Port: %0d", i)); - default_ar_mst_port_en: assert property( - @(posedge clk_i) (slv_ports_req_i[i].ar_valid && !slv_ports_resp_o[i].ar_ready) - |=> $stable(en_default_mst_port_i[i])) - else $fatal (1, $sformatf("It is not allowed to change the enable, when\ - there is an unserved Ar beat. Slave Port: %0d", i)); - default_ar_mst_port: assert property( - @(posedge clk_i) (slv_ports_req_i[i].ar_valid && !slv_ports_resp_o[i].ar_ready) - |=> $stable(default_mst_port_i[i])) - else $fatal (1, $sformatf("It is not allowed to change the default mst port\ - when there is an unserved Ar beat. Slave Port: %0d", i)); - `endif - `endif // pragma translate_on - axi_demux #( + axi_mcast_demux #( .AxiIdWidth ( Cfg.AxiIdWidthSlvPorts ), // ID Width .AtopSupport ( ATOPs ), .aw_chan_t ( slv_aw_chan_t ), // AW Channel Type @@ -280,7 +231,7 @@ endmodule `include "axi/assign.svh" `include "axi/typedef.svh" -module axi_xbar_intf +module axi_mcast_xbar_intf import cf_math_pkg::idx_width; #( parameter int unsigned AXI_USER_WIDTH = 0, @@ -288,23 +239,13 @@ import cf_math_pkg::idx_width; parameter bit ATOPS = 1'b1, parameter bit [Cfg.NoSlvPorts-1:0][Cfg.NoMstPorts-1:0] CONNECTIVITY = '1, parameter type rule_t = axi_pkg::xbar_rule_64_t -`ifdef VCS - , localparam int unsigned MstPortsIdxWidth = - (Cfg.NoMstPorts == 32'd1) ? 32'd1 : unsigned'($clog2(Cfg.NoMstPorts)) -`endif ) ( input logic clk_i, input logic rst_ni, input logic test_i, AXI_BUS.Slave slv_ports [Cfg.NoSlvPorts-1:0], AXI_BUS.Master mst_ports [Cfg.NoMstPorts-1:0], - input rule_t [Cfg.NoAddrRules-1:0] addr_map_i, - input logic [Cfg.NoSlvPorts-1:0] en_default_mst_port_i, -`ifdef VCS - input logic [Cfg.NoSlvPorts-1:0][MstPortsIdxWidth-1:0] default_mst_port_i -`else - input logic [Cfg.NoSlvPorts-1:0][idx_width(Cfg.NoMstPorts)-1:0] default_mst_port_i -`endif + input rule_t [Cfg.NoAddrRules-1:0] addr_map_i ); localparam int unsigned AxiIdWidthMstPorts = Cfg.AxiIdWidthSlvPorts + $clog2(Cfg.NoSlvPorts); @@ -345,7 +286,7 @@ import cf_math_pkg::idx_width; `AXI_ASSIGN_FROM_RESP(slv_ports[i], slv_resps[i]) end - axi_xbar #( + axi_mcast_xbar #( .Cfg (Cfg), .ATOPs ( ATOPS ), .Connectivity ( CONNECTIVITY ), @@ -371,9 +312,7 @@ import cf_math_pkg::idx_width; .slv_ports_resp_o (slv_resps), .mst_ports_req_o (mst_reqs ), .mst_ports_resp_i (mst_resps), - .addr_map_i, - .en_default_mst_port_i, - .default_mst_port_i + .addr_map_i ); endmodule diff --git a/test/tb_axi_xbar.sv b/test/tb_axi_xbar.sv index d8d75900d..793879cf9 100644 --- a/test/tb_axi_xbar.sv +++ b/test/tb_axi_xbar.sv @@ -26,6 +26,7 @@ module tb_axi_xbar #( parameter bit TbEnAtop = 1'b1, // enable atomic operations (ATOPs) parameter bit TbEnExcl = 1'b0, // enable exclusive accesses parameter bit TbUniqueIds = 1'b0, // restrict to only unique IDs + parameter bit TbMulticast = 1'b0, // test the multicast XBAR parameter int unsigned TbNumMst = 32'd6, // how many AXI masters there are parameter int unsigned TbNumSlv = 32'd8 // how many AXI slaves there are ); @@ -258,20 +259,36 @@ module tb_axi_xbar #( //----------------------------------- // DUT //----------------------------------- - axi_xbar_intf #( - .AXI_USER_WIDTH ( AxiUserWidth ), - .Cfg ( xbar_cfg ), - .rule_t ( rule_t ) - ) i_xbar_dut ( - .clk_i ( clk ), - .rst_ni ( rst_n ), - .test_i ( 1'b0 ), - .slv_ports ( master ), - .mst_ports ( slave ), - .addr_map_i ( AddrMap ), - .en_default_mst_port_i ( '0 ), - .default_mst_port_i ( '0 ) - ); + + if (TbMulticast) begin : g_multicast_xbar + axi_mcast_xbar_intf #( + .AXI_USER_WIDTH ( AxiUserWidth ), + .Cfg ( xbar_cfg ), + .rule_t ( rule_t ) + ) i_xbar_dut ( + .clk_i ( clk ), + .rst_ni ( rst_n ), + .test_i ( 1'b0 ), + .slv_ports ( master ), + .mst_ports ( slave ), + .addr_map_i ( AddrMap ) + ); + end else begin : g_standard_xbar + axi_xbar_intf #( + .AXI_USER_WIDTH ( AxiUserWidth ), + .Cfg ( xbar_cfg ), + .rule_t ( rule_t ) + ) i_xbar_dut ( + .clk_i ( clk ), + .rst_ni ( rst_n ), + .test_i ( 1'b0 ), + .slv_ports ( master ), + .mst_ports ( slave ), + .addr_map_i ( AddrMap ), + .en_default_mst_port_i ( '0 ), + .default_mst_port_i ( '0 ) + ); + end // logger for master modules for (genvar i = 0; i < TbNumMst; i++) begin : gen_master_logger