From cb979cba7f4c9012a35649ea03b371bd8fff4555 Mon Sep 17 00:00:00 2001
From: Luca Colagrande <luca.colagrande3@gmail.com>
Date: Fri, 3 Nov 2023 19:00:16 +0100
Subject: [PATCH] axi_mcast_xbar: Add option to multicast to default slave

---
 src/axi_mcast_demux.sv | 61 ++++++++++++++++++++++++++++--------------
 src/axi_mcast_xbar.sv  |  5 ++--
 src/axi_pkg.sv         |  2 ++
 3 files changed, 46 insertions(+), 22 deletions(-)

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).