Skip to content

Commit

Permalink
axi_mcast_xbar: Allow both regular and mask-based address rules
Browse files Browse the repository at this point in the history
  • Loading branch information
colluca committed Apr 26, 2023
1 parent f037dc0 commit 9a2cb6b
Show file tree
Hide file tree
Showing 6 changed files with 166 additions and 102 deletions.
89 changes: 72 additions & 17 deletions src/axi_mcast_demux.sv
Original file line number Diff line number Diff line change
Expand Up @@ -58,17 +58,24 @@ module axi_mcast_demux #(
parameter bit SpillB = 1'b0,
parameter bit SpillAr = 1'b1,
parameter bit SpillR = 1'b0,
parameter type aw_rule_t = logic,
parameter type rule_t = logic,
parameter int unsigned NoAddrRules = 32'd0,
parameter int unsigned NoMulticastRules = 32'd0,
parameter int unsigned NoMulticastPorts = 32'd0,
// 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,
parameter type decode_idx_t = logic [DecodeIdxWidth-1:0],
parameter type idx_select_t = logic [IdxSelectWidth-1:0],
parameter type mask_select_t = logic [NoMstPorts-1:0]
) (
input logic clk_i,
input logic rst_ni,
input logic test_i,
input rule_t [NoAddrRules-1:0] addr_map_i,
input logic en_default_mst_port_i,
input decode_idx_t default_mst_port_i,
// Slave Port
input aw_rule_t [NoMstPorts-2:0] slv_aw_addr_map_i,
input axi_req_t slv_req_i,
input idx_select_t slv_ar_select_i,
output axi_resp_t slv_resp_o,
Expand All @@ -82,6 +89,11 @@ module axi_mcast_demux #(
localparam int unsigned IdCounterWidth = cf_math_pkg::idx_width(MaxTrans);
typedef logic [IdCounterWidth-1:0] id_cnt_t;

typedef struct packed {
int unsigned idx;
aw_addr_t addr;
aw_addr_t mask;
} mask_rule_t;

// pass through if only one master port
if (NoMstPorts == 32'h1) begin : gen_no_demux
Expand Down Expand Up @@ -169,10 +181,14 @@ module axi_mcast_demux #(
logic slv_aw_ready;

// AW address decoder
logic dec_aw_valid, dec_aw_error;
aw_addr_t [NoMstPorts-2:0] dec_aw_addr, dec_aw_mask;
mask_rule_t [NoMulticastRules-1:0] multicast_rules;
logic dec_aw_idx_valid, dec_aw_idx_error;
logic dec_aw_select_valid, dec_aw_select_error;
decode_idx_t dec_aw_idx;
aw_addr_t [NoMstPorts-2:0] dec_aw_addr, dec_aw_mask;
logic [NoMstPorts-2:0] dec_aw_select;
aw_addr_t [NoMstPorts-1:0] slv_aw_addr, slv_aw_mask;
logic [NoMulticastPorts-1:0] dec_aw_select_partial;
aw_addr_t [NoMstPorts-1:0] slv_aw_addr, slv_aw_mask;
mask_select_t slv_aw_select_mask;
idx_select_t slv_aw_select;

Expand Down Expand Up @@ -275,21 +291,60 @@ module axi_mcast_demux #(
.data_o ( slv_aw_chan )
);

if (NoMulticastRules != NoAddrRules) begin : g_aw_idx_decode
// Compare request against {start_addr, end_addr} rules
addr_decode #(
.NoIndices(NoMstPorts - 1),
.NoRules (NoAddrRules - NoMulticastRules),
.addr_t (aw_addr_t),
.rule_t (rule_t)
) i_axi_aw_idx_decode (
.addr_i (slv_aw_chan.addr),
.addr_map_i (addr_map_i[NoAddrRules-1:NoMulticastRules]),
.idx_o (dec_aw_idx),
.dec_valid_o (dec_aw_idx_valid),
.dec_error_o (dec_aw_idx_error),
.en_default_idx_i(en_default_mst_port_i),
.default_idx_i (default_mst_port_i)
);
end else begin
assign dec_aw_idx_valid = '0;
assign dec_aw_idx = '0;
end

// Convert multicast rules to mask (NAPOT) form
// - mask = {'0, {log2(end_addr - start_addr){1'b1}}}
// - addr = start_addr / (end_addr - start_addr)
// More info in `multiaddr_decode` module
// TODO colluca: add checks on conversion feasibility
for (genvar i = 0; i < NoMulticastRules; i++) begin : g_multicast_rules
assign multicast_rules[i].idx = addr_map_i[i].idx;
assign multicast_rules[i].mask = addr_map_i[i].end_addr - addr_map_i[i].start_addr - 1;
assign multicast_rules[i].addr = addr_map_i[i].start_addr;
end

// Compare request against {addr, mask} rules
multiaddr_decode #(
.NoRules(NoMstPorts-1),
.NoIndices(NoMulticastPorts),
.NoRules(NoMulticastRules),
.addr_t (aw_addr_t),
.rule_t (aw_rule_t)
) i_axi_aw_decode (
.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),
.addr_map_i (slv_aw_addr_map_i),
.select_o (dec_aw_select),
.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_error)
.dec_valid_o(),
.dec_error_o(dec_aw_select_error)
);
assign slv_aw_select_mask = (dec_aw_error) ?

