diff --git a/src/axi_mcast_demux.sv b/src/axi_mcast_demux.sv index a38780a1a..130c16cea 100644 --- a/src/axi_mcast_demux.sv +++ b/src/axi_mcast_demux.sv @@ -60,9 +60,10 @@ module axi_mcast_demux #( parameter bit SpillR = 1'b0, parameter type rule_t = logic, parameter int unsigned NoAddrRules = 32'd0, - parameter int unsigned NoMulticastRules = 32'd0, - parameter int unsigned NoMulticastPorts = 32'd0, - parameter int unsigned MaxMcastTrans = 32'd7, + parameter int unsigned NoMulticastRules = 32'd0, + parameter int unsigned NoMulticastPorts = 32'd0, + parameter int unsigned MaxMcastTrans = 32'd7, + parameter int unsigned McastToDefaultSlave = 1'b0, // Dependent parameters, DO NOT OVERRIDE! parameter int unsigned DecodeIdxWidth = ((NoMstPorts - 1) > 32'd1) ? $clog2(NoMstPorts - 1) : 32'd1, parameter int unsigned IdxSelectWidth = (NoMstPorts > 32'd1) ? $clog2(NoMstPorts) : 32'd1, @@ -186,11 +187,13 @@ module axi_mcast_demux #( // AW address decoder mask_rule_t [NoMulticastRules-1:0] multicast_rules; + logic idx_decoder_en_default, mask_decoder_en_default; decode_idx_t dec_aw_idx; logic dec_aw_idx_valid, dec_aw_idx_error; - logic [NoMulticastPorts-1:0] dec_aw_select_partial; + logic [NoMulticastPorts-1:0] dec_aw_select_partial, dec_aw_select_mask; aw_addr_t [NoMulticastPorts-1:0] dec_aw_addr, dec_aw_mask; - logic dec_aw_select_error; + logic dec_aw_valid, dec_aw_select_error; + logic [NoMstPorts-2:0] dec_aw_idx_mask; logic [NoMstPorts-2:0] dec_aw_select; aw_addr_t [NoMstPorts-1:0] slv_aw_addr, slv_aw_mask; mask_select_t slv_aw_select_mask; @@ -307,12 +310,12 @@ module axi_mcast_demux #( .idx_o (dec_aw_idx), .dec_valid_o (dec_aw_idx_valid), .dec_error_o (dec_aw_idx_error), - .en_default_idx_i(1'b0), - .default_idx_i ('0) + .en_default_idx_i(idx_decoder_en_default), + .default_idx_i (default_mst_port_i) ); end else begin : g_no_aw_idx_decode - assign dec_aw_idx_valid = en_default_mst_port_i & dec_aw_select_error; - assign dec_aw_idx_error = !en_default_mst_port_i; + assign dec_aw_idx_valid = 0; + assign dec_aw_idx_error = (!McastToDefaultSlave) ? !en_default_mst_port_i : 1'b1; assign dec_aw_idx = default_mst_port_i; end @@ -334,19 +337,37 @@ module axi_mcast_demux #( .addr_t (aw_addr_t), .rule_t (mask_rule_t) ) i_axi_aw_mask_decode ( - .addr_map_i (multicast_rules), - .addr_i (slv_aw_chan.addr), - .mask_i (slv_aw_chan.user.mcast), - .select_o (dec_aw_select_partial), - .addr_o (dec_aw_addr), - .mask_o (dec_aw_mask), - .dec_valid_o(), - .dec_error_o(dec_aw_select_error) + .addr_map_i (multicast_rules), + .addr_i (slv_aw_chan.addr), + .mask_i (slv_aw_chan.user.mcast), + .select_o (dec_aw_select_partial), + .addr_o (dec_aw_addr), + .mask_o (dec_aw_mask), + .dec_valid_o (dec_aw_valid), + .dec_error_o (dec_aw_select_error), + .en_default_idx_i(mask_decoder_en_default), + .default_idx_i (default_mst_port_i) ); - // Combine output from the two address decoders - // Note: assumes the slaves targeted by multicast lie at the lower indices - assign dec_aw_select = (dec_aw_idx_valid << dec_aw_idx) | dec_aw_select_partial; + // Enable default slave either on the regular address decoder or on the multi-address decoder. + // The multi-address decoder should be selected if the default slave can be a multicast target, + // whereas the regular address decoder should be selected when the default slave is not + // configured to be a multicast target (!McastToDefaultSlave). + assign idx_decoder_en_default = (!McastToDefaultSlave) && en_default_mst_port_i; + assign mask_decoder_en_default = McastToDefaultSlave && en_default_mst_port_i; + + // Combine output from the two address decoders. + // Note: assumes the slaves targeted by multicast lie at the lower indices. + // The two address decoders use two disjoint address maps, so it is guaranteed that only one + // at a time has valid output. This is true so long as the default slave is not enabled. In + // this case, one address decoder might match the default slave while the other matches a + // regular rule. We must prevent this, and only select the default slave if the other decoder + // had no match. + // TODO + assign idx_decoder_default_valid = idx_decoder_en_default && !dec_aw_idx_valid && !dec_aw_valid; + assign dec_aw_idx_mask = (dec_aw_idx_valid || idx_decoder_default_valid) << dec_aw_idx; + assign dec_aw_select_mask = dec_aw_select_partial & ~{NoMulticastPorts{dec_aw_idx_valid}}; + assign dec_aw_select = dec_aw_idx_mask | dec_aw_select_mask; assign slv_aw_select_mask = (dec_aw_idx_error && dec_aw_select_error) ? {1'b1, {(NoMstPorts-1){1'b0}}} : {1'b0, dec_aw_select}; diff --git a/src/axi_mcast_xbar.sv b/src/axi_mcast_xbar.sv index 4195255be..57da3651c 100644 --- a/src/axi_mcast_xbar.sv +++ b/src/axi_mcast_xbar.sv @@ -169,8 +169,9 @@ import cf_math_pkg::idx_width; .SpillR ( Cfg.LatencyMode[5] ), .rule_t ( rule_t ), .NoAddrRules ( Cfg.NoAddrRules ), - .NoMulticastRules( Cfg.NoMulticastRules ), - .NoMulticastPorts( Cfg.NoMulticastPorts ) + .NoMulticastRules ( Cfg.NoMulticastRules ), + .NoMulticastPorts ( Cfg.NoMulticastPorts ), + .McastToDefaultSlave( Cfg.McastToDefaultSlave ) ) i_axi_demux ( .clk_i, // Clock .rst_ni, // Asynchronous reset active low diff --git a/src/axi_pkg.sv b/src/axi_pkg.sv index 15c439752..c2b22e231 100644 --- a/src/axi_pkg.sv +++ b/src/axi_pkg.sv @@ -522,6 +522,8 @@ package axi_pkg; /// Number of master ports of the crossbar which can be targets of a multicast request. /// These are assumed to be connected at the lower indices. int unsigned NoMulticastPorts; + /// Whether the default slave (if any) is considered for multicast requests. + bit McastToDefaultSlave; } xbar_cfg_t; /// Commonly used rule types for `axi_xbar` (64-bit addresses).