// 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;

assign slv_aw_select_mask = (dec_aw_idx_error && dec_aw_select_error) ?
{1'b1, {(NoMstPorts-1){1'b0}}} : {1'b0, dec_aw_select};
assign slv_aw_addr = {'0, dec_aw_addr};
assign slv_aw_mask = {'0, dec_aw_mask};
Expand Down Expand Up @@ -1039,7 +1094,7 @@ module axi_mcast_demux_intf #(
parameter bit SPILL_B = 1'b0,
parameter bit SPILL_AR = 1'b1,
parameter bit SPILL_R = 1'b0,
parameter type aw_rule_t = logic,
parameter type rule_t = logic,
// Dependent parameters, DO NOT OVERRIDE!
parameter int unsigned SELECT_WIDTH = (NO_MST_PORTS > 32'd1) ? $clog2(NO_MST_PORTS) : 32'd1,
parameter type idx_select_t = logic [SELECT_WIDTH-1:0],
Expand All @@ -1048,7 +1103,7 @@ module axi_mcast_demux_intf #(
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low
input logic test_i, // Testmode enable
input aw_rule_t [NO_MST_PORTS-2:0] slv_aw_addr_map_i,
input rule_t [NO_MST_PORTS-2:0] addr_map_i,
input idx_select_t slv_ar_select_i, // has to be stable, when ar_valid
AXI_BUS.Slave slv, // slave port
AXI_BUS.Master mst [NO_MST_PORTS-1:0] // master ports
Expand Down Expand Up @@ -1099,14 +1154,14 @@ module axi_mcast_demux_intf #(
.SpillB ( SPILL_B ),
.SpillAr ( SPILL_AR ),
.SpillR ( SPILL_R ),
.aw_rule_t ( aw_rule_t )
.rule_t ( rule_t )
) i_axi_demux (
.clk_i, // Clock
.rst_ni, // Asynchronous reset active low
.test_i, // Testmode enable
.addr_map_i ( addr_map_i ),
// slave port
.slv_req_i ( slv_req ),
.slv_aw_addr_map_i ( slv_aw_addr_map_i ),
.slv_ar_select_i ( slv_ar_select_i ),
.slv_resp_o ( slv_resp ),
// master port
Expand Down
70 changes: 42 additions & 28 deletions src/axi_mcast_xbar.sv
Original file line number Diff line number Diff line change
Expand Up @@ -61,17 +61,7 @@ import cf_math_pkg::idx_width;
/// axi_addr_t end_addr;
/// } rule_t;
/// ```
parameter type ar_rule_t = axi_pkg::xbar_rule_32_t,
/// Address rule type for the address decoders from `common_cells:multiaddr_decode`.
/// Example types are provided in `axi_pkg`.
/// Required struct fields:
/// ```
/// typedef struct packed {
/// axi_addr_t addr;
/// axi_addr_t mask;
/// } rule_t;
/// ```
parameter type aw_rule_t = axi_pkg::xbar_mask_rule_32_t
parameter type rule_t = axi_pkg::xbar_rule_32_t
) (
/// Clock, positive edge triggered.
input logic clk_i,
Expand All @@ -89,9 +79,20 @@ import cf_math_pkg::idx_width;
input mst_resp_t [Cfg.NoMstPorts-1:0] mst_ports_resp_i,
/// Address map array input for the crossbar. This map is global for the whole module.
/// It is used for routing the transactions to the respective master ports.

input ar_rule_t [Cfg.NoAddrRules-1:0] ar_addr_map_i,
input aw_rule_t [Cfg.NoAddrRules-1:0] aw_addr_map_i
input rule_t [Cfg.NoAddrRules-1:0] addr_map_i,
/// Enable default master port.
input logic [Cfg.NoSlvPorts-1:0] en_default_mst_port_i,
`ifdef VCS
/// Enables a default master port for each slave port. When this is enabled unmapped
/// transactions get issued at the master port given by `default_mst_port_i`.
/// When not used, tie to `'0`.
input logic [Cfg.NoSlvPorts-1:0][MstPortsIdxWidth-1:0] default_mst_port_i
`else
/// Enables a default master port for each slave port. When this is enabled unmapped
/// transactions get issued at the master port given by `default_mst_port_i`.
/// When not used, tie to `'0`.
input logic [Cfg.NoSlvPorts-1:0][idx_width(Cfg.NoMstPorts)-1:0] default_mst_port_i
`endif
);

// Address type for individual address signals
Expand Down Expand Up @@ -133,15 +134,15 @@ import cf_math_pkg::idx_width;
.NoIndices ( Cfg.NoMstPorts ),
.addr_t ( addr_t ),
.NoRules ( Cfg.NoAddrRules ),
.rule_t ( ar_rule_t )
.rule_t ( rule_t )
) i_axi_ar_decode (
.addr_i ( slv_ports_req_i[i].ar.addr ),
.addr_map_i ( ar_addr_map_i ),
.addr_map_i ( addr_map_i ),
.idx_o ( dec_ar_select ),
.dec_valid_o ( dec_ar_valid ),
.dec_error_o ( dec_ar_error ),
.en_default_idx_i ( '0 ),
.default_idx_i ( '0 )
.en_default_idx_i ( en_default_mst_port_i[i] ),
.default_idx_i ( default_mst_port_i[i] )
);
assign slv_ar_select = (dec_ar_error) ?
mst_port_idx_t'(Cfg.NoMstPorts) : mst_port_idx_t'(dec_ar_select);
Expand All @@ -166,12 +167,17 @@ import cf_math_pkg::idx_width;
.SpillB ( Cfg.LatencyMode[7] ),
.SpillAr ( Cfg.LatencyMode[6] ),
.SpillR ( Cfg.LatencyMode[5] ),
.aw_rule_t ( aw_rule_t )
.rule_t ( rule_t ),
.NoAddrRules ( Cfg.NoAddrRules ),
.NoMulticastRules( Cfg.NoMulticastRules ),
.NoMulticastPorts( Cfg.NoMulticastPorts )
) i_axi_demux (
.clk_i, // Clock
.rst_ni, // Asynchronous reset active low
.test_i, // Testmode enable
.slv_aw_addr_map_i( aw_addr_map_i ),
.addr_map_i ( addr_map_i ),
.en_default_mst_port_i ( en_default_mst_port_i[i] ),
.default_mst_port_i ( default_mst_port_i[i] ),
.slv_req_i ( slv_ports_req_i[i] ),
.slv_ar_select_i ( slv_ar_select ),
.slv_resp_o ( slv_ports_resp_o[i] ),
Expand Down Expand Up @@ -312,16 +318,24 @@ import cf_math_pkg::idx_width;
parameter axi_pkg::xbar_cfg_t Cfg = '0,
parameter bit ATOPS = 1'b1,
parameter bit [Cfg.NoSlvPorts-1:0][Cfg.NoMstPorts-1:0] CONNECTIVITY = '1,
parameter type ar_rule_t = axi_pkg::xbar_rule_64_t,
parameter type aw_rule_t = axi_pkg::xbar_mask_rule_64_t
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 ar_rule_t [Cfg.NoAddrRules-1:0] ar_addr_map_i,
input aw_rule_t [Cfg.NoAddrRules-1:0] aw_addr_map_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
);

localparam int unsigned AxiIdWidthMstPorts = Cfg.AxiIdWidthSlvPorts + $clog2(Cfg.NoSlvPorts);
Expand Down Expand Up @@ -383,8 +397,7 @@ import cf_math_pkg::idx_width;
.slv_resp_t ( slv_resp_t ),
.mst_req_t ( mst_req_t ),
.mst_resp_t ( mst_resp_t ),
.ar_rule_t ( ar_rule_t ),
.aw_rule_t ( aw_rule_t )
.rule_t ( rule_t )
) i_xbar (
.clk_i,
.rst_ni,
Expand All @@ -393,8 +406,9 @@ import cf_math_pkg::idx_width;
.slv_ports_resp_o(slv_resps),
.mst_ports_req_o (mst_reqs),
.mst_ports_resp_i(mst_resps),
.ar_addr_map_i,
.aw_addr_map_i
.addr_map_i,
.en_default_mst_port_i,
.default_mst_port_i
);

endmodule
8 changes: 7 additions & 1 deletion src/axi_pkg.sv
Original file line number Diff line number Diff line change
Expand Up @@ -510,10 +510,16 @@ package axi_pkg;
int unsigned AxiAddrWidth;
/// AXI4+ATOP data field width.
int unsigned AxiDataWidth;
/// The number of address rules defined for routing of the transactions.
/// The number of address rules defined for routing of the AR transactions.
/// Each master port can have multiple rules, should have however at least one.
/// If a transaction can not be routed the xbar will answer with an `axi_pkg::RESP_DECERR`.
int unsigned NoAddrRules;
/// The number of address rules to be considered for multicasting,
/// assumed to be at the start of `addr_map_i`.
int unsigned NoMulticastRules;
/// 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;
} xbar_cfg_t;

/// Commonly used rule types for `axi_xbar` (64-bit addresses).
Expand Down
4 changes: 3 additions & 1 deletion test/axi_synth_bench.sv
Original file line number Diff line number Diff line change
Expand Up @@ -920,7 +920,9 @@ module synth_axi_xbar #(
UniqueIds: UniqueIds,
AxiAddrWidth: AxiAddrWidth,
AxiDataWidth: AxiDataWidth,
NoAddrRules: NoSlvMst
NoAddrRules: NoSlvMst,
NoMulticastRules: 0,
NoMulticastPorts: 0
};

typedef axi_pkg::xbar_mask_rule_32_t aw_rule_t; // Has to be the same width as axi addr
Expand Down
Loading

0 comments on commit 9a2cb6b

Please sign in to comment.