From 0b7a6cda5ab9eccc8fbd9083e9c8fc4eba49366b Mon Sep 17 00:00:00 2001 From: Luca Colagrande Date: Fri, 15 May 2026 10:49:25 +0200 Subject: [PATCH 01/41] Bump to common_cells v2 --- Bender.yml | 9 +- doc/axi_demux.md | 1 - doc/axi_lite_demux.md | 1 - doc/axi_lite_mailbox.md | 1 - doc/axi_lite_xbar.md | 1 - doc/axi_xbar.md | 1 - scripts/axi_intercon_gen.py | 1 - src/axi_atop_filter.sv | 5 +- src/axi_burst_splitter_gran.sv | 44 ++++---- src/axi_burst_unwrap.sv | 36 +++---- src/axi_bus_compare.sv | 172 ++++++++++++++----------------- src/axi_cdc_dst.sv | 50 ++++----- src/axi_cdc_src.sv | 50 ++++----- src/axi_cut.sv | 20 ++-- src/axi_demux.sv | 32 +++--- src/axi_demux_id_counters.sv | 8 +- src/axi_demux_simple.sv | 12 +-- src/axi_dw_downsizer.sv | 38 ++++--- src/axi_dw_upsizer.sv | 27 +++-- src/axi_err_slv.sv | 32 +++--- src/axi_fifo.sv | 48 ++++----- src/axi_fifo_delay_dyn.sv | 22 ++-- src/axi_id_remap.sv | 32 +++--- src/axi_id_serialize.sv | 4 +- src/axi_interleaved_xbar.sv | 15 +-- src/axi_inval_filter.sv | 11 +- src/axi_isolate.sv | 12 +-- src/axi_lfsr.sv | 4 - src/axi_lite_demux.sv | 74 ++++++------- src/axi_lite_dw_converter.sv | 48 +++++---- src/axi_lite_from_mem.sv | 13 ++- src/axi_lite_lfsr.sv | 13 +-- src/axi_lite_mailbox.sv | 45 ++++---- src/axi_lite_mux.sv | 80 +++++++------- src/axi_lite_regs.sv | 16 +-- src/axi_lite_to_apb.sv | 39 ++++--- src/axi_lite_xbar.sv | 10 +- src/axi_mux.sv | 2 +- src/axi_serializer.sv | 20 ++-- src/axi_slave_compare.sv | 15 ++- src/axi_throttle.sv | 4 +- src/axi_to_axi_lite.sv | 23 ++--- src/axi_to_detailed_mem.sv | 83 +++++++-------- src/axi_to_mem_banked.sv | 14 +-- src/axi_to_mem_interleaved.sv | 15 +-- src/axi_to_mem_split.sv | 4 - src/axi_xbar.sv | 4 +- src/axi_xbar_unmuxed.sv | 4 +- src/axi_xp.sv | 3 +- test/tb_axi_bus_compare.sv | 7 +- test/tb_axi_fifo.sv | 1 - test/tb_axi_fifo.wave.do | 5 - test/tb_axi_lite_mailbox.sv | 1 - test/tb_axi_lite_mailbox.wave.do | 1 - test/tb_axi_lite_xbar.sv | 1 - test/tb_axi_lite_xbar.wave.do | 1 - test/tb_axi_slave_compare.sv | 1 - test/tb_axi_to_axi_lite.sv | 1 - test/tb_axi_to_mem_banked.sv | 3 +- test/tb_axi_xbar.sv | 1 - test/tb_axi_xbar.wave.do | 1 - 61 files changed, 551 insertions(+), 691 deletions(-) diff --git a/Bender.yml b/Bender.yml index 7105eca20..1fb1c458e 100644 --- a/Bender.yml +++ b/Bender.yml @@ -20,10 +20,13 @@ package: - "Nils Wistoff " - "Florian Zaruba " +remotes: + pulp: https://github.com/pulp-platform + dependencies: - common_cells: { git: "https://github.com/pulp-platform/common_cells.git", version: 1.39.0 } - common_verification: { git: "https://github.com/pulp-platform/common_verification.git", version: 0.2.5 } - tech_cells_generic: { git: "https://github.com/pulp-platform/tech_cells_generic.git", version: 0.2.2 } + common_cells: { git: "https://github.com/pulp-platform/common_cells.git", rev: v2-dev } + common_verification: 0.2.5 + tech_cells_generic: 0.2.2 export_include_dirs: - include diff --git a/doc/axi_demux.md b/doc/axi_demux.md index 4b8b964ed..ac28fcd99 100644 --- a/doc/axi_demux.md +++ b/doc/axi_demux.md @@ -45,7 +45,6 @@ If all `SpillXX` and `FallThrough` are disabled, all paths through this multiple |:----------------------------------|:------------| | `clk_i` | Clock to which all other signals (except `rst_ni`) are synchronous. | | `rst_ni` | Reset, asynchronous, active-low. | -| `test_i` | Test mode enable (active-high). | | `slv_*` (except `slv_*_select_i`) | Single slave port of the demultiplexer. | | `slv_{aw,ar}_select_i` | Index of the master port to which a write or read, respectively, is demultiplexed. This signal must be stable while a handshake on the AW respectively AR channel is [pending](../doc#pending). | | `mst_*` | Array of master ports of the demultiplexer. The array index of each port is the index of the master port. | diff --git a/doc/axi_lite_demux.md b/doc/axi_lite_demux.md index cafbf267a..b08bffc9f 100644 --- a/doc/axi_lite_demux.md +++ b/doc/axi_lite_demux.md @@ -38,7 +38,6 @@ If all `SpillXX` and `FallThrough` are disabled, all paths through this multiple |:----------------------------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `clk_i` | Clock to which all other signals (except `rst_ni`) are synchronous. | | `rst_ni` | Reset, asynchronous, active-low. | -| `test_i` | Test mode enable (active-high). | | `slv_*` (except `slv_*_select_i`) | Single slave port of the demultiplexer. | | `slv_{aw,ar}_select_i` | Index of the master port to which a write or read, respectively, is demultiplexed. This signal must be stable while a handshake on the AW respectively AR channel is [pending](../doc#pending). | | `mst_*` | Array of master ports of the demultiplexer. The array index of each port is the index of the master port. | diff --git a/doc/axi_lite_mailbox.md b/doc/axi_lite_mailbox.md index 7d5e2de52..e636e052f 100644 --- a/doc/axi_lite_mailbox.md +++ b/doc/axi_lite_mailbox.md @@ -27,7 +27,6 @@ This table describes the ports of the module. |:---------------|:---------------------------|:-------------------------------------------------------| | `clk_i` | `input logic` | clock | | `rst_ni` | `input logic` | asynchronous reset active low | -| `test_i` | `input logic` | testmode enable | | `slv_reqs_i` | `input req_lite_t [1:0]` | requests of the two AXI4-Lite ports | | `slv_resps_o` | `output resp_lite_t [1:0]` | responses of the two AXI4-Lite ports | | `irq_o` | `output logic [1:0]` | interrupt output for each port | diff --git a/doc/axi_lite_xbar.md b/doc/axi_lite_xbar.md index 047b3966d..af515e32d 100644 --- a/doc/axi_lite_xbar.md +++ b/doc/axi_lite_xbar.md @@ -55,7 +55,6 @@ If two crossbars are connected in both directions, meaning both have one of thei |:------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `clk_i` | Clock to which all other signals (except `rst_ni`) are synchronous. | | `rst_ni` | Reset, asynchronous, active-low. | -| `test_i` | Test mode enable (active-high). | | `slv_ports_*` | Array of slave ports of the crossbar. The array index of each port is the index of the slave port. This index will be prepended to all requests at one of the master ports. | | `mst_ports_*` | Array of master ports of the crossbar. The array index of each port is the index of the master port. | | `addr_map_i` | Address map of the crossbar (see section *Address Map* above). | diff --git a/doc/axi_xbar.md b/doc/axi_xbar.md index ca0c12108..ef33dda9a 100644 --- a/doc/axi_xbar.md +++ b/doc/axi_xbar.md @@ -71,7 +71,6 @@ If two crossbars are connected in both directions, meaning both have one of thei |:------------------------|:------------| | `clk_i` | Clock to which all other signals (except `rst_ni`) are synchronous. | | `rst_ni` | Reset, asynchronous, active-low. | -| `test_i` | Test mode enable (active-high). | | `slv_ports_*` | Array of slave ports of the crossbar. The array index of each port is the index of the slave port. This index will be prepended to all requests at one of the master ports. | | `mst_ports_*` | Array of master ports of the crossbar. The array index of each port is the index of the master port. | | `addr_map_i` | Address map of the crossbar (see section *Address Map* above). | diff --git a/scripts/axi_intercon_gen.py b/scripts/axi_intercon_gen.py index 9e8e606d5..2880cf965 100644 --- a/scripts/axi_intercon_gen.py +++ b/scripts/axi_intercon_gen.py @@ -150,7 +150,6 @@ def assigns(w, max_idw, masters, slaves): def instance_ports(w, id_width, masters, slaves): ports = [Port('clk_i' , 'clk_i'), Port('rst_ni', 'rst_ni'), - Port('test_i', "1'b0"), Port('slv_ports_req_i' , 'masters_req'), Port('slv_ports_resp_o', 'masters_resp'), Port('mst_ports_req_o' , 'slaves_req'), diff --git a/src/axi_atop_filter.sv b/src/axi_atop_filter.sv index 55ad491b2..64c82e1e4 100644 --- a/src/axi_atop_filter.sv +++ b/src/axi_atop_filter.sv @@ -345,13 +345,12 @@ module axi_atop_filter #( end end - stream_register #( - .T(r_resp_cmd_t) + cc_stream_register #( + .data_t(r_resp_cmd_t) ) r_resp_cmd ( .clk_i (clk_i), .rst_ni (rst_ni), .clr_i (1'b0), - .testmode_i (1'b0), .valid_i (r_resp_cmd_push_valid), .ready_o (r_resp_cmd_push_ready), .data_i (r_resp_cmd_push), diff --git a/src/axi_burst_splitter_gran.sv b/src/axi_burst_splitter_gran.sv index 2ae847a4d..1e244cbbd 100644 --- a/src/axi_burst_splitter_gran.sv +++ b/src/axi_burst_splitter_gran.sv @@ -92,7 +92,6 @@ module axi_burst_splitter_gran #( ) i_demux_supported_vs_unsupported ( .clk_i, .rst_ni, - .test_i ( 1'b0 ), .slv_req_i ( slv_req ), .slv_aw_select_i ( sel_aw_unsupported ), .slv_ar_select_i ( sel_ar_unsupported ), @@ -148,7 +147,6 @@ module axi_burst_splitter_gran #( ) i_err_slv ( .clk_i, .rst_ni, - .test_i ( 1'b0 ), .slv_req_i ( unsupported_req ), .slv_resp_o ( unsupported_resp ) ); @@ -384,12 +382,12 @@ module axi_burst_splitter_gran #( // -------------------------------------------------- // Flip-Flops // -------------------------------------------------- - `FFARN(b_err_q, b_err_d, 1'b0, clk_i, rst_ni) - `FFARN(b_state_q, b_state_d, BReady, clk_i, rst_ni) - `FFARN(r_last_q, r_last_d, 1'b0, clk_i, rst_ni) - `FFARN(r_state_q, r_state_d, RFeedthrough, clk_i, rst_ni) - `FFARN(w_len_q, w_len_d, 8'h00, clk_i, rst_ni) - `FFARN(w_len_vld_q, w_len_vld_d, 1'b0, clk_i, rst_ni) + `FF(b_err_q, b_err_d, 1'b0, clk_i, rst_ni) + `FF(b_state_q, b_state_d, BReady, clk_i, rst_ni) + `FF(r_last_q, r_last_d, 1'b0, clk_i, rst_ni) + `FF(r_state_q, r_state_d, RFeedthrough, clk_i, rst_ni) + `FF(w_len_q, w_len_d, 8'h00, clk_i, rst_ni) + `FF(w_len_vld_q, w_len_vld_d, 1'b0, clk_i, rst_ni) // -------------------------------------------------- // Assumptions and assertions @@ -572,9 +570,9 @@ module axi_burst_splitter_gran_ax_chan #( end // registers - `FFARN(ax_q, ax_d, '0, clk_i, rst_ni) - `FFARN(state_q, state_d, Idle, clk_i, rst_ni) - `FFARN(num_beats_q, num_beats_d, 9'h000, clk_i, rst_ni) + `FF(ax_q, ax_d, '0, clk_i, rst_ni) + `FF(state_q, state_d, Idle, clk_i, rst_ni) + `FF(num_beats_q, num_beats_d, 9'h000, clk_i, rst_ni) endmodule @@ -621,8 +619,8 @@ module axi_burst_splitter_gran_counters #( assign alloc_pld_in.len = alloc_len_i; if (CutPath) begin : gen_spill - spill_register #( - .T ( alloc_pld_t ), + cc_spill_register #( + .data_t ( alloc_pld_t ), .Bypass ( 1'b0 ) ) i_spill_register_alloc ( .clk_i, @@ -647,8 +645,8 @@ module axi_burst_splitter_gran_counters #( cnt_t [MaxTxns-1:0] cnt_oup; cnt_idx_t cnt_free_idx, cnt_r_idx; for (genvar i = 0; i < MaxTxns; i++) begin : gen_cnt - delta_counter #( - .WIDTH ( $bits(cnt_t) ) + cc_delta_counter #( + .Width ( $bits(cnt_t) ) ) i_cnt ( .clk_i, .rst_ni, @@ -665,9 +663,9 @@ module axi_burst_splitter_gran_counters #( end assign cnt_inp = {1'b0, alloc_pld_out.len} + 1; - lzc #( - .WIDTH ( MaxTxns ), - .MODE ( 1'b0 ) // start counting at index 0 + cc_lzc #( + .Width ( MaxTxns ), + .Mode ( cc_pkg::LZC_TRAILING_ZERO_CNT ) ) i_lzc ( .in_i ( cnt_free ), .cnt_o ( cnt_free_idx ), @@ -676,10 +674,10 @@ module axi_burst_splitter_gran_counters #( logic idq_inp_req, idq_inp_gnt, idq_oup_gnt, idq_oup_valid, idq_oup_pop; - id_queue #( - .ID_WIDTH ( $bits(id_t) ), - .CAPACITY ( MaxTxns ), - .FULL_BW ( FullBW ), + cc_id_queue #( + .IdWidth ( $bits(id_t) ), + .Capacity ( MaxTxns ), + .FullBw ( FullBW ), .data_t ( cnt_idx_t ) ) i_idq ( .clk_i, @@ -731,7 +729,7 @@ module axi_burst_splitter_gran_counters #( end // registers - `FFARN(err_q, err_d, '0, clk_i, rst_ni) + `FF(err_q, err_d, '0, clk_i, rst_ni) `ifndef VERILATOR // pragma translate_off diff --git a/src/axi_burst_unwrap.sv b/src/axi_burst_unwrap.sv index 70f8cc9eb..516fb1847 100644 --- a/src/axi_burst_unwrap.sv +++ b/src/axi_burst_unwrap.sv @@ -85,7 +85,6 @@ module axi_burst_unwrap #( ) i_demux_supported_vs_unsupported ( .clk_i, .rst_ni, - .test_i ( 1'b0 ), .slv_req_i, .slv_aw_select_i ( sel_aw_unsupported ), .slv_ar_select_i ( sel_ar_unsupported ), @@ -123,7 +122,6 @@ module axi_burst_unwrap #( ) i_err_slv ( .clk_i, .rst_ni, - .test_i ( 1'b0 ), .slv_req_i ( unsupported_req ), .slv_resp_o ( unsupported_resp ) ); @@ -353,12 +351,12 @@ module axi_burst_unwrap #( // -------------------------------------------------- // Flip-Flops // -------------------------------------------------- - `FFARN(b_err_q, b_err_d, 1'b0, clk_i, rst_ni) - `FFARN(b_state_q, b_state_d, BReady, clk_i, rst_ni) - `FFARN(r_last_q, r_last_d, 1'b0, clk_i, rst_ni) - `FFARN(r_state_q, r_state_d, RFeedthrough, clk_i, rst_ni) - `FFARN(w_last_q, w_last_d, 1'b0, clk_i, rst_ni) - `FFARN(w_state_q, w_state_d, WReady, clk_i, rst_ni) + `FF(b_err_q, b_err_d, 1'b0, clk_i, rst_ni) + `FF(b_state_q, b_state_d, BReady, clk_i, rst_ni) + `FF(r_last_q, r_last_d, 1'b0, clk_i, rst_ni) + `FF(r_state_q, r_state_d, RFeedthrough, clk_i, rst_ni) + `FF(w_last_q, w_last_d, 1'b0, clk_i, rst_ni) + `FF(w_state_q, w_state_d, WReady, clk_i, rst_ni) // -------------------------------------------------- // Assumptions and assertions @@ -533,8 +531,8 @@ module axi_burst_unwrap_ax_chan #( end // registers - `FFARN(ax_q, ax_d, '0, clk_i, rst_ni) - `FFARN(state_q, state_d, Idle, clk_i, rst_ni) + `FF(ax_q, ax_d, '0, clk_i, rst_ni) + `FF(state_q, state_d, Idle, clk_i, rst_ni) endmodule /// Internal module of [`axi_burst_splitter`](module.axi_burst_splitter) to order transactions. @@ -567,8 +565,8 @@ module axi_burst_counters #( cnt_t [MaxTxns-1:0] cnt_oup; cnt_idx_t cnt_free_idx, cnt_r_idx; for (genvar i = 0; i < MaxTxns; i++) begin : gen_cnt - counter #( - .WIDTH ( $bits(cnt_t) ) + cc_counter #( + .Width ( $bits(cnt_t) ) ) i_cnt ( .clk_i, .rst_ni, @@ -584,9 +582,9 @@ module axi_burst_counters #( end assign cnt_inp = {1'b0, alloc_len_i} + 1; - lzc #( - .WIDTH ( MaxTxns ), - .MODE ( 1'b0 ) // start counting at index 0 + cc_lzc #( + .Width ( MaxTxns ), + .Mode ( 1'b0 ) // start counting at index 0 ) i_lzc ( .in_i ( cnt_free ), .cnt_o ( cnt_free_idx ), @@ -595,9 +593,9 @@ module axi_burst_counters #( logic idq_inp_req, idq_inp_gnt, idq_oup_gnt, idq_oup_valid, idq_oup_pop; - id_queue #( - .ID_WIDTH ( $bits(id_t) ), - .CAPACITY ( MaxTxns ), + cc_id_queue #( + .IdWidth ( $bits(id_t) ), + .Capacity ( MaxTxns ), .data_t ( cnt_idx_t ) ) i_idq ( .clk_i, @@ -649,6 +647,6 @@ module axi_burst_counters #( end // registers - `FFARN(err_q, err_d, '0, clk_i, rst_ni) + `FF(err_q, err_d, '0, clk_i, rst_ni) endmodule diff --git a/src/axi_bus_compare.sv b/src/axi_bus_compare.sv index e1a3426ee..09031a573 100644 --- a/src/axi_bus_compare.sv +++ b/src/axi_bus_compare.sv @@ -45,8 +45,6 @@ module axi_bus_compare #( input logic clk_i, /// Asynchronous reset, active low input logic rst_ni, - /// Testmode - input logic testmode_i, /// AXI4+ATOP A channel request in input axi_req_t axi_a_req_i, /// AXI4+ATOP A channel response out @@ -164,8 +162,8 @@ module axi_bus_compare #( //----------------------------------- // Channel A stream forks //----------------------------------- - stream_fork #( - .N_OUP ( 32'd2 ) + cc_stream_fork #( + .NumOup ( 32'd2 ) ) i_stream_fork_aw_a ( .clk_i, .rst_ni, @@ -175,8 +173,8 @@ module axi_bus_compare #( .ready_i ( {fifo_sel_ready_aw_a, axi_a_rsp_i.aw_ready} ) ); - stream_fork #( - .N_OUP ( 32'd2 ) + cc_stream_fork #( + .NumOup ( 32'd2 ) ) i_stream_fork_w_a ( .clk_i, .rst_ni, @@ -186,8 +184,8 @@ module axi_bus_compare #( .ready_i ( {fifo_sel_ready_w_a, axi_a_rsp_i.w_ready} ) ); - stream_fork #( - .N_OUP ( 32'd2 ) + cc_stream_fork #( + .NumOup ( 32'd2 ) ) i_stream_fork_b_a ( .clk_i, .rst_ni, @@ -197,8 +195,8 @@ module axi_bus_compare #( .ready_i ( {fifo_sel_ready_b_a, axi_a_req_i.b_ready} ) ); - stream_fork #( - .N_OUP ( 32'd2 ) + cc_stream_fork #( + .NumOup ( 32'd2 ) ) i_stream_fork_ar_a ( .clk_i, .rst_ni, @@ -208,8 +206,8 @@ module axi_bus_compare #( .ready_i ( {fifo_sel_ready_ar_a, axi_a_rsp_i.ar_ready} ) ); - stream_fork #( - .N_OUP ( 32'd2 ) + cc_stream_fork #( + .NumOup ( 32'd2 ) ) i_stream_fork_r_a ( .clk_i, .rst_ni, @@ -225,15 +223,14 @@ module axi_bus_compare #( //----------------------------------- for (genvar id = 0; id < 2**AxiIdWidth; id++) begin : gen_fifos_a - stream_fifo #( - .FALL_THROUGH ( 1'b0 ), - .DATA_WIDTH ( 1'b0 ), - .DEPTH ( FifoDepth ), - .T ( axi_aw_chan_t ) + cc_stream_fifo #( + .FallThrough ( 1'b0 ), + .DataWidth ( 1'b0 ), + .Depth ( FifoDepth ), + .data_t ( axi_aw_chan_t ) ) i_stream_fifo_aw_a ( .clk_i, .rst_ni, - .testmode_i, .flush_i ( 1'b0 ), .usage_o ( /* NOT CONNECTED */ ), .data_i ( axi_a_req_i.aw ), @@ -244,15 +241,14 @@ module axi_bus_compare #( .ready_i ( fifo_cmp_valid_aw_a [id] & fifo_cmp_valid_aw_b [id] ) ); - stream_fifo #( - .FALL_THROUGH ( 1'b0 ), - .DATA_WIDTH ( 1'b0 ), - .DEPTH ( FifoDepth ), - .T ( axi_b_chan_t ) + cc_stream_fifo #( + .FallThrough ( 1'b0 ), + .DataWidth ( 1'b0 ), + .Depth ( FifoDepth ), + .data_t ( axi_b_chan_t ) ) i_stream_fifo_b_a ( .clk_i, .rst_ni, - .testmode_i, .flush_i ( 1'b0 ), .usage_o ( /* NOT CONNECTED */ ), .data_i ( axi_a_rsp_i.b ), @@ -263,15 +259,14 @@ module axi_bus_compare #( .ready_i ( fifo_cmp_valid_b_a [id] & fifo_cmp_valid_b_b [id] ) ); - stream_fifo #( - .FALL_THROUGH ( 1'b0 ), - .DATA_WIDTH ( 1'b0 ), - .DEPTH ( FifoDepth ), - .T ( axi_ar_chan_t ) + cc_stream_fifo #( + .FallThrough ( 1'b0 ), + .DataWidth ( 1'b0 ), + .Depth ( FifoDepth ), + .data_t ( axi_ar_chan_t ) ) i_stream_fifo_ar_a ( .clk_i, .rst_ni, - .testmode_i, .flush_i ( 1'b0 ), .usage_o ( /* NOT CONNECTED */ ), .data_i ( axi_a_req_i.ar ), @@ -283,15 +278,13 @@ module axi_bus_compare #( ); if (UseSize) begin : gen_r_size - stream_fifo #( - .FALL_THROUGH ( 1'b0 ), - .DATA_WIDTH ( $clog2(DataWidth/8)+3 ), - // .DATA_WIDTH ( 7+3 ), - .DEPTH ( 2*FifoDepth ) + cc_stream_fifo #( + .FallThrough ( 1'b0 ), + .DataWidth ( $clog2(DataWidth/8)+3 ), + .Depth ( 2*FifoDepth ) ) i_stream_fifo_w_size ( .clk_i, .rst_ni, - .testmode_i, .flush_i ( 1'b0 ), .usage_o (), .data_i ( {axi_a_req_i.ar.addr[$clog2(DataWidth/8)-1:0], axi_a_req_i.ar.size} ), @@ -322,15 +315,14 @@ module axi_bus_compare #( end - stream_fifo #( - .FALL_THROUGH ( 1'b0 ), - .DATA_WIDTH ( 1'b0 ), - .DEPTH ( FifoDepth ), - .T ( axi_r_chan_t ) + cc_stream_fifo #( + .FallThrough ( 1'b0 ), + .DataWidth ( 1'b0 ), + .Depth ( FifoDepth ), + .data_t ( axi_r_chan_t ) ) i_stream_fifo_r_a ( .clk_i, .rst_ni, - .testmode_i, .flush_i ( 1'b0 ), .usage_o ( /* NOT CONNECTED */ ), .data_i ( axi_a_rsp_i.r ), @@ -343,15 +335,13 @@ module axi_bus_compare #( end if (UseSize) begin : gen_w_size - stream_fifo #( - .FALL_THROUGH ( 1'b0 ), - .DATA_WIDTH ( $clog2(DataWidth/8)+3 ), - // .DATA_WIDTH ( 7+3 ), - .DEPTH ( FifoDepth ) + cc_stream_fifo #( + .FallThrough ( 1'b0 ), + .DataWidth ( $clog2(DataWidth/8)+3 ), + .Depth ( FifoDepth ) ) i_stream_fifo_w_size ( .clk_i, .rst_ni, - .testmode_i, .flush_i ( 1'b0 ), .usage_o (), .data_i ( {axi_a_req_i.aw.addr[$clog2(DataWidth/8)-1:0], axi_a_req_i.aw.size} ), @@ -381,15 +371,14 @@ module axi_bus_compare #( assign w_lower = '0; end - stream_fifo #( - .FALL_THROUGH ( 1'b0 ), - .DATA_WIDTH ( 1'b0 ), - .DEPTH ( FifoDepth ), - .T ( axi_w_chan_t ) + cc_stream_fifo #( + .FallThrough ( 1'b0 ), + .DataWidth ( 1'b0 ), + .Depth ( FifoDepth ), + .data_t ( axi_w_chan_t ) ) i_stream_fifo_w_a ( .clk_i, .rst_ni, - .testmode_i, .flush_i ( 1'b0 ), .usage_o ( /* NOT CONNECTED */ ), .data_i ( axi_a_req_i.w ), @@ -443,8 +432,8 @@ module axi_bus_compare #( //----------------------------------- // Channel B stream forks //----------------------------------- - stream_fork #( - .N_OUP ( 32'd2 ) + cc_stream_fork #( + .NumOup ( 32'd2 ) ) i_stream_fork_aw_b ( .clk_i, .rst_ni, @@ -454,8 +443,8 @@ module axi_bus_compare #( .ready_i ( {fifo_sel_ready_aw_b, axi_b_rsp_i.aw_ready} ) ); - stream_fork #( - .N_OUP ( 32'd2 ) + cc_stream_fork #( + .NumOup ( 32'd2 ) ) i_stream_fork_w_b ( .clk_i, .rst_ni, @@ -465,8 +454,8 @@ module axi_bus_compare #( .ready_i ( {fifo_sel_ready_w_b, axi_b_rsp_i.w_ready} ) ); - stream_fork #( - .N_OUP ( 32'd2 ) + cc_stream_fork #( + .NumOup ( 32'd2 ) ) i_stream_fork_b_b ( .clk_i, .rst_ni, @@ -476,8 +465,8 @@ module axi_bus_compare #( .ready_i ( {fifo_sel_ready_b_b, axi_b_req_i.b_ready} ) ); - stream_fork #( - .N_OUP ( 32'd2 ) + cc_stream_fork #( + .NumOup ( 32'd2 ) ) i_stream_fork_ar_b ( .clk_i, .rst_ni, @@ -487,8 +476,8 @@ module axi_bus_compare #( .ready_i ( {fifo_sel_ready_ar_b, axi_b_rsp_i.ar_ready} ) ); - stream_fork #( - .N_OUP ( 32'd2 ) + cc_stream_fork #( + .NumOup ( 32'd2 ) ) i_stream_fork_r_b ( .clk_i, .rst_ni, @@ -504,15 +493,14 @@ module axi_bus_compare #( //----------------------------------- for (genvar id = 0; id < 2**AxiIdWidth; id++) begin : gen_fifos_b - stream_fifo #( - .FALL_THROUGH ( 1'b0 ), - .DATA_WIDTH ( 1'b0 ), - .DEPTH ( FifoDepth ), - .T ( axi_aw_chan_t ) + cc_stream_fifo #( + .FallThrough ( 1'b0 ), + .DataWidth ( 1'b0 ), + .Depth ( FifoDepth ), + .data_t ( axi_aw_chan_t ) ) i_stream_fifo_aw_b ( .clk_i, .rst_ni, - .testmode_i, .flush_i ( 1'b0 ), .usage_o ( /* NOT CONNECTED */ ), .data_i ( axi_b_req_i.aw ), @@ -523,15 +511,14 @@ module axi_bus_compare #( .ready_i ( fifo_cmp_valid_aw_a [id] & fifo_cmp_valid_aw_b [id] ) ); - stream_fifo #( - .FALL_THROUGH ( 1'b0 ), - .DATA_WIDTH ( 1'b0 ), - .DEPTH ( FifoDepth ), - .T ( axi_b_chan_t ) + cc_stream_fifo #( + .FallThrough ( 1'b0 ), + .DataWidth ( 1'b0 ), + .Depth ( FifoDepth ), + .data_t ( axi_b_chan_t ) ) i_stream_fifo_b_b ( .clk_i, .rst_ni, - .testmode_i, .flush_i ( 1'b0 ), .usage_o ( /* NOT CONNECTED */ ), .data_i ( axi_b_rsp_i.b ), @@ -542,15 +529,14 @@ module axi_bus_compare #( .ready_i ( fifo_cmp_valid_b_a [id] & fifo_cmp_valid_b_b [id] ) ); - stream_fifo #( - .FALL_THROUGH ( 1'b0 ), - .DATA_WIDTH ( 1'b0 ), - .DEPTH ( FifoDepth ), - .T ( axi_ar_chan_t ) + cc_stream_fifo #( + .FallThrough ( 1'b0 ), + .DataWidth ( 1'b0 ), + .Depth ( FifoDepth ), + .data_t ( axi_ar_chan_t ) ) i_stream_fifo_ar_b ( .clk_i, .rst_ni, - .testmode_i, .flush_i ( 1'b0 ), .usage_o ( /* NOT CONNECTED */ ), .data_i ( axi_b_req_i.ar ), @@ -561,15 +547,14 @@ module axi_bus_compare #( .ready_i ( fifo_cmp_valid_ar_a [id] & fifo_cmp_valid_ar_b [id] ) ); - stream_fifo #( - .FALL_THROUGH ( 1'b0 ), - .DATA_WIDTH ( 1'b0 ), - .DEPTH ( FifoDepth ), - .T ( axi_r_chan_t ) + cc_stream_fifo #( + .FallThrough ( 1'b0 ), + .DataWidth ( 1'b0 ), + .Depth ( FifoDepth ), + .data_t ( axi_r_chan_t ) ) i_stream_fifo_r_b ( .clk_i, .rst_ni, - .testmode_i, .flush_i ( 1'b0 ), .usage_o ( /* NOT CONNECTED */ ), .data_i ( axi_b_rsp_i.r ), @@ -581,15 +566,14 @@ module axi_bus_compare #( ); end - stream_fifo #( - .FALL_THROUGH ( 1'b0 ), - .DATA_WIDTH ( 1'b0 ), - .DEPTH ( FifoDepth ), - .T ( axi_w_chan_t ) + cc_stream_fifo #( + .FallThrough ( 1'b0 ), + .DataWidth ( 1'b0 ), + .Depth ( FifoDepth ), + .data_t ( axi_w_chan_t ) ) i_stream_fifo_w_b ( .clk_i, .rst_ni, - .testmode_i, .flush_i ( 1'b0 ), .usage_o ( /* NOT CONNECTED */ ), .data_i ( axi_b_req_i.w ), diff --git a/src/axi_cdc_dst.sv b/src/axi_cdc_dst.sv index c3e76bfc1..cb831869f 100644 --- a/src/axi_cdc_dst.sv +++ b/src/axi_cdc_dst.sv @@ -57,16 +57,16 @@ module axi_cdc_dst #( input axi_resp_t dst_resp_i ); - cdc_fifo_gray_dst #( + cc_cdc_fifo_gray_dst #( `ifdef QUESTA // Workaround for a bug in Questa: Pass flat logic vector instead of struct to type parameter. - .T ( logic [$bits(aw_chan_t)-1:0] ), + .data_t ( logic [$bits(aw_chan_t)-1:0] ), `else // Other tools, such as VCS, have problems with type parameters constructed through `$bits()`. - .T ( aw_chan_t ), + .data_t ( aw_chan_t ), `endif - .LOG_DEPTH ( LogDepth ), - .SYNC_STAGES ( SyncStages ) + .LogDepth ( LogDepth ), + .SyncStages ( SyncStages ) ) i_cdc_fifo_gray_dst_aw ( .async_data_i ( async_data_slave_aw_data_i ), .async_wptr_i ( async_data_slave_aw_wptr_i ), @@ -78,14 +78,14 @@ module axi_cdc_dst #( .dst_ready_i ( dst_resp_i.aw_ready ) ); - cdc_fifo_gray_dst #( + cc_cdc_fifo_gray_dst #( `ifdef QUESTA - .T ( logic [$bits(w_chan_t)-1:0] ), + .data_t ( logic [$bits(w_chan_t)-1:0] ), `else - .T ( w_chan_t ), + .data_t ( w_chan_t ), `endif - .LOG_DEPTH ( LogDepth ), - .SYNC_STAGES ( SyncStages ) + .LogDepth ( LogDepth ), + .SyncStages ( SyncStages ) ) i_cdc_fifo_gray_dst_w ( .async_data_i ( async_data_slave_w_data_i ), .async_wptr_i ( async_data_slave_w_wptr_i ), @@ -97,14 +97,14 @@ module axi_cdc_dst #( .dst_ready_i ( dst_resp_i.w_ready ) ); - cdc_fifo_gray_src #( + cc_cdc_fifo_gray_src #( `ifdef QUESTA - .T ( logic [$bits(b_chan_t)-1:0] ), + .data_t ( logic [$bits(b_chan_t)-1:0] ), `else - .T ( b_chan_t ), + .data_t ( b_chan_t ), `endif - .LOG_DEPTH ( LogDepth ), - .SYNC_STAGES ( SyncStages ) + .LogDepth ( LogDepth ), + .SyncStages ( SyncStages ) ) i_cdc_fifo_gray_src_b ( .src_clk_i ( dst_clk_i ), .src_rst_ni ( dst_rst_ni ), @@ -116,14 +116,14 @@ module axi_cdc_dst #( .async_rptr_i ( async_data_slave_b_rptr_i ) ); - cdc_fifo_gray_dst #( + cc_cdc_fifo_gray_dst #( `ifdef QUESTA - .T ( logic [$bits(ar_chan_t)-1:0] ), + .data_t ( logic [$bits(ar_chan_t)-1:0] ), `else - .T ( ar_chan_t ), + .data_t ( ar_chan_t ), `endif - .LOG_DEPTH ( LogDepth ), - .SYNC_STAGES ( SyncStages ) + .LogDepth ( LogDepth ), + .SyncStages ( SyncStages ) ) i_cdc_fifo_gray_dst_ar ( .dst_clk_i, .dst_rst_ni, @@ -135,14 +135,14 @@ module axi_cdc_dst #( .async_rptr_o ( async_data_slave_ar_rptr_o ) ); - cdc_fifo_gray_src #( + cc_cdc_fifo_gray_src #( `ifdef QUESTA - .T ( logic [$bits(r_chan_t)-1:0] ), + .data_t ( logic [$bits(r_chan_t)-1:0] ), `else - .T ( r_chan_t ), + .data_t ( r_chan_t ), `endif - .LOG_DEPTH ( LogDepth ), - .SYNC_STAGES ( SyncStages ) + .LogDepth ( LogDepth ), + .SyncStages ( SyncStages ) ) i_cdc_fifo_gray_src_r ( .src_clk_i ( dst_clk_i ), .src_rst_ni ( dst_rst_ni ), diff --git a/src/axi_cdc_src.sv b/src/axi_cdc_src.sv index 36e4e6119..230d1eddc 100644 --- a/src/axi_cdc_src.sv +++ b/src/axi_cdc_src.sv @@ -57,15 +57,15 @@ module axi_cdc_src #( output logic [LogDepth:0] async_data_master_r_rptr_o ); - cdc_fifo_gray_src #( + cc_cdc_fifo_gray_src #( // Workaround for a bug in Questa (see comment in `axi_cdc_dst` for details). `ifdef QUESTA - .T ( logic [$bits(aw_chan_t)-1:0] ), + .data_t ( logic [$bits(aw_chan_t)-1:0] ), `else - .T ( aw_chan_t ), + .data_t ( aw_chan_t ), `endif - .LOG_DEPTH ( LogDepth ), - .SYNC_STAGES ( SyncStages ) + .LogDepth ( LogDepth ), + .SyncStages ( SyncStages ) ) i_cdc_fifo_gray_src_aw ( .src_clk_i, .src_rst_ni, @@ -77,14 +77,14 @@ module axi_cdc_src #( .async_rptr_i ( async_data_master_aw_rptr_i ) ); - cdc_fifo_gray_src #( + cc_cdc_fifo_gray_src #( `ifdef QUESTA - .T ( logic [$bits(w_chan_t)-1:0] ), + .data_t ( logic [$bits(w_chan_t)-1:0] ), `else - .T ( w_chan_t ), + .data_t ( w_chan_t ), `endif - .LOG_DEPTH ( LogDepth ), - .SYNC_STAGES ( SyncStages ) + .LogDepth ( LogDepth ), + .SyncStages ( SyncStages ) ) i_cdc_fifo_gray_src_w ( .src_clk_i, .src_rst_ni, @@ -96,14 +96,14 @@ module axi_cdc_src #( .async_rptr_i ( async_data_master_w_rptr_i ) ); - cdc_fifo_gray_dst #( + cc_cdc_fifo_gray_dst #( `ifdef QUESTA - .T ( logic [$bits(b_chan_t)-1:0] ), + .data_t ( logic [$bits(b_chan_t)-1:0] ), `else - .T ( b_chan_t ), + .data_t ( b_chan_t ), `endif - .LOG_DEPTH ( LogDepth ), - .SYNC_STAGES ( SyncStages ) + .LogDepth ( LogDepth ), + .SyncStages ( SyncStages ) ) i_cdc_fifo_gray_dst_b ( .dst_clk_i ( src_clk_i ), .dst_rst_ni ( src_rst_ni ), @@ -115,14 +115,14 @@ module axi_cdc_src #( .async_rptr_o ( async_data_master_b_rptr_o ) ); - cdc_fifo_gray_src #( + cc_cdc_fifo_gray_src #( `ifdef QUESTA - .T ( logic [$bits(ar_chan_t)-1:0] ), + .data_t ( logic [$bits(ar_chan_t)-1:0] ), `else - .T ( ar_chan_t ), + .data_t ( ar_chan_t ), `endif - .LOG_DEPTH ( LogDepth ), - .SYNC_STAGES ( SyncStages ) + .LogDepth ( LogDepth ), + .SyncStages ( SyncStages ) ) i_cdc_fifo_gray_src_ar ( .src_clk_i, .src_rst_ni, @@ -134,14 +134,14 @@ module axi_cdc_src #( .async_rptr_i ( async_data_master_ar_rptr_i ) ); - cdc_fifo_gray_dst #( + cc_cdc_fifo_gray_dst #( `ifdef QUESTA - .T ( logic [$bits(r_chan_t)-1:0] ), + .data_t ( logic [$bits(r_chan_t)-1:0] ), `else - .T ( r_chan_t ), + .data_t ( r_chan_t ), `endif - .LOG_DEPTH ( LogDepth ), - .SYNC_STAGES ( SyncStages ) + .LogDepth ( LogDepth ), + .SyncStages ( SyncStages ) ) i_cdc_fifo_gray_dst_r ( .dst_clk_i ( src_clk_i ), .dst_rst_ni ( src_rst_ni ), diff --git a/src/axi_cut.sv b/src/axi_cut.sv index ace6d7497..42c55d673 100644 --- a/src/axi_cut.sv +++ b/src/axi_cut.sv @@ -46,8 +46,8 @@ module axi_cut #( ); // a spill register for each channel - spill_register #( - .T ( aw_chan_t ), + cc_spill_register #( + .data_t ( aw_chan_t ), .Bypass ( BypassAw ) ) i_reg_aw ( .clk_i ( clk_i ), @@ -60,8 +60,8 @@ module axi_cut #( .data_o ( mst_req_o.aw ) ); - spill_register #( - .T ( w_chan_t ), + cc_spill_register #( + .data_t ( w_chan_t ), .Bypass ( BypassW ) ) i_reg_w ( .clk_i ( clk_i ), @@ -74,8 +74,8 @@ module axi_cut #( .data_o ( mst_req_o.w ) ); - spill_register #( - .T ( b_chan_t ), + cc_spill_register #( + .data_t ( b_chan_t ), .Bypass ( BypassB ) ) i_reg_b ( .clk_i ( clk_i ), @@ -88,8 +88,8 @@ module axi_cut #( .data_o ( slv_resp_o.b ) ); - spill_register #( - .T ( ar_chan_t ), + cc_spill_register #( + .data_t ( ar_chan_t ), .Bypass ( BypassAr ) ) i_reg_ar ( .clk_i ( clk_i ), @@ -102,8 +102,8 @@ module axi_cut #( .data_o ( mst_req_o.ar ) ); - spill_register #( - .T ( r_chan_t ), + cc_spill_register #( + .data_t ( r_chan_t ), .Bypass ( BypassR ) ) i_reg_r ( .clk_i ( clk_i ), diff --git a/src/axi_demux.sv b/src/axi_demux.sv index 899d83521..99a19c056 100644 --- a/src/axi_demux.sv +++ b/src/axi_demux.sv @@ -64,7 +64,6 @@ module axi_demux #( ) ( input logic clk_i, input logic rst_ni, - input logic test_i, // Slave Port input axi_req_t slv_req_i, input select_t slv_aw_select_i, @@ -86,8 +85,8 @@ module axi_demux #( select_t slv_aw_select, slv_ar_select; - spill_register #( - .T ( aw_chan_t ), + cc_spill_register #( + .data_t ( aw_chan_t ), .Bypass ( ~SpillAw ) ) i_aw_spill_reg ( .clk_i, @@ -99,8 +98,8 @@ module axi_demux #( .ready_i ( slv_resp_cut.aw_ready ), .data_o ( slv_req_cut.aw ) ); - spill_register #( - .T ( select_t ), + cc_spill_register #( + .data_t ( select_t ), .Bypass ( ~SpillAw ) ) i_aw_select_spill_reg ( .clk_i, @@ -116,8 +115,8 @@ module axi_demux #( assign slv_resp_o.aw_ready = slv_aw_ready_chan & slv_aw_ready_sel; assign slv_req_cut.aw_valid = slv_aw_valid_chan & slv_aw_valid_sel; - spill_register #( - .T ( w_chan_t ), + cc_spill_register #( + .data_t ( w_chan_t ), .Bypass ( ~SpillW ) ) i_w_spill_reg ( .clk_i, @@ -129,8 +128,8 @@ module axi_demux #( .ready_i ( slv_resp_cut.w_ready ), .data_o ( slv_req_cut.w ) ); - spill_register #( - .T ( ar_chan_t ), + cc_spill_register #( + .data_t ( ar_chan_t ), .Bypass ( ~SpillAr ) ) i_ar_spill_reg ( .clk_i, @@ -142,8 +141,8 @@ module axi_demux #( .ready_i ( slv_resp_cut.ar_ready ), .data_o ( slv_req_cut.ar ) ); - spill_register #( - .T ( select_t ), + cc_spill_register #( + .data_t ( select_t ), .Bypass ( ~SpillAr ) ) i_ar_sel_spill_reg ( .clk_i, @@ -159,8 +158,8 @@ module axi_demux #( assign slv_resp_o.ar_ready = slv_ar_ready_chan & slv_ar_ready_sel; assign slv_req_cut.ar_valid = slv_ar_valid_chan & slv_ar_valid_sel; - spill_register #( - .T ( b_chan_t ), + cc_spill_register #( + .data_t ( b_chan_t ), .Bypass ( ~SpillB ) ) i_b_spill_reg ( .clk_i, @@ -172,8 +171,8 @@ module axi_demux #( .ready_i ( slv_req_i.b_ready ), .data_o ( slv_resp_o.b ) ); - spill_register #( - .T ( r_chan_t ), + cc_spill_register #( + .data_t ( r_chan_t ), .Bypass ( ~SpillR ) ) i_r_spill_reg ( .clk_i, @@ -198,7 +197,6 @@ module axi_demux #( ) i_demux_simple ( .clk_i, .rst_ni, - .test_i, .slv_req_i ( slv_req_cut ), .slv_aw_select_i ( slv_aw_select ), @@ -234,7 +232,6 @@ module axi_demux_intf #( ) ( input logic clk_i, // Clock input logic rst_ni, // Asynchronous reset active low - input logic test_i, // Testmode enable input select_t slv_aw_select_i, // has to be stable, when aw_valid input select_t slv_ar_select_i, // has to be stable, when ar_valid AXI_BUS.Slave slv, // slave port @@ -289,7 +286,6 @@ module axi_demux_intf #( ) i_axi_demux ( .clk_i, // Clock .rst_ni, // Asynchronous reset active low - .test_i, // Testmode enable // slave port .slv_req_i ( slv_req ), .slv_aw_select_i ( slv_aw_select_i ), diff --git a/src/axi_demux_id_counters.sv b/src/axi_demux_id_counters.sv index 7e8c88da5..ab089dcc6 100644 --- a/src/axi_demux_id_counters.sv +++ b/src/axi_demux_id_counters.sv @@ -109,9 +109,9 @@ module axi_demux_id_counters #( endcase end - delta_counter #( - .WIDTH ( CounterWidth ), - .STICKY_OVERFLOW ( 1'b0 ) + cc_delta_counter #( + .Width ( CounterWidth ), + .StickyOverflow ( 1'b0 ) ) i_in_flight_cnt ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), @@ -128,7 +128,7 @@ module axi_demux_id_counters #( 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) + `FFL(mst_select_q[i], push_mst_select_i, push_en[i], '0, clk_i, rst_ni) // pragma translate_off `ifndef VERILATOR diff --git a/src/axi_demux_simple.sv b/src/axi_demux_simple.sv index 3f854c14f..75f1db53c 100644 --- a/src/axi_demux_simple.sv +++ b/src/axi_demux_simple.sv @@ -66,7 +66,7 @@ module axi_demux_simple #( input axi_resp_t [NoMstPorts-1:0] mst_resps_i ); - localparam int unsigned IdCounterWidth = cf_math_pkg::idx_width(MaxTrans); + localparam int unsigned IdCounterWidth = cc_pkg::idx_width(MaxTrans); typedef logic [IdCounterWidth-1:0] id_cnt_t; // pass through if only one master port @@ -195,7 +195,7 @@ module axi_demux_simple #( // lock the valid signal, as the selection gets pushed into the W FIFO on first assertion, // prevent further pushing - `FFLARN(lock_aw_valid_q, lock_aw_valid_d, load_aw_lock, '0, clk_i, rst_ni) + `FFL(lock_aw_valid_q, lock_aw_valid_d, load_aw_lock, '0, clk_i, rst_ni) if (UniqueIds) begin : gen_unique_ids_aw // If the `UniqueIds` parameter is set, each write transaction has an ID that is unique among @@ -249,7 +249,7 @@ module axi_demux_simple #( .overflow_o ( /*not used*/ ) ); - `FFLARN(w_select_q, slv_aw_select_i, w_cnt_up, select_t'(0), clk_i, rst_ni) + `FFL(w_select_q, slv_aw_select_i, w_cnt_up, select_t'(0), clk_i, rst_ni) assign w_select = (|w_open) ? w_select_q : slv_aw_select_i; assign w_select_valid = w_cnt_up | (|w_open); @@ -260,7 +260,7 @@ module axi_demux_simple #( //-------------------------------------- // B Channel //-------------------------------------- - logic [cf_math_pkg::idx_width(NoMstPorts)-1:0] b_idx; + logic [cc_pkg::idx_width(NoMstPorts)-1:0] b_idx; // Arbitration of the different B responses rr_arb_tree #( @@ -341,7 +341,7 @@ module axi_demux_simple #( end // this ff is needed so that ar does not get de-asserted if an atop gets injected - `FFLARN(lock_ar_valid_q, lock_ar_valid_d, load_ar_lock, '0, clk_i, rst_ni) + `FFL(lock_ar_valid_q, lock_ar_valid_d, load_ar_lock, '0, clk_i, rst_ni) if (UniqueIds) begin : gen_unique_ids_ar // If the `UniqueIds` parameter is set, each read transaction has an ID that is unique among @@ -379,7 +379,7 @@ module axi_demux_simple #( // R Channel //-------------------------------------- - logic [cf_math_pkg::idx_width(NoMstPorts)-1:0] r_idx; + logic [cc_pkg::idx_width(NoMstPorts)-1:0] r_idx; // Arbitration of the different r responses rr_arb_tree #( diff --git a/src/axi_dw_downsizer.sv b/src/axi_dw_downsizer.sv index b508e31ca..766119b3e 100644 --- a/src/axi_dw_downsizer.sv +++ b/src/axi_dw_downsizer.sv @@ -53,7 +53,7 @@ module axi_dw_downsizer #( import axi_pkg::aligned_addr; import axi_pkg::modifiable ; - import cf_math_pkg::idx_width; + import cc_pkg::idx_width; // Type used to index which adapter is handling each outstanding transaction. localparam TranIdWidth = AxiMaxReads > 1 ? $clog2(AxiMaxReads) : 1; @@ -96,9 +96,9 @@ module axi_dw_downsizer #( logic [AxiMaxReads-1:0] slv_r_valid_tran; logic [AxiMaxReads-1:0] slv_r_ready_tran; - rr_arb_tree #( + cc_rr_arb_tree #( .NumIn (AxiMaxReads ), - .DataType (slv_r_chan_t), + .data_t (slv_r_chan_t), .AxiVldRdy(1'b1 ), .ExtPrio (1'b0 ), .LockIn (1'b1 ) @@ -132,7 +132,7 @@ module axi_dw_downsizer #( assign arb_slv_ar_gnt = |arb_slv_ar_gnt_tran; - rr_arb_tree #( + cc_rr_arb_tree #( .NumIn (2 ), .DataWidth (AxiIdWidth), .ExtPrio (1'b0 ), @@ -158,9 +158,9 @@ module axi_dw_downsizer #( logic [AxiMaxReads-1:0] mst_ar_ready_tran; tran_id_t mst_req_idx; - rr_arb_tree #( + cc_rr_arb_tree #( .NumIn (AxiMaxReads), - .DataType (ar_chan_t ), + .data_t (ar_chan_t ), .AxiVldRdy(1'b1 ), .ExtPrio (1'b0 ), .LockIn (1'b1 ) @@ -193,7 +193,6 @@ module axi_dw_downsizer #( ) i_axi_err_slv ( .clk_i (clk_i ), .rst_ni (rst_ni ), - .test_i (1'b0 ), .slv_req_i (axi_err_req ), .slv_resp_o(axi_err_resp) ); @@ -224,7 +223,6 @@ module axi_dw_downsizer #( ) i_axi_demux ( .clk_i (clk_i ), .rst_ni (rst_ni ), - .test_i (1'b0 ), .mst_reqs_o ({axi_err_req, mst_req_o} ), .mst_resps_i ({axi_err_resp, mst_resp_i} ), .slv_ar_select_i(mst_req_ar_err[mst_req_idx]), @@ -276,8 +274,9 @@ module axi_dw_downsizer #( // Find an idle downsizer to handle this transaction tran_id_t idx_idle_downsizer; - lzc #( - .WIDTH(AxiMaxReads) + cc_lzc #( + .Width(AxiMaxReads), + .Mode (cc_pkg::LZC_TRAILING_ZERO_CNT) ) i_idle_lzc ( .in_i (idle_read_downsizer), .cnt_o (idx_idle_downsizer ), @@ -291,8 +290,8 @@ module axi_dw_downsizer #( assign id_clash_downsizer[t] = arb_slv_ar_id == mst_ar_id[t] && !idle_read_downsizer[t]; end - onehot_to_bin #( - .ONEHOT_WIDTH(AxiMaxReads) + cc_onehot_to_bin #( + .OnehotWidth(AxiMaxReads) ) i_id_clash_onehot_to_bin ( .onehot(id_clash_downsizer ), .bin (idx_id_clash_downsizer) @@ -309,9 +308,9 @@ module axi_dw_downsizer #( tran_id_t idqueue_id; logic idqueue_valid; - id_queue #( - .ID_WIDTH(AxiIdWidth ), - .CAPACITY(AxiMaxReads), + cc_id_queue #( + .IdWidth (AxiIdWidth ), + .Capacity(AxiMaxReads), .data_t (tran_id_t ) ) i_read_id_queue ( .clk_i (clk_i ), @@ -679,15 +678,14 @@ module axi_dw_downsizer #( logic forward_b_beat_pop; logic forward_b_beat_full; - fifo_v3 #( - .DATA_WIDTH (1 ), - .DEPTH (AxiMaxReads), - .FALL_THROUGH(1'b1 ) + cc_fifo #( + .DataWidth (1 ), + .Depth (AxiMaxReads), + .FallThrough(1'b1 ) ) i_forward_b_beats_queue ( .clk_i (clk_i ), .rst_ni (rst_ni ), .flush_i (1'b0 ), - .testmode_i(1'b0 ), .data_i (forward_b_beat_i ), .push_i (forward_b_beat_push ), .full_o (forward_b_beat_full ), diff --git a/src/axi_dw_upsizer.sv b/src/axi_dw_upsizer.sv index 623df8235..7fc49a2fa 100644 --- a/src/axi_dw_upsizer.sv +++ b/src/axi_dw_upsizer.sv @@ -53,7 +53,7 @@ module axi_dw_upsizer #( import axi_pkg::beat_addr ; import axi_pkg::modifiable ; - import cf_math_pkg::idx_width; + import cc_pkg::idx_width; // Type used to index which adapter is handling each outstanding transaction. localparam TranIdWidth = AxiMaxReads > 1 ? $clog2(AxiMaxReads) : 1; @@ -93,9 +93,9 @@ module axi_dw_upsizer #( logic [AxiMaxReads-1:0] slv_r_valid_tran; logic [AxiMaxReads-1:0] slv_r_ready_tran; - rr_arb_tree #( + cc_rr_arb_tree #( .NumIn (AxiMaxReads ), - .DataType (slv_r_chan_t), + .data_t (slv_r_chan_t), .AxiVldRdy(1'b1 ), .ExtPrio (1'b0 ), .LockIn (1'b1 ) @@ -129,7 +129,7 @@ module axi_dw_upsizer #( assign arb_slv_ar_gnt = |arb_slv_ar_gnt_tran; - rr_arb_tree #( + cc_rr_arb_tree #( .NumIn (2 ), .DataWidth (AxiIdWidth), .ExtPrio (1'b0 ), @@ -155,9 +155,9 @@ module axi_dw_upsizer #( logic [AxiMaxReads-1:0] mst_ar_ready_tran; tran_id_t mst_req_idx; - rr_arb_tree #( + cc_rr_arb_tree #( .NumIn (AxiMaxReads), - .DataType (ar_chan_t ), + .data_t (ar_chan_t ), .AxiVldRdy(1'b1 ), .ExtPrio (1'b0 ), .LockIn (1'b1 ) @@ -190,7 +190,6 @@ module axi_dw_upsizer #( ) i_axi_err_slv ( .clk_i (clk_i ), .rst_ni (rst_ni ), - .test_i (1'b0 ), .slv_req_i (axi_err_req ), .slv_resp_o(axi_err_resp) ); @@ -221,7 +220,6 @@ module axi_dw_upsizer #( ) i_axi_demux ( .clk_i (clk_i ), .rst_ni (rst_ni ), - .test_i (1'b0 ), .mst_reqs_o ({axi_err_req, mst_req_o} ), .mst_resps_i ({axi_err_resp, mst_resp_i} ), .slv_ar_select_i(mst_req_ar_err[mst_req_idx]), @@ -260,8 +258,9 @@ module axi_dw_upsizer #( // Find an idle upsizer to handle this transaction tran_id_t idx_idle_upsizer; - lzc #( - .WIDTH(AxiMaxReads) + cc_lzc #( + .Width(AxiMaxReads), + .Mode (cc_pkg::LZC_TRAILING_ZERO_CNT) ) i_idle_lzc ( .in_i (idle_read_upsizer), .cnt_o (idx_idle_upsizer ), @@ -275,8 +274,8 @@ module axi_dw_upsizer #( assign id_clash_upsizer[t] = arb_slv_ar_id == mst_ar_id[t] && !idle_read_upsizer[t]; end - onehot_to_bin #( - .ONEHOT_WIDTH(AxiMaxReads) + cc_onehot_to_bin #( + .OnehotWidth(AxiMaxReads) ) i_id_clash_onehot_to_bin ( .onehot(id_clash_upsizer ), .bin (idx_id_clash_upsizer) @@ -300,8 +299,8 @@ module axi_dw_upsizer #( assign rid_upsizer_match[t] = (mst_resp.r.id == mst_ar_id[t]) && !idle_read_upsizer[t]; end - onehot_to_bin #( - .ONEHOT_WIDTH(AxiMaxReads) + cc_onehot_to_bin #( + .OnehotWidth(AxiMaxReads) ) i_rid_upsizer_lzc ( .onehot(rid_upsizer_match), .bin (idx_r_upsizer ) diff --git a/src/axi_err_slv.sv b/src/axi_err_slv.sv index 9035d9a80..83215e9cb 100644 --- a/src/axi_err_slv.sv +++ b/src/axi_err_slv.sv @@ -28,7 +28,6 @@ module axi_err_slv #( ) ( input logic clk_i, // Clock input logic rst_ni, // Asynchronous reset active low - input logic test_i, // Testmode enable // slave port input axi_req_t slv_req_i, output axi_resp_t slv_resp_o @@ -87,15 +86,14 @@ module axi_err_slv #( assign w_fifo_push = err_req.aw_valid & ~w_fifo_full; assign err_resp.aw_ready = ~w_fifo_full; - fifo_v3 #( - .FALL_THROUGH ( 1'b1 ), - .DEPTH ( MaxTrans ), - .dtype ( id_t ) + cc_fifo #( + .FallThrough ( 1'b1 ), + .Depth ( MaxTrans ), + .data_t ( id_t ) ) i_w_fifo ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), .flush_i ( 1'b0 ), - .testmode_i ( test_i ), .full_o ( w_fifo_full ), .empty_o ( w_fifo_empty ), .usage_o ( ), @@ -120,15 +118,14 @@ module axi_err_slv #( end end - fifo_v3 #( - .FALL_THROUGH ( 1'b0 ), - .DEPTH ( unsigned'(2) ), // two placed so that w can eat beats if b is not sent - .dtype ( id_t ) + cc_fifo #( + .FallThrough ( 1'b0 ), + .Depth ( unsigned'(2) ), // two placed so that w can eat beats if b is not sent + .data_t ( id_t ) ) i_b_fifo ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), .flush_i ( 1'b0 ), - .testmode_i ( test_i ), .full_o ( b_fifo_full ), .empty_o ( b_fifo_empty ), .usage_o ( ), @@ -162,15 +159,14 @@ module axi_err_slv #( assign r_fifo_inp.id = err_req.ar.id; assign r_fifo_inp.len = err_req.ar.len; - fifo_v3 #( - .FALL_THROUGH ( 1'b0 ), - .DEPTH ( MaxTrans ), - .dtype ( r_data_t ) + cc_fifo #( + .FallThrough ( 1'b0 ), + .Depth ( MaxTrans ), + .data_t ( r_data_t ) ) i_r_fifo ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), .flush_i ( 1'b0 ), - .testmode_i( test_i ), .full_o ( r_fifo_full ), .empty_o ( r_fifo_empty ), .usage_o ( ), @@ -228,8 +224,8 @@ module axi_err_slv #( end end - counter #( - .WIDTH ($bits(axi_pkg::len_t)) + cc_counter #( + .Width ($bits(axi_pkg::len_t)) ) i_r_counter ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), diff --git a/src/axi_fifo.sv b/src/axi_fifo.sv index 8e4cbdfb1..c0e08cfe9 100644 --- a/src/axi_fifo.sv +++ b/src/axi_fifo.sv @@ -33,7 +33,6 @@ module axi_fifo #( ) ( input logic clk_i, // Clock input logic rst_ni, // Asynchronous reset active low - input logic test_i, // slave port input axi_req_t slv_req_i, output axi_resp_t slv_resp_o, @@ -63,15 +62,14 @@ module axi_fifo #( assign mst_req_o.b_ready = ~b_fifo_full; // A FiFo for each channel - fifo_v3 #( - .dtype(aw_chan_t), - .DEPTH(Depth), - .FALL_THROUGH(FallThrough) + cc_fifo #( + .data_t(aw_chan_t), + .Depth(Depth), + .FallThrough(FallThrough) ) i_aw_fifo ( .clk_i, .rst_ni, .flush_i (1'b0), - .testmode_i(test_i), .full_o (aw_fifo_full), .empty_o (aw_fifo_empty), .usage_o (), @@ -80,15 +78,14 @@ module axi_fifo #( .data_o (mst_req_o.aw), .pop_i (mst_req_o.aw_valid && mst_resp_i.aw_ready) ); - fifo_v3 #( - .dtype(ar_chan_t), - .DEPTH(Depth), - .FALL_THROUGH(FallThrough) + cc_fifo #( + .data_t(ar_chan_t), + .Depth(Depth), + .FallThrough(FallThrough) ) i_ar_fifo ( .clk_i, .rst_ni, .flush_i (1'b0), - .testmode_i(test_i), .full_o (ar_fifo_full), .empty_o (ar_fifo_empty), .usage_o (), @@ -97,15 +94,14 @@ module axi_fifo #( .data_o (mst_req_o.ar), .pop_i (mst_req_o.ar_valid && mst_resp_i.ar_ready) ); - fifo_v3 #( - .dtype(w_chan_t), - .DEPTH(Depth), - .FALL_THROUGH(FallThrough) + cc_fifo #( + .data_t(w_chan_t), + .Depth(Depth), + .FallThrough(FallThrough) ) i_w_fifo ( .clk_i, .rst_ni, .flush_i (1'b0), - .testmode_i(test_i), .full_o (w_fifo_full), .empty_o (w_fifo_empty), .usage_o (), @@ -114,15 +110,14 @@ module axi_fifo #( .data_o (mst_req_o.w), .pop_i (mst_req_o.w_valid && mst_resp_i.w_ready) ); - fifo_v3 #( - .dtype(r_chan_t), - .DEPTH(Depth), - .FALL_THROUGH(FallThrough) + cc_fifo #( + .data_t(r_chan_t), + .Depth(Depth), + .FallThrough(FallThrough) ) i_r_fifo ( .clk_i, .rst_ni, .flush_i (1'b0), - .testmode_i(test_i), .full_o (r_fifo_full), .empty_o (r_fifo_empty), .usage_o (), @@ -131,15 +126,14 @@ module axi_fifo #( .data_o (slv_resp_o.r), .pop_i (slv_resp_o.r_valid && slv_req_i.r_ready) ); - fifo_v3 #( - .dtype(b_chan_t), - .DEPTH(Depth), - .FALL_THROUGH(FallThrough) + cc_fifo #( + .data_t(b_chan_t), + .Depth(Depth), + .FallThrough(FallThrough) ) i_b_fifo ( .clk_i, .rst_ni, .flush_i (1'b0), - .testmode_i(test_i), .full_o (b_fifo_full), .empty_o (b_fifo_empty), .usage_o (), @@ -174,7 +168,6 @@ module axi_fifo_intf #( ) ( input logic clk_i, input logic rst_ni, - input logic test_i, AXI_BUS.Slave slv, AXI_BUS.Master mst ); @@ -215,7 +208,6 @@ module axi_fifo_intf #( ) i_axi_fifo ( .clk_i, .rst_ni, - .test_i, .slv_req_i (slv_req), .slv_resp_o(slv_resp), .mst_req_o (mst_req), diff --git a/src/axi_fifo_delay_dyn.sv b/src/axi_fifo_delay_dyn.sv index c06db637d..8c064c262 100644 --- a/src/axi_fifo_delay_dyn.sv +++ b/src/axi_fifo_delay_dyn.sv @@ -327,8 +327,8 @@ module stream_fifo_delay_dyn #( assign payload_o = head_data; - counter #( - .WIDTH ( CounterWidth ) + cc_counter #( + .Width ( CounterWidth ) ) i_counter ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), @@ -374,15 +374,14 @@ module stream_fifo_delay_dyn #( .dout ( head_data ) ); `else - fifo_v3 #( - .DATA_WIDTH ( $bits(payload_t) ), - .DEPTH ( Depth ), - .FALL_THROUGH ( 1'b0 ) + cc_fifo #( + .DataWidth ( $bits(payload_t) ), + .Depth ( Depth ), + .FallThrough ( 1'b0 ) ) data_fifo ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), .flush_i ( 1'b0 ), - .testmode_i ( 1'b0 ), .data_i ( payload_i ), .push_i ( fifo_data_push ), .full_o ( fifo_data_full ), @@ -426,15 +425,14 @@ module stream_fifo_delay_dyn #( .dout ( head_deadline ) ); `else - fifo_v3 #( - .DATA_WIDTH ( CounterWidth ), - .DEPTH ( Depth ), - .FALL_THROUGH ( 1'b0 ) + cc_fifo #( + .DataWidth ( CounterWidth ), + .Depth ( Depth ), + .FallThrough ( 1'b0 ) ) deadline_fifo ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), .flush_i ( 1'b0 ), - .testmode_i ( 1'b0 ), .data_i ( tail_deadline ), .push_i ( fifo_dead_push ), .full_o ( fifo_dead_full ), diff --git a/src/axi_id_remap.sv b/src/axi_id_remap.sv index f97c52fd1..333a95f86 100644 --- a/src/axi_id_remap.sv +++ b/src/axi_id_remap.sv @@ -128,7 +128,7 @@ module axi_id_remap #( // Remap tables keep track of in-flight bursts and their input and output IDs. - localparam int unsigned IdxWidth = cf_math_pkg::idx_width(AxiSlvPortMaxUniqIds); + localparam int unsigned IdxWidth = cc_pkg::idx_width(AxiSlvPortMaxUniqIds); typedef logic [AxiSlvPortMaxUniqIds-1:0] field_t; typedef logic [AxiSlvPortIdWidth-1:0] id_inp_t; typedef logic [IdxWidth-1:0] idx_t; @@ -185,9 +185,9 @@ module axi_id_remap #( .pop_inp_id_o ( slv_resp_o.r.id ) ); assign both_free = wr_free & rd_free; - lzc #( - .WIDTH ( AxiSlvPortMaxUniqIds ), - .MODE ( 1'b0 ) + cc_lzc #( + .Width ( AxiSlvPortMaxUniqIds ), + .Mode ( 1'b0 ) ) i_lzc ( .in_i ( both_free ), .cnt_o ( both_free_oup_id ), @@ -415,10 +415,10 @@ module axi_id_remap #( end // Registers - `FFARN(ar_id_q, ar_id_d, '0, clk_i, rst_ni) - `FFARN(ar_prio_q, ar_prio_d, 1'b0, clk_i, rst_ni) - `FFARN(aw_id_q, aw_id_d, '0, clk_i, rst_ni) - `FFARN(state_q, state_d, Ready, clk_i, rst_ni) + `FF(ar_id_q, ar_id_d, '0, clk_i, rst_ni) + `FF(ar_prio_q, ar_prio_d, 1'b0, clk_i, rst_ni) + `FF(aw_id_q, aw_id_d, '0, clk_i, rst_ni) + `FF(state_q, state_d, Ready, clk_i, rst_ni) // pragma translate_off `ifndef VERILATOR @@ -505,7 +505,7 @@ module axi_id_remap_table #( localparam type id_inp_t = logic [InpIdWidth-1:0], /// Derived (**=do not override**) width of table index (ceiled binary logarithm of /// `MaxUniqInpIds`). - localparam int unsigned IdxWidth = cf_math_pkg::idx_width(MaxUniqInpIds), + localparam int unsigned IdxWidth = cc_pkg::idx_width(MaxUniqInpIds), /// Derived (**=do not override**) type of table index (width = `IdxWidth`). localparam type idx_t = logic [IdxWidth-1:0], /// Derived (**=do not override**) type with one bit per table entry (thus also output ID). @@ -569,9 +569,9 @@ module axi_id_remap_table #( for (genvar i = 0; i < MaxUniqInpIds; i++) begin : gen_free_o assign free_o[i] = table_q[i].cnt == '0; end - lzc #( - .WIDTH ( MaxUniqInpIds ), - .MODE ( 1'b0 ) + cc_lzc #( + .Width ( MaxUniqInpIds ), + .Mode ( 1'b0 ) ) i_lzc_free ( .in_i ( free_o ), .cnt_o ( free_oup_id_o ), @@ -591,9 +591,9 @@ module axi_id_remap_table #( assign match[i] = table_q[i].cnt > 0 && table_q[i].inp_id == exists_inp_id_i; end logic no_match; - lzc #( - .WIDTH ( MaxUniqInpIds ), - .MODE ( 1'b0 ) + cc_lzc #( + .Width ( MaxUniqInpIds ), + .Mode ( 1'b0 ) ) i_lzc_match ( .in_i ( match ), .cnt_o ( exists_oup_id_o ), @@ -619,7 +619,7 @@ module axi_id_remap_table #( end // Registers - `FFARN(table_q, table_d, '0, clk_i, rst_ni) + `FF(table_q, table_d, '0, clk_i, rst_ni) // Assertions // pragma translate_off diff --git a/src/axi_id_serialize.sv b/src/axi_id_serialize.sv index 94051786c..9cfc82651 100644 --- a/src/axi_id_serialize.sv +++ b/src/axi_id_serialize.sv @@ -83,7 +83,7 @@ module axi_id_serialize #( ); /// Number of bits of the slave port ID that determine the mapping to the master port ID - localparam int unsigned SelectWidth = cf_math_pkg::idx_width(AxiMstPortMaxUniqIds); + localparam int unsigned SelectWidth = cc_pkg::idx_width(AxiMstPortMaxUniqIds); /// Slice of slave port IDs that determines the master port ID typedef logic [SelectWidth-1:0] select_t; @@ -200,7 +200,6 @@ module axi_id_serialize #( ) i_axi_demux ( .clk_i, .rst_ni, - .test_i ( 1'b0 ), .slv_req_i ( slv_req_i ), .slv_aw_select_i ( slv_aw_select ), .slv_ar_select_i ( slv_ar_select ), @@ -270,7 +269,6 @@ module axi_id_serialize #( ) i_axi_mux ( .clk_i, .rst_ni, - .test_i ( 1'b0 ), .slv_reqs_i ( from_serializer_reqs ), .slv_resps_o ( from_serializer_resps ), .mst_req_o ( axi_mux_req ), diff --git a/src/axi_interleaved_xbar.sv b/src/axi_interleaved_xbar.sv index 83d215df7..8339d8930 100644 --- a/src/axi_interleaved_xbar.sv +++ b/src/axi_interleaved_xbar.sv @@ -17,7 +17,7 @@ /// Interleaved version of the crossbar. This module is experimental; use at your own risk. module axi_interleaved_xbar -import cf_math_pkg::idx_width; +import cc_pkg::idx_width; #( parameter axi_pkg::xbar_cfg_t Cfg = '0, parameter bit ATOPs = 1'b1, @@ -42,7 +42,6 @@ import cf_math_pkg::idx_width; ) ( 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, @@ -118,7 +117,7 @@ import cf_math_pkg::idx_width; end end - addr_decode #( + cc_addr_decode #( .NoIndices ( Cfg.NoMstPorts ), .NoRules ( Cfg.NoAddrRules ), .addr_t ( addr_t ), @@ -133,7 +132,7 @@ import cf_math_pkg::idx_width; .default_idx_i ( default_mst_port_i[i] ) ); - addr_decode #( + cc_addr_decode #( .NoIndices ( Cfg.NoMstPorts ), .addr_t ( addr_t ), .NoRules ( Cfg.NoAddrRules ), @@ -210,7 +209,6 @@ import cf_math_pkg::idx_width; ) i_axi_demux ( .clk_i, // Clock .rst_ni, // Asynchronous reset active low - .test_i, // Testmode enable .slv_req_i ( slv_reqs_mod[i] ), .slv_aw_select_i ( slv_aw_select ), .slv_ar_select_i ( slv_ar_select ), @@ -231,7 +229,6 @@ import cf_math_pkg::idx_width; ) i_axi_err_slv ( .clk_i, // Clock .rst_ni, // Asynchronous reset active low - .test_i, // Testmode enable // slave port .slv_req_i ( slv_reqs[i][Cfg.NoMstPorts] ), .slv_resp_o ( slv_resps[i][cfg_NoMstPorts] ) @@ -257,7 +254,6 @@ import cf_math_pkg::idx_width; ) i_axi_err_slv ( .clk_i, .rst_ni, - .test_i, .slv_req_i ( slv_reqs[i][j] ), .slv_resp_o ( slv_resps[i][j] ) ); @@ -292,7 +288,6 @@ import cf_math_pkg::idx_width; ) i_axi_mux ( .clk_i, // Clock .rst_ni, // Asynchronous reset active low - .test_i, // Test Mode enable .slv_reqs_i ( mst_reqs[i] ), .slv_resps_o ( mst_resps[i] ), .mst_req_o ( mst_ports_req_o[i] ), @@ -318,7 +313,7 @@ endmodule : axi_interleaved_xbar `include "axi/typedef.svh" module axi_interleaved_xbar_intf -import cf_math_pkg::idx_width; +import cc_pkg::idx_width; #( parameter axi_pkg::xbar_cfg_t Cfg = '0, parameter int unsigned AXI_USER_WIDTH = 0, @@ -332,7 +327,6 @@ import cf_math_pkg::idx_width; ) ( 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, @@ -404,7 +398,6 @@ import cf_math_pkg::idx_width; ) i_interleaved_xbar ( .clk_i, .rst_ni, - .test_i, .slv_ports_req_i (slv_reqs ), .slv_ports_resp_o (slv_resps), .mst_ports_req_o (mst_reqs ), diff --git a/src/axi_inval_filter.sv b/src/axi_inval_filter.sv index 272f9043f..2c9e8854c 100644 --- a/src/axi_inval_filter.sv +++ b/src/axi_inval_filter.sv @@ -35,7 +35,7 @@ module axi_inval_filter #( input logic inval_ready_i ); - import cf_math_pkg::idx_width; + import cc_pkg::idx_width; // Includes `include "axi/typedef.svh" @@ -127,15 +127,14 @@ module axi_inval_filter #( end end - fifo_v3 #( - .FALL_THROUGH ( 1'b1 ), - .DEPTH ( MaxTxns ), - .dtype ( aw_chan_t ) + cc_fifo #( + .FallThrough ( 1'b1 ), + .Depth ( MaxTxns ), + .data_t ( aw_chan_t ) ) i_aw_fifo ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), .flush_i ( 1'b0 ), - .testmode_i ( 1'b0 ), .full_o ( aw_fifo_full ), .empty_o ( aw_fifo_empty ), .usage_o ( ), diff --git a/src/axi_isolate.sv b/src/axi_isolate.sv index cb9a14852..e414c3c5e 100644 --- a/src/axi_isolate.sv +++ b/src/axi_isolate.sv @@ -115,7 +115,6 @@ module axi_isolate #( ) i_axi_demux ( .clk_i, .rst_ni, - .test_i ( 1'b0 ), .slv_req_i, .slv_aw_select_i ( isolated_o ), .slv_ar_select_i ( isolated_o ), @@ -135,7 +134,6 @@ module axi_isolate #( ) i_axi_err_slv ( .clk_i, .rst_ni, - .test_i ( 1'b0 ), .slv_req_i ( demux_req[1] ), .slv_resp_o ( demux_rsp[1] ) ); @@ -200,11 +198,11 @@ module axi_isolate_inner #( cnt_t pending_ar_d, pending_ar_q; logic update_ar_cnt; - `FFLARN(pending_aw_q, pending_aw_d, update_aw_cnt, '0, clk_i, rst_ni) - `FFLARN(pending_w_q, pending_w_d, update_w_cnt, '0, clk_i, rst_ni) - `FFLARN(pending_ar_q, pending_ar_d, update_ar_cnt, '0, clk_i, rst_ni) - `FFLARN(state_aw_q, state_aw_d, update_aw_state, Isolate, clk_i, rst_ni) - `FFLARN(state_ar_q, state_ar_d, update_ar_state, Isolate, clk_i, rst_ni) + `FFL(pending_aw_q, pending_aw_d, update_aw_cnt, '0, clk_i, rst_ni) + `FFL(pending_w_q, pending_w_d, update_w_cnt, '0, clk_i, rst_ni) + `FFL(pending_ar_q, pending_ar_d, update_ar_cnt, '0, clk_i, rst_ni) + `FFL(state_aw_q, state_aw_d, update_aw_state, Isolate, clk_i, rst_ni) + `FFL(state_ar_q, state_ar_d, update_ar_state, Isolate, clk_i, rst_ni) // Update counters. always_comb begin diff --git a/src/axi_lfsr.sv b/src/axi_lfsr.sv index 2085a76fe..530d581d3 100644 --- a/src/axi_lfsr.sv +++ b/src/axi_lfsr.sv @@ -33,8 +33,6 @@ module axi_lfsr #( input logic clk_i, /// Active-low reset input logic rst_ni, - /// Testmode - input logic testmode_i, /// AXI4 request struct input axi_req_t req_i, /// AXI4 response struct @@ -93,7 +91,6 @@ module axi_lfsr #( ) i_axi_to_axi_lite ( .clk_i, .rst_ni, - .test_i ( testmode_i ), .slv_req_i ( req_i ), .slv_resp_o ( rsp_o ), .mst_req_o ( axi_lite_req ), @@ -107,7 +104,6 @@ module axi_lfsr #( ) i_axi_lite_lfsr ( .clk_i, .rst_ni, - .testmode_i, .w_ser_data_i, .w_ser_data_o, .w_ser_en_i, diff --git a/src/axi_lite_demux.sv b/src/axi_lite_demux.sv index 1b979d874..d14dc49ba 100644 --- a/src/axi_lite_demux.sv +++ b/src/axi_lite_demux.sv @@ -45,7 +45,6 @@ module axi_lite_demux #( ) ( input logic clk_i, input logic rst_ni, - input logic test_i, // slave port (AXI4-Lite input), connect master module here input axi_req_t slv_req_i, input select_t slv_aw_select_i, @@ -70,8 +69,8 @@ module axi_lite_demux #( if (NoMstPorts == 32'd1) begin : gen_no_demux // degenerate case, connect slave to master port - spill_register #( - .T ( aw_chan_t ), + cc_spill_register #( + .data_t ( aw_chan_t ), .Bypass ( ~SpillAw ) ) i_aw_spill_reg ( .clk_i ( clk_i ), @@ -83,8 +82,8 @@ module axi_lite_demux #( .ready_i ( mst_resps_i[0].aw_ready ), .data_o ( mst_reqs_o[0].aw ) ); - spill_register #( - .T ( w_chan_t ), + cc_spill_register #( + .data_t ( w_chan_t ), .Bypass ( ~SpillW ) ) i_w_spill_reg ( .clk_i ( clk_i ), @@ -96,8 +95,8 @@ module axi_lite_demux #( .ready_i ( mst_resps_i[0].w_ready ), .data_o ( mst_reqs_o[0].w ) ); - spill_register #( - .T ( b_chan_t ), + cc_spill_register #( + .data_t ( b_chan_t ), .Bypass ( ~SpillB ) ) i_b_spill_reg ( .clk_i ( clk_i ), @@ -109,8 +108,8 @@ module axi_lite_demux #( .ready_i ( slv_req_i.b_ready ), .data_o ( slv_resp_o.b ) ); - spill_register #( - .T ( ar_chan_t ), + cc_spill_register #( + .data_t ( ar_chan_t ), .Bypass ( ~SpillAr ) ) i_ar_spill_reg ( .clk_i ( clk_i ), @@ -122,8 +121,8 @@ module axi_lite_demux #( .ready_i ( mst_resps_i[0].ar_ready ), .data_o ( mst_reqs_o[0].ar ) ); - spill_register #( - .T ( r_chan_t ), + cc_spill_register #( + .data_t ( r_chan_t ), .Bypass ( ~SpillR ) ) i_r_spill_reg ( .clk_i ( clk_i ), @@ -194,7 +193,7 @@ module axi_lite_demux #( //-------------------------------------- `ifdef TARGET_VSIM // Workaround for bug in Questa 2020.2 and 2021.1: Flatten the struct into a logic vector before - // instantiating `spill_register`. + // instantiating `cc_spill_register`. typedef logic [$bits(aw_chan_select_t)-1:0] aw_chan_select_flat_t; `else // Other tools, such as VCS, have problems with `$bits()`, so the workaround cannot be used @@ -204,8 +203,8 @@ module axi_lite_demux #( aw_chan_select_flat_t slv_aw_chan_select_in_flat, slv_aw_chan_select_out_flat; assign slv_aw_chan_select_in_flat = {slv_req_i.aw, slv_aw_select_i}; - spill_register #( - .T ( aw_chan_select_flat_t ), + cc_spill_register #( + .data_t ( aw_chan_select_flat_t ), .Bypass ( ~SpillAw ) ) i_aw_spill_reg ( .clk_i ( clk_i ), @@ -265,17 +264,16 @@ module axi_lite_demux #( // lock the valid signal, as the selection gets pushed into the W FIFO on first assertion, // prevent further pushing - `FFLARN(lock_aw_valid_q, lock_aw_valid_d, load_aw_lock, '0, clk_i, rst_ni) + `FFL(lock_aw_valid_q, lock_aw_valid_d, load_aw_lock, '0, clk_i, rst_ni) - fifo_v3 #( - .FALL_THROUGH( FallThrough ), - .DEPTH ( MaxTrans ), - .dtype ( select_t ) + cc_fifo #( + .FallThrough ( FallThrough ), + .Depth ( MaxTrans ), + .data_t ( select_t ) ) i_w_fifo ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), .flush_i ( 1'b0 ), // not used, because AXI4-Lite no preemtion rule - .testmode_i ( test_i ), .full_o ( w_fifo_full ), .empty_o ( w_fifo_empty ), .usage_o ( /*not used*/ ), @@ -288,8 +286,8 @@ module axi_lite_demux #( //-------------------------------------- // W Channel //-------------------------------------- - spill_register #( - .T ( w_chan_t ), + cc_spill_register #( + .data_t ( w_chan_t ), .Bypass ( ~SpillW ) ) i_w_spill_reg ( .clk_i ( clk_i ), @@ -311,15 +309,14 @@ module axi_lite_demux #( assign slv_w_ready = ~w_fifo_empty & ~b_fifo_full & mst_resps_i[w_select].w_ready; assign w_fifo_pop = slv_w_valid & slv_w_ready; - fifo_v3 #( - .FALL_THROUGH( FallThrough ), - .DEPTH ( MaxTrans ), - .dtype ( select_t ) + cc_fifo #( + .FallThrough ( FallThrough ), + .Depth ( MaxTrans ), + .data_t ( select_t ) ) i_b_fifo ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), .flush_i ( 1'b0 ), // not used, because AXI4-Lite no preemption - .testmode_i ( test_i ), .full_o ( b_fifo_full ), .empty_o ( b_fifo_empty ), .usage_o ( /*not used*/ ), @@ -332,8 +329,8 @@ module axi_lite_demux #( //-------------------------------------- // B Channel //-------------------------------------- - spill_register #( - .T ( b_chan_t ), + cc_spill_register #( + .data_t ( b_chan_t ), .Bypass ( ~SpillB ) ) i_b_spill_reg ( .clk_i ( clk_i ), @@ -366,8 +363,8 @@ module axi_lite_demux #( ar_chan_select_flat_t slv_ar_chan_select_in_flat, slv_ar_chan_select_out_flat; assign slv_ar_chan_select_in_flat = {slv_req_i.ar, slv_ar_select_i}; - spill_register #( - .T ( ar_chan_select_flat_t ), + cc_spill_register #( + .data_t ( ar_chan_select_flat_t ), .Bypass ( ~SpillAr ) ) i_ar_spill_reg ( .clk_i ( clk_i ), @@ -390,15 +387,14 @@ module axi_lite_demux #( assign slv_ar_ready = ~r_fifo_full & mst_resps_i[slv_ar_chan.select].ar_ready; assign r_fifo_push = slv_ar_valid & slv_ar_ready; - fifo_v3 #( - .FALL_THROUGH( FallThrough ), - .DEPTH ( MaxTrans ), - .dtype ( select_t ) + cc_fifo #( + .FallThrough ( FallThrough ), + .Depth ( MaxTrans ), + .data_t ( select_t ) ) i_r_fifo ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), .flush_i ( 1'b0 ), // not used, because AXI4-Lite no preemption rule - .testmode_i ( test_i ), .full_o ( r_fifo_full ), .empty_o ( r_fifo_empty ), .usage_o ( /*not used*/ ), @@ -411,8 +407,8 @@ module axi_lite_demux #( //-------------------------------------- // R Channel //-------------------------------------- - spill_register #( - .T ( r_chan_t ), + cc_spill_register #( + .data_t ( r_chan_t ), .Bypass ( ~SpillR ) ) i_r_spill_reg ( .clk_i ( clk_i ), @@ -498,7 +494,6 @@ module axi_lite_demux_intf #( ) ( input logic clk_i, // Clock input logic rst_ni, // Asynchronous reset active low - input logic test_i, // Testmode enable input select_t slv_aw_select_i, // has to be stable, when aw_valid input select_t slv_ar_select_i, // has to be stable, when ar_valid AXI_LITE.Slave slv, // slave port @@ -547,7 +542,6 @@ module axi_lite_demux_intf #( ) i_axi_demux ( .clk_i, .rst_ni, - .test_i, // slave Port .slv_req_i ( slv_req ), .slv_aw_select_i ( slv_aw_select_i ), // must be stable while slv_aw_valid_i diff --git a/src/axi_lite_dw_converter.sv b/src/axi_lite_dw_converter.sv index 139c2d313..1d1794843 100644 --- a/src/axi_lite_dw_converter.sv +++ b/src/axi_lite_dw_converter.sv @@ -133,8 +133,8 @@ module axi_lite_dw_converter #( axi_lite_aw_t aw_chan_spill; logic aw_chan_spill_valid, aw_chan_spill_ready; - spill_register #( - .T ( axi_lite_aw_t ), + cc_spill_register #( + .data_t ( axi_lite_aw_t ), .Bypass ( 1'b0 ) ) i_spill_register_aw ( .clk_i, @@ -160,13 +160,13 @@ module axi_lite_dw_converter #( assign aw_sel_load = mst_req_o.aw_valid & mst_res_i.aw_ready; assign aw_sel_d = sel_t'(aw_sel_q + 1'b1); - `FFLARN(aw_sel_q, aw_sel_d, aw_sel_load, '0, clk_i, rst_ni) + `FFL(aw_sel_q, aw_sel_d, aw_sel_load, '0, clk_i, rst_ni) // Input spill register of the W channel. axi_lite_slv_w_t w_chan_spill; logic w_chan_spill_valid, w_chan_spill_ready; - spill_register #( - .T ( axi_lite_slv_w_t ), + cc_spill_register #( + .data_t ( axi_lite_slv_w_t ), .Bypass ( 1'b0 ) ) i_spill_register_w ( .clk_i, @@ -193,7 +193,7 @@ module axi_lite_dw_converter #( assign w_sel_load = mst_req_o.w_valid & mst_res_i.w_ready; assign w_sel_d = sel_t'(w_sel_q + 1'b1); - `FFLARN(w_sel_q, w_sel_d, w_sel_load, '0, clk_i, rst_ni) + `FFL(w_sel_q, w_sel_d, w_sel_load, '0, clk_i, rst_ni) // B response aggregation // Slave port B output is the aggregated error of the last few B responses. @@ -216,16 +216,16 @@ module axi_lite_dw_converter #( assign b_sel_d = sel_t'(b_sel_q + 1'b1); assign b_resp_d = (&b_sel_q) ? axi_pkg::RESP_OKAY : (b_resp_q | mst_res_i.b.resp); assign b_resp_load = mst_res_i.b_valid & mst_req_o.b_ready; - `FFLARN(b_sel_q, b_sel_d, b_resp_load, '0, clk_i, rst_ni) - `FFLARN(b_resp_q, b_resp_d, b_resp_load, axi_pkg::RESP_OKAY, clk_i, rst_ni) + `FFL(b_sel_q, b_sel_d, b_resp_load, '0, clk_i, rst_ni) + `FFL(b_resp_q, b_resp_d, b_resp_load, axi_pkg::RESP_OKAY, clk_i, rst_ni) // Read channels. // Input spill register of the AW channel. axi_lite_ar_t ar_chan_spill; logic ar_chan_spill_valid, ar_chan_spill_ready; - spill_register #( - .T ( axi_lite_ar_t ), + cc_spill_register #( + .data_t ( axi_lite_ar_t ), .Bypass ( 1'b0 ) ) i_spill_register_ar ( .clk_i, @@ -251,7 +251,7 @@ module axi_lite_dw_converter #( assign ar_sel_load = mst_req_o.ar_valid & mst_res_i.ar_ready; assign ar_sel_d = sel_t'(ar_sel_q + 1'b1); - `FFLARN(ar_sel_q, ar_sel_d, ar_sel_load, '0, clk_i, rst_ni) + `FFL(ar_sel_q, ar_sel_d, ar_sel_load, '0, clk_i, rst_ni) // Responses have to be aggregated, one FF less, as the last data is feed directly through. sel_t r_sel_q, r_sel_d; @@ -260,11 +260,11 @@ module axi_lite_dw_converter #( logic [DownsizeFactor-2:0] r_chan_mst_load; for (genvar i = 0; unsigned'(i) < (DownsizeFactor-1); i++) begin : gen_r_chan_ff assign r_chan_mst_load[i] = (sel_t'(i) == r_sel_q) & mst_res_i.r_valid & mst_req_o.r_ready; - `FFLARN(r_chan_mst_q[i], mst_res_i.r, r_chan_mst_load[i], axi_lite_mst_r_t'{default: '0}, clk_i, rst_ni) + `FFL(r_chan_mst_q[i], mst_res_i.r, r_chan_mst_load[i], axi_lite_mst_r_t'{default: '0}, clk_i, rst_ni) end assign r_sel_load = mst_res_i.r_valid & mst_req_o.r_ready; assign r_sel_d = sel_t'(r_sel_q + 1'b1); - `FFLARN(r_sel_q, r_sel_d, r_sel_load, '0, clk_i, rst_ni) + `FFL(r_sel_q, r_sel_d, r_sel_load, '0, clk_i, rst_ni) always_comb begin : proc_r_chan_oup slv_res_o.r = axi_lite_slv_r_t'{ @@ -332,20 +332,19 @@ module axi_lite_dw_converter #( end end assign lock_aw_d = ~lock_aw_q; - `FFLARN(lock_aw_q, lock_aw_d, load_aw_lock, 1'b0, clk_i, rst_ni) + `FFL(lock_aw_q, lock_aw_d, load_aw_lock, 1'b0, clk_i, rst_ni) // The selection comes from part of the AW address. assign aw_sel = sel_t'(slv_req_i.aw.addr >> SelOffset); - fifo_v3 #( - .FALL_THROUGH ( 1'b1 ), - .DEPTH ( UpsizeFactor ), - .dtype ( sel_t ) + cc_fifo #( + .FallThrough ( 1'b1 ), + .Depth ( UpsizeFactor ), + .data_t ( sel_t ) ) i_fifo_w_sel ( .clk_i, .rst_ni, .flush_i ( 1'b0 ), - .testmode_i ( 1'b0 ), .full_o ( w_full ), .empty_o ( w_empty ), .usage_o ( /*not used*/ ), @@ -414,20 +413,19 @@ module axi_lite_dw_converter #( end end assign lock_ar_d = ~lock_ar_q; - `FFLARN(lock_ar_q, lock_ar_d, load_ar_lock, 1'b0, clk_i, rst_ni) + `FFL(lock_ar_q, lock_ar_d, load_ar_lock, 1'b0, clk_i, rst_ni) // The selection comes from part of the AW address. assign ar_sel = sel_t'(slv_req_i.ar.addr >> SelOffset); - fifo_v3 #( - .FALL_THROUGH ( 1'b1 ), - .DEPTH ( UpsizeFactor ), - .dtype ( sel_t ) + cc_fifo #( + .FallThrough ( 1'b1 ), + .Depth ( UpsizeFactor ), + .data_t ( sel_t ) ) i_fifo_r_sel ( .clk_i, .rst_ni, .flush_i ( 1'b0 ), - .testmode_i ( 1'b0 ), .full_o ( r_full ), .empty_o ( r_empty ), .usage_o ( /*not used*/ ), diff --git a/src/axi_lite_from_mem.sv b/src/axi_lite_from_mem.sv index 2b7e9e38c..6976f35b1 100644 --- a/src/axi_lite_from_mem.sv +++ b/src/axi_lite_from_mem.sv @@ -170,21 +170,20 @@ module axi_lite_from_mem #( end end - `FFARN(aw_sent_q, aw_sent_d, 1'b0, clk_i, rst_ni) - `FFARN(w_sent_q, w_sent_d, 1'b0, clk_i, rst_ni) + `FF(aw_sent_q, aw_sent_d, 1'b0, clk_i, rst_ni) + `FF(w_sent_q, w_sent_d, 1'b0, clk_i, rst_ni) // Select which response should be forwarded. `1` write response, `0` read response. logic rsp_sel; - fifo_v3 #( - .FALL_THROUGH ( 1'b0 ), // No fallthrough for one cycle delay before ready on AXI. - .DEPTH ( MaxRequests ), - .dtype ( logic ) + cc_fifo #( + .FallThrough ( 1'b0 ), // No fallthrough for one cycle delay before ready on AXI. + .Depth ( MaxRequests ), + .data_t ( logic ) ) i_fifo_rsp_mux ( .clk_i, .rst_ni, .flush_i ( 1'b0 ), - .testmode_i ( 1'b0 ), .full_o ( fifo_full ), .empty_o ( fifo_empty ), .usage_o ( /*not used*/ ), diff --git a/src/axi_lite_lfsr.sv b/src/axi_lite_lfsr.sv index 7d4710d5f..e9a60020a 100644 --- a/src/axi_lite_lfsr.sv +++ b/src/axi_lite_lfsr.sv @@ -27,8 +27,6 @@ module axi_lite_lfsr #( input logic clk_i, /// Active-low reset input logic rst_ni, - /// Testmode - input logic testmode_i, /// AXI4 Lite request struct input axi_lite_req_t req_i, /// AXI4 Lite response struct @@ -93,14 +91,13 @@ module axi_lite_lfsr #( end // B - stream_fifo #( - .FALL_THROUGH ( 1'b0 ), - .DATA_WIDTH ( 'd1 ), - .DEPTH ( 'd2 ) + cc_stream_fifo #( + .FallThrough ( 1'b0 ), + .DataWidth ( 'd1 ), + .Depth ( 'd2 ) ) i_stream_fifo_w_b ( .clk_i, .rst_ni, - .testmode_i, .flush_i ( 1'b0 ), .usage_o ( /* NOT CONNECTED */ ), .data_i ( 1'b0 ), @@ -156,7 +153,7 @@ module axi_opt_lfsr #( ); /// Number of bits required to hold the LFSR tab configuration - localparam int unsigned LfsrIdxWidth = cf_math_pkg::idx_width(Width); + localparam int unsigned LfsrIdxWidth = cc_pkg::idx_width(Width); /// Maximum number of tabs localparam int unsigned MaxNumTabs = 4; diff --git a/src/axi_lite_mailbox.sv b/src/axi_lite_mailbox.sv index 13d0785c6..e417e7a99 100644 --- a/src/axi_lite_mailbox.sv +++ b/src/axi_lite_mailbox.sv @@ -31,7 +31,6 @@ module axi_lite_mailbox #( ) ( input logic clk_i, // Clock input logic rst_ni, // Asynchronous reset active low - input logic test_i, // Testmode enable // slave ports [1:0] input req_lite_t [1:0] slv_reqs_i, output resp_lite_t [1:0] slv_resps_o, @@ -122,14 +121,13 @@ module axi_lite_mailbox #( // the usage gets concatinated with the full flag to have consistent threshold detection logic [FifoUsageWidth-1:0] mbox_0_to_1_usage, mbox_1_to_0_usage; - fifo_v3 #( - .FALL_THROUGH ( 1'b0 ), - .DEPTH ( MailboxDepth ), - .dtype ( data_t ) + cc_fifo #( + .FallThrough ( 1'b0 ), + .Depth ( MailboxDepth ), + .data_t ( data_t ) ) i_mbox_0_to_1 ( .clk_i, .rst_ni, - .testmode_i( test_i ), .flush_i ( w_mbox_flush[0] | r_mbox_flush[1] ), .full_o ( mbox_full[0] ), .empty_o ( mbox_empty[0] ), @@ -142,14 +140,13 @@ module axi_lite_mailbox #( // assign the MSB of the FIFO to the correct usage signal assign mbox_usage[0] = {mbox_full[0], mbox_0_to_1_usage}; - fifo_v3 #( - .FALL_THROUGH ( 1'b0 ), - .DEPTH ( MailboxDepth ), - .dtype ( data_t ) + cc_fifo #( + .FallThrough ( 1'b0 ), + .Depth ( MailboxDepth ), + .data_t ( data_t ) ) i_mbox_1_to_0 ( .clk_i, .rst_ni, - .testmode_i( test_i ), .flush_i ( w_mbox_flush[1] | r_mbox_flush[0] ), .full_o ( mbox_full[1] ), .empty_o ( mbox_empty[1] ), @@ -181,7 +178,7 @@ module axi_lite_mailbox #( end end - `FFLARN(irq_q, irq_d, update_irq, '0, clk_i, rst_ni) + `FFL(irq_q, irq_d, update_irq, '0, clk_i, rst_ni) end else begin : gen_irq_level assign irq_o[i] = (IrqActHigh) ? slv_irq[i] : ~slv_irq[i]; end @@ -292,11 +289,11 @@ module axi_lite_mailbox_slave #( logic update_regs; // register enable signal // register instantiation - `FFLARN(error_q, error_d, update_regs, '0, clk_i, rst_ni) - `FFLARN(wirqt_q, wirqt_d, update_regs, '0, clk_i, rst_ni) - `FFLARN(rirqt_q, rirqt_d, update_regs, '0, clk_i, rst_ni) - `FFLARN(irqs_q, irqs_d, update_regs, '0, clk_i, rst_ni) - `FFLARN(irqen_q, irqen_d, update_regs, '0, clk_i, rst_ni) + `FFL(error_q, error_d, update_regs, '0, clk_i, rst_ni) + `FFL(wirqt_q, wirqt_d, update_regs, '0, clk_i, rst_ni) + `FFL(rirqt_q, rirqt_d, update_regs, '0, clk_i, rst_ni) + `FFL(irqs_q, irqs_d, update_regs, '0, clk_i, rst_ni) + `FFL(irqen_q, irqen_d, update_regs, '0, clk_i, rst_ni) // Mailbox FIFO data assignments for (genvar i = 0; i < (AxiDataWidth/8); i++) begin : gen_w_mbox_data @@ -489,7 +486,7 @@ module axi_lite_mailbox_slave #( // address decoder and response FIFOs for the LITE channel, the port can take a new transaction if // these FIFOs are not full, not fall through to prevent combinational paths to the return path - addr_decode #( + cc_addr_decode #( .NoIndices( NoRegs ), .NoRules ( NoRegs ), .addr_t ( addr_t ), @@ -503,8 +500,8 @@ module axi_lite_mailbox_slave #( .en_default_idx_i ( 1'b0 ), .default_idx_i ( '0 ) ); - spill_register #( - .T ( b_chan_lite_t ) + cc_spill_register #( + .data_t ( b_chan_lite_t ) ) i_b_chan_outp ( .clk_i, .rst_ni, @@ -515,7 +512,7 @@ module axi_lite_mailbox_slave #( .ready_i ( slv_req_i.b_ready ), .data_o ( slv_resp_o.b ) ); - addr_decode #( + cc_addr_decode #( .NoIndices( NoRegs ), .NoRules ( NoRegs ), .addr_t ( addr_t ), @@ -529,8 +526,8 @@ module axi_lite_mailbox_slave #( .en_default_idx_i ( 1'b0 ), .default_idx_i ( '0 ) ); - spill_register #( - .T ( r_chan_lite_t ) + cc_spill_register #( + .data_t ( r_chan_lite_t ) ) i_r_chan_outp ( .clk_i, .rst_ni, @@ -566,7 +563,6 @@ module axi_lite_mailbox_intf #( ) ( input logic clk_i, // Clock input logic rst_ni, // Asynchronous reset active low - input logic test_i, // Testmode enable AXI_LITE.Slave slv [1:0], // slave ports [1:0] output logic [1:0] irq_o, // interrupt output for each port input addr_t [1:0] base_addr_i // base address for each port @@ -600,7 +596,6 @@ module axi_lite_mailbox_intf #( ) i_axi_lite_mailbox ( .clk_i, // Clock .rst_ni, // Asynchronous reset active low - .test_i, // Testmode enable // slave ports [1:0] .slv_reqs_i ( slv_reqs ), .slv_resps_o ( slv_resps ), diff --git a/src/axi_lite_mux.sv b/src/axi_lite_mux.sv index 26f97b589..0df045f7d 100644 --- a/src/axi_lite_mux.sv +++ b/src/axi_lite_mux.sv @@ -44,7 +44,6 @@ module axi_lite_mux #( ) ( input logic clk_i, // Clock input logic rst_ni, // Asynchronous reset active low - input logic test_i, // Test Mode enable // slave ports (AXI4-Lite inputs), connect master modules here input axi_req_t [NoSlvPorts-1:0] slv_reqs_i, output axi_resp_t [NoSlvPorts-1:0] slv_resps_o, @@ -54,8 +53,8 @@ module axi_lite_mux #( ); // pass through if only one slave port if (NoSlvPorts == 32'h1) begin : gen_no_mux - spill_register #( - .T ( aw_chan_t ), + cc_spill_register #( + .data_t ( aw_chan_t ), .Bypass ( ~SpillAw ) ) i_aw_spill_reg ( .clk_i ( clk_i ), @@ -67,8 +66,8 @@ module axi_lite_mux #( .ready_i ( mst_resp_i.aw_ready ), .data_o ( mst_req_o.aw ) ); - spill_register #( - .T ( w_chan_t ), + cc_spill_register #( + .data_t ( w_chan_t ), .Bypass ( ~SpillW ) ) i_w_spill_reg ( .clk_i ( clk_i ), @@ -80,8 +79,8 @@ module axi_lite_mux #( .ready_i ( mst_resp_i.w_ready ), .data_o ( mst_req_o.w ) ); - spill_register #( - .T ( b_chan_t ), + cc_spill_register #( + .data_t ( b_chan_t ), .Bypass ( ~SpillB ) ) i_b_spill_reg ( .clk_i ( clk_i ), @@ -93,8 +92,8 @@ module axi_lite_mux #( .ready_i ( slv_reqs_i[0].b_ready ), .data_o ( slv_resps_o[0].b ) ); - spill_register #( - .T ( ar_chan_t ), + cc_spill_register #( + .data_t ( ar_chan_t ), .Bypass ( ~SpillAr ) ) i_ar_spill_reg ( .clk_i ( clk_i ), @@ -106,8 +105,8 @@ module axi_lite_mux #( .ready_i ( mst_resp_i.ar_ready ), .data_o ( mst_req_o.ar ) ); - spill_register #( - .T ( r_chan_t ), + cc_spill_register #( + .data_t ( r_chan_t ), .Bypass ( ~SpillR ) ) i_r_spill_reg ( .clk_i ( clk_i ), @@ -196,9 +195,9 @@ module axi_lite_mux #( assign slv_aw_valids[i] = slv_reqs_i[i].aw_valid; assign slv_resps_o[i].aw_ready = slv_aw_readies[i]; end - rr_arb_tree #( + cc_rr_arb_tree #( .NumIn ( NoSlvPorts ), - .DataType ( aw_chan_t ), + .data_t ( aw_chan_t ), .AxiVldRdy( 1'b1 ), .LockIn ( 1'b1 ) ) i_aw_arbiter ( @@ -247,17 +246,16 @@ module axi_lite_mux #( end end - `FFLARN(lock_aw_valid_q, lock_aw_valid_d, load_aw_lock, '0, clk_i, rst_ni) + `FFL(lock_aw_valid_q, lock_aw_valid_d, load_aw_lock, '0, clk_i, rst_ni) - fifo_v3 #( - .FALL_THROUGH ( FallThrough ), - .DEPTH ( MaxTrans ), - .dtype ( select_t ) + cc_fifo #( + .FallThrough ( FallThrough ), + .Depth ( MaxTrans ), + .data_t ( select_t ) ) i_w_fifo ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), .flush_i ( 1'b0 ), - .testmode_i( test_i ), .full_o ( w_fifo_full ), .empty_o ( w_fifo_empty ), .usage_o ( ), @@ -267,8 +265,8 @@ module axi_lite_mux #( .pop_i ( w_fifo_pop ) ); - spill_register #( - .T ( aw_chan_t ), + cc_spill_register #( + .data_t ( aw_chan_t ), .Bypass ( ~SpillAw ) // Param indicated that we want a spill reg ) i_aw_spill_reg ( .clk_i ( clk_i ), @@ -293,15 +291,14 @@ module axi_lite_mux #( end assign w_fifo_pop = mst_w_valid & mst_w_ready; - fifo_v3 #( - .FALL_THROUGH ( FallThrough ), - .DEPTH ( MaxTrans ), - .dtype ( select_t ) + cc_fifo #( + .FallThrough ( FallThrough ), + .Depth ( MaxTrans ), + .data_t ( select_t ) ) i_b_fifo ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), .flush_i ( 1'b0 ), - .testmode_i( test_i ), .full_o ( b_fifo_full ), .empty_o ( b_fifo_empty ), .usage_o ( ), @@ -311,8 +308,8 @@ module axi_lite_mux #( .pop_i ( b_fifo_pop ) ); - spill_register #( - .T ( w_chan_t ), + cc_spill_register #( + .data_t ( w_chan_t ), .Bypass ( ~SpillW ) ) i_w_spill_reg ( .clk_i ( clk_i ), @@ -336,8 +333,8 @@ module axi_lite_mux #( assign mst_b_ready = ~b_fifo_empty & slv_reqs_i[b_select].b_ready; assign b_fifo_pop = mst_b_valid & mst_b_ready; - spill_register #( - .T ( b_chan_t ), + cc_spill_register #( + .data_t ( b_chan_t ), .Bypass ( ~SpillB ) ) i_b_spill_reg ( .clk_i ( clk_i ), @@ -359,9 +356,9 @@ module axi_lite_mux #( assign slv_ar_valids[i] = slv_reqs_i[i].ar_valid; assign slv_resps_o[i].ar_ready = slv_ar_readies[i]; end - rr_arb_tree #( + cc_rr_arb_tree #( .NumIn ( NoSlvPorts ), - .DataType ( ar_chan_t ), + .data_t ( ar_chan_t ), .AxiVldRdy( 1'b1 ), .LockIn ( 1'b1 ) ) i_ar_arbiter ( @@ -384,15 +381,14 @@ module axi_lite_mux #( assign ar_ready = (!r_fifo_full) ? mst_ar_ready : 1'b0; assign r_fifo_push = mst_ar_valid & mst_ar_ready; - fifo_v3 #( - .FALL_THROUGH ( FallThrough ), - .DEPTH ( MaxTrans ), - .dtype ( select_t ) + cc_fifo #( + .FallThrough ( FallThrough ), + .Depth ( MaxTrans ), + .data_t ( select_t ) ) i_r_fifo ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), .flush_i ( 1'b0 ), - .testmode_i( test_i ), .full_o ( r_fifo_full ), .empty_o ( r_fifo_empty ), .usage_o ( ), @@ -402,8 +398,8 @@ module axi_lite_mux #( .pop_i ( r_fifo_pop ) ); - spill_register #( - .T ( ar_chan_t ), + cc_spill_register #( + .data_t ( ar_chan_t ), .Bypass ( ~SpillAr ) ) i_ar_spill_reg ( .clk_i ( clk_i ), @@ -427,8 +423,8 @@ module axi_lite_mux #( assign mst_r_ready = ~r_fifo_empty & slv_reqs_i[r_select].r_ready; assign r_fifo_pop = mst_r_valid & mst_r_ready; - spill_register #( - .T ( r_chan_t ), + cc_spill_register #( + .data_t ( r_chan_t ), .Bypass ( ~SpillR ) ) i_r_spill_reg ( .clk_i ( clk_i ), @@ -474,7 +470,6 @@ module axi_lite_mux_intf #( ) ( input logic clk_i, // Clock input logic rst_ni, // Asynchronous reset active low - input logic test_i, // Testmode enable AXI_LITE.Slave slv [NoSlvPorts-1:0], // slave ports AXI_LITE.Master mst // master port ); @@ -523,7 +518,6 @@ module axi_lite_mux_intf #( ) i_axi_mux ( .clk_i, // Clock .rst_ni, // Asynchronous reset active low - .test_i, // Test Mode enable .slv_reqs_i ( slv_reqs ), .slv_resps_o ( slv_resps ), .mst_req_o ( mst_req ), diff --git a/src/axi_lite_regs.sv b/src/axi_lite_regs.sv index 392bd17f1..00692f275 100644 --- a/src/axi_lite_regs.sv +++ b/src/axi_lite_regs.sv @@ -141,7 +141,7 @@ module axi_lite_regs #( // Reg byte: B A 9 8 7 6 5 4 3 2 1 0 // | chunk_2 | chunk_1 | chunk_0 | localparam int unsigned AxiStrbWidth = AxiDataWidth / 32'd8; - localparam int unsigned NumChunks = cf_math_pkg::ceil_div(RegNumBytes, AxiStrbWidth); + localparam int unsigned NumChunks = cc_pkg::ceil_div(RegNumBytes, AxiStrbWidth); localparam int unsigned ChunkIdxWidth = (NumChunks > 32'd1) ? $clog2(NumChunks) : 32'd1; // Type of the index to identify a specific register chunk. typedef logic [ChunkIdxWidth-1:0] chunk_idx_t; @@ -313,11 +313,11 @@ module axi_lite_regs #( // Register array mapping, even read only register can be loaded over `reg_load_i`. for (genvar i = 0; i < RegNumBytes; i++) begin : gen_rw_regs - `FFLARN(reg_q[i], reg_d[i], reg_update[i], RegRstVal[i], clk_i, rst_ni) + `FFL(reg_q[i], reg_d[i], reg_update[i], RegRstVal[i], clk_i, rst_ni) assign reg_q_o[i] = reg_q[i]; end - addr_decode #( + cc_addr_decode #( .NoIndices ( NumChunks ), .NoRules ( NumChunks ), .addr_t ( addr_t ), @@ -332,7 +332,7 @@ module axi_lite_regs #( .default_idx_i ( '0 ) ); - addr_decode #( + cc_addr_decode #( .NoIndices ( NumChunks ), .NoRules ( NumChunks ), .addr_t ( addr_t ), @@ -348,8 +348,8 @@ module axi_lite_regs #( ); // Add a cycle delay on AXI response, cut all comb paths between slave port inputs and outputs. - spill_register #( - .T ( b_chan_lite_t ), + cc_spill_register #( + .data_t ( b_chan_lite_t ), .Bypass ( 1'b0 ) ) i_b_spill_register ( .clk_i, @@ -363,8 +363,8 @@ module axi_lite_regs #( ); // Add a cycle delay on AXI response, cut all comb paths between slave port inputs and outputs. - spill_register #( - .T ( r_chan_lite_t ), + cc_spill_register #( + .data_t ( r_chan_lite_t ), .Bypass ( 1'b0 ) ) i_r_spill_register ( .clk_i, diff --git a/src/axi_lite_to_apb.sv b/src/axi_lite_to_apb.sv index 4d58d0c4a..f41817055 100644 --- a/src/axi_lite_to_apb.sv +++ b/src/axi_lite_to_apb.sv @@ -146,9 +146,9 @@ module axi_lite_to_apb #( int_resp_t apb_rresp; logic apb_rresp_valid, apb_rresp_ready; - rr_arb_tree #( + cc_rr_arb_tree #( .NumIn ( 32'd2 ), - .DataType ( int_req_t ), + .data_t ( int_req_t ), .ExtPrio ( 1'b0 ), .AxiVldRdy( 1'b1 ), .LockIn ( 1'b1 ) @@ -167,8 +167,8 @@ module axi_lite_to_apb #( ); if (PipelineRequest) begin : gen_req_spill - spill_register #( - .T ( int_req_t ), + cc_spill_register #( + .data_t ( int_req_t ), .Bypass ( 1'b0 ) ) i_req_spill ( .clk_i, @@ -181,13 +181,12 @@ module axi_lite_to_apb #( .data_o ( apb_req ) ); end else begin : gen_req_ft_reg - fall_through_register #( - .T ( int_req_t ) + cc_fall_through_register #( + .data_t ( int_req_t ) ) i_req_ft_reg ( .clk_i, .rst_ni, .clr_i ( 1'b0 ), - .testmode_i ( 1'b0 ), .valid_i ( arb_req_valid ), .ready_o ( arb_req_ready ), .data_i ( arb_req ), @@ -198,8 +197,8 @@ module axi_lite_to_apb #( end if (PipelineResponse) begin : gen_resp_spill - spill_register #( - .T ( axi_pkg::resp_t ), + cc_spill_register #( + .data_t ( axi_pkg::resp_t ), .Bypass ( 1'b0 ) ) i_write_resp_spill ( .clk_i, @@ -211,8 +210,8 @@ module axi_lite_to_apb #( .ready_i ( axi_lite_req_i.b_ready ), .data_o ( axi_bresp ) ); - spill_register #( - .T ( int_resp_t ), + cc_spill_register #( + .data_t ( int_resp_t ), .Bypass ( 1'b0 ) ) i_read_resp_spill ( .clk_i, @@ -225,13 +224,12 @@ module axi_lite_to_apb #( .data_o ( axi_rresp ) ); end else begin : gen_resp_ft_reg - fall_through_register #( - .T ( axi_pkg::resp_t ) + cc_fall_through_register #( + .data_t ( axi_pkg::resp_t ) ) i_write_resp_ft_reg ( .clk_i, .rst_ni, .clr_i ( 1'b0 ), - .testmode_i ( 1'b0 ), .valid_i ( apb_wresp_valid ), .ready_o ( apb_wresp_ready ), .data_i ( apb_wresp ), @@ -239,13 +237,12 @@ module axi_lite_to_apb #( .ready_i ( axi_lite_req_i.b_ready ), .data_o ( axi_bresp ) ); - fall_through_register #( - .T ( int_resp_t ) + cc_fall_through_register #( + .data_t ( int_resp_t ) ) i_read_resp_ft_reg ( .clk_i, .rst_ni, .clr_i ( 1'b0 ), - .testmode_i ( 1'b0 ), .valid_i ( apb_rresp_valid ), .ready_o ( apb_rresp_ready ), .data_i ( apb_rresp ), @@ -264,7 +261,7 @@ module axi_lite_to_apb #( // output of address decoder to determine PSELx signal logic apb_dec_valid; sel_idx_t apb_sel_idx; - addr_decode #( + cc_addr_decode #( .NoIndices( NoApbSlaves ), .NoRules ( NoRules ), .addr_t ( addr_t ), @@ -360,7 +357,7 @@ module axi_lite_to_apb #( endcase end - `FFLARN(apb_state_q, apb_state_d, apb_update, Setup, clk_i, rst_ni) + `FFL(apb_state_q, apb_state_d, apb_update, Setup, clk_i, rst_ni) // parameter check // pragma translate_off @@ -451,8 +448,8 @@ module axi_lite_to_apb_intf #( `AXI_LITE_ASSIGN_TO_REQ(axi_req, slv) `AXI_LITE_ASSIGN_FROM_RESP(slv, axi_resp) - onehot_to_bin #( - .ONEHOT_WIDTH ( NoApbSlaves ) + cc_onehot_to_bin #( + .OnehotWidth ( NoApbSlaves ) ) i_onehot_to_bin ( .onehot ( pselx_o ), .bin ( apb_sel ) diff --git a/src/axi_lite_xbar.sv b/src/axi_lite_xbar.sv index 72d1e0356..307350195 100644 --- a/src/axi_lite_xbar.sv +++ b/src/axi_lite_xbar.sv @@ -34,7 +34,6 @@ module axi_lite_xbar #( ) ( input logic clk_i, input logic rst_ni, - input logic test_i, input axi_req_t [Cfg.NoSlvPorts-1:0] slv_ports_req_i, output axi_resp_t [Cfg.NoSlvPorts-1:0] slv_ports_resp_o, output axi_req_t [Cfg.NoMstPorts-1:0] mst_ports_req_o, @@ -76,7 +75,7 @@ module axi_lite_xbar #( full_req_t decerr_req; full_resp_t decerr_resp; - addr_decode #( + cc_addr_decode #( .NoIndices ( Cfg.NoMstPorts ), .NoRules ( Cfg.NoAddrRules ), .addr_t ( addr_t ), @@ -91,7 +90,7 @@ module axi_lite_xbar #( .default_idx_i ( default_mst_port_i[i] ) ); - addr_decode #( + cc_addr_decode #( .NoIndices ( Cfg.NoMstPorts ), .addr_t ( addr_t ), .NoRules ( Cfg.NoAddrRules ), @@ -158,7 +157,6 @@ module axi_lite_xbar #( ) i_axi_lite_demux ( .clk_i, // Clock .rst_ni, // Asynchronous reset active low - .test_i, // Testmode enable .slv_req_i ( slv_ports_req_i[i] ), .slv_aw_select_i ( slv_aw_select ), .slv_ar_select_i ( slv_ar_select ), @@ -195,7 +193,6 @@ module axi_lite_xbar #( ) i_axi_err_slv ( .clk_i ( clk_i ), // Clock .rst_ni ( rst_ni ), // Asynchronous reset active low - .test_i ( test_i ), // Testmode enable // slave port .slv_req_i ( decerr_req ), .slv_resp_o ( decerr_resp ) @@ -230,7 +227,6 @@ module axi_lite_xbar #( ) i_axi_lite_mux ( .clk_i, // Clock .rst_ni, // Asynchronous reset active low - .test_i, // Test Mode enable .slv_reqs_i ( mst_reqs[i] ), .slv_resps_o ( mst_resps[i] ), .mst_req_o ( mst_ports_req_o[i] ), @@ -247,7 +243,6 @@ module axi_lite_xbar_intf #( ) ( input logic clk_i, input logic rst_ni, - input logic test_i, AXI_LITE.Slave slv_ports [Cfg.NoSlvPorts-1:0], AXI_LITE.Master mst_ports [Cfg.NoMstPorts-1:0], input rule_t [Cfg.NoAddrRules-1:0] addr_map_i, @@ -294,7 +289,6 @@ module axi_lite_xbar_intf #( ) i_xbar ( .clk_i, .rst_ni, - .test_i, .slv_ports_req_i (slv_reqs ), .slv_ports_resp_o (slv_resps), .mst_ports_req_o (mst_reqs ), diff --git a/src/axi_mux.sv b/src/axi_mux.sv index da17e2b8c..62b64e4f5 100644 --- a/src/axi_mux.sv +++ b/src/axi_mux.sv @@ -312,7 +312,7 @@ module axi_mux #( end end - `FFLARN(lock_aw_valid_q, lock_aw_valid_d, load_aw_lock, '0, clk_i, rst_ni) + `FFL(lock_aw_valid_q, lock_aw_valid_d, load_aw_lock, '0, clk_i, rst_ni) fifo_v3 #( .FALL_THROUGH ( FallThrough ), diff --git a/src/axi_serializer.sv b/src/axi_serializer.sv index 317faa062..da024983f 100644 --- a/src/axi_serializer.sv +++ b/src/axi_serializer.sv @@ -146,15 +146,14 @@ module axi_serializer #( mst_req_o.r_ready = slv_req_i.r_ready & ~rd_fifo_empty; end - fifo_v3 #( - .FALL_THROUGH ( 1'b0 ), // No fall-through as response has to come a cycle later anyway - .DEPTH ( MaxReadTxns ), - .dtype ( id_t ) + cc_fifo #( + .FallThrough ( 1'b0 ), // No fall-through as response has to come a cycle later anyway + .Depth ( MaxReadTxns ), + .data_t ( id_t ) ) i_rd_id_fifo ( .clk_i, .rst_ni, .flush_i ( 1'b0 ), - .testmode_i ( 1'b0 ), .data_i ( ar_id ), .push_i ( rd_fifo_push ), .full_o ( rd_fifo_full ), @@ -166,15 +165,14 @@ module axi_serializer #( // Assign as this condition is needed in FSM assign rd_fifo_pop = slv_resp_o.r_valid & slv_req_i.r_ready & slv_resp_o.r.last; - fifo_v3 #( - .FALL_THROUGH ( 1'b0 ), - .DEPTH ( MaxWriteTxns ), - .dtype ( id_t ) + cc_fifo #( + .FallThrough ( 1'b0 ), + .Depth ( MaxWriteTxns ), + .data_t ( id_t ) ) i_wr_id_fifo ( .clk_i, .rst_ni, .flush_i ( 1'b0 ), - .testmode_i ( 1'b0 ), .data_i ( slv_req_i.aw.id ), .push_i ( wr_fifo_push ), .full_o ( wr_fifo_full ), @@ -186,7 +184,7 @@ module axi_serializer #( // Assign as this condition is needed in FSM assign wr_fifo_pop = slv_resp_o.b_valid & slv_req_i.b_ready; - `FFARN(state_q, state_d, AtopIdle, clk_i, rst_ni) + `FF(state_q, state_d, AtopIdle, clk_i, rst_ni) // pragma translate_off `ifndef VERILATOR diff --git a/src/axi_slave_compare.sv b/src/axi_slave_compare.sv index 6cda82e05..54f1eb8c9 100644 --- a/src/axi_slave_compare.sv +++ b/src/axi_slave_compare.sv @@ -47,8 +47,6 @@ module axi_slave_compare #( input logic clk_i, /// Asynchronous reset, active low input logic rst_ni, - /// Testmode - input logic testmode_i, /// AXI4+ATOP channel request in input axi_req_t axi_mst_req_i, /// AXI4+ATOP channel response out @@ -92,8 +90,8 @@ module axi_slave_compare #( logic w_ready_mst; logic ar_ready_mst; - stream_fork #( - .N_OUP ( 32'd2 ) + cc_stream_fork #( + .NumOup ( 32'd2 ) ) i_stream_fork_aw ( .clk_i, .rst_ni, @@ -103,8 +101,8 @@ module axi_slave_compare #( .ready_i ( { aw_ready_ref, aw_ready_test } ) ); - stream_fork #( - .N_OUP ( 32'd2 ) + cc_stream_fork #( + .NumOup ( 32'd2 ) ) i_stream_fork_ar ( .clk_i, .rst_ni, @@ -114,8 +112,8 @@ module axi_slave_compare #( .ready_i ( { ar_ready_ref, ar_ready_test } ) ); - stream_fork #( - .N_OUP ( 32'd2 ) + cc_stream_fork #( + .NumOup ( 32'd2 ) ) i_stream_fork_w ( .clk_i, .rst_ni, @@ -170,7 +168,6 @@ module axi_slave_compare #( ) i_axi_bus_compare ( .clk_i, .rst_ni, - .testmode_i, .aw_mismatch_o, .w_mismatch_o, .b_mismatch_o, diff --git a/src/axi_throttle.sv b/src/axi_throttle.sv index 3e7973a08..ee91090fa 100644 --- a/src/axi_throttle.sv +++ b/src/axi_throttle.sv @@ -19,9 +19,9 @@ module axi_throttle #( /// AXI4+ATOP response type parameter type axi_rsp_t = logic, /// The width of the write credit counter (*DO NOT OVERWRITE*) - parameter int unsigned WCntWidth = cf_math_pkg::idx_width(MaxNumAwPending), + parameter int unsigned WCntWidth = cc_pkg::idx_width(MaxNumAwPending), /// The width of the read credit counter (*DO NOT OVERWRITE*) - parameter int unsigned RCntWidth = cf_math_pkg::idx_width(MaxNumArPending), + parameter int unsigned RCntWidth = cc_pkg::idx_width(MaxNumArPending), /// The type of the write credit counter (*DO NOT OVERWRITE*) parameter type w_credit_t = logic [WCntWidth-1:0], /// The type of the read credit counter (*DO NOT OVERWRITE*) diff --git a/src/axi_to_axi_lite.sv b/src/axi_to_axi_lite.sv index ad2e41414..16b7bad81 100644 --- a/src/axi_to_axi_lite.sv +++ b/src/axi_to_axi_lite.sv @@ -31,7 +31,6 @@ module axi_to_axi_lite #( ) ( input logic clk_i, // Clock input logic rst_ni, // Asynchronous reset active low - input logic test_i, // Testmode enable // slave port full AXI4+ATOP input full_req_t slv_req_i, output full_resp_t slv_resp_o, @@ -91,7 +90,6 @@ module axi_to_axi_lite #( ) i_axi_to_axi_lite_id_reflect ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), - .test_i ( test_i ), .slv_req_i ( splitted_req ), .slv_resp_o ( splitted_resp ), .mst_req_o ( mst_req_o ), @@ -127,7 +125,6 @@ module axi_to_axi_lite_id_reflect #( ) ( input logic clk_i, // Clock input logic rst_ni, // Asynchronous reset active low - input logic test_i, // Testmode enable // slave port full AXI input full_req_t slv_req_i, output full_resp_t slv_resp_o, @@ -165,15 +162,14 @@ module axi_to_axi_lite_id_reflect #( // Write ID reflection assign aw_push = mst_req_o.aw_valid & slv_resp_o.aw_ready; assign aw_pop = slv_resp_o.b_valid & mst_req_o.b_ready; - fifo_v3 #( - .FALL_THROUGH ( FallThrough ), - .DEPTH ( AxiMaxWriteTxns ), - .dtype ( id_t ) + cc_fifo #( + .FallThrough ( FallThrough ), + .Depth ( AxiMaxWriteTxns ), + .data_t ( id_t ) ) i_aw_id_fifo ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), .flush_i ( 1'b0 ), - .testmode_i( test_i ), .full_o ( aw_full ), .empty_o ( aw_empty ), .usage_o ( /*not used*/ ), @@ -186,15 +182,14 @@ module axi_to_axi_lite_id_reflect #( // Read ID reflection assign ar_push = mst_req_o.ar_valid & slv_resp_o.ar_ready; assign ar_pop = slv_resp_o.r_valid & mst_req_o.r_ready; - fifo_v3 #( - .FALL_THROUGH ( FallThrough ), - .DEPTH ( AxiMaxReadTxns ), - .dtype ( id_t ) + cc_fifo #( + .FallThrough ( FallThrough ), + .Depth ( AxiMaxReadTxns ), + .data_t ( id_t ) ) i_ar_id_fifo ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), .flush_i ( 1'b0 ), - .testmode_i( test_i ), .full_o ( ar_full ), .empty_o ( ar_empty ), .usage_o ( /*not used*/ ), @@ -262,7 +257,6 @@ module axi_to_axi_lite_intf #( ) ( input logic clk_i, input logic rst_ni, - input logic testmode_i, AXI_BUS.Slave slv, AXI_LITE.Master mst ); @@ -315,7 +309,6 @@ module axi_to_axi_lite_intf #( ) i_axi_to_axi_lite ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), - .test_i ( testmode_i ), // slave port full AXI4+ATOP .slv_req_i ( full_req ), .slv_resp_o ( full_resp ), diff --git a/src/axi_to_detailed_mem.sv b/src/axi_to_detailed_mem.sv index 376a48f07..70ad9e2c5 100644 --- a/src/axi_to_detailed_mem.sv +++ b/src/axi_to_detailed_mem.sv @@ -264,9 +264,9 @@ module axi_to_detailed_mem #( end // Arbitrate between reads and writes. - stream_mux #( - .DATA_T ( meta_t ), - .N_INP ( 32'd2 ) + cc_stream_mux #( + .data_t ( meta_t ), + .NumInp ( 32'd2 ) ) i_ax_mux ( .inp_data_i ({wr_meta, rd_meta }), .inp_valid_i ({wr_valid, rd_valid}), @@ -321,8 +321,8 @@ module axi_to_detailed_mem #( end // Fork arbitrated stream to meta data, memory requests, and R/B channel selection. - stream_fork #( - .N_OUP ( 32'd3 ) + cc_stream_fork #( + .NumOup ( 32'd3 ) ) i_fork ( .clk_i, .rst_ni, @@ -335,15 +335,14 @@ module axi_to_detailed_mem #( assign sel_b = meta.write & meta.last; assign sel_r = ~meta.write | meta.atop[5]; - stream_fifo #( - .FALL_THROUGH ( 1'b1 ), - .DEPTH ( 32'd1 + BufDepth ), - .T ( logic[1:0] ) + cc_stream_fifo #( + .FallThrough ( 1'b1 ), + .Depth ( 32'd1 + BufDepth ), + .data_t ( logic[1:0] ) ) i_sel_buf ( .clk_i, .rst_ni, .flush_i ( 1'b0 ), - .testmode_i ( 1'b0 ), .data_i ({sel_b, sel_r }), .valid_i ( sel_valid ), .ready_o ( sel_ready ), @@ -353,15 +352,14 @@ module axi_to_detailed_mem #( .usage_o ( /* unused */ ) ); - stream_fifo #( - .FALL_THROUGH ( 1'b1 ), - .DEPTH ( 32'd1 + BufDepth ), - .T ( meta_t ) + cc_stream_fifo #( + .FallThrough ( 1'b1 ), + .Depth ( 32'd1 + BufDepth ), + .data_t ( meta_t ) ) i_meta_buf ( .clk_i, .rst_ni, .flush_i ( 1'b0 ), - .testmode_i ( 1'b0 ), .data_i ( meta ), .valid_i ( meta_valid ), .ready_o ( meta_ready ), @@ -470,8 +468,8 @@ module axi_to_detailed_mem #( // Join memory read data and meta data stream. logic mem_join_valid, mem_join_ready; - stream_join #( - .N_INP ( 32'd2 ) + cc_stream_join #( + .NumInp ( 32'd2 ) ) i_join ( .inp_valid_i ({m2s_resp_valid, meta_buf_valid}), .inp_ready_o ({m2s_resp_ready, meta_buf_ready}), @@ -480,8 +478,8 @@ module axi_to_detailed_mem #( ); // Dynamically fork the joined stream to B and R channels. - stream_fork_dynamic #( - .N_OUP ( 32'd2 ) + cc_stream_fork_dynamic #( + .NumOup ( 32'd2 ) ) i_fork_dynamic ( .clk_i, .rst_ni, @@ -555,14 +553,14 @@ module axi_to_detailed_mem #( }; // Registers - `FFARN(meta_sel_q, meta_sel_d, 1'b0, clk_i, rst_ni) - `FFARN(sel_lock_q, sel_lock_d, 1'b0, clk_i, rst_ni) - `FFARN(rd_meta_q, rd_meta_d, meta_t'{default: '0}, clk_i, rst_ni) - `FFARN(wr_meta_q, wr_meta_d, meta_t'{default: '0}, clk_i, rst_ni) - `FFARN(r_cnt_q, r_cnt_d, '0, clk_i, rst_ni) - `FFARN(w_cnt_q, w_cnt_d, '0, clk_i, rst_ni) - `FFARN(collect_b_err_q, collect_b_err_d, '0, clk_i, rst_ni) - `FFARN(collect_b_exokay_q, collect_b_exokay_d, 1'b1, clk_i, rst_ni) + `FF(meta_sel_q, meta_sel_d, 1'b0, clk_i, rst_ni) + `FF(sel_lock_q, sel_lock_d, 1'b0, clk_i, rst_ni) + `FF(rd_meta_q, rd_meta_d, meta_t'{default: '0}, clk_i, rst_ni) + `FF(wr_meta_q, wr_meta_d, meta_t'{default: '0}, clk_i, rst_ni) + `FF(r_cnt_q, r_cnt_d, '0, clk_i, rst_ni) + `FF(w_cnt_q, w_cnt_d, '0, clk_i, rst_ni) + `FF(collect_b_err_q, collect_b_err_d, '0, clk_i, rst_ni) + `FF(collect_b_exokay_q, collect_b_exokay_d, 1'b1, clk_i, rst_ni) // Assertions // pragma translate_off @@ -864,7 +862,7 @@ module mem_stream_to_banks_detailed #( assign mem_req_valid = req_i & cnt_req_ready; // Register - `FFARN(cnt_q, cnt_d, '0, clk_i, rst_ni) + `FF(cnt_q, cnt_d, '0, clk_i, rst_ni) end // Handle requests. @@ -875,16 +873,15 @@ module mem_stream_to_banks_detailed #( assign bank_req[i].strb = strb_i[i*BytesPerBank+:BytesPerBank]; assign bank_req[i].wuser = wuser_i; assign bank_req[i].we = we_i; - stream_fifo #( - .FALL_THROUGH ( 1'b1 ), - .DATA_WIDTH ( $bits(req_t) ), - .DEPTH ( OutFifoDepth ), - .T ( req_t ) + cc_stream_fifo #( + .FallThrough ( 1'b1 ), + .DataWidth ( $bits(req_t) ), + .Depth ( OutFifoDepth ), + .data_t ( req_t ) ) i_ft_reg ( .clk_i, .rst_ni, .flush_i ( 1'b0 ), - .testmode_i ( 1'b0 ), .usage_o (), .data_i ( bank_req[i] ), .valid_i ( req_valid ), @@ -921,15 +918,14 @@ module mem_stream_to_banks_detailed #( for (genvar i = 0; unsigned'(i) < NumBanks; i++) begin assign zero_strobe_on_input[i] = (strb_i[i*BytesPerBank+:BytesPerBank] == '0); end - fifo_v3 #( - .FALL_THROUGH ( 1'b0 ), - .DEPTH ( MaxTrans+1 ), - .DATA_WIDTH ( NumBanks ) + cc_fifo #( + .FallThrough ( 1'b0 ), + .Depth ( MaxTrans+1 ), + .DataWidth ( NumBanks ) ) i_dead_write_fifo ( .clk_i, .rst_ni, .flush_i ( 1'b0 ), - .testmode_i ( 1'b0 ), .full_o ( dead_write_fifo_full ), .empty_o ( dead_write_fifo_empty ), .usage_o ( ), @@ -948,15 +944,14 @@ module mem_stream_to_banks_detailed #( // Handle responses. for (genvar i = 0; unsigned'(i) < NumBanks; i++) begin : gen_resp_regs - stream_fifo #( - .FALL_THROUGH ( 1'b1 ), - .DATA_WIDTH ( $bits(oup_data_t) + $bits(oup_ruser_t) ), - .DEPTH ( MaxTrans ) + cc_stream_fifo #( + .FallThrough ( 1'b1 ), + .DataWidth ( $bits(oup_data_t) + $bits(oup_ruser_t) ), + .Depth ( MaxTrans ) ) i_ft_reg ( .clk_i, .rst_ni, .flush_i ( 1'b0 ), - .testmode_i ( 1'b0 ), .usage_o (), .data_i ( {bank_rdata_i[i], bank_ruser_i[i]} ), .valid_i ( bank_rvalid_i[i] ), diff --git a/src/axi_to_mem_banked.sv b/src/axi_to_mem_banked.sv index 548339f37..977217a62 100644 --- a/src/axi_to_mem_banked.sv +++ b/src/axi_to_mem_banked.sv @@ -69,7 +69,6 @@ module axi_to_mem_banked #( /// Asynchronous reset, active low input logic rst_ni, /// Testmode enable - input logic test_i, /// AXI4+ATOP slave port, request struct input axi_req_t axi_req_i, /// AXI4+ATOP slave port, response struct @@ -101,7 +100,7 @@ module axi_to_mem_banked #( localparam int unsigned BankSelOffset = $clog2(MemDataWidth / 32'd8); /// Selection signal width of the xbar. This is the reason for power of two banks, otherwise /// There are holes in the address mapping. - localparam int unsigned BankSelWidth = cf_math_pkg::idx_width(MemNumBanks); + localparam int unsigned BankSelWidth = cc_pkg::idx_width(MemNumBanks); typedef logic [BankSelWidth-1:0] xbar_sel_t; // Typedef for defining the channels @@ -159,7 +158,6 @@ module axi_to_mem_banked #( ) i_axi_demux ( .clk_i, .rst_ni, - .test_i, .slv_req_i ( axi_req_i ), .slv_aw_select_i ( WriteAccess ), .slv_ar_select_i ( ReadAccess ), @@ -240,9 +238,9 @@ module axi_to_mem_banked #( assign res_rdata[j] = mem_rdata_i[r_shift_oup.sel]; // Connect for the response data `MemLatency` cycles after a request was made to the xbar. - shift_reg #( - .dtype ( read_sel_t ), - .Depth ( MemLatency ) + cc_shift_reg #( + .data_t ( read_sel_t ), + .Depth ( MemLatency ) ) i_shift_reg_rdata_mux ( .clk_i, .rst_ni, @@ -255,7 +253,7 @@ module axi_to_mem_banked #( // Xbar to arbitrate data over the different memory banks xbar_payload_t [MemNumBanks-1:0] mem_payload; - stream_xbar #( + cc_stream_xbar #( .NumInp ( 32'd2 * BanksPerAxiChannel ), .NumOut ( MemNumBanks ), .payload_t ( xbar_payload_t ), @@ -346,7 +344,6 @@ module axi_to_mem_banked_intf #( /// Asynchronous reset, active low input logic rst_ni, /// Testmode enable - input logic test_i, /// AXI4+ATOP slave port AXI_BUS.Slave slv, /// Memory bank request @@ -407,7 +404,6 @@ module axi_to_mem_banked_intf #( ) i_axi_to_mem_banked ( .clk_i, .rst_ni, - .test_i, .axi_to_mem_busy_o, .axi_req_i ( mem_axi_req ), .axi_resp_o ( mem_axi_resp ), diff --git a/src/axi_to_mem_interleaved.sv b/src/axi_to_mem_interleaved.sv index 94d2bbef0..c84e8f8fc 100644 --- a/src/axi_to_mem_interleaved.sv +++ b/src/axi_to_mem_interleaved.sv @@ -48,7 +48,6 @@ module axi_to_mem_interleaved #( /// Asynchronous reset, active low. input logic rst_ni, /// Testmode enable - input logic test_i, /// The unit is busy handling an AXI4+ATOP request. output logic busy_o, /// AXI4+ATOP slave port, request input. @@ -113,7 +112,6 @@ module axi_to_mem_interleaved #( ) i_split_read_write ( .clk_i, .rst_ni, - .test_i, .slv_req_i ( axi_req_i ), .slv_ar_select_i ( 1'b0 ), .slv_aw_select_i ( 1'b1 ), @@ -221,9 +219,9 @@ module axi_to_mem_interleaved #( assign r_axi_to_mem_gnt[i] = r_mem_gnt[i] & ~fifo_full[i]; // fine-grain arbitration - rr_arb_tree #( + cc_rr_arb_tree #( .NumIn ( 2 ), - .DataType ( mem_req_payload_t ) + .data_t ( mem_req_payload_t ) ) i_rr_arb_tree ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), @@ -239,14 +237,13 @@ module axi_to_mem_interleaved #( ); // back-routing store - fifo_v3 #( - .DATA_WIDTH ( 1 ), - .DEPTH ( BufDepth + 1 ) + cc_fifo #( + .DataWidth ( 1 ), + .Depth ( BufDepth + 1 ) ) i_fifo_v3_response_trgt_store ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), .flush_i ( 1'b0 ), - .testmode_i ( 1'b0 ), .full_o ( fifo_full[i] ), .empty_o ( ), .usage_o ( ), @@ -294,7 +291,6 @@ module axi_to_mem_interleaved_intf #( /// Asynchronous reset, active low input logic rst_ni, /// Testmode enable - input logic test_i, /// Status output, busy flag of `axi_to_mem` output logic busy_o, /// AXI4+ATOP slave port @@ -350,7 +346,6 @@ module axi_to_mem_interleaved_intf #( ) i_axi_to_mem_interleaved ( .clk_i, .rst_ni, - .test_i, .busy_o, .axi_req_i ( mem_axi_req ), .axi_resp_o ( mem_axi_resp ), diff --git a/src/axi_to_mem_split.sv b/src/axi_to_mem_split.sv index 3e98bda2e..df52d3c2a 100644 --- a/src/axi_to_mem_split.sv +++ b/src/axi_to_mem_split.sv @@ -51,7 +51,6 @@ module axi_to_mem_split #( /// Asynchronous reset, active low. input logic rst_ni, /// Testmode enable - input logic test_i, /// The unit is busy handling an AXI4+ATOP request. output logic busy_o, /// AXI4+ATOP slave port, request input. @@ -97,7 +96,6 @@ module axi_to_mem_split #( ) i_split_read_write ( .clk_i, .rst_ni, - .test_i, .slv_req_i ( axi_req_i ), .slv_ar_select_i ( 1'b0 ), .slv_aw_select_i ( 1'b1 ), @@ -197,7 +195,6 @@ module axi_to_mem_split_intf #( /// Asynchronous reset, active low. input logic rst_ni, /// Testmode enable - input logic test_i, /// See `axi_to_mem_split`, port `busy_o`. output logic busy_o, /// AXI4+ATOP slave interface port. @@ -246,7 +243,6 @@ module axi_to_mem_split_intf #( ) i_axi_to_mem_split ( .clk_i, .rst_ni, - .test_i, .busy_o, .axi_req_i (axi_req), .axi_resp_o (axi_resp), diff --git a/src/axi_xbar.sv b/src/axi_xbar.sv index 5baa854ba..16ef708e7 100644 --- a/src/axi_xbar.sv +++ b/src/axi_xbar.sv @@ -16,7 +16,7 @@ /// axi_xbar: 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 -import cf_math_pkg::idx_width; +import cc_pkg::idx_width; #( /// Configuration struct for the crossbar see `axi_pkg` for fields and definitions. parameter axi_pkg::xbar_cfg_t Cfg = '0, @@ -160,7 +160,7 @@ endmodule `include "axi/typedef.svh" module axi_xbar_intf -import cf_math_pkg::idx_width; +import cc_pkg::idx_width; #( parameter int unsigned AXI_USER_WIDTH = 0, parameter axi_pkg::xbar_cfg_t Cfg = '0, diff --git a/src/axi_xbar_unmuxed.sv b/src/axi_xbar_unmuxed.sv index 73e50975c..e926461c2 100644 --- a/src/axi_xbar_unmuxed.sv +++ b/src/axi_xbar_unmuxed.sv @@ -16,7 +16,7 @@ /// axi_xbar: 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_unmuxed -import cf_math_pkg::idx_width; +import cc_pkg::idx_width; #( /// Configuration struct for the crossbar see `axi_pkg` for fields and definitions. parameter axi_pkg::xbar_cfg_t Cfg = '0, @@ -274,7 +274,7 @@ endmodule `include "axi/typedef.svh" module axi_xbar_unmuxed_intf -import cf_math_pkg::idx_width; +import cc_pkg::idx_width; #( parameter int unsigned AXI_USER_WIDTH = 0, parameter axi_pkg::xbar_cfg_t Cfg = '0, diff --git a/src/axi_xp.sv b/src/axi_xp.sv index 5ccbfb9ff..db8c21851 100644 --- a/src/axi_xp.sv +++ b/src/axi_xp.sv @@ -135,7 +135,6 @@ module axi_xp #( ) i_xbar ( .clk_i, .rst_ni, - .test_i ( test_en_i ), .slv_ports_req_i ( slv_req_i ), .slv_ports_resp_o ( slv_resp_o ), .mst_ports_req_o ( xbar_req ), @@ -171,7 +170,7 @@ endmodule `include "axi/typedef.svh" module axi_xp_intf -import cf_math_pkg::idx_width; +import cc_pkg::idx_width; #( parameter bit ATOPs = 1'b1, parameter axi_pkg::xbar_cfg_t Cfg = '0, diff --git a/test/tb_axi_bus_compare.sv b/test/tb_axi_bus_compare.sv index c8cd1c91c..4542af7ca 100644 --- a/test/tb_axi_bus_compare.sv +++ b/test/tb_axi_bus_compare.sv @@ -79,7 +79,7 @@ module tb_axi_bus_compare #( logic w_ready; logic ar_ready; - stream_fork #(.N_OUP(32'd2)) i_stream_fork_aw ( + cc_stream_fork #(.NumOup(32'd2)) i_stream_fork_aw ( .clk_i ( clk ), .rst_ni ( rst_n ), .valid_i ( axi_req.aw_valid ), @@ -88,7 +88,7 @@ module tb_axi_bus_compare #( .ready_i ( { aw_ready_a, aw_ready_b } ) ); - stream_fork #(.N_OUP(32'd2)) i_stream_fork_ar ( + cc_stream_fork #(.NumOup(32'd2)) i_stream_fork_ar ( .clk_i ( clk ), .rst_ni ( rst_n ), .valid_i ( axi_req.ar_valid ), @@ -97,7 +97,7 @@ module tb_axi_bus_compare #( .ready_i ( { ar_ready_a, ar_ready_b } ) ); - stream_fork #(.N_OUP(32'd2)) i_stream_fork_w ( + cc_stream_fork #(.NumOup(32'd2)) i_stream_fork_w ( .clk_i ( clk ), .rst_ni ( rst_n ), .valid_i ( axi_req.w_valid ), @@ -149,7 +149,6 @@ module tb_axi_bus_compare #( ) i_axi_bus_compare ( .clk_i ( clk ), .rst_ni ( rst_n ), - .testmode_i ( 1'b0 ), .axi_a_req_i ( axi_req_a_in ), .axi_a_rsp_o ( axi_rsp_a_in ), .axi_a_req_o ( axi_req_a_out ), diff --git a/test/tb_axi_fifo.sv b/test/tb_axi_fifo.sv index 2e79044e0..b962fa952 100644 --- a/test/tb_axi_fifo.sv +++ b/test/tb_axi_fifo.sv @@ -111,7 +111,6 @@ module tb_axi_fifo #( ) i_dut ( .clk_i (clk), // clock .rst_ni(rst_n), // asynchronous reset active low - .test_i(1'b0), .slv (master), // slave port .mst (slave) // master port ); diff --git a/test/tb_axi_fifo.wave.do b/test/tb_axi_fifo.wave.do index bdf1d9e20..5e0fdf5a6 100644 --- a/test/tb_axi_fifo.wave.do +++ b/test/tb_axi_fifo.wave.do @@ -98,7 +98,6 @@ add wave -noupdate -divider Custom add wave -noupdate -expand -group {AW FiFo} /tb_axi_fifo/i_dut/i_axi_fifo/gen_axi_fifo/i_aw_fifo/clk_i add wave -noupdate -expand -group {AW FiFo} /tb_axi_fifo/i_dut/i_axi_fifo/gen_axi_fifo/i_aw_fifo/rst_ni add wave -noupdate -expand -group {AW FiFo} /tb_axi_fifo/i_dut/i_axi_fifo/gen_axi_fifo/i_aw_fifo/flush_i -add wave -noupdate -expand -group {AW FiFo} /tb_axi_fifo/i_dut/i_axi_fifo/gen_axi_fifo/i_aw_fifo/testmode_i add wave -noupdate -expand -group {AW FiFo} /tb_axi_fifo/i_dut/i_axi_fifo/gen_axi_fifo/i_aw_fifo/full_o add wave -noupdate -expand -group {AW FiFo} /tb_axi_fifo/i_dut/i_axi_fifo/gen_axi_fifo/i_aw_fifo/empty_o add wave -noupdate -expand -group {AW FiFo} /tb_axi_fifo/i_dut/i_axi_fifo/gen_axi_fifo/i_aw_fifo/usage_o @@ -109,7 +108,6 @@ add wave -noupdate -expand -group {AW FiFo} /tb_axi_fifo/i_dut/i_axi_fifo/gen_ax add wave -noupdate -expand -group {W FiFo} /tb_axi_fifo/i_dut/i_axi_fifo/gen_axi_fifo/i_w_fifo/clk_i add wave -noupdate -expand -group {W FiFo} /tb_axi_fifo/i_dut/i_axi_fifo/gen_axi_fifo/i_w_fifo/rst_ni add wave -noupdate -expand -group {W FiFo} /tb_axi_fifo/i_dut/i_axi_fifo/gen_axi_fifo/i_w_fifo/flush_i -add wave -noupdate -expand -group {W FiFo} /tb_axi_fifo/i_dut/i_axi_fifo/gen_axi_fifo/i_w_fifo/testmode_i add wave -noupdate -expand -group {W FiFo} /tb_axi_fifo/i_dut/i_axi_fifo/gen_axi_fifo/i_w_fifo/full_o add wave -noupdate -expand -group {W FiFo} /tb_axi_fifo/i_dut/i_axi_fifo/gen_axi_fifo/i_w_fifo/empty_o add wave -noupdate -expand -group {W FiFo} /tb_axi_fifo/i_dut/i_axi_fifo/gen_axi_fifo/i_w_fifo/usage_o @@ -120,7 +118,6 @@ add wave -noupdate -expand -group {W FiFo} /tb_axi_fifo/i_dut/i_axi_fifo/gen_axi add wave -noupdate -expand -group {B FiFo} /tb_axi_fifo/i_dut/i_axi_fifo/gen_axi_fifo/i_b_fifo/clk_i add wave -noupdate -expand -group {B FiFo} /tb_axi_fifo/i_dut/i_axi_fifo/gen_axi_fifo/i_b_fifo/rst_ni add wave -noupdate -expand -group {B FiFo} /tb_axi_fifo/i_dut/i_axi_fifo/gen_axi_fifo/i_b_fifo/flush_i -add wave -noupdate -expand -group {B FiFo} /tb_axi_fifo/i_dut/i_axi_fifo/gen_axi_fifo/i_b_fifo/testmode_i add wave -noupdate -expand -group {B FiFo} /tb_axi_fifo/i_dut/i_axi_fifo/gen_axi_fifo/i_b_fifo/full_o add wave -noupdate -expand -group {B FiFo} /tb_axi_fifo/i_dut/i_axi_fifo/gen_axi_fifo/i_b_fifo/empty_o add wave -noupdate -expand -group {B FiFo} /tb_axi_fifo/i_dut/i_axi_fifo/gen_axi_fifo/i_b_fifo/usage_o @@ -131,7 +128,6 @@ add wave -noupdate -expand -group {B FiFo} /tb_axi_fifo/i_dut/i_axi_fifo/gen_axi add wave -noupdate -expand -group {Ar FiFo} /tb_axi_fifo/i_dut/i_axi_fifo/gen_axi_fifo/i_ar_fifo/clk_i add wave -noupdate -expand -group {Ar FiFo} /tb_axi_fifo/i_dut/i_axi_fifo/gen_axi_fifo/i_ar_fifo/rst_ni add wave -noupdate -expand -group {Ar FiFo} /tb_axi_fifo/i_dut/i_axi_fifo/gen_axi_fifo/i_ar_fifo/flush_i -add wave -noupdate -expand -group {Ar FiFo} /tb_axi_fifo/i_dut/i_axi_fifo/gen_axi_fifo/i_ar_fifo/testmode_i add wave -noupdate -expand -group {Ar FiFo} /tb_axi_fifo/i_dut/i_axi_fifo/gen_axi_fifo/i_ar_fifo/full_o add wave -noupdate -expand -group {Ar FiFo} /tb_axi_fifo/i_dut/i_axi_fifo/gen_axi_fifo/i_ar_fifo/empty_o add wave -noupdate -expand -group {Ar FiFo} /tb_axi_fifo/i_dut/i_axi_fifo/gen_axi_fifo/i_ar_fifo/usage_o @@ -142,7 +138,6 @@ add wave -noupdate -expand -group {Ar FiFo} /tb_axi_fifo/i_dut/i_axi_fifo/gen_ax add wave -noupdate -expand -group {R FiFo} /tb_axi_fifo/i_dut/i_axi_fifo/gen_axi_fifo/i_r_fifo/clk_i add wave -noupdate -expand -group {R FiFo} /tb_axi_fifo/i_dut/i_axi_fifo/gen_axi_fifo/i_r_fifo/rst_ni add wave -noupdate -expand -group {R FiFo} /tb_axi_fifo/i_dut/i_axi_fifo/gen_axi_fifo/i_r_fifo/flush_i -add wave -noupdate -expand -group {R FiFo} /tb_axi_fifo/i_dut/i_axi_fifo/gen_axi_fifo/i_r_fifo/testmode_i add wave -noupdate -expand -group {R FiFo} /tb_axi_fifo/i_dut/i_axi_fifo/gen_axi_fifo/i_r_fifo/full_o add wave -noupdate -expand -group {R FiFo} /tb_axi_fifo/i_dut/i_axi_fifo/gen_axi_fifo/i_r_fifo/empty_o add wave -noupdate -expand -group {R FiFo} /tb_axi_fifo/i_dut/i_axi_fifo/gen_axi_fifo/i_r_fifo/usage_o diff --git a/test/tb_axi_lite_mailbox.sv b/test/tb_axi_lite_mailbox.sv index 255702922..14fab56fe 100644 --- a/test/tb_axi_lite_mailbox.sv +++ b/test/tb_axi_lite_mailbox.sv @@ -456,7 +456,6 @@ module tb_axi_lite_mailbox; ) i_mailbox_dut ( .clk_i ( clk ), .rst_ni ( rst_n ), - .test_i ( 1'b0 ), .slv ( master ), .irq_o ( irq ), .base_addr_i ( '0 ) // set base address to '0 diff --git a/test/tb_axi_lite_mailbox.wave.do b/test/tb_axi_lite_mailbox.wave.do index c272b4fa2..3e1572ba3 100644 --- a/test/tb_axi_lite_mailbox.wave.do +++ b/test/tb_axi_lite_mailbox.wave.do @@ -3,7 +3,6 @@ onerror {resume} quietly WaveActivateNextPane {} 0 add wave -noupdate /tb_axi_lite_mailbox/i_mailbox_dut/i_axi_lite_mailbox/clk_i add wave -noupdate /tb_axi_lite_mailbox/i_mailbox_dut/i_axi_lite_mailbox/rst_ni -add wave -noupdate /tb_axi_lite_mailbox/i_mailbox_dut/i_axi_lite_mailbox/test_i add wave -noupdate -divider Ports add wave -noupdate /tb_axi_lite_mailbox/i_mailbox_dut/i_axi_lite_mailbox/slv_reqs_i add wave -noupdate /tb_axi_lite_mailbox/i_mailbox_dut/i_axi_lite_mailbox/slv_resps_o diff --git a/test/tb_axi_lite_xbar.sv b/test/tb_axi_lite_xbar.sv index 54697344a..d4d460af1 100644 --- a/test/tb_axi_lite_xbar.sv +++ b/test/tb_axi_lite_xbar.sv @@ -175,7 +175,6 @@ module tb_axi_lite_xbar; ) i_xbar_dut ( .clk_i ( clk ), .rst_ni ( rst_n ), - .test_i ( 1'b0 ), .slv_ports ( master ), .mst_ports ( slave ), .addr_map_i ( AddrMap ), diff --git a/test/tb_axi_lite_xbar.wave.do b/test/tb_axi_lite_xbar.wave.do index 604e70c80..1eb256870 100644 --- a/test/tb_axi_lite_xbar.wave.do +++ b/test/tb_axi_lite_xbar.wave.do @@ -3,7 +3,6 @@ onerror {resume} quietly WaveActivateNextPane {} 0 add wave -noupdate -label Clock /tb_axi_lite_xbar/i_xbar_dut/clk_i add wave -noupdate -label Reset /tb_axi_lite_xbar/i_xbar_dut/rst_ni -add wave -noupdate -label {Test Mode} /tb_axi_lite_xbar/i_xbar_dut/test_i add wave -noupdate -divider {Slave Ports} add wave -noupdate /tb_axi_lite_xbar/i_xbar_dut/slv_ports_req_i add wave -noupdate /tb_axi_lite_xbar/i_xbar_dut/slv_ports_resp_o diff --git a/test/tb_axi_slave_compare.sv b/test/tb_axi_slave_compare.sv index 2fa47bdc7..65283bc0b 100644 --- a/test/tb_axi_slave_compare.sv +++ b/test/tb_axi_slave_compare.sv @@ -82,7 +82,6 @@ module tb_axi_slave_compare #( ) i_axi_bus_compare ( .clk_i ( clk ), .rst_ni ( rst_n ), - .testmode_i ( 1'b0 ), .axi_mst_req_i ( axi_req ), .axi_mst_rsp_o ( axi_rsp ), .axi_ref_req_o ( axi_req_a_out ), diff --git a/test/tb_axi_to_axi_lite.sv b/test/tb_axi_to_axi_lite.sv index 39589af19..09d41f0f1 100644 --- a/test/tb_axi_to_axi_lite.sv +++ b/test/tb_axi_to_axi_lite.sv @@ -74,7 +74,6 @@ module tb_axi_to_axi_lite; ) i_dut ( .clk_i ( clk ), .rst_ni ( rst ), - .testmode_i ( 1'b0 ), .slv ( axi ), .mst ( axi_lite ) ); diff --git a/test/tb_axi_to_mem_banked.sv b/test/tb_axi_to_mem_banked.sv index 64667998d..c5b31daaa 100644 --- a/test/tb_axi_to_mem_banked.sv +++ b/test/tb_axi_to_mem_banked.sv @@ -165,7 +165,7 @@ module tb_axi_to_mem_banked #( assign mem_rvalid[i] = mem_req[i]; end else begin : gen_mem_lat logic [TbMemLatency-1:0] mem_lat_q, mem_lat_d; - `FFARN(mem_lat_q, mem_lat_d, '0, clk, rst_n) + `FF(mem_lat_q, mem_lat_d, '0, clk, rst_n) assign mem_lat_d[TbMemLatency-1] = mem_req[i]; if (TbMemLatency > 1) begin for (genvar lat_i = 0; lat_i < TbMemLatency - 1; lat_i++) begin @@ -198,7 +198,6 @@ module tb_axi_to_mem_banked #( ) i_axi_to_mem_banked_dut ( .clk_i ( clk ), .rst_ni ( rst_n ), - .test_i ( 1'b0 ), .axi_to_mem_busy_o ( dut_busy ), .slv ( mem_axi ), .mem_req_o ( mem_req ), diff --git a/test/tb_axi_xbar.sv b/test/tb_axi_xbar.sv index bb54e69a8..3f8b3ffba 100644 --- a/test/tb_axi_xbar.sv +++ b/test/tb_axi_xbar.sv @@ -316,7 +316,6 @@ module tb_axi_xbar #( ) i_xbar_dut ( .clk_i ( clk ), .rst_ni ( rst_n ), - .test_i ( 1'b0 ), .slv_ports ( master ), .mst_ports ( slave ), .addr_map_i ( AddrMap ), diff --git a/test/tb_axi_xbar.wave.do b/test/tb_axi_xbar.wave.do index 23a9095a2..1f19f390c 100644 --- a/test/tb_axi_xbar.wave.do +++ b/test/tb_axi_xbar.wave.do @@ -3,7 +3,6 @@ onerror {resume} quietly WaveActivateNextPane {} 0 add wave -noupdate -label Clock /tb_axi_xbar/i_xbar_dut/clk_i add wave -noupdate -label Reset /tb_axi_xbar/i_xbar_dut/rst_ni -add wave -noupdate -label {Test Mode} /tb_axi_xbar/i_xbar_dut/test_i add wave -noupdate -divider {Slave Ports} add wave -noupdate /tb_axi_xbar/i_xbar_dut/slv_ports_req_i add wave -noupdate /tb_axi_xbar/i_xbar_dut/slv_ports_resp_o From 663b4ba13e9ebf1c45681725f185fce1f898761c Mon Sep 17 00:00:00 2001 From: Lorenzo Leone Date: Thu, 25 Jun 2026 15:56:32 +0200 Subject: [PATCH 02/41] fix(cc): fix cc_ module parameter names for common_cells v2 Update parameter names to match the actual cc_ module API in v2-test: - cc_delta_counter: Width->WIDTH, StickyOverflow->STICKY_OVERFLOW - cc_stream_register: data_t->T - cc_fifo: FallThrough->FALL_THROUGH, Depth->DEPTH, data_t->dtype - cc_counter: Width->WIDTH Co-Authored-By: Claude Sonnet 4.6 --- src/axi_atop_filter.sv | 2 +- src/axi_demux_id_counters.sv | 4 ++-- src/axi_err_slv.sv | 20 ++++++++++---------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/axi_atop_filter.sv b/src/axi_atop_filter.sv index 64c82e1e4..2b71d37d9 100644 --- a/src/axi_atop_filter.sv +++ b/src/axi_atop_filter.sv @@ -346,7 +346,7 @@ module axi_atop_filter #( end cc_stream_register #( - .data_t(r_resp_cmd_t) + .T(r_resp_cmd_t) ) r_resp_cmd ( .clk_i (clk_i), .rst_ni (rst_ni), diff --git a/src/axi_demux_id_counters.sv b/src/axi_demux_id_counters.sv index ab089dcc6..5635b5be8 100644 --- a/src/axi_demux_id_counters.sv +++ b/src/axi_demux_id_counters.sv @@ -110,8 +110,8 @@ module axi_demux_id_counters #( end cc_delta_counter #( - .Width ( CounterWidth ), - .StickyOverflow ( 1'b0 ) + .WIDTH ( CounterWidth ), + .STICKY_OVERFLOW( 1'b0 ) ) i_in_flight_cnt ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), diff --git a/src/axi_err_slv.sv b/src/axi_err_slv.sv index 83215e9cb..ad489110e 100644 --- a/src/axi_err_slv.sv +++ b/src/axi_err_slv.sv @@ -87,9 +87,9 @@ module axi_err_slv #( assign err_resp.aw_ready = ~w_fifo_full; cc_fifo #( - .FallThrough ( 1'b1 ), - .Depth ( MaxTrans ), - .data_t ( id_t ) + .FALL_THROUGH ( 1'b1 ), + .DEPTH ( MaxTrans ), + .dtype ( id_t ) ) i_w_fifo ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), @@ -119,9 +119,9 @@ module axi_err_slv #( end cc_fifo #( - .FallThrough ( 1'b0 ), - .Depth ( unsigned'(2) ), // two placed so that w can eat beats if b is not sent - .data_t ( id_t ) + .FALL_THROUGH ( 1'b0 ), + .DEPTH ( unsigned'(2) ), // two placed so that w can eat beats if b is not sent + .dtype ( id_t ) ) i_b_fifo ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), @@ -160,9 +160,9 @@ module axi_err_slv #( assign r_fifo_inp.len = err_req.ar.len; cc_fifo #( - .FallThrough ( 1'b0 ), - .Depth ( MaxTrans ), - .data_t ( r_data_t ) + .FALL_THROUGH ( 1'b0 ), + .DEPTH ( MaxTrans ), + .dtype ( r_data_t ) ) i_r_fifo ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), @@ -225,7 +225,7 @@ module axi_err_slv #( end cc_counter #( - .Width ($bits(axi_pkg::len_t)) + .WIDTH ($bits(axi_pkg::len_t)) ) i_r_counter ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), From a12fc28c25f95f3356126143944eab013f83c836 Mon Sep 17 00:00:00 2001 From: Lorenzo Leone Date: Thu, 25 Jun 2026 17:55:15 +0200 Subject: [PATCH 03/41] hw: Align mux and demux to common_cells v2 --- src/axi_demux_simple.sv | 4 ++-- src/axi_mux.sv | 20 ++++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/axi_demux_simple.sv b/src/axi_demux_simple.sv index 75f1db53c..015f99f65 100644 --- a/src/axi_demux_simple.sv +++ b/src/axi_demux_simple.sv @@ -263,7 +263,7 @@ module axi_demux_simple #( logic [cc_pkg::idx_width(NoMstPorts)-1:0] b_idx; // Arbitration of the different B responses - rr_arb_tree #( + cc_rr_arb_tree #( .NumIn ( NoMstPorts ), .DataType ( logic ), .AxiVldRdy( 1'b1 ), @@ -382,7 +382,7 @@ module axi_demux_simple #( logic [cc_pkg::idx_width(NoMstPorts)-1:0] r_idx; // Arbitration of the different r responses - rr_arb_tree #( + cc_rr_arb_tree #( .NumIn ( NoMstPorts ), .DataType ( logic ), .AxiVldRdy( 1'b1 ), diff --git a/src/axi_mux.sv b/src/axi_mux.sv index 62b64e4f5..c68d39842 100644 --- a/src/axi_mux.sv +++ b/src/axi_mux.sv @@ -70,7 +70,7 @@ module axi_mux #( // pass through if only one slave port if (NoSlvPorts == 32'h1) begin : gen_no_mux - spill_register #( + cc_spill_register #( .T ( mst_aw_chan_t ), .Bypass ( ~SpillAw ) ) i_aw_spill_reg ( @@ -83,7 +83,7 @@ module axi_mux #( .ready_i ( mst_resp_i.aw_ready ), .data_o ( mst_req_o.aw ) ); - spill_register #( + cc_spill_register #( .T ( w_chan_t ), .Bypass ( ~SpillW ) ) i_w_spill_reg ( @@ -96,7 +96,7 @@ module axi_mux #( .ready_i ( mst_resp_i.w_ready ), .data_o ( mst_req_o.w ) ); - spill_register #( + cc_spill_register #( .T ( mst_b_chan_t ), .Bypass ( ~SpillB ) ) i_b_spill_reg ( @@ -109,7 +109,7 @@ module axi_mux #( .ready_i ( slv_reqs_i[0].b_ready ), .data_o ( slv_resps_o[0].b ) ); - spill_register #( + cc_spill_register #( .T ( mst_ar_chan_t ), .Bypass ( ~SpillAr ) ) i_ar_spill_reg ( @@ -122,7 +122,7 @@ module axi_mux #( .ready_i ( mst_resp_i.ar_ready ), .data_o ( mst_req_o.ar ) ); - spill_register #( + cc_spill_register #( .T ( mst_r_chan_t ), .Bypass ( ~SpillR ) ) i_r_spill_reg ( @@ -332,7 +332,7 @@ module axi_mux #( .pop_i ( w_fifo_pop ) ); - spill_register #( + cc_spill_register #( .T ( mst_aw_chan_t ), .Bypass ( ~SpillAw ) // Param indicated that we want a spill reg ) i_aw_spill_reg ( @@ -366,7 +366,7 @@ module axi_mux #( end end - spill_register #( + cc_spill_register #( .T ( w_chan_t ), .Bypass ( ~SpillW ) ) i_w_spill_reg ( @@ -389,7 +389,7 @@ module axi_mux #( assign switch_b_id = mst_b_chan.id[SlvAxiIDWidth+:MstIdxBits]; assign slv_b_valids = (mst_b_valid) ? (1 << switch_b_id) : '0; - spill_register #( + cc_spill_register #( .T ( mst_b_chan_t ), .Bypass ( ~SpillB ) ) i_b_spill_reg ( @@ -425,7 +425,7 @@ module axi_mux #( .idx_o ( ) ); - spill_register #( + cc_spill_register #( .T ( mst_ar_chan_t ), .Bypass ( ~SpillAr ) ) i_ar_spill_reg ( @@ -448,7 +448,7 @@ module axi_mux #( assign switch_r_id = mst_r_chan.id[SlvAxiIDWidth+:MstIdxBits]; assign slv_r_valids = (mst_r_valid) ? (1 << switch_r_id) : '0; - spill_register #( + cc_spill_register #( .T ( mst_r_chan_t ), .Bypass ( ~SpillR ) ) i_r_spill_reg ( From 4d2876c26ffc7dbd5a67e34340695860aa77ac0f Mon Sep 17 00:00:00 2001 From: Lorenzo Leone Date: Fri, 26 Jun 2026 09:35:47 +0200 Subject: [PATCH 04/41] hw: Align params name to common cells v2-test --- Bender.yml | 2 +- src/axi_burst_splitter_gran.sv | 14 ++--- src/axi_burst_unwrap.sv | 10 +-- src/axi_bus_compare.sv | 112 ++++++++++++++++----------------- src/axi_cdc_dst.sv | 40 ++++++------ src/axi_cdc_src.sv | 40 ++++++------ src/axi_cut.sv | 10 +-- src/axi_delayer.sv | 10 +-- src/axi_demux.sv | 14 ++--- src/axi_demux_simple.sv | 2 +- src/axi_dw_downsizer.sv | 20 +++--- src/axi_dw_upsizer.sv | 12 ++-- src/axi_fifo.sv | 30 ++++----- src/axi_fifo_delay_dyn.sv | 14 ++--- src/axi_id_remap.sv | 12 ++-- src/axi_inval_filter.sv | 6 +- src/axi_lite_demux.sv | 38 +++++------ src/axi_lite_dw_converter.sv | 18 +++--- src/axi_lite_from_mem.sv | 6 +- src/axi_lite_lfsr.sv | 6 +- src/axi_lite_mailbox.sv | 16 ++--- src/axi_lite_mux.sv | 42 ++++++------- src/axi_lite_regs.sv | 4 +- src/axi_lite_to_apb.sv | 16 ++--- src/axi_mux.sv | 7 +-- src/axi_serializer.sv | 12 ++-- src/axi_slave_compare.sv | 6 +- src/axi_throttle.sv | 4 +- src/axi_to_axi_lite.sv | 12 ++-- src/axi_to_detailed_mem.sv | 42 ++++++------- src/axi_to_mem_banked.sv | 6 +- src/axi_to_mem_interleaved.sv | 6 +- src/axi_xbar_unmuxed.sv | 4 +- test/tb_axi_bus_compare.sv | 6 +- 34 files changed, 299 insertions(+), 300 deletions(-) diff --git a/Bender.yml b/Bender.yml index 1fb1c458e..cd94cd522 100644 --- a/Bender.yml +++ b/Bender.yml @@ -24,7 +24,7 @@ remotes: pulp: https://github.com/pulp-platform dependencies: - common_cells: { git: "https://github.com/pulp-platform/common_cells.git", rev: v2-dev } + common_cells: { git: "https://github.com/pulp-platform/common_cells.git", rev: v2-test } common_verification: 0.2.5 tech_cells_generic: 0.2.2 diff --git a/src/axi_burst_splitter_gran.sv b/src/axi_burst_splitter_gran.sv index 1e244cbbd..28f4e85f7 100644 --- a/src/axi_burst_splitter_gran.sv +++ b/src/axi_burst_splitter_gran.sv @@ -620,7 +620,7 @@ module axi_burst_splitter_gran_counters #( if (CutPath) begin : gen_spill cc_spill_register #( - .data_t ( alloc_pld_t ), + .T ( alloc_pld_t ), .Bypass ( 1'b0 ) ) i_spill_register_alloc ( .clk_i, @@ -646,7 +646,7 @@ module axi_burst_splitter_gran_counters #( cnt_idx_t cnt_free_idx, cnt_r_idx; for (genvar i = 0; i < MaxTxns; i++) begin : gen_cnt cc_delta_counter #( - .Width ( $bits(cnt_t) ) + .WIDTH ( $bits(cnt_t) ) ) i_cnt ( .clk_i, .rst_ni, @@ -664,8 +664,8 @@ module axi_burst_splitter_gran_counters #( assign cnt_inp = {1'b0, alloc_pld_out.len} + 1; cc_lzc #( - .Width ( MaxTxns ), - .Mode ( cc_pkg::LZC_TRAILING_ZERO_CNT ) + .WIDTH ( MaxTxns ), + .MODE ( cc_pkg::LZC_TRAILING_ZERO_CNT ) ) i_lzc ( .in_i ( cnt_free ), .cnt_o ( cnt_free_idx ), @@ -675,9 +675,9 @@ module axi_burst_splitter_gran_counters #( logic idq_inp_req, idq_inp_gnt, idq_oup_gnt, idq_oup_valid, idq_oup_pop; cc_id_queue #( - .IdWidth ( $bits(id_t) ), - .Capacity ( MaxTxns ), - .FullBw ( FullBW ), + .ID_WIDTH ( $bits(id_t) ), + .CAPACITY ( MaxTxns ), + .FULL_BW ( FullBW ), .data_t ( cnt_idx_t ) ) i_idq ( .clk_i, diff --git a/src/axi_burst_unwrap.sv b/src/axi_burst_unwrap.sv index 516fb1847..f97a99790 100644 --- a/src/axi_burst_unwrap.sv +++ b/src/axi_burst_unwrap.sv @@ -566,7 +566,7 @@ module axi_burst_counters #( cnt_idx_t cnt_free_idx, cnt_r_idx; for (genvar i = 0; i < MaxTxns; i++) begin : gen_cnt cc_counter #( - .Width ( $bits(cnt_t) ) + .WIDTH ( $bits(cnt_t) ) ) i_cnt ( .clk_i, .rst_ni, @@ -583,8 +583,8 @@ module axi_burst_counters #( assign cnt_inp = {1'b0, alloc_len_i} + 1; cc_lzc #( - .Width ( MaxTxns ), - .Mode ( 1'b0 ) // start counting at index 0 + .WIDTH ( MaxTxns ), + .MODE ( 1'b0 ) // start counting at index 0 ) i_lzc ( .in_i ( cnt_free ), .cnt_o ( cnt_free_idx ), @@ -594,8 +594,8 @@ module axi_burst_counters #( logic idq_inp_req, idq_inp_gnt, idq_oup_gnt, idq_oup_valid, idq_oup_pop; cc_id_queue #( - .IdWidth ( $bits(id_t) ), - .Capacity ( MaxTxns ), + .ID_WIDTH ( $bits(id_t) ), + .CAPACITY ( MaxTxns ), .data_t ( cnt_idx_t ) ) i_idq ( .clk_i, diff --git a/src/axi_bus_compare.sv b/src/axi_bus_compare.sv index 09031a573..38810269a 100644 --- a/src/axi_bus_compare.sv +++ b/src/axi_bus_compare.sv @@ -163,7 +163,7 @@ module axi_bus_compare #( // Channel A stream forks //----------------------------------- cc_stream_fork #( - .NumOup ( 32'd2 ) + .N_OUP ( 32'd2 ) ) i_stream_fork_aw_a ( .clk_i, .rst_ni, @@ -174,7 +174,7 @@ module axi_bus_compare #( ); cc_stream_fork #( - .NumOup ( 32'd2 ) + .N_OUP ( 32'd2 ) ) i_stream_fork_w_a ( .clk_i, .rst_ni, @@ -185,7 +185,7 @@ module axi_bus_compare #( ); cc_stream_fork #( - .NumOup ( 32'd2 ) + .N_OUP ( 32'd2 ) ) i_stream_fork_b_a ( .clk_i, .rst_ni, @@ -196,7 +196,7 @@ module axi_bus_compare #( ); cc_stream_fork #( - .NumOup ( 32'd2 ) + .N_OUP ( 32'd2 ) ) i_stream_fork_ar_a ( .clk_i, .rst_ni, @@ -207,7 +207,7 @@ module axi_bus_compare #( ); cc_stream_fork #( - .NumOup ( 32'd2 ) + .N_OUP ( 32'd2 ) ) i_stream_fork_r_a ( .clk_i, .rst_ni, @@ -224,10 +224,10 @@ module axi_bus_compare #( for (genvar id = 0; id < 2**AxiIdWidth; id++) begin : gen_fifos_a cc_stream_fifo #( - .FallThrough ( 1'b0 ), - .DataWidth ( 1'b0 ), - .Depth ( FifoDepth ), - .data_t ( axi_aw_chan_t ) + .FALL_THROUGH ( 1'b0 ), + .DATA_WIDTH ( 1'b0 ), + .DEPTH ( FifoDepth ), + .T ( axi_aw_chan_t ) ) i_stream_fifo_aw_a ( .clk_i, .rst_ni, @@ -242,10 +242,10 @@ module axi_bus_compare #( ); cc_stream_fifo #( - .FallThrough ( 1'b0 ), - .DataWidth ( 1'b0 ), - .Depth ( FifoDepth ), - .data_t ( axi_b_chan_t ) + .FALL_THROUGH ( 1'b0 ), + .DATA_WIDTH ( 1'b0 ), + .DEPTH ( FifoDepth ), + .T ( axi_b_chan_t ) ) i_stream_fifo_b_a ( .clk_i, .rst_ni, @@ -260,10 +260,10 @@ module axi_bus_compare #( ); cc_stream_fifo #( - .FallThrough ( 1'b0 ), - .DataWidth ( 1'b0 ), - .Depth ( FifoDepth ), - .data_t ( axi_ar_chan_t ) + .FALL_THROUGH ( 1'b0 ), + .DATA_WIDTH ( 1'b0 ), + .DEPTH ( FifoDepth ), + .T ( axi_ar_chan_t ) ) i_stream_fifo_ar_a ( .clk_i, .rst_ni, @@ -279,9 +279,9 @@ module axi_bus_compare #( if (UseSize) begin : gen_r_size cc_stream_fifo #( - .FallThrough ( 1'b0 ), - .DataWidth ( $clog2(DataWidth/8)+3 ), - .Depth ( 2*FifoDepth ) + .FALL_THROUGH ( 1'b0 ), + .DATA_WIDTH ( $clog2(DataWidth/8)+3 ), + .DEPTH ( 2*FifoDepth ) ) i_stream_fifo_w_size ( .clk_i, .rst_ni, @@ -316,10 +316,10 @@ module axi_bus_compare #( cc_stream_fifo #( - .FallThrough ( 1'b0 ), - .DataWidth ( 1'b0 ), - .Depth ( FifoDepth ), - .data_t ( axi_r_chan_t ) + .FALL_THROUGH ( 1'b0 ), + .DATA_WIDTH ( 1'b0 ), + .DEPTH ( FifoDepth ), + .T ( axi_r_chan_t ) ) i_stream_fifo_r_a ( .clk_i, .rst_ni, @@ -336,9 +336,9 @@ module axi_bus_compare #( if (UseSize) begin : gen_w_size cc_stream_fifo #( - .FallThrough ( 1'b0 ), - .DataWidth ( $clog2(DataWidth/8)+3 ), - .Depth ( FifoDepth ) + .FALL_THROUGH ( 1'b0 ), + .DATA_WIDTH ( $clog2(DataWidth/8)+3 ), + .DEPTH ( FifoDepth ) ) i_stream_fifo_w_size ( .clk_i, .rst_ni, @@ -372,10 +372,10 @@ module axi_bus_compare #( end cc_stream_fifo #( - .FallThrough ( 1'b0 ), - .DataWidth ( 1'b0 ), - .Depth ( FifoDepth ), - .data_t ( axi_w_chan_t ) + .FALL_THROUGH ( 1'b0 ), + .DATA_WIDTH ( 1'b0 ), + .DEPTH ( FifoDepth ), + .T ( axi_w_chan_t ) ) i_stream_fifo_w_a ( .clk_i, .rst_ni, @@ -433,7 +433,7 @@ module axi_bus_compare #( // Channel B stream forks //----------------------------------- cc_stream_fork #( - .NumOup ( 32'd2 ) + .N_OUP ( 32'd2 ) ) i_stream_fork_aw_b ( .clk_i, .rst_ni, @@ -444,7 +444,7 @@ module axi_bus_compare #( ); cc_stream_fork #( - .NumOup ( 32'd2 ) + .N_OUP ( 32'd2 ) ) i_stream_fork_w_b ( .clk_i, .rst_ni, @@ -455,7 +455,7 @@ module axi_bus_compare #( ); cc_stream_fork #( - .NumOup ( 32'd2 ) + .N_OUP ( 32'd2 ) ) i_stream_fork_b_b ( .clk_i, .rst_ni, @@ -466,7 +466,7 @@ module axi_bus_compare #( ); cc_stream_fork #( - .NumOup ( 32'd2 ) + .N_OUP ( 32'd2 ) ) i_stream_fork_ar_b ( .clk_i, .rst_ni, @@ -477,7 +477,7 @@ module axi_bus_compare #( ); cc_stream_fork #( - .NumOup ( 32'd2 ) + .N_OUP ( 32'd2 ) ) i_stream_fork_r_b ( .clk_i, .rst_ni, @@ -494,10 +494,10 @@ module axi_bus_compare #( for (genvar id = 0; id < 2**AxiIdWidth; id++) begin : gen_fifos_b cc_stream_fifo #( - .FallThrough ( 1'b0 ), - .DataWidth ( 1'b0 ), - .Depth ( FifoDepth ), - .data_t ( axi_aw_chan_t ) + .FALL_THROUGH ( 1'b0 ), + .DATA_WIDTH ( 1'b0 ), + .DEPTH ( FifoDepth ), + .T ( axi_aw_chan_t ) ) i_stream_fifo_aw_b ( .clk_i, .rst_ni, @@ -512,10 +512,10 @@ module axi_bus_compare #( ); cc_stream_fifo #( - .FallThrough ( 1'b0 ), - .DataWidth ( 1'b0 ), - .Depth ( FifoDepth ), - .data_t ( axi_b_chan_t ) + .FALL_THROUGH ( 1'b0 ), + .DATA_WIDTH ( 1'b0 ), + .DEPTH ( FifoDepth ), + .T ( axi_b_chan_t ) ) i_stream_fifo_b_b ( .clk_i, .rst_ni, @@ -530,10 +530,10 @@ module axi_bus_compare #( ); cc_stream_fifo #( - .FallThrough ( 1'b0 ), - .DataWidth ( 1'b0 ), - .Depth ( FifoDepth ), - .data_t ( axi_ar_chan_t ) + .FALL_THROUGH ( 1'b0 ), + .DATA_WIDTH ( 1'b0 ), + .DEPTH ( FifoDepth ), + .T ( axi_ar_chan_t ) ) i_stream_fifo_ar_b ( .clk_i, .rst_ni, @@ -548,10 +548,10 @@ module axi_bus_compare #( ); cc_stream_fifo #( - .FallThrough ( 1'b0 ), - .DataWidth ( 1'b0 ), - .Depth ( FifoDepth ), - .data_t ( axi_r_chan_t ) + .FALL_THROUGH ( 1'b0 ), + .DATA_WIDTH ( 1'b0 ), + .DEPTH ( FifoDepth ), + .T ( axi_r_chan_t ) ) i_stream_fifo_r_b ( .clk_i, .rst_ni, @@ -567,10 +567,10 @@ module axi_bus_compare #( end cc_stream_fifo #( - .FallThrough ( 1'b0 ), - .DataWidth ( 1'b0 ), - .Depth ( FifoDepth ), - .data_t ( axi_w_chan_t ) + .FALL_THROUGH ( 1'b0 ), + .DATA_WIDTH ( 1'b0 ), + .DEPTH ( FifoDepth ), + .T ( axi_w_chan_t ) ) i_stream_fifo_w_b ( .clk_i, .rst_ni, diff --git a/src/axi_cdc_dst.sv b/src/axi_cdc_dst.sv index cb831869f..88afc6ff3 100644 --- a/src/axi_cdc_dst.sv +++ b/src/axi_cdc_dst.sv @@ -60,13 +60,13 @@ module axi_cdc_dst #( cc_cdc_fifo_gray_dst #( `ifdef QUESTA // Workaround for a bug in Questa: Pass flat logic vector instead of struct to type parameter. - .data_t ( logic [$bits(aw_chan_t)-1:0] ), + .T ( logic [$bits(aw_chan_t)-1:0] ), `else // Other tools, such as VCS, have problems with type parameters constructed through `$bits()`. - .data_t ( aw_chan_t ), + .T ( aw_chan_t ), `endif - .LogDepth ( LogDepth ), - .SyncStages ( SyncStages ) + .LOG_DEPTH ( LogDepth ), + .SYNC_STAGES ( SyncStages ) ) i_cdc_fifo_gray_dst_aw ( .async_data_i ( async_data_slave_aw_data_i ), .async_wptr_i ( async_data_slave_aw_wptr_i ), @@ -80,12 +80,12 @@ module axi_cdc_dst #( cc_cdc_fifo_gray_dst #( `ifdef QUESTA - .data_t ( logic [$bits(w_chan_t)-1:0] ), + .T ( logic [$bits(w_chan_t)-1:0] ), `else - .data_t ( w_chan_t ), + .T ( w_chan_t ), `endif - .LogDepth ( LogDepth ), - .SyncStages ( SyncStages ) + .LOG_DEPTH ( LogDepth ), + .SYNC_STAGES ( SyncStages ) ) i_cdc_fifo_gray_dst_w ( .async_data_i ( async_data_slave_w_data_i ), .async_wptr_i ( async_data_slave_w_wptr_i ), @@ -99,12 +99,12 @@ module axi_cdc_dst #( cc_cdc_fifo_gray_src #( `ifdef QUESTA - .data_t ( logic [$bits(b_chan_t)-1:0] ), + .T ( logic [$bits(b_chan_t)-1:0] ), `else - .data_t ( b_chan_t ), + .T ( b_chan_t ), `endif - .LogDepth ( LogDepth ), - .SyncStages ( SyncStages ) + .LOG_DEPTH ( LogDepth ), + .SYNC_STAGES ( SyncStages ) ) i_cdc_fifo_gray_src_b ( .src_clk_i ( dst_clk_i ), .src_rst_ni ( dst_rst_ni ), @@ -118,12 +118,12 @@ module axi_cdc_dst #( cc_cdc_fifo_gray_dst #( `ifdef QUESTA - .data_t ( logic [$bits(ar_chan_t)-1:0] ), + .T ( logic [$bits(ar_chan_t)-1:0] ), `else - .data_t ( ar_chan_t ), + .T ( ar_chan_t ), `endif - .LogDepth ( LogDepth ), - .SyncStages ( SyncStages ) + .LOG_DEPTH ( LogDepth ), + .SYNC_STAGES ( SyncStages ) ) i_cdc_fifo_gray_dst_ar ( .dst_clk_i, .dst_rst_ni, @@ -137,12 +137,12 @@ module axi_cdc_dst #( cc_cdc_fifo_gray_src #( `ifdef QUESTA - .data_t ( logic [$bits(r_chan_t)-1:0] ), + .T ( logic [$bits(r_chan_t)-1:0] ), `else - .data_t ( r_chan_t ), + .T ( r_chan_t ), `endif - .LogDepth ( LogDepth ), - .SyncStages ( SyncStages ) + .LOG_DEPTH ( LogDepth ), + .SYNC_STAGES ( SyncStages ) ) i_cdc_fifo_gray_src_r ( .src_clk_i ( dst_clk_i ), .src_rst_ni ( dst_rst_ni ), diff --git a/src/axi_cdc_src.sv b/src/axi_cdc_src.sv index 230d1eddc..73d3c864c 100644 --- a/src/axi_cdc_src.sv +++ b/src/axi_cdc_src.sv @@ -60,12 +60,12 @@ module axi_cdc_src #( cc_cdc_fifo_gray_src #( // Workaround for a bug in Questa (see comment in `axi_cdc_dst` for details). `ifdef QUESTA - .data_t ( logic [$bits(aw_chan_t)-1:0] ), + .T ( logic [$bits(aw_chan_t)-1:0] ), `else - .data_t ( aw_chan_t ), + .T ( aw_chan_t ), `endif - .LogDepth ( LogDepth ), - .SyncStages ( SyncStages ) + .LOG_DEPTH ( LogDepth ), + .SYNC_STAGES ( SyncStages ) ) i_cdc_fifo_gray_src_aw ( .src_clk_i, .src_rst_ni, @@ -79,12 +79,12 @@ module axi_cdc_src #( cc_cdc_fifo_gray_src #( `ifdef QUESTA - .data_t ( logic [$bits(w_chan_t)-1:0] ), + .T ( logic [$bits(w_chan_t)-1:0] ), `else - .data_t ( w_chan_t ), + .T ( w_chan_t ), `endif - .LogDepth ( LogDepth ), - .SyncStages ( SyncStages ) + .LOG_DEPTH ( LogDepth ), + .SYNC_STAGES ( SyncStages ) ) i_cdc_fifo_gray_src_w ( .src_clk_i, .src_rst_ni, @@ -98,12 +98,12 @@ module axi_cdc_src #( cc_cdc_fifo_gray_dst #( `ifdef QUESTA - .data_t ( logic [$bits(b_chan_t)-1:0] ), + .T ( logic [$bits(b_chan_t)-1:0] ), `else - .data_t ( b_chan_t ), + .T ( b_chan_t ), `endif - .LogDepth ( LogDepth ), - .SyncStages ( SyncStages ) + .LOG_DEPTH ( LogDepth ), + .SYNC_STAGES ( SyncStages ) ) i_cdc_fifo_gray_dst_b ( .dst_clk_i ( src_clk_i ), .dst_rst_ni ( src_rst_ni ), @@ -117,12 +117,12 @@ module axi_cdc_src #( cc_cdc_fifo_gray_src #( `ifdef QUESTA - .data_t ( logic [$bits(ar_chan_t)-1:0] ), + .T ( logic [$bits(ar_chan_t)-1:0] ), `else - .data_t ( ar_chan_t ), + .T ( ar_chan_t ), `endif - .LogDepth ( LogDepth ), - .SyncStages ( SyncStages ) + .LOG_DEPTH ( LogDepth ), + .SYNC_STAGES ( SyncStages ) ) i_cdc_fifo_gray_src_ar ( .src_clk_i, .src_rst_ni, @@ -136,12 +136,12 @@ module axi_cdc_src #( cc_cdc_fifo_gray_dst #( `ifdef QUESTA - .data_t ( logic [$bits(r_chan_t)-1:0] ), + .T ( logic [$bits(r_chan_t)-1:0] ), `else - .data_t ( r_chan_t ), + .T ( r_chan_t ), `endif - .LogDepth ( LogDepth ), - .SyncStages ( SyncStages ) + .LOG_DEPTH ( LogDepth ), + .SYNC_STAGES ( SyncStages ) ) i_cdc_fifo_gray_dst_r ( .dst_clk_i ( src_clk_i ), .dst_rst_ni ( src_rst_ni ), diff --git a/src/axi_cut.sv b/src/axi_cut.sv index 42c55d673..6c9449ac7 100644 --- a/src/axi_cut.sv +++ b/src/axi_cut.sv @@ -47,7 +47,7 @@ module axi_cut #( // a spill register for each channel cc_spill_register #( - .data_t ( aw_chan_t ), + .T ( aw_chan_t ), .Bypass ( BypassAw ) ) i_reg_aw ( .clk_i ( clk_i ), @@ -61,7 +61,7 @@ module axi_cut #( ); cc_spill_register #( - .data_t ( w_chan_t ), + .T ( w_chan_t ), .Bypass ( BypassW ) ) i_reg_w ( .clk_i ( clk_i ), @@ -75,7 +75,7 @@ module axi_cut #( ); cc_spill_register #( - .data_t ( b_chan_t ), + .T ( b_chan_t ), .Bypass ( BypassB ) ) i_reg_b ( .clk_i ( clk_i ), @@ -89,7 +89,7 @@ module axi_cut #( ); cc_spill_register #( - .data_t ( ar_chan_t ), + .T ( ar_chan_t ), .Bypass ( BypassAr ) ) i_reg_ar ( .clk_i ( clk_i ), @@ -103,7 +103,7 @@ module axi_cut #( ); cc_spill_register #( - .data_t ( r_chan_t ), + .T ( r_chan_t ), .Bypass ( BypassR ) ) i_reg_r ( .clk_i ( clk_i ), diff --git a/src/axi_delayer.sv b/src/axi_delayer.sv index 8d217d14e..77cdc522b 100644 --- a/src/axi_delayer.sv +++ b/src/axi_delayer.sv @@ -40,7 +40,7 @@ module axi_delayer #( input axi_resp_t mst_resp_i ); // AW - stream_delay #( + cc_stream_delay #( .StallRandom ( StallRandomInput ), .FixedDelay ( FixedDelayInput ), .payload_t ( aw_chan_t ) @@ -56,7 +56,7 @@ module axi_delayer #( ); // AR - stream_delay #( + cc_stream_delay #( .StallRandom ( StallRandomInput ), .FixedDelay ( FixedDelayInput ), .payload_t ( ar_chan_t ) @@ -72,7 +72,7 @@ module axi_delayer #( ); // W - stream_delay #( + cc_stream_delay #( .StallRandom ( StallRandomInput ), .FixedDelay ( FixedDelayInput ), .payload_t ( w_chan_t ) @@ -88,7 +88,7 @@ module axi_delayer #( ); // B - stream_delay #( + cc_stream_delay #( .StallRandom ( StallRandomOutput ), .FixedDelay ( FixedDelayOutput ), .payload_t ( b_chan_t ) @@ -104,7 +104,7 @@ module axi_delayer #( ); // R - stream_delay #( + cc_stream_delay #( .StallRandom ( StallRandomOutput ), .FixedDelay ( FixedDelayOutput ), .payload_t ( r_chan_t ) diff --git a/src/axi_demux.sv b/src/axi_demux.sv index 99a19c056..246bfb2e2 100644 --- a/src/axi_demux.sv +++ b/src/axi_demux.sv @@ -86,7 +86,7 @@ module axi_demux #( select_t slv_aw_select, slv_ar_select; cc_spill_register #( - .data_t ( aw_chan_t ), + .T ( aw_chan_t ), .Bypass ( ~SpillAw ) ) i_aw_spill_reg ( .clk_i, @@ -99,7 +99,7 @@ module axi_demux #( .data_o ( slv_req_cut.aw ) ); cc_spill_register #( - .data_t ( select_t ), + .T ( select_t ), .Bypass ( ~SpillAw ) ) i_aw_select_spill_reg ( .clk_i, @@ -116,7 +116,7 @@ module axi_demux #( assign slv_req_cut.aw_valid = slv_aw_valid_chan & slv_aw_valid_sel; cc_spill_register #( - .data_t ( w_chan_t ), + .T ( w_chan_t ), .Bypass ( ~SpillW ) ) i_w_spill_reg ( .clk_i, @@ -129,7 +129,7 @@ module axi_demux #( .data_o ( slv_req_cut.w ) ); cc_spill_register #( - .data_t ( ar_chan_t ), + .T ( ar_chan_t ), .Bypass ( ~SpillAr ) ) i_ar_spill_reg ( .clk_i, @@ -142,7 +142,7 @@ module axi_demux #( .data_o ( slv_req_cut.ar ) ); cc_spill_register #( - .data_t ( select_t ), + .T ( select_t ), .Bypass ( ~SpillAr ) ) i_ar_sel_spill_reg ( .clk_i, @@ -159,7 +159,7 @@ module axi_demux #( assign slv_req_cut.ar_valid = slv_ar_valid_chan & slv_ar_valid_sel; cc_spill_register #( - .data_t ( b_chan_t ), + .T ( b_chan_t ), .Bypass ( ~SpillB ) ) i_b_spill_reg ( .clk_i, @@ -172,7 +172,7 @@ module axi_demux #( .data_o ( slv_resp_o.b ) ); cc_spill_register #( - .data_t ( r_chan_t ), + .T ( r_chan_t ), .Bypass ( ~SpillR ) ) i_r_spill_reg ( .clk_i, diff --git a/src/axi_demux_simple.sv b/src/axi_demux_simple.sv index 015f99f65..303aebd4f 100644 --- a/src/axi_demux_simple.sv +++ b/src/axi_demux_simple.sv @@ -234,7 +234,7 @@ module axi_demux_simple #( // `w_select` determines, which handshaking is connected. // AWs are only forwarded, if the counter is empty, or `w_select_q` is the same as // `slv_aw_select_i`. - counter #( + cc_counter #( .WIDTH ( IdCounterWidth ), .STICKY_OVERFLOW ( 1'b0 ) ) i_counter_open_w ( diff --git a/src/axi_dw_downsizer.sv b/src/axi_dw_downsizer.sv index 766119b3e..094ef143b 100644 --- a/src/axi_dw_downsizer.sv +++ b/src/axi_dw_downsizer.sv @@ -98,7 +98,7 @@ module axi_dw_downsizer #( cc_rr_arb_tree #( .NumIn (AxiMaxReads ), - .data_t (slv_r_chan_t), + .DataType (slv_r_chan_t), .AxiVldRdy(1'b1 ), .ExtPrio (1'b0 ), .LockIn (1'b1 ) @@ -160,7 +160,7 @@ module axi_dw_downsizer #( cc_rr_arb_tree #( .NumIn (AxiMaxReads), - .data_t (ar_chan_t ), + .DataType (ar_chan_t ), .AxiVldRdy(1'b1 ), .ExtPrio (1'b0 ), .LockIn (1'b1 ) @@ -275,8 +275,8 @@ module axi_dw_downsizer #( // Find an idle downsizer to handle this transaction tran_id_t idx_idle_downsizer; cc_lzc #( - .Width(AxiMaxReads), - .Mode (cc_pkg::LZC_TRAILING_ZERO_CNT) + .WIDTH(AxiMaxReads), + .MODE (cc_pkg::LZC_TRAILING_ZERO_CNT) ) i_idle_lzc ( .in_i (idle_read_downsizer), .cnt_o (idx_idle_downsizer ), @@ -291,7 +291,7 @@ module axi_dw_downsizer #( end cc_onehot_to_bin #( - .OnehotWidth(AxiMaxReads) + .ONEHOT_WIDTH(AxiMaxReads) ) i_id_clash_onehot_to_bin ( .onehot(id_clash_downsizer ), .bin (idx_id_clash_downsizer) @@ -309,8 +309,8 @@ module axi_dw_downsizer #( logic idqueue_valid; cc_id_queue #( - .IdWidth (AxiIdWidth ), - .Capacity(AxiMaxReads), + .ID_WIDTH (AxiIdWidth ), + .CAPACITY(AxiMaxReads), .data_t (tran_id_t ) ) i_read_id_queue ( .clk_i (clk_i ), @@ -679,9 +679,9 @@ module axi_dw_downsizer #( logic forward_b_beat_full; cc_fifo #( - .DataWidth (1 ), - .Depth (AxiMaxReads), - .FallThrough(1'b1 ) + .DATA_WIDTH (1 ), + .DEPTH (AxiMaxReads), + .FALL_THROUGH(1'b1 ) ) i_forward_b_beats_queue ( .clk_i (clk_i ), .rst_ni (rst_ni ), diff --git a/src/axi_dw_upsizer.sv b/src/axi_dw_upsizer.sv index 7fc49a2fa..05cf499dc 100644 --- a/src/axi_dw_upsizer.sv +++ b/src/axi_dw_upsizer.sv @@ -95,7 +95,7 @@ module axi_dw_upsizer #( cc_rr_arb_tree #( .NumIn (AxiMaxReads ), - .data_t (slv_r_chan_t), + .DataType (slv_r_chan_t), .AxiVldRdy(1'b1 ), .ExtPrio (1'b0 ), .LockIn (1'b1 ) @@ -157,7 +157,7 @@ module axi_dw_upsizer #( cc_rr_arb_tree #( .NumIn (AxiMaxReads), - .data_t (ar_chan_t ), + .DataType (ar_chan_t ), .AxiVldRdy(1'b1 ), .ExtPrio (1'b0 ), .LockIn (1'b1 ) @@ -259,8 +259,8 @@ module axi_dw_upsizer #( // Find an idle upsizer to handle this transaction tran_id_t idx_idle_upsizer; cc_lzc #( - .Width(AxiMaxReads), - .Mode (cc_pkg::LZC_TRAILING_ZERO_CNT) + .WIDTH(AxiMaxReads), + .MODE (cc_pkg::LZC_TRAILING_ZERO_CNT) ) i_idle_lzc ( .in_i (idle_read_upsizer), .cnt_o (idx_idle_upsizer ), @@ -275,7 +275,7 @@ module axi_dw_upsizer #( end cc_onehot_to_bin #( - .OnehotWidth(AxiMaxReads) + .ONEHOT_WIDTH(AxiMaxReads) ) i_id_clash_onehot_to_bin ( .onehot(id_clash_upsizer ), .bin (idx_id_clash_upsizer) @@ -300,7 +300,7 @@ module axi_dw_upsizer #( end cc_onehot_to_bin #( - .OnehotWidth(AxiMaxReads) + .ONEHOT_WIDTH(AxiMaxReads) ) i_rid_upsizer_lzc ( .onehot(rid_upsizer_match), .bin (idx_r_upsizer ) diff --git a/src/axi_fifo.sv b/src/axi_fifo.sv index c0e08cfe9..790ef4960 100644 --- a/src/axi_fifo.sv +++ b/src/axi_fifo.sv @@ -63,9 +63,9 @@ module axi_fifo #( // A FiFo for each channel cc_fifo #( - .data_t(aw_chan_t), - .Depth(Depth), - .FallThrough(FallThrough) + .dtype(aw_chan_t), + .DEPTH(Depth), + .FALL_THROUGH(FallThrough) ) i_aw_fifo ( .clk_i, .rst_ni, @@ -79,9 +79,9 @@ module axi_fifo #( .pop_i (mst_req_o.aw_valid && mst_resp_i.aw_ready) ); cc_fifo #( - .data_t(ar_chan_t), - .Depth(Depth), - .FallThrough(FallThrough) + .dtype(ar_chan_t), + .DEPTH(Depth), + .FALL_THROUGH(FallThrough) ) i_ar_fifo ( .clk_i, .rst_ni, @@ -95,9 +95,9 @@ module axi_fifo #( .pop_i (mst_req_o.ar_valid && mst_resp_i.ar_ready) ); cc_fifo #( - .data_t(w_chan_t), - .Depth(Depth), - .FallThrough(FallThrough) + .dtype(w_chan_t), + .DEPTH(Depth), + .FALL_THROUGH(FallThrough) ) i_w_fifo ( .clk_i, .rst_ni, @@ -111,9 +111,9 @@ module axi_fifo #( .pop_i (mst_req_o.w_valid && mst_resp_i.w_ready) ); cc_fifo #( - .data_t(r_chan_t), - .Depth(Depth), - .FallThrough(FallThrough) + .dtype(r_chan_t), + .DEPTH(Depth), + .FALL_THROUGH(FallThrough) ) i_r_fifo ( .clk_i, .rst_ni, @@ -127,9 +127,9 @@ module axi_fifo #( .pop_i (slv_resp_o.r_valid && slv_req_i.r_ready) ); cc_fifo #( - .data_t(b_chan_t), - .Depth(Depth), - .FallThrough(FallThrough) + .dtype(b_chan_t), + .DEPTH(Depth), + .FALL_THROUGH(FallThrough) ) i_b_fifo ( .clk_i, .rst_ni, diff --git a/src/axi_fifo_delay_dyn.sv b/src/axi_fifo_delay_dyn.sv index 8c064c262..0185d478b 100644 --- a/src/axi_fifo_delay_dyn.sv +++ b/src/axi_fifo_delay_dyn.sv @@ -328,7 +328,7 @@ module stream_fifo_delay_dyn #( assign payload_o = head_data; cc_counter #( - .Width ( CounterWidth ) + .WIDTH ( CounterWidth ) ) i_counter ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), @@ -375,9 +375,9 @@ module stream_fifo_delay_dyn #( ); `else cc_fifo #( - .DataWidth ( $bits(payload_t) ), - .Depth ( Depth ), - .FallThrough ( 1'b0 ) + .DATA_WIDTH ( $bits(payload_t) ), + .DEPTH ( Depth ), + .FALL_THROUGH ( 1'b0 ) ) data_fifo ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), @@ -426,9 +426,9 @@ module stream_fifo_delay_dyn #( ); `else cc_fifo #( - .DataWidth ( CounterWidth ), - .Depth ( Depth ), - .FallThrough ( 1'b0 ) + .DATA_WIDTH ( CounterWidth ), + .DEPTH ( Depth ), + .FALL_THROUGH ( 1'b0 ) ) deadline_fifo ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), diff --git a/src/axi_id_remap.sv b/src/axi_id_remap.sv index 333a95f86..ac59e0e0f 100644 --- a/src/axi_id_remap.sv +++ b/src/axi_id_remap.sv @@ -186,8 +186,8 @@ module axi_id_remap #( ); assign both_free = wr_free & rd_free; cc_lzc #( - .Width ( AxiSlvPortMaxUniqIds ), - .Mode ( 1'b0 ) + .WIDTH ( AxiSlvPortMaxUniqIds ), + .MODE ( 1'b0 ) ) i_lzc ( .in_i ( both_free ), .cnt_o ( both_free_oup_id ), @@ -570,8 +570,8 @@ module axi_id_remap_table #( assign free_o[i] = table_q[i].cnt == '0; end cc_lzc #( - .Width ( MaxUniqInpIds ), - .Mode ( 1'b0 ) + .WIDTH ( MaxUniqInpIds ), + .MODE ( 1'b0 ) ) i_lzc_free ( .in_i ( free_o ), .cnt_o ( free_oup_id_o ), @@ -592,8 +592,8 @@ module axi_id_remap_table #( end logic no_match; cc_lzc #( - .Width ( MaxUniqInpIds ), - .Mode ( 1'b0 ) + .WIDTH ( MaxUniqInpIds ), + .MODE ( 1'b0 ) ) i_lzc_match ( .in_i ( match ), .cnt_o ( exists_oup_id_o ), diff --git a/src/axi_inval_filter.sv b/src/axi_inval_filter.sv index 2c9e8854c..875900f80 100644 --- a/src/axi_inval_filter.sv +++ b/src/axi_inval_filter.sv @@ -128,9 +128,9 @@ module axi_inval_filter #( end cc_fifo #( - .FallThrough ( 1'b1 ), - .Depth ( MaxTxns ), - .data_t ( aw_chan_t ) + .FALL_THROUGH ( 1'b1 ), + .DEPTH ( MaxTxns ), + .dtype ( aw_chan_t ) ) i_aw_fifo ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), diff --git a/src/axi_lite_demux.sv b/src/axi_lite_demux.sv index d14dc49ba..872f6726f 100644 --- a/src/axi_lite_demux.sv +++ b/src/axi_lite_demux.sv @@ -70,7 +70,7 @@ module axi_lite_demux #( if (NoMstPorts == 32'd1) begin : gen_no_demux // degenerate case, connect slave to master port cc_spill_register #( - .data_t ( aw_chan_t ), + .T ( aw_chan_t ), .Bypass ( ~SpillAw ) ) i_aw_spill_reg ( .clk_i ( clk_i ), @@ -83,7 +83,7 @@ module axi_lite_demux #( .data_o ( mst_reqs_o[0].aw ) ); cc_spill_register #( - .data_t ( w_chan_t ), + .T ( w_chan_t ), .Bypass ( ~SpillW ) ) i_w_spill_reg ( .clk_i ( clk_i ), @@ -96,7 +96,7 @@ module axi_lite_demux #( .data_o ( mst_reqs_o[0].w ) ); cc_spill_register #( - .data_t ( b_chan_t ), + .T ( b_chan_t ), .Bypass ( ~SpillB ) ) i_b_spill_reg ( .clk_i ( clk_i ), @@ -109,7 +109,7 @@ module axi_lite_demux #( .data_o ( slv_resp_o.b ) ); cc_spill_register #( - .data_t ( ar_chan_t ), + .T ( ar_chan_t ), .Bypass ( ~SpillAr ) ) i_ar_spill_reg ( .clk_i ( clk_i ), @@ -122,7 +122,7 @@ module axi_lite_demux #( .data_o ( mst_reqs_o[0].ar ) ); cc_spill_register #( - .data_t ( r_chan_t ), + .T ( r_chan_t ), .Bypass ( ~SpillR ) ) i_r_spill_reg ( .clk_i ( clk_i ), @@ -204,7 +204,7 @@ module axi_lite_demux #( slv_aw_chan_select_out_flat; assign slv_aw_chan_select_in_flat = {slv_req_i.aw, slv_aw_select_i}; cc_spill_register #( - .data_t ( aw_chan_select_flat_t ), + .T ( aw_chan_select_flat_t ), .Bypass ( ~SpillAw ) ) i_aw_spill_reg ( .clk_i ( clk_i ), @@ -267,9 +267,9 @@ module axi_lite_demux #( `FFL(lock_aw_valid_q, lock_aw_valid_d, load_aw_lock, '0, clk_i, rst_ni) cc_fifo #( - .FallThrough ( FallThrough ), - .Depth ( MaxTrans ), - .data_t ( select_t ) + .FALL_THROUGH ( FallThrough ), + .DEPTH ( MaxTrans ), + .dtype ( select_t ) ) i_w_fifo ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), @@ -287,7 +287,7 @@ module axi_lite_demux #( // W Channel //-------------------------------------- cc_spill_register #( - .data_t ( w_chan_t ), + .T ( w_chan_t ), .Bypass ( ~SpillW ) ) i_w_spill_reg ( .clk_i ( clk_i ), @@ -310,9 +310,9 @@ module axi_lite_demux #( assign w_fifo_pop = slv_w_valid & slv_w_ready; cc_fifo #( - .FallThrough ( FallThrough ), - .Depth ( MaxTrans ), - .data_t ( select_t ) + .FALL_THROUGH ( FallThrough ), + .DEPTH ( MaxTrans ), + .dtype ( select_t ) ) i_b_fifo ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), @@ -330,7 +330,7 @@ module axi_lite_demux #( // B Channel //-------------------------------------- cc_spill_register #( - .data_t ( b_chan_t ), + .T ( b_chan_t ), .Bypass ( ~SpillB ) ) i_b_spill_reg ( .clk_i ( clk_i ), @@ -364,7 +364,7 @@ module axi_lite_demux #( slv_ar_chan_select_out_flat; assign slv_ar_chan_select_in_flat = {slv_req_i.ar, slv_ar_select_i}; cc_spill_register #( - .data_t ( ar_chan_select_flat_t ), + .T ( ar_chan_select_flat_t ), .Bypass ( ~SpillAr ) ) i_ar_spill_reg ( .clk_i ( clk_i ), @@ -388,9 +388,9 @@ module axi_lite_demux #( assign r_fifo_push = slv_ar_valid & slv_ar_ready; cc_fifo #( - .FallThrough ( FallThrough ), - .Depth ( MaxTrans ), - .data_t ( select_t ) + .FALL_THROUGH ( FallThrough ), + .DEPTH ( MaxTrans ), + .dtype ( select_t ) ) i_r_fifo ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), @@ -408,7 +408,7 @@ module axi_lite_demux #( // R Channel //-------------------------------------- cc_spill_register #( - .data_t ( r_chan_t ), + .T ( r_chan_t ), .Bypass ( ~SpillR ) ) i_r_spill_reg ( .clk_i ( clk_i ), diff --git a/src/axi_lite_dw_converter.sv b/src/axi_lite_dw_converter.sv index 1d1794843..fe8d96641 100644 --- a/src/axi_lite_dw_converter.sv +++ b/src/axi_lite_dw_converter.sv @@ -134,7 +134,7 @@ module axi_lite_dw_converter #( logic aw_chan_spill_valid, aw_chan_spill_ready; cc_spill_register #( - .data_t ( axi_lite_aw_t ), + .T ( axi_lite_aw_t ), .Bypass ( 1'b0 ) ) i_spill_register_aw ( .clk_i, @@ -166,7 +166,7 @@ module axi_lite_dw_converter #( axi_lite_slv_w_t w_chan_spill; logic w_chan_spill_valid, w_chan_spill_ready; cc_spill_register #( - .data_t ( axi_lite_slv_w_t ), + .T ( axi_lite_slv_w_t ), .Bypass ( 1'b0 ) ) i_spill_register_w ( .clk_i, @@ -225,7 +225,7 @@ module axi_lite_dw_converter #( logic ar_chan_spill_valid, ar_chan_spill_ready; cc_spill_register #( - .data_t ( axi_lite_ar_t ), + .T ( axi_lite_ar_t ), .Bypass ( 1'b0 ) ) i_spill_register_ar ( .clk_i, @@ -338,9 +338,9 @@ module axi_lite_dw_converter #( assign aw_sel = sel_t'(slv_req_i.aw.addr >> SelOffset); cc_fifo #( - .FallThrough ( 1'b1 ), - .Depth ( UpsizeFactor ), - .data_t ( sel_t ) + .FALL_THROUGH ( 1'b1 ), + .DEPTH ( UpsizeFactor ), + .dtype ( sel_t ) ) i_fifo_w_sel ( .clk_i, .rst_ni, @@ -419,9 +419,9 @@ module axi_lite_dw_converter #( assign ar_sel = sel_t'(slv_req_i.ar.addr >> SelOffset); cc_fifo #( - .FallThrough ( 1'b1 ), - .Depth ( UpsizeFactor ), - .data_t ( sel_t ) + .FALL_THROUGH ( 1'b1 ), + .DEPTH ( UpsizeFactor ), + .dtype ( sel_t ) ) i_fifo_r_sel ( .clk_i, .rst_ni, diff --git a/src/axi_lite_from_mem.sv b/src/axi_lite_from_mem.sv index 6976f35b1..d55a3a605 100644 --- a/src/axi_lite_from_mem.sv +++ b/src/axi_lite_from_mem.sv @@ -177,9 +177,9 @@ module axi_lite_from_mem #( logic rsp_sel; cc_fifo #( - .FallThrough ( 1'b0 ), // No fallthrough for one cycle delay before ready on AXI. - .Depth ( MaxRequests ), - .data_t ( logic ) + .FALL_THROUGH ( 1'b0 ), // No fallthrough for one cycle delay before ready on AXI. + .DEPTH ( MaxRequests ), + .dtype ( logic ) ) i_fifo_rsp_mux ( .clk_i, .rst_ni, diff --git a/src/axi_lite_lfsr.sv b/src/axi_lite_lfsr.sv index e9a60020a..b7c812d0e 100644 --- a/src/axi_lite_lfsr.sv +++ b/src/axi_lite_lfsr.sv @@ -92,9 +92,9 @@ module axi_lite_lfsr #( // B cc_stream_fifo #( - .FallThrough ( 1'b0 ), - .DataWidth ( 'd1 ), - .Depth ( 'd2 ) + .FALL_THROUGH ( 1'b0 ), + .DATA_WIDTH ( 'd1 ), + .DEPTH ( 'd2 ) ) i_stream_fifo_w_b ( .clk_i, .rst_ni, diff --git a/src/axi_lite_mailbox.sv b/src/axi_lite_mailbox.sv index e417e7a99..7a4d7311d 100644 --- a/src/axi_lite_mailbox.sv +++ b/src/axi_lite_mailbox.sv @@ -122,9 +122,9 @@ module axi_lite_mailbox #( // the usage gets concatinated with the full flag to have consistent threshold detection logic [FifoUsageWidth-1:0] mbox_0_to_1_usage, mbox_1_to_0_usage; cc_fifo #( - .FallThrough ( 1'b0 ), - .Depth ( MailboxDepth ), - .data_t ( data_t ) + .FALL_THROUGH ( 1'b0 ), + .DEPTH ( MailboxDepth ), + .dtype ( data_t ) ) i_mbox_0_to_1 ( .clk_i, .rst_ni, @@ -141,9 +141,9 @@ module axi_lite_mailbox #( assign mbox_usage[0] = {mbox_full[0], mbox_0_to_1_usage}; cc_fifo #( - .FallThrough ( 1'b0 ), - .Depth ( MailboxDepth ), - .data_t ( data_t ) + .FALL_THROUGH ( 1'b0 ), + .DEPTH ( MailboxDepth ), + .dtype ( data_t ) ) i_mbox_1_to_0 ( .clk_i, .rst_ni, @@ -501,7 +501,7 @@ module axi_lite_mailbox_slave #( .default_idx_i ( '0 ) ); cc_spill_register #( - .data_t ( b_chan_lite_t ) + .T ( b_chan_lite_t ) ) i_b_chan_outp ( .clk_i, .rst_ni, @@ -527,7 +527,7 @@ module axi_lite_mailbox_slave #( .default_idx_i ( '0 ) ); cc_spill_register #( - .data_t ( r_chan_lite_t ) + .T ( r_chan_lite_t ) ) i_r_chan_outp ( .clk_i, .rst_ni, diff --git a/src/axi_lite_mux.sv b/src/axi_lite_mux.sv index 0df045f7d..891660ce6 100644 --- a/src/axi_lite_mux.sv +++ b/src/axi_lite_mux.sv @@ -54,7 +54,7 @@ module axi_lite_mux #( // pass through if only one slave port if (NoSlvPorts == 32'h1) begin : gen_no_mux cc_spill_register #( - .data_t ( aw_chan_t ), + .T ( aw_chan_t ), .Bypass ( ~SpillAw ) ) i_aw_spill_reg ( .clk_i ( clk_i ), @@ -67,7 +67,7 @@ module axi_lite_mux #( .data_o ( mst_req_o.aw ) ); cc_spill_register #( - .data_t ( w_chan_t ), + .T ( w_chan_t ), .Bypass ( ~SpillW ) ) i_w_spill_reg ( .clk_i ( clk_i ), @@ -80,7 +80,7 @@ module axi_lite_mux #( .data_o ( mst_req_o.w ) ); cc_spill_register #( - .data_t ( b_chan_t ), + .T ( b_chan_t ), .Bypass ( ~SpillB ) ) i_b_spill_reg ( .clk_i ( clk_i ), @@ -93,7 +93,7 @@ module axi_lite_mux #( .data_o ( slv_resps_o[0].b ) ); cc_spill_register #( - .data_t ( ar_chan_t ), + .T ( ar_chan_t ), .Bypass ( ~SpillAr ) ) i_ar_spill_reg ( .clk_i ( clk_i ), @@ -106,7 +106,7 @@ module axi_lite_mux #( .data_o ( mst_req_o.ar ) ); cc_spill_register #( - .data_t ( r_chan_t ), + .T ( r_chan_t ), .Bypass ( ~SpillR ) ) i_r_spill_reg ( .clk_i ( clk_i ), @@ -197,7 +197,7 @@ module axi_lite_mux #( end cc_rr_arb_tree #( .NumIn ( NoSlvPorts ), - .data_t ( aw_chan_t ), + .DataType ( aw_chan_t ), .AxiVldRdy( 1'b1 ), .LockIn ( 1'b1 ) ) i_aw_arbiter ( @@ -249,9 +249,9 @@ module axi_lite_mux #( `FFL(lock_aw_valid_q, lock_aw_valid_d, load_aw_lock, '0, clk_i, rst_ni) cc_fifo #( - .FallThrough ( FallThrough ), - .Depth ( MaxTrans ), - .data_t ( select_t ) + .FALL_THROUGH ( FallThrough ), + .DEPTH ( MaxTrans ), + .dtype ( select_t ) ) i_w_fifo ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), @@ -266,7 +266,7 @@ module axi_lite_mux #( ); cc_spill_register #( - .data_t ( aw_chan_t ), + .T ( aw_chan_t ), .Bypass ( ~SpillAw ) // Param indicated that we want a spill reg ) i_aw_spill_reg ( .clk_i ( clk_i ), @@ -292,9 +292,9 @@ module axi_lite_mux #( assign w_fifo_pop = mst_w_valid & mst_w_ready; cc_fifo #( - .FallThrough ( FallThrough ), - .Depth ( MaxTrans ), - .data_t ( select_t ) + .FALL_THROUGH ( FallThrough ), + .DEPTH ( MaxTrans ), + .dtype ( select_t ) ) i_b_fifo ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), @@ -309,7 +309,7 @@ module axi_lite_mux #( ); cc_spill_register #( - .data_t ( w_chan_t ), + .T ( w_chan_t ), .Bypass ( ~SpillW ) ) i_w_spill_reg ( .clk_i ( clk_i ), @@ -334,7 +334,7 @@ module axi_lite_mux #( assign b_fifo_pop = mst_b_valid & mst_b_ready; cc_spill_register #( - .data_t ( b_chan_t ), + .T ( b_chan_t ), .Bypass ( ~SpillB ) ) i_b_spill_reg ( .clk_i ( clk_i ), @@ -358,7 +358,7 @@ module axi_lite_mux #( end cc_rr_arb_tree #( .NumIn ( NoSlvPorts ), - .data_t ( ar_chan_t ), + .DataType ( ar_chan_t ), .AxiVldRdy( 1'b1 ), .LockIn ( 1'b1 ) ) i_ar_arbiter ( @@ -382,9 +382,9 @@ module axi_lite_mux #( assign r_fifo_push = mst_ar_valid & mst_ar_ready; cc_fifo #( - .FallThrough ( FallThrough ), - .Depth ( MaxTrans ), - .data_t ( select_t ) + .FALL_THROUGH ( FallThrough ), + .DEPTH ( MaxTrans ), + .dtype ( select_t ) ) i_r_fifo ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), @@ -399,7 +399,7 @@ module axi_lite_mux #( ); cc_spill_register #( - .data_t ( ar_chan_t ), + .T ( ar_chan_t ), .Bypass ( ~SpillAr ) ) i_ar_spill_reg ( .clk_i ( clk_i ), @@ -424,7 +424,7 @@ module axi_lite_mux #( assign r_fifo_pop = mst_r_valid & mst_r_ready; cc_spill_register #( - .data_t ( r_chan_t ), + .T ( r_chan_t ), .Bypass ( ~SpillR ) ) i_r_spill_reg ( .clk_i ( clk_i ), diff --git a/src/axi_lite_regs.sv b/src/axi_lite_regs.sv index 00692f275..edc8c2c36 100644 --- a/src/axi_lite_regs.sv +++ b/src/axi_lite_regs.sv @@ -349,7 +349,7 @@ module axi_lite_regs #( // Add a cycle delay on AXI response, cut all comb paths between slave port inputs and outputs. cc_spill_register #( - .data_t ( b_chan_lite_t ), + .T ( b_chan_lite_t ), .Bypass ( 1'b0 ) ) i_b_spill_register ( .clk_i, @@ -364,7 +364,7 @@ module axi_lite_regs #( // Add a cycle delay on AXI response, cut all comb paths between slave port inputs and outputs. cc_spill_register #( - .data_t ( r_chan_lite_t ), + .T ( r_chan_lite_t ), .Bypass ( 1'b0 ) ) i_r_spill_register ( .clk_i, diff --git a/src/axi_lite_to_apb.sv b/src/axi_lite_to_apb.sv index f41817055..c5609ba87 100644 --- a/src/axi_lite_to_apb.sv +++ b/src/axi_lite_to_apb.sv @@ -148,7 +148,7 @@ module axi_lite_to_apb #( cc_rr_arb_tree #( .NumIn ( 32'd2 ), - .data_t ( int_req_t ), + .DataType ( int_req_t ), .ExtPrio ( 1'b0 ), .AxiVldRdy( 1'b1 ), .LockIn ( 1'b1 ) @@ -168,7 +168,7 @@ module axi_lite_to_apb #( if (PipelineRequest) begin : gen_req_spill cc_spill_register #( - .data_t ( int_req_t ), + .T ( int_req_t ), .Bypass ( 1'b0 ) ) i_req_spill ( .clk_i, @@ -182,7 +182,7 @@ module axi_lite_to_apb #( ); end else begin : gen_req_ft_reg cc_fall_through_register #( - .data_t ( int_req_t ) + .T ( int_req_t ) ) i_req_ft_reg ( .clk_i, .rst_ni, @@ -198,7 +198,7 @@ module axi_lite_to_apb #( if (PipelineResponse) begin : gen_resp_spill cc_spill_register #( - .data_t ( axi_pkg::resp_t ), + .T ( axi_pkg::resp_t ), .Bypass ( 1'b0 ) ) i_write_resp_spill ( .clk_i, @@ -211,7 +211,7 @@ module axi_lite_to_apb #( .data_o ( axi_bresp ) ); cc_spill_register #( - .data_t ( int_resp_t ), + .T ( int_resp_t ), .Bypass ( 1'b0 ) ) i_read_resp_spill ( .clk_i, @@ -225,7 +225,7 @@ module axi_lite_to_apb #( ); end else begin : gen_resp_ft_reg cc_fall_through_register #( - .data_t ( axi_pkg::resp_t ) + .T ( axi_pkg::resp_t ) ) i_write_resp_ft_reg ( .clk_i, .rst_ni, @@ -238,7 +238,7 @@ module axi_lite_to_apb #( .data_o ( axi_bresp ) ); cc_fall_through_register #( - .data_t ( int_resp_t ) + .T ( int_resp_t ) ) i_read_resp_ft_reg ( .clk_i, .rst_ni, @@ -449,7 +449,7 @@ module axi_lite_to_apb_intf #( `AXI_LITE_ASSIGN_FROM_RESP(slv, axi_resp) cc_onehot_to_bin #( - .OnehotWidth ( NoApbSlaves ) + .ONEHOT_WIDTH ( NoApbSlaves ) ) i_onehot_to_bin ( .onehot ( pselx_o ), .bin ( apb_sel ) diff --git a/src/axi_mux.sv b/src/axi_mux.sv index c68d39842..38e4ed9b7 100644 --- a/src/axi_mux.sv +++ b/src/axi_mux.sv @@ -261,7 +261,7 @@ module axi_mux #( //-------------------------------------- // AW Channel //-------------------------------------- - rr_arb_tree #( + cc_rr_arb_tree #( .NumIn ( NoSlvPorts ), .DataType ( mst_aw_chan_t ), .AxiVldRdy( 1'b1 ), @@ -314,7 +314,7 @@ module axi_mux #( `FFL(lock_aw_valid_q, lock_aw_valid_d, load_aw_lock, '0, clk_i, rst_ni) - fifo_v3 #( + cc_fifo #( .FALL_THROUGH ( FallThrough ), .DEPTH ( MaxWTrans ), .dtype ( switch_id_t ) @@ -322,7 +322,6 @@ module axi_mux #( .clk_i ( clk_i ), .rst_ni ( rst_ni ), .flush_i ( 1'b0 ), - .testmode_i( test_i ), .full_o ( w_fifo_full ), .empty_o ( w_fifo_empty ), .usage_o ( ), @@ -406,7 +405,7 @@ module axi_mux #( //-------------------------------------- // AR Channel //-------------------------------------- - rr_arb_tree #( + cc_rr_arb_tree #( .NumIn ( NoSlvPorts ), .DataType ( mst_ar_chan_t ), .AxiVldRdy( 1'b1 ), diff --git a/src/axi_serializer.sv b/src/axi_serializer.sv index da024983f..cddc33316 100644 --- a/src/axi_serializer.sv +++ b/src/axi_serializer.sv @@ -147,9 +147,9 @@ module axi_serializer #( end cc_fifo #( - .FallThrough ( 1'b0 ), // No fall-through as response has to come a cycle later anyway - .Depth ( MaxReadTxns ), - .data_t ( id_t ) + .FALL_THROUGH ( 1'b0 ), // No fall-through as response has to come a cycle later anyway + .DEPTH ( MaxReadTxns ), + .dtype ( id_t ) ) i_rd_id_fifo ( .clk_i, .rst_ni, @@ -166,9 +166,9 @@ module axi_serializer #( assign rd_fifo_pop = slv_resp_o.r_valid & slv_req_i.r_ready & slv_resp_o.r.last; cc_fifo #( - .FallThrough ( 1'b0 ), - .Depth ( MaxWriteTxns ), - .data_t ( id_t ) + .FALL_THROUGH ( 1'b0 ), + .DEPTH ( MaxWriteTxns ), + .dtype ( id_t ) ) i_wr_id_fifo ( .clk_i, .rst_ni, diff --git a/src/axi_slave_compare.sv b/src/axi_slave_compare.sv index 54f1eb8c9..976bab3e3 100644 --- a/src/axi_slave_compare.sv +++ b/src/axi_slave_compare.sv @@ -91,7 +91,7 @@ module axi_slave_compare #( logic ar_ready_mst; cc_stream_fork #( - .NumOup ( 32'd2 ) + .N_OUP ( 32'd2 ) ) i_stream_fork_aw ( .clk_i, .rst_ni, @@ -102,7 +102,7 @@ module axi_slave_compare #( ); cc_stream_fork #( - .NumOup ( 32'd2 ) + .N_OUP ( 32'd2 ) ) i_stream_fork_ar ( .clk_i, .rst_ni, @@ -113,7 +113,7 @@ module axi_slave_compare #( ); cc_stream_fork #( - .NumOup ( 32'd2 ) + .N_OUP ( 32'd2 ) ) i_stream_fork_w ( .clk_i, .rst_ni, diff --git a/src/axi_throttle.sv b/src/axi_throttle.sv index ee91090fa..5b305f1ea 100644 --- a/src/axi_throttle.sv +++ b/src/axi_throttle.sv @@ -56,7 +56,7 @@ module axi_throttle #( logic throttled_ar_ready; // limit Aw requests -> wait for b - stream_throttle #( + cc_stream_throttle #( .MaxNumPending ( MaxNumAwPending ) ) i_stream_throttle_aw ( .clk_i, @@ -71,7 +71,7 @@ module axi_throttle #( ); // limit Ar requests -> wait for r.last - stream_throttle #( + cc_stream_throttle #( .MaxNumPending ( MaxNumArPending ) ) i_stream_throttle_ar ( .clk_i, diff --git a/src/axi_to_axi_lite.sv b/src/axi_to_axi_lite.sv index 16b7bad81..0ea9827cd 100644 --- a/src/axi_to_axi_lite.sv +++ b/src/axi_to_axi_lite.sv @@ -163,9 +163,9 @@ module axi_to_axi_lite_id_reflect #( assign aw_push = mst_req_o.aw_valid & slv_resp_o.aw_ready; assign aw_pop = slv_resp_o.b_valid & mst_req_o.b_ready; cc_fifo #( - .FallThrough ( FallThrough ), - .Depth ( AxiMaxWriteTxns ), - .data_t ( id_t ) + .FALL_THROUGH ( FallThrough ), + .DEPTH ( AxiMaxWriteTxns ), + .dtype ( id_t ) ) i_aw_id_fifo ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), @@ -183,9 +183,9 @@ module axi_to_axi_lite_id_reflect #( assign ar_push = mst_req_o.ar_valid & slv_resp_o.ar_ready; assign ar_pop = slv_resp_o.r_valid & mst_req_o.r_ready; cc_fifo #( - .FallThrough ( FallThrough ), - .Depth ( AxiMaxReadTxns ), - .data_t ( id_t ) + .FALL_THROUGH ( FallThrough ), + .DEPTH ( AxiMaxReadTxns ), + .dtype ( id_t ) ) i_ar_id_fifo ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), diff --git a/src/axi_to_detailed_mem.sv b/src/axi_to_detailed_mem.sv index 70ad9e2c5..07ee85a57 100644 --- a/src/axi_to_detailed_mem.sv +++ b/src/axi_to_detailed_mem.sv @@ -265,8 +265,8 @@ module axi_to_detailed_mem #( // Arbitrate between reads and writes. cc_stream_mux #( - .data_t ( meta_t ), - .NumInp ( 32'd2 ) + .DATA_T ( meta_t ), + .N_INP ( 32'd2 ) ) i_ax_mux ( .inp_data_i ({wr_meta, rd_meta }), .inp_valid_i ({wr_valid, rd_valid}), @@ -322,7 +322,7 @@ module axi_to_detailed_mem #( // Fork arbitrated stream to meta data, memory requests, and R/B channel selection. cc_stream_fork #( - .NumOup ( 32'd3 ) + .N_OUP ( 32'd3 ) ) i_fork ( .clk_i, .rst_ni, @@ -336,9 +336,9 @@ module axi_to_detailed_mem #( assign sel_r = ~meta.write | meta.atop[5]; cc_stream_fifo #( - .FallThrough ( 1'b1 ), - .Depth ( 32'd1 + BufDepth ), - .data_t ( logic[1:0] ) + .FALL_THROUGH ( 1'b1 ), + .DEPTH ( 32'd1 + BufDepth ), + .T ( logic[1:0] ) ) i_sel_buf ( .clk_i, .rst_ni, @@ -353,9 +353,9 @@ module axi_to_detailed_mem #( ); cc_stream_fifo #( - .FallThrough ( 1'b1 ), - .Depth ( 32'd1 + BufDepth ), - .data_t ( meta_t ) + .FALL_THROUGH ( 1'b1 ), + .DEPTH ( 32'd1 + BufDepth ), + .T ( meta_t ) ) i_meta_buf ( .clk_i, .rst_ni, @@ -469,7 +469,7 @@ module axi_to_detailed_mem #( // Join memory read data and meta data stream. logic mem_join_valid, mem_join_ready; cc_stream_join #( - .NumInp ( 32'd2 ) + .N_INP ( 32'd2 ) ) i_join ( .inp_valid_i ({m2s_resp_valid, meta_buf_valid}), .inp_ready_o ({m2s_resp_ready, meta_buf_ready}), @@ -479,7 +479,7 @@ module axi_to_detailed_mem #( // Dynamically fork the joined stream to B and R channels. cc_stream_fork_dynamic #( - .NumOup ( 32'd2 ) + .N_OUP ( 32'd2 ) ) i_fork_dynamic ( .clk_i, .rst_ni, @@ -874,10 +874,10 @@ module mem_stream_to_banks_detailed #( assign bank_req[i].wuser = wuser_i; assign bank_req[i].we = we_i; cc_stream_fifo #( - .FallThrough ( 1'b1 ), - .DataWidth ( $bits(req_t) ), - .Depth ( OutFifoDepth ), - .data_t ( req_t ) + .FALL_THROUGH ( 1'b1 ), + .DATA_WIDTH ( $bits(req_t) ), + .DEPTH ( OutFifoDepth ), + .T ( req_t ) ) i_ft_reg ( .clk_i, .rst_ni, @@ -919,9 +919,9 @@ module mem_stream_to_banks_detailed #( assign zero_strobe_on_input[i] = (strb_i[i*BytesPerBank+:BytesPerBank] == '0); end cc_fifo #( - .FallThrough ( 1'b0 ), - .Depth ( MaxTrans+1 ), - .DataWidth ( NumBanks ) + .FALL_THROUGH ( 1'b0 ), + .DEPTH ( MaxTrans+1 ), + .DATA_WIDTH ( NumBanks ) ) i_dead_write_fifo ( .clk_i, .rst_ni, @@ -945,9 +945,9 @@ module mem_stream_to_banks_detailed #( // Handle responses. for (genvar i = 0; unsigned'(i) < NumBanks; i++) begin : gen_resp_regs cc_stream_fifo #( - .FallThrough ( 1'b1 ), - .DataWidth ( $bits(oup_data_t) + $bits(oup_ruser_t) ), - .Depth ( MaxTrans ) + .FALL_THROUGH ( 1'b1 ), + .DATA_WIDTH ( $bits(oup_data_t) + $bits(oup_ruser_t) ), + .DEPTH ( MaxTrans ) ) i_ft_reg ( .clk_i, .rst_ni, diff --git a/src/axi_to_mem_banked.sv b/src/axi_to_mem_banked.sv index 977217a62..0525f1c7e 100644 --- a/src/axi_to_mem_banked.sv +++ b/src/axi_to_mem_banked.sv @@ -238,8 +238,8 @@ module axi_to_mem_banked #( assign res_rdata[j] = mem_rdata_i[r_shift_oup.sel]; // Connect for the response data `MemLatency` cycles after a request was made to the xbar. - cc_shift_reg #( - .data_t ( read_sel_t ), + cc_shift_register #( + .dtype ( read_sel_t ), .Depth ( MemLatency ) ) i_shift_reg_rdata_mux ( .clk_i, @@ -304,6 +304,7 @@ module axi_to_mem_banked #( // pragma translate_on endmodule + `include "axi/typedef.svh" `include "axi/assign.svh" /// AXI4+ATOP interface wrapper for `axi_to_mem` @@ -428,4 +429,3 @@ module axi_to_mem_banked_intf #( `endif // pragma translate_on endmodule - diff --git a/src/axi_to_mem_interleaved.sv b/src/axi_to_mem_interleaved.sv index c84e8f8fc..2a5739304 100644 --- a/src/axi_to_mem_interleaved.sv +++ b/src/axi_to_mem_interleaved.sv @@ -221,7 +221,7 @@ module axi_to_mem_interleaved #( // fine-grain arbitration cc_rr_arb_tree #( .NumIn ( 2 ), - .data_t ( mem_req_payload_t ) + .DataType ( mem_req_payload_t ) ) i_rr_arb_tree ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), @@ -238,8 +238,8 @@ module axi_to_mem_interleaved #( // back-routing store cc_fifo #( - .DataWidth ( 1 ), - .Depth ( BufDepth + 1 ) + .DATA_WIDTH ( 1 ), + .DEPTH ( BufDepth + 1 ) ) i_fifo_v3_response_trgt_store ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), diff --git a/src/axi_xbar_unmuxed.sv b/src/axi_xbar_unmuxed.sv index e926461c2..fa3dd92ac 100644 --- a/src/axi_xbar_unmuxed.sv +++ b/src/axi_xbar_unmuxed.sv @@ -98,7 +98,7 @@ import cc_pkg::idx_width; logic dec_aw_valid, dec_aw_error; logic dec_ar_valid, dec_ar_error; - addr_decode #( + cc_addr_decode #( .NoIndices ( Cfg.NoMstPorts ), .NoRules ( Cfg.NoAddrRules ), .addr_t ( addr_t ), @@ -113,7 +113,7 @@ import cc_pkg::idx_width; .default_idx_i ( default_mst_port_i[i] ) ); - addr_decode #( + cc_addr_decode #( .NoIndices ( Cfg.NoMstPorts ), .addr_t ( addr_t ), .NoRules ( Cfg.NoAddrRules ), diff --git a/test/tb_axi_bus_compare.sv b/test/tb_axi_bus_compare.sv index 4542af7ca..7f8a0c031 100644 --- a/test/tb_axi_bus_compare.sv +++ b/test/tb_axi_bus_compare.sv @@ -79,7 +79,7 @@ module tb_axi_bus_compare #( logic w_ready; logic ar_ready; - cc_stream_fork #(.NumOup(32'd2)) i_stream_fork_aw ( + cc_stream_fork #(.N_OUP(32'd2)) i_stream_fork_aw ( .clk_i ( clk ), .rst_ni ( rst_n ), .valid_i ( axi_req.aw_valid ), @@ -88,7 +88,7 @@ module tb_axi_bus_compare #( .ready_i ( { aw_ready_a, aw_ready_b } ) ); - cc_stream_fork #(.NumOup(32'd2)) i_stream_fork_ar ( + cc_stream_fork #(.N_OUP(32'd2)) i_stream_fork_ar ( .clk_i ( clk ), .rst_ni ( rst_n ), .valid_i ( axi_req.ar_valid ), @@ -97,7 +97,7 @@ module tb_axi_bus_compare #( .ready_i ( { ar_ready_a, ar_ready_b } ) ); - cc_stream_fork #(.NumOup(32'd2)) i_stream_fork_w ( + cc_stream_fork #(.N_OUP(32'd2)) i_stream_fork_w ( .clk_i ( clk ), .rst_ni ( rst_n ), .valid_i ( axi_req.w_valid ), From dd14a3ba8f3cda590553266c4b6c040e670c2ac6 Mon Sep 17 00:00:00 2001 From: Lorenzo Leone Date: Fri, 26 Jun 2026 10:13:50 +0200 Subject: [PATCH 05/41] hw: Remove test_i ports --- src/axi_demux_simple.sv | 1 - src/axi_xbar_unmuxed.sv | 3 --- 2 files changed, 4 deletions(-) diff --git a/src/axi_demux_simple.sv b/src/axi_demux_simple.sv index 303aebd4f..2cfceefbe 100644 --- a/src/axi_demux_simple.sv +++ b/src/axi_demux_simple.sv @@ -55,7 +55,6 @@ module axi_demux_simple #( ) ( input logic clk_i, input logic rst_ni, - input logic test_i, // Slave Port input axi_req_t slv_req_i, input select_t slv_aw_select_i, diff --git a/src/axi_xbar_unmuxed.sv b/src/axi_xbar_unmuxed.sv index fa3dd92ac..851a745b6 100644 --- a/src/axi_xbar_unmuxed.sv +++ b/src/axi_xbar_unmuxed.sv @@ -183,7 +183,6 @@ import cc_pkg::idx_width; ) i_axi_demux ( .clk_i, // Clock .rst_ni, // Asynchronous reset active low - .test_i, // Testmode enable .slv_req_i ( slv_ports_req_i[i] ), .slv_aw_select_i ( slv_aw_select ), .slv_ar_select_i ( slv_ar_select ), @@ -204,7 +203,6 @@ import cc_pkg::idx_width; ) i_axi_err_slv ( .clk_i, // Clock .rst_ni, // Asynchronous reset active low - .test_i, // Testmode enable // slave port .slv_req_i ( slv_reqs[i][Cfg.NoMstPorts] ), .slv_resp_o ( slv_resps[i][cfg_NoMstPorts] ) @@ -245,7 +243,6 @@ import cc_pkg::idx_width; ) i_axi_err_slv ( .clk_i, .rst_ni, - .test_i, .slv_req_i ( slv_reqs[i][j] ), .slv_resp_o ( slv_resps[i][j] ) ); From 57779b81d7a1e776454f0b1db358747c11371272 Mon Sep 17 00:00:00 2001 From: Chen Wu Date: Mon, 29 Jun 2026 19:51:17 +0200 Subject: [PATCH 06/41] hw: clean up dead test_i ports and use cc_pkg::lzc_mode_e enum for the cc_lzc MODE parameter. --- Bender.lock | 4 ++-- src/axi_burst_unwrap.sv | 2 +- src/axi_id_remap.sv | 6 +++--- src/axi_mux.sv | 3 --- src/axi_xbar.sv | 6 ------ src/axi_xbar_unmuxed.sv | 4 ---- src/axi_xp.sv | 4 ---- test/axi_synth_bench.sv | 7 ------- 8 files changed, 6 insertions(+), 30 deletions(-) diff --git a/Bender.lock b/Bender.lock index da9205fe2..ccfb70bda 100644 --- a/Bender.lock +++ b/Bender.lock @@ -1,7 +1,7 @@ packages: common_cells: - revision: 9ca8a7655f741e7dd5736669a20a301325194c28 - version: 1.39.0 + revision: e42f76dcb1e8a1a171943b22f36c94f640508994 + version: null source: Git: https://github.com/pulp-platform/common_cells.git dependencies: diff --git a/src/axi_burst_unwrap.sv b/src/axi_burst_unwrap.sv index f97a99790..fcf35aa39 100644 --- a/src/axi_burst_unwrap.sv +++ b/src/axi_burst_unwrap.sv @@ -584,7 +584,7 @@ module axi_burst_counters #( cc_lzc #( .WIDTH ( MaxTxns ), - .MODE ( 1'b0 ) // start counting at index 0 + .MODE ( cc_pkg::LZC_TRAILING_ZERO_CNT ) // start counting at index 0 ) i_lzc ( .in_i ( cnt_free ), .cnt_o ( cnt_free_idx ), diff --git a/src/axi_id_remap.sv b/src/axi_id_remap.sv index ac59e0e0f..33175521c 100644 --- a/src/axi_id_remap.sv +++ b/src/axi_id_remap.sv @@ -187,7 +187,7 @@ module axi_id_remap #( assign both_free = wr_free & rd_free; cc_lzc #( .WIDTH ( AxiSlvPortMaxUniqIds ), - .MODE ( 1'b0 ) + .MODE ( cc_pkg::LZC_TRAILING_ZERO_CNT ) ) i_lzc ( .in_i ( both_free ), .cnt_o ( both_free_oup_id ), @@ -571,7 +571,7 @@ module axi_id_remap_table #( end cc_lzc #( .WIDTH ( MaxUniqInpIds ), - .MODE ( 1'b0 ) + .MODE ( cc_pkg::LZC_TRAILING_ZERO_CNT ) ) i_lzc_free ( .in_i ( free_o ), .cnt_o ( free_oup_id_o ), @@ -593,7 +593,7 @@ module axi_id_remap_table #( logic no_match; cc_lzc #( .WIDTH ( MaxUniqInpIds ), - .MODE ( 1'b0 ) + .MODE ( cc_pkg::LZC_TRAILING_ZERO_CNT ) ) i_lzc_match ( .in_i ( match ), .cnt_o ( exists_oup_id_o ), diff --git a/src/axi_mux.sv b/src/axi_mux.sv index 38e4ed9b7..16e7bec7d 100644 --- a/src/axi_mux.sv +++ b/src/axi_mux.sv @@ -56,7 +56,6 @@ module axi_mux #( ) ( input logic clk_i, // Clock input logic rst_ni, // Asynchronous reset active low - input logic test_i, // Test Mode enable // slave ports (AXI inputs), connect master modules here input slv_req_t [NoSlvPorts-1:0] slv_reqs_i, output slv_resp_t [NoSlvPorts-1:0] slv_resps_o, @@ -517,7 +516,6 @@ module axi_mux_intf #( ) ( input logic clk_i, // Clock input logic rst_ni, // Asynchronous reset active low - input logic test_i, // Testmode enable AXI_BUS.Slave slv [NO_SLV_PORTS-1:0], // slave ports AXI_BUS.Master mst // master port ); @@ -588,7 +586,6 @@ module axi_mux_intf #( ) i_axi_mux ( .clk_i ( clk_i ), // Clock .rst_ni ( rst_ni ), // Asynchronous reset active low - .test_i ( test_i ), // Test Mode enable .slv_reqs_i ( slv_reqs ), .slv_resps_o ( slv_resps ), .mst_req_o ( mst_req ), diff --git a/src/axi_xbar.sv b/src/axi_xbar.sv index 16ef708e7..e541392bd 100644 --- a/src/axi_xbar.sv +++ b/src/axi_xbar.sv @@ -68,8 +68,6 @@ import cc_pkg::idx_width; input logic clk_i, /// Asynchronous reset, active low. input logic rst_ni, - /// Testmode enable, active high. - input logic test_i, /// AXI4+ATOP requests to the slave ports. input slv_req_t [Cfg.NoSlvPorts-1:0] slv_ports_req_i, /// AXI4+ATOP responses of the slave ports. @@ -109,7 +107,6 @@ import cc_pkg::idx_width; ) i_xbar_unmuxed ( .clk_i, .rst_ni, - .test_i, .slv_ports_req_i, .slv_ports_resp_o, .mst_ports_req_o (mst_reqs), @@ -146,7 +143,6 @@ import cc_pkg::idx_width; ) i_axi_mux ( .clk_i, // Clock .rst_ni, // Asynchronous reset active low - .test_i, // Test Mode enable .slv_reqs_i ( mst_reqs[i] ), .slv_resps_o ( mst_resps[i] ), .mst_req_o ( mst_ports_req_o[i] ), @@ -172,7 +168,6 @@ import cc_pkg::idx_width; ) ( 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, @@ -239,7 +234,6 @@ import cc_pkg::idx_width; ) i_xbar ( .clk_i, .rst_ni, - .test_i, .slv_ports_req_i (slv_reqs ), .slv_ports_resp_o (slv_resps), .mst_ports_req_o (mst_reqs ), diff --git a/src/axi_xbar_unmuxed.sv b/src/axi_xbar_unmuxed.sv index 851a745b6..740c02367 100644 --- a/src/axi_xbar_unmuxed.sv +++ b/src/axi_xbar_unmuxed.sv @@ -56,8 +56,6 @@ import cc_pkg::idx_width; input logic clk_i, /// Asynchronous reset, active low. input logic rst_ni, - /// Testmode enable, active high. - input logic test_i, /// AXI4+ATOP requests to the slave ports. input req_t [Cfg.NoSlvPorts-1:0] slv_ports_req_i, /// AXI4+ATOP responses of the slave ports. @@ -281,7 +279,6 @@ import cc_pkg::idx_width; ) ( 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][Cfg.NoSlvPorts-1:0], input rule_t [Cfg.NoAddrRules-1:0] addr_map_i, @@ -335,7 +332,6 @@ import cc_pkg::idx_width; ) i_xbar ( .clk_i, .rst_ni, - .test_i, .slv_ports_req_i (slv_reqs ), .slv_ports_resp_o (slv_resps), .mst_ports_req_o (mst_reqs ), diff --git a/src/axi_xp.sv b/src/axi_xp.sv index db8c21851..b0af8c4b0 100644 --- a/src/axi_xp.sv +++ b/src/axi_xp.sv @@ -84,8 +84,6 @@ module axi_xp #( input logic clk_i, /// Asynchronous reset, active low input logic rst_ni, - /// Test mode enable - input logic test_en_i, /// Slave ports request input axi_req_t [NumSlvPorts-1:0] slv_req_i, /// Slave ports response @@ -191,7 +189,6 @@ import cc_pkg::idx_width; ) ( input logic clk_i, input logic rst_ni, - input logic test_en_i, AXI_BUS.Slave slv_ports [NumSlvPorts-1:0], AXI_BUS.Master mst_ports [NumMstPorts-1:0], input rule_t [NumAddrRules-1:0] addr_map_i @@ -244,7 +241,6 @@ import cc_pkg::idx_width; ) i_xp ( .clk_i, .rst_ni, - .test_en_i, .slv_req_i (slv_reqs ), .slv_resp_o (slv_resps), .mst_req_o (mst_reqs ), diff --git a/test/axi_synth_bench.sv b/test/axi_synth_bench.sv index 334846abc..e5caff06f 100644 --- a/test/axi_synth_bench.sv +++ b/test/axi_synth_bench.sv @@ -241,7 +241,6 @@ module synth_slice #( ) a ( .clk_i (clk_i), .rst_ni (rst_ni), - .testmode_i (1'b0), .slv (a_full.Slave), .mst (a_lite.Master) ); @@ -434,7 +433,6 @@ module synth_axi_lite_xbar #( }; axi_pkg::xbar_rule_32_t [NoSlvMst-1:0] addr_map; - logic test; axi_req_t [NoSlvMst-1:0] mst_reqs, slv_reqs; axi_resp_t [NoSlvMst-1:0] mst_resps, slv_resps; @@ -451,7 +449,6 @@ module synth_axi_lite_xbar #( ) i_xbar_dut ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), - .test_i ( test ), .slv_ports_req_i ( mst_reqs ), .slv_ports_resp_o ( mst_resps ), .mst_ports_req_o ( slv_reqs ), @@ -477,7 +474,6 @@ module synth_axi_lite_mailbox #( .AXI_DATA_WIDTH (32'd32) ) slv [1:0] (); - logic test; logic [1:0] irq; addr_t [1:0] base_addr; @@ -490,7 +486,6 @@ module synth_axi_lite_mailbox #( ) i_axi_lite_mailbox ( .clk_i ( clk_i ), // Clock .rst_ni ( rst_ni ), // Asynchronous reset active low - .test_i ( test ), // Testmode enable // slave ports [1:0] .slv ( slv ), .irq_o ( irq ), // interrupt output for each port @@ -720,7 +715,6 @@ module synth_axi_to_mem_banked #( ) axi (); // Misc signals - logic test; logic [1:0] axi_to_mem_busy; // Signals for mem macros logic [BankNum-1:0] mem_req; @@ -745,7 +739,6 @@ module synth_axi_to_mem_banked #( ) i_axi_to_mem_banked_intf ( .clk_i, .rst_ni, - .test_i ( test ), .slv ( axi ), .mem_req_o ( mem_req ), .mem_gnt_i ( mem_gnt ), From 33e16fbfdb02c5ec88b8264a42fe3e51b8bf5e44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niccol=C3=B2=20Giuliani?= Date: Wed, 1 Jul 2026 16:01:11 +0200 Subject: [PATCH 07/41] fixed indentation --- src/axi_burst_splitter_gran.sv | 6 ++--- src/axi_burst_unwrap.sv | 12 ++++----- src/axi_bus_compare.sv | 44 +++++++++++++++---------------- src/axi_cdc_dst.sv | 20 +++++++------- src/axi_cdc_src.sv | 20 +++++++------- src/axi_cut.sv | 10 +++---- src/axi_demux.sv | 14 +++++----- src/axi_dw_downsizer.sv | 8 +++--- src/axi_dw_upsizer.sv | 4 +-- src/axi_fifo.sv | 30 ++++++++++----------- src/axi_fifo_delay_dyn.sv | 4 +-- src/axi_id_remap.sv | 6 ++--- src/axi_inval_filter.sv | 4 +-- src/axi_lite_demux.sv | 32 +++++++++++------------ src/axi_lite_dw_converter.sv | 14 +++++----- src/axi_lite_from_mem.sv | 4 +-- src/axi_lite_lfsr.sv | 2 +- src/axi_lite_mailbox.sv | 8 +++--- src/axi_lite_mux.sv | 48 +++++++++++++++++----------------- src/axi_lite_regs.sv | 4 +-- src/axi_lite_to_apb.sv | 16 ++++++------ src/axi_serializer.sv | 8 +++--- src/axi_to_axi_lite.sv | 8 +++--- src/axi_to_detailed_mem.sv | 18 ++++++------- src/axi_to_mem_interleaved.sv | 4 +-- 25 files changed, 174 insertions(+), 174 deletions(-) diff --git a/src/axi_burst_splitter_gran.sv b/src/axi_burst_splitter_gran.sv index 28f4e85f7..e53d1027d 100644 --- a/src/axi_burst_splitter_gran.sv +++ b/src/axi_burst_splitter_gran.sv @@ -620,7 +620,7 @@ module axi_burst_splitter_gran_counters #( if (CutPath) begin : gen_spill cc_spill_register #( - .T ( alloc_pld_t ), + .T ( alloc_pld_t ), .Bypass ( 1'b0 ) ) i_spill_register_alloc ( .clk_i, @@ -675,9 +675,9 @@ module axi_burst_splitter_gran_counters #( logic idq_inp_req, idq_inp_gnt, idq_oup_gnt, idq_oup_valid, idq_oup_pop; cc_id_queue #( - .ID_WIDTH ( $bits(id_t) ), + .ID_WIDTH ( $bits(id_t) ), .CAPACITY ( MaxTxns ), - .FULL_BW ( FullBW ), + .FULL_BW ( FullBW ), .data_t ( cnt_idx_t ) ) i_idq ( .clk_i, diff --git a/src/axi_burst_unwrap.sv b/src/axi_burst_unwrap.sv index fcf35aa39..84c8fc300 100644 --- a/src/axi_burst_unwrap.sv +++ b/src/axi_burst_unwrap.sv @@ -133,11 +133,11 @@ module axi_burst_unwrap #( logic w_cnt_dec, w_cnt_req, w_cnt_gnt; axi_pkg::len_t b_cnt_len, w_cnt_len; axi_burst_unwrap_ax_chan #( - .AwChan ( 1'b1 ), - .chan_t ( aw_chan_t ), + .AwChan ( 1'b1 ), + .chan_t ( aw_chan_t ), .AddrWidth ( AddrWidth ), - .IdWidth ( IdWidth ), - .MaxTxns ( MaxWriteTxns ) + .IdWidth ( IdWidth ), + .MaxTxns ( MaxWriteTxns ) ) i_axi_burst_unwrap_aw_chan ( .clk_i, .rst_ni, @@ -583,7 +583,7 @@ module axi_burst_counters #( assign cnt_inp = {1'b0, alloc_len_i} + 1; cc_lzc #( - .WIDTH ( MaxTxns ), + .WIDTH ( MaxTxns ), .MODE ( cc_pkg::LZC_TRAILING_ZERO_CNT ) // start counting at index 0 ) i_lzc ( .in_i ( cnt_free ), @@ -594,7 +594,7 @@ module axi_burst_counters #( logic idq_inp_req, idq_inp_gnt, idq_oup_gnt, idq_oup_valid, idq_oup_pop; cc_id_queue #( - .ID_WIDTH ( $bits(id_t) ), + .ID_WIDTH ( $bits(id_t) ), .CAPACITY ( MaxTxns ), .data_t ( cnt_idx_t ) ) i_idq ( diff --git a/src/axi_bus_compare.sv b/src/axi_bus_compare.sv index 38810269a..2faa44f1d 100644 --- a/src/axi_bus_compare.sv +++ b/src/axi_bus_compare.sv @@ -226,8 +226,8 @@ module axi_bus_compare #( cc_stream_fifo #( .FALL_THROUGH ( 1'b0 ), .DATA_WIDTH ( 1'b0 ), - .DEPTH ( FifoDepth ), - .T ( axi_aw_chan_t ) + .DEPTH ( FifoDepth ), + .T ( axi_aw_chan_t ) ) i_stream_fifo_aw_a ( .clk_i, .rst_ni, @@ -244,8 +244,8 @@ module axi_bus_compare #( cc_stream_fifo #( .FALL_THROUGH ( 1'b0 ), .DATA_WIDTH ( 1'b0 ), - .DEPTH ( FifoDepth ), - .T ( axi_b_chan_t ) + .DEPTH ( FifoDepth ), + .T ( axi_b_chan_t ) ) i_stream_fifo_b_a ( .clk_i, .rst_ni, @@ -262,8 +262,8 @@ module axi_bus_compare #( cc_stream_fifo #( .FALL_THROUGH ( 1'b0 ), .DATA_WIDTH ( 1'b0 ), - .DEPTH ( FifoDepth ), - .T ( axi_ar_chan_t ) + .DEPTH ( FifoDepth ), + .T ( axi_ar_chan_t ) ) i_stream_fifo_ar_a ( .clk_i, .rst_ni, @@ -281,7 +281,7 @@ module axi_bus_compare #( cc_stream_fifo #( .FALL_THROUGH ( 1'b0 ), .DATA_WIDTH ( $clog2(DataWidth/8)+3 ), - .DEPTH ( 2*FifoDepth ) + .DEPTH ( 2*FifoDepth ) ) i_stream_fifo_w_size ( .clk_i, .rst_ni, @@ -318,8 +318,8 @@ module axi_bus_compare #( cc_stream_fifo #( .FALL_THROUGH ( 1'b0 ), .DATA_WIDTH ( 1'b0 ), - .DEPTH ( FifoDepth ), - .T ( axi_r_chan_t ) + .DEPTH ( FifoDepth ), + .T ( axi_r_chan_t ) ) i_stream_fifo_r_a ( .clk_i, .rst_ni, @@ -338,7 +338,7 @@ module axi_bus_compare #( cc_stream_fifo #( .FALL_THROUGH ( 1'b0 ), .DATA_WIDTH ( $clog2(DataWidth/8)+3 ), - .DEPTH ( FifoDepth ) + .DEPTH ( FifoDepth ) ) i_stream_fifo_w_size ( .clk_i, .rst_ni, @@ -374,8 +374,8 @@ module axi_bus_compare #( cc_stream_fifo #( .FALL_THROUGH ( 1'b0 ), .DATA_WIDTH ( 1'b0 ), - .DEPTH ( FifoDepth ), - .T ( axi_w_chan_t ) + .DEPTH ( FifoDepth ), + .T ( axi_w_chan_t ) ) i_stream_fifo_w_a ( .clk_i, .rst_ni, @@ -496,8 +496,8 @@ module axi_bus_compare #( cc_stream_fifo #( .FALL_THROUGH ( 1'b0 ), .DATA_WIDTH ( 1'b0 ), - .DEPTH ( FifoDepth ), - .T ( axi_aw_chan_t ) + .DEPTH ( FifoDepth ), + .T ( axi_aw_chan_t ) ) i_stream_fifo_aw_b ( .clk_i, .rst_ni, @@ -514,8 +514,8 @@ module axi_bus_compare #( cc_stream_fifo #( .FALL_THROUGH ( 1'b0 ), .DATA_WIDTH ( 1'b0 ), - .DEPTH ( FifoDepth ), - .T ( axi_b_chan_t ) + .DEPTH ( FifoDepth ), + .T ( axi_b_chan_t ) ) i_stream_fifo_b_b ( .clk_i, .rst_ni, @@ -532,8 +532,8 @@ module axi_bus_compare #( cc_stream_fifo #( .FALL_THROUGH ( 1'b0 ), .DATA_WIDTH ( 1'b0 ), - .DEPTH ( FifoDepth ), - .T ( axi_ar_chan_t ) + .DEPTH ( FifoDepth ), + .T ( axi_ar_chan_t ) ) i_stream_fifo_ar_b ( .clk_i, .rst_ni, @@ -550,8 +550,8 @@ module axi_bus_compare #( cc_stream_fifo #( .FALL_THROUGH ( 1'b0 ), .DATA_WIDTH ( 1'b0 ), - .DEPTH ( FifoDepth ), - .T ( axi_r_chan_t ) + .DEPTH ( FifoDepth ), + .T ( axi_r_chan_t ) ) i_stream_fifo_r_b ( .clk_i, .rst_ni, @@ -569,8 +569,8 @@ module axi_bus_compare #( cc_stream_fifo #( .FALL_THROUGH ( 1'b0 ), .DATA_WIDTH ( 1'b0 ), - .DEPTH ( FifoDepth ), - .T ( axi_w_chan_t ) + .DEPTH ( FifoDepth ), + .T ( axi_w_chan_t ) ) i_stream_fifo_w_b ( .clk_i, .rst_ni, diff --git a/src/axi_cdc_dst.sv b/src/axi_cdc_dst.sv index 88afc6ff3..3d5bf7649 100644 --- a/src/axi_cdc_dst.sv +++ b/src/axi_cdc_dst.sv @@ -60,10 +60,10 @@ module axi_cdc_dst #( cc_cdc_fifo_gray_dst #( `ifdef QUESTA // Workaround for a bug in Questa: Pass flat logic vector instead of struct to type parameter. - .T ( logic [$bits(aw_chan_t)-1:0] ), + .T ( logic [$bits(aw_chan_t)-1:0] ), `else // Other tools, such as VCS, have problems with type parameters constructed through `$bits()`. - .T ( aw_chan_t ), + .T ( aw_chan_t ), `endif .LOG_DEPTH ( LogDepth ), .SYNC_STAGES ( SyncStages ) @@ -80,9 +80,9 @@ module axi_cdc_dst #( cc_cdc_fifo_gray_dst #( `ifdef QUESTA - .T ( logic [$bits(w_chan_t)-1:0] ), + .T ( logic [$bits(w_chan_t)-1:0] ), `else - .T ( w_chan_t ), + .T ( w_chan_t ), `endif .LOG_DEPTH ( LogDepth ), .SYNC_STAGES ( SyncStages ) @@ -99,9 +99,9 @@ module axi_cdc_dst #( cc_cdc_fifo_gray_src #( `ifdef QUESTA - .T ( logic [$bits(b_chan_t)-1:0] ), + .T ( logic [$bits(b_chan_t)-1:0] ), `else - .T ( b_chan_t ), + .T ( b_chan_t ), `endif .LOG_DEPTH ( LogDepth ), .SYNC_STAGES ( SyncStages ) @@ -118,9 +118,9 @@ module axi_cdc_dst #( cc_cdc_fifo_gray_dst #( `ifdef QUESTA - .T ( logic [$bits(ar_chan_t)-1:0] ), + .T ( logic [$bits(ar_chan_t)-1:0] ), `else - .T ( ar_chan_t ), + .T ( ar_chan_t ), `endif .LOG_DEPTH ( LogDepth ), .SYNC_STAGES ( SyncStages ) @@ -137,9 +137,9 @@ module axi_cdc_dst #( cc_cdc_fifo_gray_src #( `ifdef QUESTA - .T ( logic [$bits(r_chan_t)-1:0] ), + .T ( logic [$bits(r_chan_t)-1:0] ), `else - .T ( r_chan_t ), + .T ( r_chan_t ), `endif .LOG_DEPTH ( LogDepth ), .SYNC_STAGES ( SyncStages ) diff --git a/src/axi_cdc_src.sv b/src/axi_cdc_src.sv index 73d3c864c..2024d2440 100644 --- a/src/axi_cdc_src.sv +++ b/src/axi_cdc_src.sv @@ -60,9 +60,9 @@ module axi_cdc_src #( cc_cdc_fifo_gray_src #( // Workaround for a bug in Questa (see comment in `axi_cdc_dst` for details). `ifdef QUESTA - .T ( logic [$bits(aw_chan_t)-1:0] ), + .T ( logic [$bits(aw_chan_t)-1:0] ), `else - .T ( aw_chan_t ), + .T ( aw_chan_t ), `endif .LOG_DEPTH ( LogDepth ), .SYNC_STAGES ( SyncStages ) @@ -79,9 +79,9 @@ module axi_cdc_src #( cc_cdc_fifo_gray_src #( `ifdef QUESTA - .T ( logic [$bits(w_chan_t)-1:0] ), + .T ( logic [$bits(w_chan_t)-1:0] ), `else - .T ( w_chan_t ), + .T ( w_chan_t ), `endif .LOG_DEPTH ( LogDepth ), .SYNC_STAGES ( SyncStages ) @@ -98,9 +98,9 @@ module axi_cdc_src #( cc_cdc_fifo_gray_dst #( `ifdef QUESTA - .T ( logic [$bits(b_chan_t)-1:0] ), + .T ( logic [$bits(b_chan_t)-1:0] ), `else - .T ( b_chan_t ), + .T ( b_chan_t ), `endif .LOG_DEPTH ( LogDepth ), .SYNC_STAGES ( SyncStages ) @@ -117,9 +117,9 @@ module axi_cdc_src #( cc_cdc_fifo_gray_src #( `ifdef QUESTA - .T ( logic [$bits(ar_chan_t)-1:0] ), + .T ( logic [$bits(ar_chan_t)-1:0] ), `else - .T ( ar_chan_t ), + .T ( ar_chan_t ), `endif .LOG_DEPTH ( LogDepth ), .SYNC_STAGES ( SyncStages ) @@ -136,9 +136,9 @@ module axi_cdc_src #( cc_cdc_fifo_gray_dst #( `ifdef QUESTA - .T ( logic [$bits(r_chan_t)-1:0] ), + .T ( logic [$bits(r_chan_t)-1:0] ), `else - .T ( r_chan_t ), + .T ( r_chan_t ), `endif .LOG_DEPTH ( LogDepth ), .SYNC_STAGES ( SyncStages ) diff --git a/src/axi_cut.sv b/src/axi_cut.sv index 6c9449ac7..9d4c8c240 100644 --- a/src/axi_cut.sv +++ b/src/axi_cut.sv @@ -47,7 +47,7 @@ module axi_cut #( // a spill register for each channel cc_spill_register #( - .T ( aw_chan_t ), + .T ( aw_chan_t ), .Bypass ( BypassAw ) ) i_reg_aw ( .clk_i ( clk_i ), @@ -61,7 +61,7 @@ module axi_cut #( ); cc_spill_register #( - .T ( w_chan_t ), + .T ( w_chan_t ), .Bypass ( BypassW ) ) i_reg_w ( .clk_i ( clk_i ), @@ -75,7 +75,7 @@ module axi_cut #( ); cc_spill_register #( - .T ( b_chan_t ), + .T ( b_chan_t ), .Bypass ( BypassB ) ) i_reg_b ( .clk_i ( clk_i ), @@ -89,7 +89,7 @@ module axi_cut #( ); cc_spill_register #( - .T ( ar_chan_t ), + .T ( ar_chan_t ), .Bypass ( BypassAr ) ) i_reg_ar ( .clk_i ( clk_i ), @@ -103,7 +103,7 @@ module axi_cut #( ); cc_spill_register #( - .T ( r_chan_t ), + .T ( r_chan_t ), .Bypass ( BypassR ) ) i_reg_r ( .clk_i ( clk_i ), diff --git a/src/axi_demux.sv b/src/axi_demux.sv index 246bfb2e2..6c95d7bb7 100644 --- a/src/axi_demux.sv +++ b/src/axi_demux.sv @@ -86,7 +86,7 @@ module axi_demux #( select_t slv_aw_select, slv_ar_select; cc_spill_register #( - .T ( aw_chan_t ), + .T ( aw_chan_t ), .Bypass ( ~SpillAw ) ) i_aw_spill_reg ( .clk_i, @@ -99,7 +99,7 @@ module axi_demux #( .data_o ( slv_req_cut.aw ) ); cc_spill_register #( - .T ( select_t ), + .T ( select_t ), .Bypass ( ~SpillAw ) ) i_aw_select_spill_reg ( .clk_i, @@ -116,7 +116,7 @@ module axi_demux #( assign slv_req_cut.aw_valid = slv_aw_valid_chan & slv_aw_valid_sel; cc_spill_register #( - .T ( w_chan_t ), + .T ( w_chan_t ), .Bypass ( ~SpillW ) ) i_w_spill_reg ( .clk_i, @@ -129,7 +129,7 @@ module axi_demux #( .data_o ( slv_req_cut.w ) ); cc_spill_register #( - .T ( ar_chan_t ), + .T ( ar_chan_t ), .Bypass ( ~SpillAr ) ) i_ar_spill_reg ( .clk_i, @@ -142,7 +142,7 @@ module axi_demux #( .data_o ( slv_req_cut.ar ) ); cc_spill_register #( - .T ( select_t ), + .T ( select_t ), .Bypass ( ~SpillAr ) ) i_ar_sel_spill_reg ( .clk_i, @@ -159,7 +159,7 @@ module axi_demux #( assign slv_req_cut.ar_valid = slv_ar_valid_chan & slv_ar_valid_sel; cc_spill_register #( - .T ( b_chan_t ), + .T ( b_chan_t ), .Bypass ( ~SpillB ) ) i_b_spill_reg ( .clk_i, @@ -172,7 +172,7 @@ module axi_demux #( .data_o ( slv_resp_o.b ) ); cc_spill_register #( - .T ( r_chan_t ), + .T ( r_chan_t ), .Bypass ( ~SpillR ) ) i_r_spill_reg ( .clk_i, diff --git a/src/axi_dw_downsizer.sv b/src/axi_dw_downsizer.sv index 094ef143b..e5e20703b 100644 --- a/src/axi_dw_downsizer.sv +++ b/src/axi_dw_downsizer.sv @@ -98,7 +98,7 @@ module axi_dw_downsizer #( cc_rr_arb_tree #( .NumIn (AxiMaxReads ), - .DataType (slv_r_chan_t), + .DataType (slv_r_chan_t), .AxiVldRdy(1'b1 ), .ExtPrio (1'b0 ), .LockIn (1'b1 ) @@ -160,7 +160,7 @@ module axi_dw_downsizer #( cc_rr_arb_tree #( .NumIn (AxiMaxReads), - .DataType (ar_chan_t ), + .DataType (ar_chan_t ), .AxiVldRdy(1'b1 ), .ExtPrio (1'b0 ), .LockIn (1'b1 ) @@ -309,7 +309,7 @@ module axi_dw_downsizer #( logic idqueue_valid; cc_id_queue #( - .ID_WIDTH (AxiIdWidth ), + .ID_WIDTH(AxiIdWidth ), .CAPACITY(AxiMaxReads), .data_t (tran_id_t ) ) i_read_id_queue ( @@ -680,7 +680,7 @@ module axi_dw_downsizer #( cc_fifo #( .DATA_WIDTH (1 ), - .DEPTH (AxiMaxReads), + .DEPTH (AxiMaxReads), .FALL_THROUGH(1'b1 ) ) i_forward_b_beats_queue ( .clk_i (clk_i ), diff --git a/src/axi_dw_upsizer.sv b/src/axi_dw_upsizer.sv index 05cf499dc..72ba049d9 100644 --- a/src/axi_dw_upsizer.sv +++ b/src/axi_dw_upsizer.sv @@ -95,7 +95,7 @@ module axi_dw_upsizer #( cc_rr_arb_tree #( .NumIn (AxiMaxReads ), - .DataType (slv_r_chan_t), + .DataType (slv_r_chan_t), .AxiVldRdy(1'b1 ), .ExtPrio (1'b0 ), .LockIn (1'b1 ) @@ -157,7 +157,7 @@ module axi_dw_upsizer #( cc_rr_arb_tree #( .NumIn (AxiMaxReads), - .DataType (ar_chan_t ), + .DataType (ar_chan_t ), .AxiVldRdy(1'b1 ), .ExtPrio (1'b0 ), .LockIn (1'b1 ) diff --git a/src/axi_fifo.sv b/src/axi_fifo.sv index 790ef4960..fb1d527a2 100644 --- a/src/axi_fifo.sv +++ b/src/axi_fifo.sv @@ -63,9 +63,9 @@ module axi_fifo #( // A FiFo for each channel cc_fifo #( - .dtype(aw_chan_t), - .DEPTH(Depth), - .FALL_THROUGH(FallThrough) + .dtype (aw_chan_t), + .DEPTH (Depth), + .FALL_THROUGH (FallThrough) ) i_aw_fifo ( .clk_i, .rst_ni, @@ -79,9 +79,9 @@ module axi_fifo #( .pop_i (mst_req_o.aw_valid && mst_resp_i.aw_ready) ); cc_fifo #( - .dtype(ar_chan_t), - .DEPTH(Depth), - .FALL_THROUGH(FallThrough) + .dtype (ar_chan_t), + .DEPTH (Depth), + .FALL_THROUGH (FallThrough) ) i_ar_fifo ( .clk_i, .rst_ni, @@ -95,9 +95,9 @@ module axi_fifo #( .pop_i (mst_req_o.ar_valid && mst_resp_i.ar_ready) ); cc_fifo #( - .dtype(w_chan_t), - .DEPTH(Depth), - .FALL_THROUGH(FallThrough) + .dtype (w_chan_t), + .DEPTH (Depth), + .FALL_THROUGH (FallThrough) ) i_w_fifo ( .clk_i, .rst_ni, @@ -111,9 +111,9 @@ module axi_fifo #( .pop_i (mst_req_o.w_valid && mst_resp_i.w_ready) ); cc_fifo #( - .dtype(r_chan_t), - .DEPTH(Depth), - .FALL_THROUGH(FallThrough) + .dtype (r_chan_t), + .DEPTH (Depth), + .FALL_THROUGH (FallThrough) ) i_r_fifo ( .clk_i, .rst_ni, @@ -127,9 +127,9 @@ module axi_fifo #( .pop_i (slv_resp_o.r_valid && slv_req_i.r_ready) ); cc_fifo #( - .dtype(b_chan_t), - .DEPTH(Depth), - .FALL_THROUGH(FallThrough) + .dtype (b_chan_t), + .DEPTH (Depth), + .FALL_THROUGH (FallThrough) ) i_b_fifo ( .clk_i, .rst_ni, diff --git a/src/axi_fifo_delay_dyn.sv b/src/axi_fifo_delay_dyn.sv index 0185d478b..d78183655 100644 --- a/src/axi_fifo_delay_dyn.sv +++ b/src/axi_fifo_delay_dyn.sv @@ -376,7 +376,7 @@ module stream_fifo_delay_dyn #( `else cc_fifo #( .DATA_WIDTH ( $bits(payload_t) ), - .DEPTH ( Depth ), + .DEPTH ( Depth ), .FALL_THROUGH ( 1'b0 ) ) data_fifo ( .clk_i ( clk_i ), @@ -427,7 +427,7 @@ module stream_fifo_delay_dyn #( `else cc_fifo #( .DATA_WIDTH ( CounterWidth ), - .DEPTH ( Depth ), + .DEPTH ( Depth ), .FALL_THROUGH ( 1'b0 ) ) deadline_fifo ( .clk_i ( clk_i ), diff --git a/src/axi_id_remap.sv b/src/axi_id_remap.sv index 33175521c..8a01d6a5a 100644 --- a/src/axi_id_remap.sv +++ b/src/axi_id_remap.sv @@ -186,7 +186,7 @@ module axi_id_remap #( ); assign both_free = wr_free & rd_free; cc_lzc #( - .WIDTH ( AxiSlvPortMaxUniqIds ), + .WIDTH ( AxiSlvPortMaxUniqIds ), .MODE ( cc_pkg::LZC_TRAILING_ZERO_CNT ) ) i_lzc ( .in_i ( both_free ), @@ -570,7 +570,7 @@ module axi_id_remap_table #( assign free_o[i] = table_q[i].cnt == '0; end cc_lzc #( - .WIDTH ( MaxUniqInpIds ), + .WIDTH ( MaxUniqInpIds ), .MODE ( cc_pkg::LZC_TRAILING_ZERO_CNT ) ) i_lzc_free ( .in_i ( free_o ), @@ -592,7 +592,7 @@ module axi_id_remap_table #( end logic no_match; cc_lzc #( - .WIDTH ( MaxUniqInpIds ), + .WIDTH ( MaxUniqInpIds ), .MODE ( cc_pkg::LZC_TRAILING_ZERO_CNT ) ) i_lzc_match ( .in_i ( match ), diff --git a/src/axi_inval_filter.sv b/src/axi_inval_filter.sv index 875900f80..5baf1d33d 100644 --- a/src/axi_inval_filter.sv +++ b/src/axi_inval_filter.sv @@ -129,8 +129,8 @@ module axi_inval_filter #( cc_fifo #( .FALL_THROUGH ( 1'b1 ), - .DEPTH ( MaxTxns ), - .dtype ( aw_chan_t ) + .DEPTH ( MaxTxns ), + .dtype ( aw_chan_t ) ) i_aw_fifo ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), diff --git a/src/axi_lite_demux.sv b/src/axi_lite_demux.sv index 872f6726f..560554e03 100644 --- a/src/axi_lite_demux.sv +++ b/src/axi_lite_demux.sv @@ -70,7 +70,7 @@ module axi_lite_demux #( if (NoMstPorts == 32'd1) begin : gen_no_demux // degenerate case, connect slave to master port cc_spill_register #( - .T ( aw_chan_t ), + .T ( aw_chan_t ), .Bypass ( ~SpillAw ) ) i_aw_spill_reg ( .clk_i ( clk_i ), @@ -83,7 +83,7 @@ module axi_lite_demux #( .data_o ( mst_reqs_o[0].aw ) ); cc_spill_register #( - .T ( w_chan_t ), + .T ( w_chan_t ), .Bypass ( ~SpillW ) ) i_w_spill_reg ( .clk_i ( clk_i ), @@ -96,7 +96,7 @@ module axi_lite_demux #( .data_o ( mst_reqs_o[0].w ) ); cc_spill_register #( - .T ( b_chan_t ), + .T ( b_chan_t ), .Bypass ( ~SpillB ) ) i_b_spill_reg ( .clk_i ( clk_i ), @@ -109,7 +109,7 @@ module axi_lite_demux #( .data_o ( slv_resp_o.b ) ); cc_spill_register #( - .T ( ar_chan_t ), + .T ( ar_chan_t ), .Bypass ( ~SpillAr ) ) i_ar_spill_reg ( .clk_i ( clk_i ), @@ -122,7 +122,7 @@ module axi_lite_demux #( .data_o ( mst_reqs_o[0].ar ) ); cc_spill_register #( - .T ( r_chan_t ), + .T ( r_chan_t ), .Bypass ( ~SpillR ) ) i_r_spill_reg ( .clk_i ( clk_i ), @@ -204,7 +204,7 @@ module axi_lite_demux #( slv_aw_chan_select_out_flat; assign slv_aw_chan_select_in_flat = {slv_req_i.aw, slv_aw_select_i}; cc_spill_register #( - .T ( aw_chan_select_flat_t ), + .T ( aw_chan_select_flat_t ), .Bypass ( ~SpillAw ) ) i_aw_spill_reg ( .clk_i ( clk_i ), @@ -268,8 +268,8 @@ module axi_lite_demux #( cc_fifo #( .FALL_THROUGH ( FallThrough ), - .DEPTH ( MaxTrans ), - .dtype ( select_t ) + .DEPTH ( MaxTrans ), + .dtype ( select_t ) ) i_w_fifo ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), @@ -287,7 +287,7 @@ module axi_lite_demux #( // W Channel //-------------------------------------- cc_spill_register #( - .T ( w_chan_t ), + .T ( w_chan_t ), .Bypass ( ~SpillW ) ) i_w_spill_reg ( .clk_i ( clk_i ), @@ -311,8 +311,8 @@ module axi_lite_demux #( cc_fifo #( .FALL_THROUGH ( FallThrough ), - .DEPTH ( MaxTrans ), - .dtype ( select_t ) + .DEPTH ( MaxTrans ), + .dtype ( select_t ) ) i_b_fifo ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), @@ -330,7 +330,7 @@ module axi_lite_demux #( // B Channel //-------------------------------------- cc_spill_register #( - .T ( b_chan_t ), + .T ( b_chan_t ), .Bypass ( ~SpillB ) ) i_b_spill_reg ( .clk_i ( clk_i ), @@ -364,7 +364,7 @@ module axi_lite_demux #( slv_ar_chan_select_out_flat; assign slv_ar_chan_select_in_flat = {slv_req_i.ar, slv_ar_select_i}; cc_spill_register #( - .T ( ar_chan_select_flat_t ), + .T ( ar_chan_select_flat_t ), .Bypass ( ~SpillAr ) ) i_ar_spill_reg ( .clk_i ( clk_i ), @@ -389,8 +389,8 @@ module axi_lite_demux #( cc_fifo #( .FALL_THROUGH ( FallThrough ), - .DEPTH ( MaxTrans ), - .dtype ( select_t ) + .DEPTH ( MaxTrans ), + .dtype ( select_t ) ) i_r_fifo ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), @@ -408,7 +408,7 @@ module axi_lite_demux #( // R Channel //-------------------------------------- cc_spill_register #( - .T ( r_chan_t ), + .T ( r_chan_t ), .Bypass ( ~SpillR ) ) i_r_spill_reg ( .clk_i ( clk_i ), diff --git a/src/axi_lite_dw_converter.sv b/src/axi_lite_dw_converter.sv index fe8d96641..b167e541a 100644 --- a/src/axi_lite_dw_converter.sv +++ b/src/axi_lite_dw_converter.sv @@ -134,7 +134,7 @@ module axi_lite_dw_converter #( logic aw_chan_spill_valid, aw_chan_spill_ready; cc_spill_register #( - .T ( axi_lite_aw_t ), + .T ( axi_lite_aw_t ), .Bypass ( 1'b0 ) ) i_spill_register_aw ( .clk_i, @@ -166,7 +166,7 @@ module axi_lite_dw_converter #( axi_lite_slv_w_t w_chan_spill; logic w_chan_spill_valid, w_chan_spill_ready; cc_spill_register #( - .T ( axi_lite_slv_w_t ), + .T ( axi_lite_slv_w_t ), .Bypass ( 1'b0 ) ) i_spill_register_w ( .clk_i, @@ -225,7 +225,7 @@ module axi_lite_dw_converter #( logic ar_chan_spill_valid, ar_chan_spill_ready; cc_spill_register #( - .T ( axi_lite_ar_t ), + .T ( axi_lite_ar_t ), .Bypass ( 1'b0 ) ) i_spill_register_ar ( .clk_i, @@ -339,8 +339,8 @@ module axi_lite_dw_converter #( cc_fifo #( .FALL_THROUGH ( 1'b1 ), - .DEPTH ( UpsizeFactor ), - .dtype ( sel_t ) + .DEPTH ( UpsizeFactor ), + .dtype ( sel_t ) ) i_fifo_w_sel ( .clk_i, .rst_ni, @@ -420,8 +420,8 @@ module axi_lite_dw_converter #( cc_fifo #( .FALL_THROUGH ( 1'b1 ), - .DEPTH ( UpsizeFactor ), - .dtype ( sel_t ) + .DEPTH ( UpsizeFactor ), + .dtype ( sel_t ) ) i_fifo_r_sel ( .clk_i, .rst_ni, diff --git a/src/axi_lite_from_mem.sv b/src/axi_lite_from_mem.sv index d55a3a605..a9e464053 100644 --- a/src/axi_lite_from_mem.sv +++ b/src/axi_lite_from_mem.sv @@ -178,8 +178,8 @@ module axi_lite_from_mem #( cc_fifo #( .FALL_THROUGH ( 1'b0 ), // No fallthrough for one cycle delay before ready on AXI. - .DEPTH ( MaxRequests ), - .dtype ( logic ) + .DEPTH ( MaxRequests ), + .dtype ( logic ) ) i_fifo_rsp_mux ( .clk_i, .rst_ni, diff --git a/src/axi_lite_lfsr.sv b/src/axi_lite_lfsr.sv index b7c812d0e..931f7cab8 100644 --- a/src/axi_lite_lfsr.sv +++ b/src/axi_lite_lfsr.sv @@ -94,7 +94,7 @@ module axi_lite_lfsr #( cc_stream_fifo #( .FALL_THROUGH ( 1'b0 ), .DATA_WIDTH ( 'd1 ), - .DEPTH ( 'd2 ) + .DEPTH ( 'd2 ) ) i_stream_fifo_w_b ( .clk_i, .rst_ni, diff --git a/src/axi_lite_mailbox.sv b/src/axi_lite_mailbox.sv index 7a4d7311d..6f43d9d9c 100644 --- a/src/axi_lite_mailbox.sv +++ b/src/axi_lite_mailbox.sv @@ -123,8 +123,8 @@ module axi_lite_mailbox #( logic [FifoUsageWidth-1:0] mbox_0_to_1_usage, mbox_1_to_0_usage; cc_fifo #( .FALL_THROUGH ( 1'b0 ), - .DEPTH ( MailboxDepth ), - .dtype ( data_t ) + .DEPTH ( MailboxDepth ), + .dtype ( data_t ) ) i_mbox_0_to_1 ( .clk_i, .rst_ni, @@ -142,8 +142,8 @@ module axi_lite_mailbox #( cc_fifo #( .FALL_THROUGH ( 1'b0 ), - .DEPTH ( MailboxDepth ), - .dtype ( data_t ) + .DEPTH ( MailboxDepth ), + .dtype ( data_t ) ) i_mbox_1_to_0 ( .clk_i, .rst_ni, diff --git a/src/axi_lite_mux.sv b/src/axi_lite_mux.sv index 891660ce6..a8467385b 100644 --- a/src/axi_lite_mux.sv +++ b/src/axi_lite_mux.sv @@ -54,7 +54,7 @@ module axi_lite_mux #( // pass through if only one slave port if (NoSlvPorts == 32'h1) begin : gen_no_mux cc_spill_register #( - .T ( aw_chan_t ), + .T ( aw_chan_t ), .Bypass ( ~SpillAw ) ) i_aw_spill_reg ( .clk_i ( clk_i ), @@ -67,7 +67,7 @@ module axi_lite_mux #( .data_o ( mst_req_o.aw ) ); cc_spill_register #( - .T ( w_chan_t ), + .T ( w_chan_t ), .Bypass ( ~SpillW ) ) i_w_spill_reg ( .clk_i ( clk_i ), @@ -80,7 +80,7 @@ module axi_lite_mux #( .data_o ( mst_req_o.w ) ); cc_spill_register #( - .T ( b_chan_t ), + .T ( b_chan_t ), .Bypass ( ~SpillB ) ) i_b_spill_reg ( .clk_i ( clk_i ), @@ -93,7 +93,7 @@ module axi_lite_mux #( .data_o ( slv_resps_o[0].b ) ); cc_spill_register #( - .T ( ar_chan_t ), + .T ( ar_chan_t ), .Bypass ( ~SpillAr ) ) i_ar_spill_reg ( .clk_i ( clk_i ), @@ -106,7 +106,7 @@ module axi_lite_mux #( .data_o ( mst_req_o.ar ) ); cc_spill_register #( - .T ( r_chan_t ), + .T ( r_chan_t ), .Bypass ( ~SpillR ) ) i_r_spill_reg ( .clk_i ( clk_i ), @@ -196,10 +196,10 @@ module axi_lite_mux #( assign slv_resps_o[i].aw_ready = slv_aw_readies[i]; end cc_rr_arb_tree #( - .NumIn ( NoSlvPorts ), - .DataType ( aw_chan_t ), - .AxiVldRdy( 1'b1 ), - .LockIn ( 1'b1 ) + .NumIn ( NoSlvPorts ), + .DataType ( aw_chan_t ), + .AxiVldRdy ( 1'b1 ), + .LockIn ( 1'b1 ) ) i_aw_arbiter ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), @@ -250,8 +250,8 @@ module axi_lite_mux #( cc_fifo #( .FALL_THROUGH ( FallThrough ), - .DEPTH ( MaxTrans ), - .dtype ( select_t ) + .DEPTH ( MaxTrans ), + .dtype ( select_t ) ) i_w_fifo ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), @@ -266,7 +266,7 @@ module axi_lite_mux #( ); cc_spill_register #( - .T ( aw_chan_t ), + .T ( aw_chan_t ), .Bypass ( ~SpillAw ) // Param indicated that we want a spill reg ) i_aw_spill_reg ( .clk_i ( clk_i ), @@ -293,8 +293,8 @@ module axi_lite_mux #( cc_fifo #( .FALL_THROUGH ( FallThrough ), - .DEPTH ( MaxTrans ), - .dtype ( select_t ) + .DEPTH ( MaxTrans ), + .dtype ( select_t ) ) i_b_fifo ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), @@ -309,7 +309,7 @@ module axi_lite_mux #( ); cc_spill_register #( - .T ( w_chan_t ), + .T ( w_chan_t ), .Bypass ( ~SpillW ) ) i_w_spill_reg ( .clk_i ( clk_i ), @@ -334,7 +334,7 @@ module axi_lite_mux #( assign b_fifo_pop = mst_b_valid & mst_b_ready; cc_spill_register #( - .T ( b_chan_t ), + .T ( b_chan_t ), .Bypass ( ~SpillB ) ) i_b_spill_reg ( .clk_i ( clk_i ), @@ -357,10 +357,10 @@ module axi_lite_mux #( assign slv_resps_o[i].ar_ready = slv_ar_readies[i]; end cc_rr_arb_tree #( - .NumIn ( NoSlvPorts ), - .DataType ( ar_chan_t ), - .AxiVldRdy( 1'b1 ), - .LockIn ( 1'b1 ) + .NumIn ( NoSlvPorts ), + .DataType ( ar_chan_t ), + .AxiVldRdy ( 1'b1 ), + .LockIn ( 1'b1 ) ) i_ar_arbiter ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), @@ -383,8 +383,8 @@ module axi_lite_mux #( cc_fifo #( .FALL_THROUGH ( FallThrough ), - .DEPTH ( MaxTrans ), - .dtype ( select_t ) + .DEPTH ( MaxTrans ), + .dtype ( select_t ) ) i_r_fifo ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), @@ -399,7 +399,7 @@ module axi_lite_mux #( ); cc_spill_register #( - .T ( ar_chan_t ), + .T ( ar_chan_t ), .Bypass ( ~SpillAr ) ) i_ar_spill_reg ( .clk_i ( clk_i ), @@ -424,7 +424,7 @@ module axi_lite_mux #( assign r_fifo_pop = mst_r_valid & mst_r_ready; cc_spill_register #( - .T ( r_chan_t ), + .T ( r_chan_t ), .Bypass ( ~SpillR ) ) i_r_spill_reg ( .clk_i ( clk_i ), diff --git a/src/axi_lite_regs.sv b/src/axi_lite_regs.sv index edc8c2c36..b6a8f45fe 100644 --- a/src/axi_lite_regs.sv +++ b/src/axi_lite_regs.sv @@ -349,7 +349,7 @@ module axi_lite_regs #( // Add a cycle delay on AXI response, cut all comb paths between slave port inputs and outputs. cc_spill_register #( - .T ( b_chan_lite_t ), + .T ( b_chan_lite_t ), .Bypass ( 1'b0 ) ) i_b_spill_register ( .clk_i, @@ -364,7 +364,7 @@ module axi_lite_regs #( // Add a cycle delay on AXI response, cut all comb paths between slave port inputs and outputs. cc_spill_register #( - .T ( r_chan_lite_t ), + .T ( r_chan_lite_t ), .Bypass ( 1'b0 ) ) i_r_spill_register ( .clk_i, diff --git a/src/axi_lite_to_apb.sv b/src/axi_lite_to_apb.sv index c5609ba87..14d5d4f1f 100644 --- a/src/axi_lite_to_apb.sv +++ b/src/axi_lite_to_apb.sv @@ -147,11 +147,11 @@ module axi_lite_to_apb #( logic apb_rresp_valid, apb_rresp_ready; cc_rr_arb_tree #( - .NumIn ( 32'd2 ), - .DataType ( int_req_t ), - .ExtPrio ( 1'b0 ), - .AxiVldRdy( 1'b1 ), - .LockIn ( 1'b1 ) + .NumIn ( 32'd2 ), + .DataType ( int_req_t ), + .ExtPrio ( 1'b0 ), + .AxiVldRdy ( 1'b1 ), + .LockIn ( 1'b1 ) ) i_req_arb ( .clk_i, .rst_ni, @@ -168,7 +168,7 @@ module axi_lite_to_apb #( if (PipelineRequest) begin : gen_req_spill cc_spill_register #( - .T ( int_req_t ), + .T ( int_req_t ), .Bypass ( 1'b0 ) ) i_req_spill ( .clk_i, @@ -198,7 +198,7 @@ module axi_lite_to_apb #( if (PipelineResponse) begin : gen_resp_spill cc_spill_register #( - .T ( axi_pkg::resp_t ), + .T ( axi_pkg::resp_t ), .Bypass ( 1'b0 ) ) i_write_resp_spill ( .clk_i, @@ -211,7 +211,7 @@ module axi_lite_to_apb #( .data_o ( axi_bresp ) ); cc_spill_register #( - .T ( int_resp_t ), + .T ( int_resp_t ), .Bypass ( 1'b0 ) ) i_read_resp_spill ( .clk_i, diff --git a/src/axi_serializer.sv b/src/axi_serializer.sv index cddc33316..1de1f9eed 100644 --- a/src/axi_serializer.sv +++ b/src/axi_serializer.sv @@ -148,8 +148,8 @@ module axi_serializer #( cc_fifo #( .FALL_THROUGH ( 1'b0 ), // No fall-through as response has to come a cycle later anyway - .DEPTH ( MaxReadTxns ), - .dtype ( id_t ) + .DEPTH ( MaxReadTxns ), + .dtype ( id_t ) ) i_rd_id_fifo ( .clk_i, .rst_ni, @@ -167,8 +167,8 @@ module axi_serializer #( cc_fifo #( .FALL_THROUGH ( 1'b0 ), - .DEPTH ( MaxWriteTxns ), - .dtype ( id_t ) + .DEPTH ( MaxWriteTxns ), + .dtype ( id_t ) ) i_wr_id_fifo ( .clk_i, .rst_ni, diff --git a/src/axi_to_axi_lite.sv b/src/axi_to_axi_lite.sv index 0ea9827cd..f1d812f1f 100644 --- a/src/axi_to_axi_lite.sv +++ b/src/axi_to_axi_lite.sv @@ -164,8 +164,8 @@ module axi_to_axi_lite_id_reflect #( assign aw_pop = slv_resp_o.b_valid & mst_req_o.b_ready; cc_fifo #( .FALL_THROUGH ( FallThrough ), - .DEPTH ( AxiMaxWriteTxns ), - .dtype ( id_t ) + .DEPTH ( AxiMaxWriteTxns ), + .dtype ( id_t ) ) i_aw_id_fifo ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), @@ -184,8 +184,8 @@ module axi_to_axi_lite_id_reflect #( assign ar_pop = slv_resp_o.r_valid & mst_req_o.r_ready; cc_fifo #( .FALL_THROUGH ( FallThrough ), - .DEPTH ( AxiMaxReadTxns ), - .dtype ( id_t ) + .DEPTH ( AxiMaxReadTxns ), + .dtype ( id_t ) ) i_ar_id_fifo ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), diff --git a/src/axi_to_detailed_mem.sv b/src/axi_to_detailed_mem.sv index 07ee85a57..b32238b99 100644 --- a/src/axi_to_detailed_mem.sv +++ b/src/axi_to_detailed_mem.sv @@ -266,7 +266,7 @@ module axi_to_detailed_mem #( // Arbitrate between reads and writes. cc_stream_mux #( .DATA_T ( meta_t ), - .N_INP ( 32'd2 ) + .N_INP ( 32'd2 ) ) i_ax_mux ( .inp_data_i ({wr_meta, rd_meta }), .inp_valid_i ({wr_valid, rd_valid}), @@ -337,8 +337,8 @@ module axi_to_detailed_mem #( cc_stream_fifo #( .FALL_THROUGH ( 1'b1 ), - .DEPTH ( 32'd1 + BufDepth ), - .T ( logic[1:0] ) + .DEPTH ( 32'd1 + BufDepth ), + .T ( logic[1:0] ) ) i_sel_buf ( .clk_i, .rst_ni, @@ -354,8 +354,8 @@ module axi_to_detailed_mem #( cc_stream_fifo #( .FALL_THROUGH ( 1'b1 ), - .DEPTH ( 32'd1 + BufDepth ), - .T ( meta_t ) + .DEPTH ( 32'd1 + BufDepth ), + .T ( meta_t ) ) i_meta_buf ( .clk_i, .rst_ni, @@ -876,8 +876,8 @@ module mem_stream_to_banks_detailed #( cc_stream_fifo #( .FALL_THROUGH ( 1'b1 ), .DATA_WIDTH ( $bits(req_t) ), - .DEPTH ( OutFifoDepth ), - .T ( req_t ) + .DEPTH ( OutFifoDepth ), + .T ( req_t ) ) i_ft_reg ( .clk_i, .rst_ni, @@ -920,7 +920,7 @@ module mem_stream_to_banks_detailed #( end cc_fifo #( .FALL_THROUGH ( 1'b0 ), - .DEPTH ( MaxTrans+1 ), + .DEPTH ( MaxTrans+1 ), .DATA_WIDTH ( NumBanks ) ) i_dead_write_fifo ( .clk_i, @@ -947,7 +947,7 @@ module mem_stream_to_banks_detailed #( cc_stream_fifo #( .FALL_THROUGH ( 1'b1 ), .DATA_WIDTH ( $bits(oup_data_t) + $bits(oup_ruser_t) ), - .DEPTH ( MaxTrans ) + .DEPTH ( MaxTrans ) ) i_ft_reg ( .clk_i, .rst_ni, diff --git a/src/axi_to_mem_interleaved.sv b/src/axi_to_mem_interleaved.sv index 2a5739304..d3df18905 100644 --- a/src/axi_to_mem_interleaved.sv +++ b/src/axi_to_mem_interleaved.sv @@ -220,7 +220,7 @@ module axi_to_mem_interleaved #( // fine-grain arbitration cc_rr_arb_tree #( - .NumIn ( 2 ), + .NumIn ( 2 ), .DataType ( mem_req_payload_t ) ) i_rr_arb_tree ( .clk_i ( clk_i ), @@ -239,7 +239,7 @@ module axi_to_mem_interleaved #( // back-routing store cc_fifo #( .DATA_WIDTH ( 1 ), - .DEPTH ( BufDepth + 1 ) + .DEPTH ( BufDepth + 1 ) ) i_fifo_v3_response_trgt_store ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), From 3c406ae59484238679c37a40afe149fbd0d08300 Mon Sep 17 00:00:00 2001 From: Riccardo Tedeschi Date: Thu, 2 Jul 2026 15:05:09 +0200 Subject: [PATCH 08/41] refactor: adopt latest version of `common_cells` v2 --- Bender.lock | 8 +- Bender.yml | 4 +- src/axi_atop_filter.sv | 2 +- src/axi_burst_splitter_gran.sv | 18 +++-- src/axi_burst_unwrap.sv | 13 ++-- src/axi_bus_compare.sv | 134 +++++++++++++++++++-------------- src/axi_cdc_dst.sv | 40 +++++----- src/axi_cdc_src.sv | 40 +++++----- src/axi_cut.sv | 15 ++-- src/axi_delayer.sv | 5 ++ src/axi_demux.sv | 21 ++++-- src/axi_demux_id_counters.sv | 6 +- src/axi_demux_simple.sv | 14 ++-- src/axi_dw_downsizer.sv | 32 ++++---- src/axi_dw_upsizer.sv | 26 +++---- src/axi_err_slv.sv | 25 +++--- src/axi_fifo.sv | 35 +++++---- src/axi_fifo_delay_dyn.sv | 18 +++-- src/axi_id_remap.sv | 12 +-- src/axi_inval_filter.sv | 7 +- src/axi_lite_demux.sv | 51 ++++++++----- src/axi_lite_dw_converter.sv | 23 +++--- src/axi_lite_from_mem.sv | 7 +- src/axi_lite_lfsr.sv | 7 +- src/axi_lite_mailbox.sv | 31 ++++---- src/axi_lite_mux.sv | 59 +++++++++------ src/axi_lite_regs.sv | 6 +- src/axi_lite_to_apb.sv | 25 +++--- src/axi_mux.sv | 45 ++++++----- src/axi_serializer.sv | 14 ++-- src/axi_slave_compare.sv | 9 ++- src/axi_throttle.sv | 2 + src/axi_to_axi_lite.sv | 14 ++-- src/axi_to_detailed_mem.sv | 49 ++++++------ src/axi_to_mem_banked.sv | 6 +- src/axi_to_mem_interleaved.sv | 9 ++- 36 files changed, 478 insertions(+), 354 deletions(-) diff --git a/Bender.lock b/Bender.lock index ccfb70bda..ede770c15 100644 --- a/Bender.lock +++ b/Bender.lock @@ -1,7 +1,7 @@ packages: common_cells: - revision: e42f76dcb1e8a1a171943b22f36c94f640508994 - version: null + revision: 88e7f97210dfce5da38390bfb9d3c21eb998810c + version: 2.0.0-beta source: Git: https://github.com/pulp-platform/common_cells.git dependencies: @@ -14,8 +14,8 @@ packages: Git: https://github.com/pulp-platform/common_verification.git dependencies: [] tech_cells_generic: - revision: 7968dd6e6180df2c644636bc6d2908a49f2190cf - version: 0.2.13 + revision: 3a3de73632a06826b1bd9c65a0a2e92b32016845 + version: 0.2.14 source: Git: https://github.com/pulp-platform/tech_cells_generic.git dependencies: diff --git a/Bender.yml b/Bender.yml index cd94cd522..dc6559d30 100644 --- a/Bender.yml +++ b/Bender.yml @@ -24,9 +24,9 @@ remotes: pulp: https://github.com/pulp-platform dependencies: - common_cells: { git: "https://github.com/pulp-platform/common_cells.git", rev: v2-test } + common_cells: { git: "https://github.com/pulp-platform/common_cells.git", version: 2.0.0-beta } common_verification: 0.2.5 - tech_cells_generic: 0.2.2 + tech_cells_generic: 0.2.14 export_include_dirs: - include diff --git a/src/axi_atop_filter.sv b/src/axi_atop_filter.sv index 2b71d37d9..d42549083 100644 --- a/src/axi_atop_filter.sv +++ b/src/axi_atop_filter.sv @@ -346,7 +346,7 @@ module axi_atop_filter #( end cc_stream_register #( - .T(r_resp_cmd_t) + .data_t (r_resp_cmd_t) ) r_resp_cmd ( .clk_i (clk_i), .rst_ni (rst_ni), diff --git a/src/axi_burst_splitter_gran.sv b/src/axi_burst_splitter_gran.sv index e53d1027d..030834681 100644 --- a/src/axi_burst_splitter_gran.sv +++ b/src/axi_burst_splitter_gran.sv @@ -620,11 +620,12 @@ module axi_burst_splitter_gran_counters #( if (CutPath) begin : gen_spill cc_spill_register #( - .T ( alloc_pld_t ), + .data_t ( alloc_pld_t ), .Bypass ( 1'b0 ) ) i_spill_register_alloc ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .valid_i ( alloc_req_i ), .ready_o ( alloc_gnt_o ), .data_i ( alloc_pld_in ), @@ -646,11 +647,11 @@ module axi_burst_splitter_gran_counters #( cnt_idx_t cnt_free_idx, cnt_r_idx; for (genvar i = 0; i < MaxTxns; i++) begin : gen_cnt cc_delta_counter #( - .WIDTH ( $bits(cnt_t) ) + .Width ( $bits(cnt_t) ) ) i_cnt ( .clk_i, .rst_ni, - .clear_i ( cnt_clr[i] ), + .clr_i ( cnt_clr[i] ), .en_i ( cnt_dec[i] ), .load_i ( cnt_set[i] ), .down_i ( 1'b1 ), @@ -664,8 +665,8 @@ module axi_burst_splitter_gran_counters #( assign cnt_inp = {1'b0, alloc_pld_out.len} + 1; cc_lzc #( - .WIDTH ( MaxTxns ), - .MODE ( cc_pkg::LZC_TRAILING_ZERO_CNT ) + .Width ( MaxTxns ), + .Mode ( cc_pkg::LZC_TRAILING_ZERO_CNT ) ) i_lzc ( .in_i ( cnt_free ), .cnt_o ( cnt_free_idx ), @@ -675,13 +676,14 @@ module axi_burst_splitter_gran_counters #( logic idq_inp_req, idq_inp_gnt, idq_oup_gnt, idq_oup_valid, idq_oup_pop; cc_id_queue #( - .ID_WIDTH ( $bits(id_t) ), - .CAPACITY ( MaxTxns ), - .FULL_BW ( FullBW ), + .IdWidth ( $bits(id_t) ), + .Capacity ( MaxTxns ), + .FullBw ( FullBW ), .data_t ( cnt_idx_t ) ) i_idq ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .inp_id_i ( alloc_pld_out.id ), .inp_data_i ( cnt_free_idx ), .inp_req_i ( idq_inp_req ), diff --git a/src/axi_burst_unwrap.sv b/src/axi_burst_unwrap.sv index 84c8fc300..48920c172 100644 --- a/src/axi_burst_unwrap.sv +++ b/src/axi_burst_unwrap.sv @@ -566,11 +566,11 @@ module axi_burst_counters #( cnt_idx_t cnt_free_idx, cnt_r_idx; for (genvar i = 0; i < MaxTxns; i++) begin : gen_cnt cc_counter #( - .WIDTH ( $bits(cnt_t) ) + .Width ( $bits(cnt_t) ) ) i_cnt ( .clk_i, .rst_ni, - .clear_i ( 1'b0 ), + .clr_i ( 1'b0 ), .en_i ( cnt_dec[i] ), .load_i ( cnt_set[i] ), .down_i ( 1'b1 ), @@ -583,8 +583,8 @@ module axi_burst_counters #( assign cnt_inp = {1'b0, alloc_len_i} + 1; cc_lzc #( - .WIDTH ( MaxTxns ), - .MODE ( cc_pkg::LZC_TRAILING_ZERO_CNT ) // start counting at index 0 + .Width ( MaxTxns ), + .Mode ( cc_pkg::LZC_TRAILING_ZERO_CNT ) // start counting at index 0 ) i_lzc ( .in_i ( cnt_free ), .cnt_o ( cnt_free_idx ), @@ -594,12 +594,13 @@ module axi_burst_counters #( logic idq_inp_req, idq_inp_gnt, idq_oup_gnt, idq_oup_valid, idq_oup_pop; cc_id_queue #( - .ID_WIDTH ( $bits(id_t) ), - .CAPACITY ( MaxTxns ), + .IdWidth ( $bits(id_t) ), + .Capacity ( MaxTxns ), .data_t ( cnt_idx_t ) ) i_idq ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .inp_id_i ( alloc_id_i ), .inp_data_i ( cnt_free_idx ), .inp_req_i ( idq_inp_req ), diff --git a/src/axi_bus_compare.sv b/src/axi_bus_compare.sv index 2faa44f1d..5f14677b6 100644 --- a/src/axi_bus_compare.sv +++ b/src/axi_bus_compare.sv @@ -163,10 +163,11 @@ module axi_bus_compare #( // Channel A stream forks //----------------------------------- cc_stream_fork #( - .N_OUP ( 32'd2 ) + .NumOup ( 32'd2 ) ) i_stream_fork_aw_a ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .valid_i ( axi_a_req_i.aw_valid ), .ready_o ( axi_a_rsp_o.aw_ready ), .valid_o ( {fifo_sel_valid_aw_a, axi_a_req_o.aw_valid} ), @@ -174,10 +175,11 @@ module axi_bus_compare #( ); cc_stream_fork #( - .N_OUP ( 32'd2 ) + .NumOup ( 32'd2 ) ) i_stream_fork_w_a ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .valid_i ( axi_a_req_i.w_valid ), .ready_o ( axi_a_rsp_o.w_ready ), .valid_o ( {fifo_sel_valid_w_a, axi_a_req_o.w_valid} ), @@ -185,10 +187,11 @@ module axi_bus_compare #( ); cc_stream_fork #( - .N_OUP ( 32'd2 ) + .NumOup ( 32'd2 ) ) i_stream_fork_b_a ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .valid_i ( axi_a_rsp_i.b_valid ), .ready_o ( axi_a_req_o.b_ready ), .valid_o ( {fifo_sel_valid_b_a, axi_a_rsp_o.b_valid} ), @@ -196,10 +199,11 @@ module axi_bus_compare #( ); cc_stream_fork #( - .N_OUP ( 32'd2 ) + .NumOup ( 32'd2 ) ) i_stream_fork_ar_a ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .valid_i ( axi_a_req_i.ar_valid ), .ready_o ( axi_a_rsp_o.ar_ready ), .valid_o ( {fifo_sel_valid_ar_a, axi_a_req_o.ar_valid} ), @@ -207,10 +211,11 @@ module axi_bus_compare #( ); cc_stream_fork #( - .N_OUP ( 32'd2 ) + .NumOup ( 32'd2 ) ) i_stream_fork_r_a ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .valid_i ( axi_a_rsp_i.r_valid ), .ready_o ( axi_a_req_o.r_ready ), .valid_o ( {fifo_sel_valid_r_a, axi_a_rsp_o.r_valid} ), @@ -224,13 +229,14 @@ module axi_bus_compare #( for (genvar id = 0; id < 2**AxiIdWidth; id++) begin : gen_fifos_a cc_stream_fifo #( - .FALL_THROUGH ( 1'b0 ), - .DATA_WIDTH ( 1'b0 ), - .DEPTH ( FifoDepth ), - .T ( axi_aw_chan_t ) + .FallThrough ( 1'b0 ), + .DataWidth ( 1'b0 ), + .Depth ( FifoDepth ), + .data_t ( axi_aw_chan_t ) ) i_stream_fifo_aw_a ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .flush_i ( 1'b0 ), .usage_o ( /* NOT CONNECTED */ ), .data_i ( axi_a_req_i.aw ), @@ -242,13 +248,14 @@ module axi_bus_compare #( ); cc_stream_fifo #( - .FALL_THROUGH ( 1'b0 ), - .DATA_WIDTH ( 1'b0 ), - .DEPTH ( FifoDepth ), - .T ( axi_b_chan_t ) + .FallThrough ( 1'b0 ), + .DataWidth ( 1'b0 ), + .Depth ( FifoDepth ), + .data_t ( axi_b_chan_t ) ) i_stream_fifo_b_a ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .flush_i ( 1'b0 ), .usage_o ( /* NOT CONNECTED */ ), .data_i ( axi_a_rsp_i.b ), @@ -260,13 +267,14 @@ module axi_bus_compare #( ); cc_stream_fifo #( - .FALL_THROUGH ( 1'b0 ), - .DATA_WIDTH ( 1'b0 ), - .DEPTH ( FifoDepth ), - .T ( axi_ar_chan_t ) + .FallThrough ( 1'b0 ), + .DataWidth ( 1'b0 ), + .Depth ( FifoDepth ), + .data_t ( axi_ar_chan_t ) ) i_stream_fifo_ar_a ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .flush_i ( 1'b0 ), .usage_o ( /* NOT CONNECTED */ ), .data_i ( axi_a_req_i.ar ), @@ -279,12 +287,13 @@ module axi_bus_compare #( if (UseSize) begin : gen_r_size cc_stream_fifo #( - .FALL_THROUGH ( 1'b0 ), - .DATA_WIDTH ( $clog2(DataWidth/8)+3 ), - .DEPTH ( 2*FifoDepth ) + .FallThrough ( 1'b0 ), + .DataWidth ( $clog2(DataWidth/8)+3 ), + .Depth ( 2*FifoDepth ) ) i_stream_fifo_w_size ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .flush_i ( 1'b0 ), .usage_o (), .data_i ( {axi_a_req_i.ar.addr[$clog2(DataWidth/8)-1:0], axi_a_req_i.ar.size} ), @@ -316,13 +325,14 @@ module axi_bus_compare #( cc_stream_fifo #( - .FALL_THROUGH ( 1'b0 ), - .DATA_WIDTH ( 1'b0 ), - .DEPTH ( FifoDepth ), - .T ( axi_r_chan_t ) + .FallThrough ( 1'b0 ), + .DataWidth ( 1'b0 ), + .Depth ( FifoDepth ), + .data_t ( axi_r_chan_t ) ) i_stream_fifo_r_a ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .flush_i ( 1'b0 ), .usage_o ( /* NOT CONNECTED */ ), .data_i ( axi_a_rsp_i.r ), @@ -336,12 +346,13 @@ module axi_bus_compare #( if (UseSize) begin : gen_w_size cc_stream_fifo #( - .FALL_THROUGH ( 1'b0 ), - .DATA_WIDTH ( $clog2(DataWidth/8)+3 ), - .DEPTH ( FifoDepth ) + .FallThrough ( 1'b0 ), + .DataWidth ( $clog2(DataWidth/8)+3 ), + .Depth ( FifoDepth ) ) i_stream_fifo_w_size ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .flush_i ( 1'b0 ), .usage_o (), .data_i ( {axi_a_req_i.aw.addr[$clog2(DataWidth/8)-1:0], axi_a_req_i.aw.size} ), @@ -372,13 +383,14 @@ module axi_bus_compare #( end cc_stream_fifo #( - .FALL_THROUGH ( 1'b0 ), - .DATA_WIDTH ( 1'b0 ), - .DEPTH ( FifoDepth ), - .T ( axi_w_chan_t ) + .FallThrough ( 1'b0 ), + .DataWidth ( 1'b0 ), + .Depth ( FifoDepth ), + .data_t ( axi_w_chan_t ) ) i_stream_fifo_w_a ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .flush_i ( 1'b0 ), .usage_o ( /* NOT CONNECTED */ ), .data_i ( axi_a_req_i.w ), @@ -433,10 +445,11 @@ module axi_bus_compare #( // Channel B stream forks //----------------------------------- cc_stream_fork #( - .N_OUP ( 32'd2 ) + .NumOup ( 32'd2 ) ) i_stream_fork_aw_b ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .valid_i ( axi_b_req_i.aw_valid ), .ready_o ( axi_b_rsp_o.aw_ready ), .valid_o ( {fifo_sel_valid_aw_b, axi_b_req_o.aw_valid} ), @@ -444,10 +457,11 @@ module axi_bus_compare #( ); cc_stream_fork #( - .N_OUP ( 32'd2 ) + .NumOup ( 32'd2 ) ) i_stream_fork_w_b ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .valid_i ( axi_b_req_i.w_valid ), .ready_o ( axi_b_rsp_o.w_ready ), .valid_o ( {fifo_sel_valid_w_b, axi_b_req_o.w_valid} ), @@ -455,10 +469,11 @@ module axi_bus_compare #( ); cc_stream_fork #( - .N_OUP ( 32'd2 ) + .NumOup ( 32'd2 ) ) i_stream_fork_b_b ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .valid_i ( axi_b_rsp_i.b_valid ), .ready_o ( axi_b_req_o.b_ready ), .valid_o ( {fifo_sel_valid_b_b, axi_b_rsp_o.b_valid} ), @@ -466,10 +481,11 @@ module axi_bus_compare #( ); cc_stream_fork #( - .N_OUP ( 32'd2 ) + .NumOup ( 32'd2 ) ) i_stream_fork_ar_b ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .valid_i ( axi_b_req_i.ar_valid ), .ready_o ( axi_b_rsp_o.ar_ready ), .valid_o ( {fifo_sel_valid_ar_b, axi_b_req_o.ar_valid} ), @@ -477,10 +493,11 @@ module axi_bus_compare #( ); cc_stream_fork #( - .N_OUP ( 32'd2 ) + .NumOup ( 32'd2 ) ) i_stream_fork_r_b ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .valid_i ( axi_b_rsp_i.r_valid ), .ready_o ( axi_b_req_o.r_ready ), .valid_o ( {fifo_sel_valid_r_b, axi_b_rsp_o.r_valid} ), @@ -494,13 +511,14 @@ module axi_bus_compare #( for (genvar id = 0; id < 2**AxiIdWidth; id++) begin : gen_fifos_b cc_stream_fifo #( - .FALL_THROUGH ( 1'b0 ), - .DATA_WIDTH ( 1'b0 ), - .DEPTH ( FifoDepth ), - .T ( axi_aw_chan_t ) + .FallThrough ( 1'b0 ), + .DataWidth ( 1'b0 ), + .Depth ( FifoDepth ), + .data_t ( axi_aw_chan_t ) ) i_stream_fifo_aw_b ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .flush_i ( 1'b0 ), .usage_o ( /* NOT CONNECTED */ ), .data_i ( axi_b_req_i.aw ), @@ -512,13 +530,14 @@ module axi_bus_compare #( ); cc_stream_fifo #( - .FALL_THROUGH ( 1'b0 ), - .DATA_WIDTH ( 1'b0 ), - .DEPTH ( FifoDepth ), - .T ( axi_b_chan_t ) + .FallThrough ( 1'b0 ), + .DataWidth ( 1'b0 ), + .Depth ( FifoDepth ), + .data_t ( axi_b_chan_t ) ) i_stream_fifo_b_b ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .flush_i ( 1'b0 ), .usage_o ( /* NOT CONNECTED */ ), .data_i ( axi_b_rsp_i.b ), @@ -530,13 +549,14 @@ module axi_bus_compare #( ); cc_stream_fifo #( - .FALL_THROUGH ( 1'b0 ), - .DATA_WIDTH ( 1'b0 ), - .DEPTH ( FifoDepth ), - .T ( axi_ar_chan_t ) + .FallThrough ( 1'b0 ), + .DataWidth ( 1'b0 ), + .Depth ( FifoDepth ), + .data_t ( axi_ar_chan_t ) ) i_stream_fifo_ar_b ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .flush_i ( 1'b0 ), .usage_o ( /* NOT CONNECTED */ ), .data_i ( axi_b_req_i.ar ), @@ -548,13 +568,14 @@ module axi_bus_compare #( ); cc_stream_fifo #( - .FALL_THROUGH ( 1'b0 ), - .DATA_WIDTH ( 1'b0 ), - .DEPTH ( FifoDepth ), - .T ( axi_r_chan_t ) + .FallThrough ( 1'b0 ), + .DataWidth ( 1'b0 ), + .Depth ( FifoDepth ), + .data_t ( axi_r_chan_t ) ) i_stream_fifo_r_b ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .flush_i ( 1'b0 ), .usage_o ( /* NOT CONNECTED */ ), .data_i ( axi_b_rsp_i.r ), @@ -567,13 +588,14 @@ module axi_bus_compare #( end cc_stream_fifo #( - .FALL_THROUGH ( 1'b0 ), - .DATA_WIDTH ( 1'b0 ), - .DEPTH ( FifoDepth ), - .T ( axi_w_chan_t ) + .FallThrough ( 1'b0 ), + .DataWidth ( 1'b0 ), + .Depth ( FifoDepth ), + .data_t ( axi_w_chan_t ) ) i_stream_fifo_w_b ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .flush_i ( 1'b0 ), .usage_o ( /* NOT CONNECTED */ ), .data_i ( axi_b_req_i.w ), diff --git a/src/axi_cdc_dst.sv b/src/axi_cdc_dst.sv index 3d5bf7649..cb831869f 100644 --- a/src/axi_cdc_dst.sv +++ b/src/axi_cdc_dst.sv @@ -60,13 +60,13 @@ module axi_cdc_dst #( cc_cdc_fifo_gray_dst #( `ifdef QUESTA // Workaround for a bug in Questa: Pass flat logic vector instead of struct to type parameter. - .T ( logic [$bits(aw_chan_t)-1:0] ), + .data_t ( logic [$bits(aw_chan_t)-1:0] ), `else // Other tools, such as VCS, have problems with type parameters constructed through `$bits()`. - .T ( aw_chan_t ), + .data_t ( aw_chan_t ), `endif - .LOG_DEPTH ( LogDepth ), - .SYNC_STAGES ( SyncStages ) + .LogDepth ( LogDepth ), + .SyncStages ( SyncStages ) ) i_cdc_fifo_gray_dst_aw ( .async_data_i ( async_data_slave_aw_data_i ), .async_wptr_i ( async_data_slave_aw_wptr_i ), @@ -80,12 +80,12 @@ module axi_cdc_dst #( cc_cdc_fifo_gray_dst #( `ifdef QUESTA - .T ( logic [$bits(w_chan_t)-1:0] ), + .data_t ( logic [$bits(w_chan_t)-1:0] ), `else - .T ( w_chan_t ), + .data_t ( w_chan_t ), `endif - .LOG_DEPTH ( LogDepth ), - .SYNC_STAGES ( SyncStages ) + .LogDepth ( LogDepth ), + .SyncStages ( SyncStages ) ) i_cdc_fifo_gray_dst_w ( .async_data_i ( async_data_slave_w_data_i ), .async_wptr_i ( async_data_slave_w_wptr_i ), @@ -99,12 +99,12 @@ module axi_cdc_dst #( cc_cdc_fifo_gray_src #( `ifdef QUESTA - .T ( logic [$bits(b_chan_t)-1:0] ), + .data_t ( logic [$bits(b_chan_t)-1:0] ), `else - .T ( b_chan_t ), + .data_t ( b_chan_t ), `endif - .LOG_DEPTH ( LogDepth ), - .SYNC_STAGES ( SyncStages ) + .LogDepth ( LogDepth ), + .SyncStages ( SyncStages ) ) i_cdc_fifo_gray_src_b ( .src_clk_i ( dst_clk_i ), .src_rst_ni ( dst_rst_ni ), @@ -118,12 +118,12 @@ module axi_cdc_dst #( cc_cdc_fifo_gray_dst #( `ifdef QUESTA - .T ( logic [$bits(ar_chan_t)-1:0] ), + .data_t ( logic [$bits(ar_chan_t)-1:0] ), `else - .T ( ar_chan_t ), + .data_t ( ar_chan_t ), `endif - .LOG_DEPTH ( LogDepth ), - .SYNC_STAGES ( SyncStages ) + .LogDepth ( LogDepth ), + .SyncStages ( SyncStages ) ) i_cdc_fifo_gray_dst_ar ( .dst_clk_i, .dst_rst_ni, @@ -137,12 +137,12 @@ module axi_cdc_dst #( cc_cdc_fifo_gray_src #( `ifdef QUESTA - .T ( logic [$bits(r_chan_t)-1:0] ), + .data_t ( logic [$bits(r_chan_t)-1:0] ), `else - .T ( r_chan_t ), + .data_t ( r_chan_t ), `endif - .LOG_DEPTH ( LogDepth ), - .SYNC_STAGES ( SyncStages ) + .LogDepth ( LogDepth ), + .SyncStages ( SyncStages ) ) i_cdc_fifo_gray_src_r ( .src_clk_i ( dst_clk_i ), .src_rst_ni ( dst_rst_ni ), diff --git a/src/axi_cdc_src.sv b/src/axi_cdc_src.sv index 2024d2440..902f5136e 100644 --- a/src/axi_cdc_src.sv +++ b/src/axi_cdc_src.sv @@ -60,12 +60,12 @@ module axi_cdc_src #( cc_cdc_fifo_gray_src #( // Workaround for a bug in Questa (see comment in `axi_cdc_dst` for details). `ifdef QUESTA - .T ( logic [$bits(aw_chan_t)-1:0] ), + .data_t ( logic [$bits(aw_chan_t)-1:0] ), `else - .T ( aw_chan_t ), + .data_t ( aw_chan_t ), `endif - .LOG_DEPTH ( LogDepth ), - .SYNC_STAGES ( SyncStages ) + .LogDepth ( LogDepth ), + .SyncStages ( SyncStages ) ) i_cdc_fifo_gray_src_aw ( .src_clk_i, .src_rst_ni, @@ -79,12 +79,12 @@ module axi_cdc_src #( cc_cdc_fifo_gray_src #( `ifdef QUESTA - .T ( logic [$bits(w_chan_t)-1:0] ), + .data_t ( logic [$bits(w_chan_t)-1:0] ), `else - .T ( w_chan_t ), + .data_t ( w_chan_t ), `endif - .LOG_DEPTH ( LogDepth ), - .SYNC_STAGES ( SyncStages ) + .LogDepth ( LogDepth ), + .SyncStages ( SyncStages ) ) i_cdc_fifo_gray_src_w ( .src_clk_i, .src_rst_ni, @@ -98,12 +98,12 @@ module axi_cdc_src #( cc_cdc_fifo_gray_dst #( `ifdef QUESTA - .T ( logic [$bits(b_chan_t)-1:0] ), + .data_t ( logic [$bits(b_chan_t)-1:0] ), `else - .T ( b_chan_t ), + .data_t ( b_chan_t ), `endif - .LOG_DEPTH ( LogDepth ), - .SYNC_STAGES ( SyncStages ) + .LogDepth ( LogDepth ), + .SyncStages ( SyncStages ) ) i_cdc_fifo_gray_dst_b ( .dst_clk_i ( src_clk_i ), .dst_rst_ni ( src_rst_ni ), @@ -117,12 +117,12 @@ module axi_cdc_src #( cc_cdc_fifo_gray_src #( `ifdef QUESTA - .T ( logic [$bits(ar_chan_t)-1:0] ), + .data_t ( logic [$bits(ar_chan_t)-1:0] ), `else - .T ( ar_chan_t ), + .data_t ( ar_chan_t ), `endif - .LOG_DEPTH ( LogDepth ), - .SYNC_STAGES ( SyncStages ) + .LogDepth ( LogDepth ), + .SyncStages ( SyncStages ) ) i_cdc_fifo_gray_src_ar ( .src_clk_i, .src_rst_ni, @@ -136,12 +136,12 @@ module axi_cdc_src #( cc_cdc_fifo_gray_dst #( `ifdef QUESTA - .T ( logic [$bits(r_chan_t)-1:0] ), + .data_t ( logic [$bits(r_chan_t)-1:0] ), `else - .T ( r_chan_t ), + .data_t ( r_chan_t ), `endif - .LOG_DEPTH ( LogDepth ), - .SYNC_STAGES ( SyncStages ) + .LogDepth ( LogDepth ), + .SyncStages ( SyncStages ) ) i_cdc_fifo_gray_dst_r ( .dst_clk_i ( src_clk_i ), .dst_rst_ni ( src_rst_ni ), diff --git a/src/axi_cut.sv b/src/axi_cut.sv index 9d4c8c240..17309198d 100644 --- a/src/axi_cut.sv +++ b/src/axi_cut.sv @@ -47,11 +47,12 @@ module axi_cut #( // a spill register for each channel cc_spill_register #( - .T ( aw_chan_t ), + .data_t ( aw_chan_t ), .Bypass ( BypassAw ) ) i_reg_aw ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .valid_i ( slv_req_i.aw_valid ), .ready_o ( slv_resp_o.aw_ready ), .data_i ( slv_req_i.aw ), @@ -61,11 +62,12 @@ module axi_cut #( ); cc_spill_register #( - .T ( w_chan_t ), + .data_t ( w_chan_t ), .Bypass ( BypassW ) ) i_reg_w ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .valid_i ( slv_req_i.w_valid ), .ready_o ( slv_resp_o.w_ready ), .data_i ( slv_req_i.w ), @@ -75,11 +77,12 @@ module axi_cut #( ); cc_spill_register #( - .T ( b_chan_t ), + .data_t ( b_chan_t ), .Bypass ( BypassB ) ) i_reg_b ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .valid_i ( mst_resp_i.b_valid ), .ready_o ( mst_req_o.b_ready ), .data_i ( mst_resp_i.b ), @@ -89,11 +92,12 @@ module axi_cut #( ); cc_spill_register #( - .T ( ar_chan_t ), + .data_t ( ar_chan_t ), .Bypass ( BypassAr ) ) i_reg_ar ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .valid_i ( slv_req_i.ar_valid ), .ready_o ( slv_resp_o.ar_ready ), .data_i ( slv_req_i.ar ), @@ -103,11 +107,12 @@ module axi_cut #( ); cc_spill_register #( - .T ( r_chan_t ), + .data_t ( r_chan_t ), .Bypass ( BypassR ) ) i_reg_r ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .valid_i ( mst_resp_i.r_valid ), .ready_o ( mst_req_o.r_ready ), .data_i ( mst_resp_i.r ), diff --git a/src/axi_delayer.sv b/src/axi_delayer.sv index 77cdc522b..3b34ed259 100644 --- a/src/axi_delayer.sv +++ b/src/axi_delayer.sv @@ -47,6 +47,7 @@ module axi_delayer #( ) i_stream_delay_aw ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .payload_i ( slv_req_i.aw ), .ready_o ( slv_resp_o.aw_ready ), .valid_i ( slv_req_i.aw_valid ), @@ -63,6 +64,7 @@ module axi_delayer #( ) i_stream_delay_ar ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .payload_i ( slv_req_i.ar ), .ready_o ( slv_resp_o.ar_ready ), .valid_i ( slv_req_i.ar_valid ), @@ -79,6 +81,7 @@ module axi_delayer #( ) i_stream_delay_w ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .payload_i ( slv_req_i.w ), .ready_o ( slv_resp_o.w_ready ), .valid_i ( slv_req_i.w_valid ), @@ -95,6 +98,7 @@ module axi_delayer #( ) i_stream_delay_b ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .payload_i ( mst_resp_i.b ), .ready_o ( mst_req_o.b_ready ), .valid_i ( mst_resp_i.b_valid ), @@ -111,6 +115,7 @@ module axi_delayer #( ) i_stream_delay_r ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .payload_i ( mst_resp_i.r ), .ready_o ( mst_req_o.r_ready ), .valid_i ( mst_resp_i.r_valid ), diff --git a/src/axi_demux.sv b/src/axi_demux.sv index 6c95d7bb7..c32efca10 100644 --- a/src/axi_demux.sv +++ b/src/axi_demux.sv @@ -86,11 +86,12 @@ module axi_demux #( select_t slv_aw_select, slv_ar_select; cc_spill_register #( - .T ( aw_chan_t ), + .data_t ( aw_chan_t ), .Bypass ( ~SpillAw ) ) i_aw_spill_reg ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .valid_i ( slv_req_i.aw_valid ), .ready_o ( slv_aw_ready_chan ), .data_i ( slv_req_i.aw ), @@ -99,11 +100,12 @@ module axi_demux #( .data_o ( slv_req_cut.aw ) ); cc_spill_register #( - .T ( select_t ), + .data_t ( select_t ), .Bypass ( ~SpillAw ) ) i_aw_select_spill_reg ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .valid_i ( slv_req_i.aw_valid ), .ready_o ( slv_aw_ready_sel ), .data_i ( slv_aw_select_i ), @@ -116,11 +118,12 @@ module axi_demux #( assign slv_req_cut.aw_valid = slv_aw_valid_chan & slv_aw_valid_sel; cc_spill_register #( - .T ( w_chan_t ), + .data_t ( w_chan_t ), .Bypass ( ~SpillW ) ) i_w_spill_reg ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .valid_i ( slv_req_i.w_valid ), .ready_o ( slv_resp_o.w_ready ), .data_i ( slv_req_i.w ), @@ -129,11 +132,12 @@ module axi_demux #( .data_o ( slv_req_cut.w ) ); cc_spill_register #( - .T ( ar_chan_t ), + .data_t ( ar_chan_t ), .Bypass ( ~SpillAr ) ) i_ar_spill_reg ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .valid_i ( slv_req_i.ar_valid ), .ready_o ( slv_ar_ready_chan ), .data_i ( slv_req_i.ar ), @@ -142,11 +146,12 @@ module axi_demux #( .data_o ( slv_req_cut.ar ) ); cc_spill_register #( - .T ( select_t ), + .data_t ( select_t ), .Bypass ( ~SpillAr ) ) i_ar_sel_spill_reg ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .valid_i ( slv_req_i.ar_valid ), .ready_o ( slv_ar_ready_sel ), .data_i ( slv_ar_select_i ), @@ -159,11 +164,12 @@ module axi_demux #( assign slv_req_cut.ar_valid = slv_ar_valid_chan & slv_ar_valid_sel; cc_spill_register #( - .T ( b_chan_t ), + .data_t ( b_chan_t ), .Bypass ( ~SpillB ) ) i_b_spill_reg ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .valid_i ( slv_resp_cut.b_valid ), .ready_o ( slv_req_cut.b_ready ), .data_i ( slv_resp_cut.b ), @@ -172,11 +178,12 @@ module axi_demux #( .data_o ( slv_resp_o.b ) ); cc_spill_register #( - .T ( r_chan_t ), + .data_t ( r_chan_t ), .Bypass ( ~SpillR ) ) i_r_spill_reg ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .valid_i ( slv_resp_cut.r_valid ), .ready_o ( slv_req_cut.r_ready ), .data_i ( slv_resp_cut.r ), diff --git a/src/axi_demux_id_counters.sv b/src/axi_demux_id_counters.sv index 5635b5be8..e37f1e1f0 100644 --- a/src/axi_demux_id_counters.sv +++ b/src/axi_demux_id_counters.sv @@ -110,12 +110,12 @@ module axi_demux_id_counters #( end cc_delta_counter #( - .WIDTH ( CounterWidth ), - .STICKY_OVERFLOW( 1'b0 ) + .Width ( CounterWidth ), + .StickyOverflow ( 1'b0 ) ) i_in_flight_cnt ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), - .clear_i ( 1'b0 ), + .clr_i ( 1'b0 ), .en_i ( cnt_en ), .load_i ( 1'b0 ), .down_i ( cnt_down ), diff --git a/src/axi_demux_simple.sv b/src/axi_demux_simple.sv index 2cfceefbe..01aad5917 100644 --- a/src/axi_demux_simple.sv +++ b/src/axi_demux_simple.sv @@ -234,12 +234,12 @@ module axi_demux_simple #( // AWs are only forwarded, if the counter is empty, or `w_select_q` is the same as // `slv_aw_select_i`. cc_counter #( - .WIDTH ( IdCounterWidth ), - .STICKY_OVERFLOW ( 1'b0 ) + .Width ( IdCounterWidth ), + .StickyOverflow ( 1'b0 ) ) i_counter_open_w ( .clk_i, .rst_ni, - .clear_i ( 1'b0 ), + .clr_i ( 1'b0 ), .en_i ( w_cnt_up ^ w_cnt_down ), .load_i ( 1'b0 ), .down_i ( w_cnt_down ), @@ -264,13 +264,13 @@ module axi_demux_simple #( // Arbitration of the different B responses cc_rr_arb_tree #( .NumIn ( NoMstPorts ), - .DataType ( logic ), + .data_t ( logic ), .AxiVldRdy( 1'b1 ), .LockIn ( 1'b1 ) ) i_b_mux ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), - .flush_i( 1'b0 ), + .clr_i ( 1'b0 ), .rr_i ( '0 ), .req_i ( mst_b_valids ), .gnt_o ( mst_b_readies ), @@ -383,13 +383,13 @@ module axi_demux_simple #( // Arbitration of the different r responses cc_rr_arb_tree #( .NumIn ( NoMstPorts ), - .DataType ( logic ), + .data_t ( logic ), .AxiVldRdy( 1'b1 ), .LockIn ( 1'b1 ) ) i_r_mux ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), - .flush_i( 1'b0 ), + .clr_i ( 1'b0 ), .rr_i ( '0 ), .req_i ( mst_r_valids ), .gnt_o ( mst_r_readies ), diff --git a/src/axi_dw_downsizer.sv b/src/axi_dw_downsizer.sv index e5e20703b..a95a672a9 100644 --- a/src/axi_dw_downsizer.sv +++ b/src/axi_dw_downsizer.sv @@ -98,14 +98,14 @@ module axi_dw_downsizer #( cc_rr_arb_tree #( .NumIn (AxiMaxReads ), - .DataType (slv_r_chan_t), + .data_t ( slv_r_chan_t ), .AxiVldRdy(1'b1 ), .ExtPrio (1'b0 ), .LockIn (1'b1 ) ) i_slv_r_arb ( .clk_i (clk_i ), .rst_ni (rst_ni ), - .flush_i(1'b0 ), + .clr_i ( 1'b0 ), .rr_i ('0 ), .req_i (slv_r_valid_tran ), .gnt_o (slv_r_ready_tran ), @@ -141,7 +141,7 @@ module axi_dw_downsizer #( ) i_slv_ar_arb ( .clk_i (clk_i ), .rst_ni (rst_ni ), - .flush_i (1'b0 ), + .clr_i ( 1'b0 ), .rr_i ('0 ), .req_i ({inject_aw_into_ar_req, slv_req_i.ar_valid} ), .gnt_o ({inject_aw_into_ar_gnt, slv_resp_o.ar_ready}), @@ -160,14 +160,14 @@ module axi_dw_downsizer #( cc_rr_arb_tree #( .NumIn (AxiMaxReads), - .DataType (ar_chan_t ), + .data_t ( ar_chan_t ), .AxiVldRdy(1'b1 ), .ExtPrio (1'b0 ), .LockIn (1'b1 ) ) i_mst_ar_arb ( .clk_i (clk_i ), .rst_ni (rst_ni ), - .flush_i(1'b0 ), + .clr_i ( 1'b0 ), .rr_i ('0 ), .req_i (mst_ar_valid_tran), .gnt_o (mst_ar_ready_tran), @@ -275,8 +275,8 @@ module axi_dw_downsizer #( // Find an idle downsizer to handle this transaction tran_id_t idx_idle_downsizer; cc_lzc #( - .WIDTH(AxiMaxReads), - .MODE (cc_pkg::LZC_TRAILING_ZERO_CNT) + .Width (AxiMaxReads), + .Mode (cc_pkg::LZC_TRAILING_ZERO_CNT) ) i_idle_lzc ( .in_i (idle_read_downsizer), .cnt_o (idx_idle_downsizer ), @@ -291,10 +291,10 @@ module axi_dw_downsizer #( end cc_onehot_to_bin #( - .ONEHOT_WIDTH(AxiMaxReads) + .OnehotWidth (AxiMaxReads) ) i_id_clash_onehot_to_bin ( - .onehot(id_clash_downsizer ), - .bin (idx_id_clash_downsizer) + .onehot_i (id_clash_downsizer ), + .bin_o (idx_id_clash_downsizer) ); // Choose an idle downsizer, unless there is an id clash @@ -309,12 +309,13 @@ module axi_dw_downsizer #( logic idqueue_valid; cc_id_queue #( - .ID_WIDTH(AxiIdWidth ), - .CAPACITY(AxiMaxReads), + .IdWidth ( AxiIdWidth ), + .Capacity ( AxiMaxReads ), .data_t (tran_id_t ) ) i_read_id_queue ( .clk_i (clk_i ), .rst_ni (rst_ni ), + .clr_i ( 1'b0 ), .inp_id_i (arb_slv_ar_id ), .inp_data_i (idx_ar_downsizer), .inp_req_i (|idqueue_push ), @@ -679,12 +680,13 @@ module axi_dw_downsizer #( logic forward_b_beat_full; cc_fifo #( - .DATA_WIDTH (1 ), - .DEPTH (AxiMaxReads), - .FALL_THROUGH(1'b1 ) + .DataWidth (1 ), + .Depth (AxiMaxReads), + .FallThrough (1'b1 ) ) i_forward_b_beats_queue ( .clk_i (clk_i ), .rst_ni (rst_ni ), + .clr_i ( 1'b0 ), .flush_i (1'b0 ), .data_i (forward_b_beat_i ), .push_i (forward_b_beat_push ), diff --git a/src/axi_dw_upsizer.sv b/src/axi_dw_upsizer.sv index 72ba049d9..d6d972bc5 100644 --- a/src/axi_dw_upsizer.sv +++ b/src/axi_dw_upsizer.sv @@ -95,14 +95,14 @@ module axi_dw_upsizer #( cc_rr_arb_tree #( .NumIn (AxiMaxReads ), - .DataType (slv_r_chan_t), + .data_t ( slv_r_chan_t ), .AxiVldRdy(1'b1 ), .ExtPrio (1'b0 ), .LockIn (1'b1 ) ) i_slv_r_arb ( .clk_i (clk_i ), .rst_ni (rst_ni ), - .flush_i(1'b0 ), + .clr_i ( 1'b0 ), .rr_i ('0 ), .req_i (slv_r_valid_tran ), .gnt_o (slv_r_ready_tran ), @@ -138,7 +138,7 @@ module axi_dw_upsizer #( ) i_slv_ar_arb ( .clk_i (clk_i ), .rst_ni (rst_ni ), - .flush_i(1'b0 ), + .clr_i ( 1'b0 ), .rr_i ('0 ), .req_i ({inject_aw_into_ar_req, slv_req_i.ar_valid} ), .gnt_o ({inject_aw_into_ar_gnt, slv_resp_o.ar_ready}), @@ -157,14 +157,14 @@ module axi_dw_upsizer #( cc_rr_arb_tree #( .NumIn (AxiMaxReads), - .DataType (ar_chan_t ), + .data_t ( ar_chan_t ), .AxiVldRdy(1'b1 ), .ExtPrio (1'b0 ), .LockIn (1'b1 ) ) i_mst_ar_arb ( .clk_i (clk_i ), .rst_ni (rst_ni ), - .flush_i(1'b0 ), + .clr_i ( 1'b0 ), .rr_i ('0 ), .req_i (mst_ar_valid_tran), .gnt_o (mst_ar_ready_tran), @@ -259,8 +259,8 @@ module axi_dw_upsizer #( // Find an idle upsizer to handle this transaction tran_id_t idx_idle_upsizer; cc_lzc #( - .WIDTH(AxiMaxReads), - .MODE (cc_pkg::LZC_TRAILING_ZERO_CNT) + .Width (AxiMaxReads), + .Mode (cc_pkg::LZC_TRAILING_ZERO_CNT) ) i_idle_lzc ( .in_i (idle_read_upsizer), .cnt_o (idx_idle_upsizer ), @@ -275,10 +275,10 @@ module axi_dw_upsizer #( end cc_onehot_to_bin #( - .ONEHOT_WIDTH(AxiMaxReads) + .OnehotWidth (AxiMaxReads) ) i_id_clash_onehot_to_bin ( - .onehot(id_clash_upsizer ), - .bin (idx_id_clash_upsizer) + .onehot_i (id_clash_upsizer ), + .bin_o (idx_id_clash_upsizer) ); // Choose an idle upsizer, unless there is an id clash @@ -300,10 +300,10 @@ module axi_dw_upsizer #( end cc_onehot_to_bin #( - .ONEHOT_WIDTH(AxiMaxReads) + .OnehotWidth (AxiMaxReads) ) i_rid_upsizer_lzc ( - .onehot(rid_upsizer_match), - .bin (idx_r_upsizer ) + .onehot_i (rid_upsizer_match), + .bin_o (idx_r_upsizer ) ); typedef struct packed { diff --git a/src/axi_err_slv.sv b/src/axi_err_slv.sv index ad489110e..5d251a606 100644 --- a/src/axi_err_slv.sv +++ b/src/axi_err_slv.sv @@ -87,12 +87,13 @@ module axi_err_slv #( assign err_resp.aw_ready = ~w_fifo_full; cc_fifo #( - .FALL_THROUGH ( 1'b1 ), - .DEPTH ( MaxTrans ), - .dtype ( id_t ) + .FallThrough ( 1'b1 ), + .Depth ( MaxTrans ), + .data_t ( id_t ) ) i_w_fifo ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .flush_i ( 1'b0 ), .full_o ( w_fifo_full ), .empty_o ( w_fifo_empty ), @@ -119,12 +120,13 @@ module axi_err_slv #( end cc_fifo #( - .FALL_THROUGH ( 1'b0 ), - .DEPTH ( unsigned'(2) ), // two placed so that w can eat beats if b is not sent - .dtype ( id_t ) + .FallThrough ( 1'b0 ), + .Depth ( unsigned'(2) ), // two placed so that w can eat beats if b is not sent + .data_t ( id_t ) ) i_b_fifo ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .flush_i ( 1'b0 ), .full_o ( b_fifo_full ), .empty_o ( b_fifo_empty ), @@ -160,12 +162,13 @@ module axi_err_slv #( assign r_fifo_inp.len = err_req.ar.len; cc_fifo #( - .FALL_THROUGH ( 1'b0 ), - .DEPTH ( MaxTrans ), - .dtype ( r_data_t ) + .FallThrough ( 1'b0 ), + .Depth ( MaxTrans ), + .data_t ( r_data_t ) ) i_r_fifo ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .flush_i ( 1'b0 ), .full_o ( r_fifo_full ), .empty_o ( r_fifo_empty ), @@ -225,11 +228,11 @@ module axi_err_slv #( end cc_counter #( - .WIDTH ($bits(axi_pkg::len_t)) + .Width ($bits(axi_pkg::len_t)) ) i_r_counter ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), - .clear_i ( r_cnt_clear ), + .clr_i ( r_cnt_clear ), .en_i ( r_cnt_en ), .load_i ( r_cnt_load ), .down_i ( 1'b1 ), diff --git a/src/axi_fifo.sv b/src/axi_fifo.sv index fb1d527a2..0b854b82a 100644 --- a/src/axi_fifo.sv +++ b/src/axi_fifo.sv @@ -63,12 +63,13 @@ module axi_fifo #( // A FiFo for each channel cc_fifo #( - .dtype (aw_chan_t), - .DEPTH (Depth), - .FALL_THROUGH (FallThrough) + .data_t (aw_chan_t), + .Depth (Depth), + .FallThrough (FallThrough) ) i_aw_fifo ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .flush_i (1'b0), .full_o (aw_fifo_full), .empty_o (aw_fifo_empty), @@ -79,12 +80,13 @@ module axi_fifo #( .pop_i (mst_req_o.aw_valid && mst_resp_i.aw_ready) ); cc_fifo #( - .dtype (ar_chan_t), - .DEPTH (Depth), - .FALL_THROUGH (FallThrough) + .data_t (ar_chan_t), + .Depth (Depth), + .FallThrough (FallThrough) ) i_ar_fifo ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .flush_i (1'b0), .full_o (ar_fifo_full), .empty_o (ar_fifo_empty), @@ -95,12 +97,13 @@ module axi_fifo #( .pop_i (mst_req_o.ar_valid && mst_resp_i.ar_ready) ); cc_fifo #( - .dtype (w_chan_t), - .DEPTH (Depth), - .FALL_THROUGH (FallThrough) + .data_t (w_chan_t), + .Depth (Depth), + .FallThrough (FallThrough) ) i_w_fifo ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .flush_i (1'b0), .full_o (w_fifo_full), .empty_o (w_fifo_empty), @@ -111,12 +114,13 @@ module axi_fifo #( .pop_i (mst_req_o.w_valid && mst_resp_i.w_ready) ); cc_fifo #( - .dtype (r_chan_t), - .DEPTH (Depth), - .FALL_THROUGH (FallThrough) + .data_t (r_chan_t), + .Depth (Depth), + .FallThrough (FallThrough) ) i_r_fifo ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .flush_i (1'b0), .full_o (r_fifo_full), .empty_o (r_fifo_empty), @@ -127,12 +131,13 @@ module axi_fifo #( .pop_i (slv_resp_o.r_valid && slv_req_i.r_ready) ); cc_fifo #( - .dtype (b_chan_t), - .DEPTH (Depth), - .FALL_THROUGH (FallThrough) + .data_t (b_chan_t), + .Depth (Depth), + .FallThrough (FallThrough) ) i_b_fifo ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .flush_i (1'b0), .full_o (b_fifo_full), .empty_o (b_fifo_empty), diff --git a/src/axi_fifo_delay_dyn.sv b/src/axi_fifo_delay_dyn.sv index d78183655..a0d7e5926 100644 --- a/src/axi_fifo_delay_dyn.sv +++ b/src/axi_fifo_delay_dyn.sv @@ -328,11 +328,11 @@ module stream_fifo_delay_dyn #( assign payload_o = head_data; cc_counter #( - .WIDTH ( CounterWidth ) + .Width ( CounterWidth ) ) i_counter ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), - .clear_i ( 1'b0 ), + .clr_i ( 1'b0 ), .en_i ( 1'b1 ), .load_i ( 1'b0 ), .down_i ( 1'b0 ), @@ -375,12 +375,13 @@ module stream_fifo_delay_dyn #( ); `else cc_fifo #( - .DATA_WIDTH ( $bits(payload_t) ), - .DEPTH ( Depth ), - .FALL_THROUGH ( 1'b0 ) + .DataWidth ( $bits(payload_t) ), + .Depth ( Depth ), + .FallThrough ( 1'b0 ) ) data_fifo ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .flush_i ( 1'b0 ), .data_i ( payload_i ), .push_i ( fifo_data_push ), @@ -426,12 +427,13 @@ module stream_fifo_delay_dyn #( ); `else cc_fifo #( - .DATA_WIDTH ( CounterWidth ), - .DEPTH ( Depth ), - .FALL_THROUGH ( 1'b0 ) + .DataWidth ( CounterWidth ), + .Depth ( Depth ), + .FallThrough ( 1'b0 ) ) deadline_fifo ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .flush_i ( 1'b0 ), .data_i ( tail_deadline ), .push_i ( fifo_dead_push ), diff --git a/src/axi_id_remap.sv b/src/axi_id_remap.sv index 8a01d6a5a..d056d1a21 100644 --- a/src/axi_id_remap.sv +++ b/src/axi_id_remap.sv @@ -186,8 +186,8 @@ module axi_id_remap #( ); assign both_free = wr_free & rd_free; cc_lzc #( - .WIDTH ( AxiSlvPortMaxUniqIds ), - .MODE ( cc_pkg::LZC_TRAILING_ZERO_CNT ) + .Width ( AxiSlvPortMaxUniqIds ), + .Mode ( cc_pkg::LZC_TRAILING_ZERO_CNT ) ) i_lzc ( .in_i ( both_free ), .cnt_o ( both_free_oup_id ), @@ -570,8 +570,8 @@ module axi_id_remap_table #( assign free_o[i] = table_q[i].cnt == '0; end cc_lzc #( - .WIDTH ( MaxUniqInpIds ), - .MODE ( cc_pkg::LZC_TRAILING_ZERO_CNT ) + .Width ( MaxUniqInpIds ), + .Mode ( cc_pkg::LZC_TRAILING_ZERO_CNT ) ) i_lzc_free ( .in_i ( free_o ), .cnt_o ( free_oup_id_o ), @@ -592,8 +592,8 @@ module axi_id_remap_table #( end logic no_match; cc_lzc #( - .WIDTH ( MaxUniqInpIds ), - .MODE ( cc_pkg::LZC_TRAILING_ZERO_CNT ) + .Width ( MaxUniqInpIds ), + .Mode ( cc_pkg::LZC_TRAILING_ZERO_CNT ) ) i_lzc_match ( .in_i ( match ), .cnt_o ( exists_oup_id_o ), diff --git a/src/axi_inval_filter.sv b/src/axi_inval_filter.sv index 5baf1d33d..fc651ae67 100644 --- a/src/axi_inval_filter.sv +++ b/src/axi_inval_filter.sv @@ -128,12 +128,13 @@ module axi_inval_filter #( end cc_fifo #( - .FALL_THROUGH ( 1'b1 ), - .DEPTH ( MaxTxns ), - .dtype ( aw_chan_t ) + .FallThrough ( 1'b1 ), + .Depth ( MaxTxns ), + .data_t ( aw_chan_t ) ) i_aw_fifo ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .flush_i ( 1'b0 ), .full_o ( aw_fifo_full ), .empty_o ( aw_fifo_empty ), diff --git a/src/axi_lite_demux.sv b/src/axi_lite_demux.sv index 560554e03..3bf6fb5b6 100644 --- a/src/axi_lite_demux.sv +++ b/src/axi_lite_demux.sv @@ -70,11 +70,12 @@ module axi_lite_demux #( if (NoMstPorts == 32'd1) begin : gen_no_demux // degenerate case, connect slave to master port cc_spill_register #( - .T ( aw_chan_t ), + .data_t ( aw_chan_t ), .Bypass ( ~SpillAw ) ) i_aw_spill_reg ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .valid_i ( slv_req_i.aw_valid ), .ready_o ( slv_resp_o.aw_ready ), .data_i ( slv_req_i.aw ), @@ -83,11 +84,12 @@ module axi_lite_demux #( .data_o ( mst_reqs_o[0].aw ) ); cc_spill_register #( - .T ( w_chan_t ), + .data_t ( w_chan_t ), .Bypass ( ~SpillW ) ) i_w_spill_reg ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .valid_i ( slv_req_i.w_valid ), .ready_o ( slv_resp_o.w_ready ), .data_i ( slv_req_i.w ), @@ -96,11 +98,12 @@ module axi_lite_demux #( .data_o ( mst_reqs_o[0].w ) ); cc_spill_register #( - .T ( b_chan_t ), + .data_t ( b_chan_t ), .Bypass ( ~SpillB ) ) i_b_spill_reg ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .valid_i ( mst_resps_i[0].b_valid ), .ready_o ( mst_reqs_o[0].b_ready ), .data_i ( mst_resps_i[0].b ), @@ -109,11 +112,12 @@ module axi_lite_demux #( .data_o ( slv_resp_o.b ) ); cc_spill_register #( - .T ( ar_chan_t ), + .data_t ( ar_chan_t ), .Bypass ( ~SpillAr ) ) i_ar_spill_reg ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .valid_i ( slv_req_i.ar_valid ), .ready_o ( slv_resp_o.ar_ready ), .data_i ( slv_req_i.ar ), @@ -122,11 +126,12 @@ module axi_lite_demux #( .data_o ( mst_reqs_o[0].ar ) ); cc_spill_register #( - .T ( r_chan_t ), + .data_t ( r_chan_t ), .Bypass ( ~SpillR ) ) i_r_spill_reg ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .valid_i ( mst_resps_i[0].r_valid ), .ready_o ( mst_reqs_o[0].r_ready ), .data_i ( mst_resps_i[0].r ), @@ -204,11 +209,12 @@ module axi_lite_demux #( slv_aw_chan_select_out_flat; assign slv_aw_chan_select_in_flat = {slv_req_i.aw, slv_aw_select_i}; cc_spill_register #( - .T ( aw_chan_select_flat_t ), + .data_t ( aw_chan_select_flat_t ), .Bypass ( ~SpillAw ) ) i_aw_spill_reg ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .valid_i ( slv_req_i.aw_valid ), .ready_o ( slv_resp_o.aw_ready ), .data_i ( slv_aw_chan_select_in_flat ), @@ -267,12 +273,13 @@ module axi_lite_demux #( `FFL(lock_aw_valid_q, lock_aw_valid_d, load_aw_lock, '0, clk_i, rst_ni) cc_fifo #( - .FALL_THROUGH ( FallThrough ), - .DEPTH ( MaxTrans ), - .dtype ( select_t ) + .FallThrough ( FallThrough ), + .Depth ( MaxTrans ), + .data_t ( select_t ) ) i_w_fifo ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .flush_i ( 1'b0 ), // not used, because AXI4-Lite no preemtion rule .full_o ( w_fifo_full ), .empty_o ( w_fifo_empty ), @@ -287,11 +294,12 @@ module axi_lite_demux #( // W Channel //-------------------------------------- cc_spill_register #( - .T ( w_chan_t ), + .data_t ( w_chan_t ), .Bypass ( ~SpillW ) ) i_w_spill_reg ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .valid_i ( slv_req_i.w_valid ), .ready_o ( slv_resp_o.w_ready ), .data_i ( slv_req_i.w ), @@ -310,12 +318,13 @@ module axi_lite_demux #( assign w_fifo_pop = slv_w_valid & slv_w_ready; cc_fifo #( - .FALL_THROUGH ( FallThrough ), - .DEPTH ( MaxTrans ), - .dtype ( select_t ) + .FallThrough ( FallThrough ), + .Depth ( MaxTrans ), + .data_t ( select_t ) ) i_b_fifo ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .flush_i ( 1'b0 ), // not used, because AXI4-Lite no preemption .full_o ( b_fifo_full ), .empty_o ( b_fifo_empty ), @@ -330,11 +339,12 @@ module axi_lite_demux #( // B Channel //-------------------------------------- cc_spill_register #( - .T ( b_chan_t ), + .data_t ( b_chan_t ), .Bypass ( ~SpillB ) ) i_b_spill_reg ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .valid_i ( slv_b_valid ), .ready_o ( slv_b_ready ), .data_i ( slv_b_chan ), @@ -364,11 +374,12 @@ module axi_lite_demux #( slv_ar_chan_select_out_flat; assign slv_ar_chan_select_in_flat = {slv_req_i.ar, slv_ar_select_i}; cc_spill_register #( - .T ( ar_chan_select_flat_t ), + .data_t ( ar_chan_select_flat_t ), .Bypass ( ~SpillAr ) ) i_ar_spill_reg ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .valid_i ( slv_req_i.ar_valid ), .ready_o ( slv_resp_o.ar_ready ), .data_i ( slv_ar_chan_select_in_flat ), @@ -388,12 +399,13 @@ module axi_lite_demux #( assign r_fifo_push = slv_ar_valid & slv_ar_ready; cc_fifo #( - .FALL_THROUGH ( FallThrough ), - .DEPTH ( MaxTrans ), - .dtype ( select_t ) + .FallThrough ( FallThrough ), + .Depth ( MaxTrans ), + .data_t ( select_t ) ) i_r_fifo ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .flush_i ( 1'b0 ), // not used, because AXI4-Lite no preemption rule .full_o ( r_fifo_full ), .empty_o ( r_fifo_empty ), @@ -408,11 +420,12 @@ module axi_lite_demux #( // R Channel //-------------------------------------- cc_spill_register #( - .T ( r_chan_t ), + .data_t ( r_chan_t ), .Bypass ( ~SpillR ) ) i_r_spill_reg ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .valid_i ( slv_r_valid ), .ready_o ( slv_r_ready ), .data_i ( slv_r_chan ), diff --git a/src/axi_lite_dw_converter.sv b/src/axi_lite_dw_converter.sv index b167e541a..614f12168 100644 --- a/src/axi_lite_dw_converter.sv +++ b/src/axi_lite_dw_converter.sv @@ -134,11 +134,12 @@ module axi_lite_dw_converter #( logic aw_chan_spill_valid, aw_chan_spill_ready; cc_spill_register #( - .T ( axi_lite_aw_t ), + .data_t ( axi_lite_aw_t ), .Bypass ( 1'b0 ) ) i_spill_register_aw ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .valid_i ( slv_req_i.aw_valid ), .ready_o ( slv_res_o.aw_ready ), .data_i ( slv_req_i.aw ), @@ -166,11 +167,12 @@ module axi_lite_dw_converter #( axi_lite_slv_w_t w_chan_spill; logic w_chan_spill_valid, w_chan_spill_ready; cc_spill_register #( - .T ( axi_lite_slv_w_t ), + .data_t ( axi_lite_slv_w_t ), .Bypass ( 1'b0 ) ) i_spill_register_w ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .valid_i ( slv_req_i.w_valid ), .ready_o ( slv_res_o.w_ready ), .data_i ( slv_req_i.w ), @@ -225,11 +227,12 @@ module axi_lite_dw_converter #( logic ar_chan_spill_valid, ar_chan_spill_ready; cc_spill_register #( - .T ( axi_lite_ar_t ), + .data_t ( axi_lite_ar_t ), .Bypass ( 1'b0 ) ) i_spill_register_ar ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .valid_i ( slv_req_i.ar_valid ), .ready_o ( slv_res_o.ar_ready ), .data_i ( slv_req_i.ar ), @@ -338,12 +341,13 @@ module axi_lite_dw_converter #( assign aw_sel = sel_t'(slv_req_i.aw.addr >> SelOffset); cc_fifo #( - .FALL_THROUGH ( 1'b1 ), - .DEPTH ( UpsizeFactor ), - .dtype ( sel_t ) + .FallThrough ( 1'b1 ), + .Depth ( UpsizeFactor ), + .data_t ( sel_t ) ) i_fifo_w_sel ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .flush_i ( 1'b0 ), .full_o ( w_full ), .empty_o ( w_empty ), @@ -419,12 +423,13 @@ module axi_lite_dw_converter #( assign ar_sel = sel_t'(slv_req_i.ar.addr >> SelOffset); cc_fifo #( - .FALL_THROUGH ( 1'b1 ), - .DEPTH ( UpsizeFactor ), - .dtype ( sel_t ) + .FallThrough ( 1'b1 ), + .Depth ( UpsizeFactor ), + .data_t ( sel_t ) ) i_fifo_r_sel ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .flush_i ( 1'b0 ), .full_o ( r_full ), .empty_o ( r_empty ), diff --git a/src/axi_lite_from_mem.sv b/src/axi_lite_from_mem.sv index a9e464053..bba0a0c2b 100644 --- a/src/axi_lite_from_mem.sv +++ b/src/axi_lite_from_mem.sv @@ -177,12 +177,13 @@ module axi_lite_from_mem #( logic rsp_sel; cc_fifo #( - .FALL_THROUGH ( 1'b0 ), // No fallthrough for one cycle delay before ready on AXI. - .DEPTH ( MaxRequests ), - .dtype ( logic ) + .FallThrough ( 1'b0 ), // No fallthrough for one cycle delay before ready on AXI. + .Depth ( MaxRequests ), + .data_t ( logic ) ) i_fifo_rsp_mux ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .flush_i ( 1'b0 ), .full_o ( fifo_full ), .empty_o ( fifo_empty ), diff --git a/src/axi_lite_lfsr.sv b/src/axi_lite_lfsr.sv index 931f7cab8..e557257e2 100644 --- a/src/axi_lite_lfsr.sv +++ b/src/axi_lite_lfsr.sv @@ -92,12 +92,13 @@ module axi_lite_lfsr #( // B cc_stream_fifo #( - .FALL_THROUGH ( 1'b0 ), - .DATA_WIDTH ( 'd1 ), - .DEPTH ( 'd2 ) + .FallThrough ( 1'b0 ), + .DataWidth ( 'd1 ), + .Depth ( 'd2 ) ) i_stream_fifo_w_b ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .flush_i ( 1'b0 ), .usage_o ( /* NOT CONNECTED */ ), .data_i ( 1'b0 ), diff --git a/src/axi_lite_mailbox.sv b/src/axi_lite_mailbox.sv index 6f43d9d9c..4877e601d 100644 --- a/src/axi_lite_mailbox.sv +++ b/src/axi_lite_mailbox.sv @@ -119,44 +119,41 @@ module axi_lite_mailbox #( .clear_irq_o ( clear_irq[1] ) ); - // the usage gets concatinated with the full flag to have consistent threshold detection - logic [FifoUsageWidth-1:0] mbox_0_to_1_usage, mbox_1_to_0_usage; cc_fifo #( - .FALL_THROUGH ( 1'b0 ), - .DEPTH ( MailboxDepth ), - .dtype ( data_t ) + .FallThrough ( 1'b0 ), + .Depth ( MailboxDepth ), + .data_t ( data_t ) ) i_mbox_0_to_1 ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .flush_i ( w_mbox_flush[0] | r_mbox_flush[1] ), .full_o ( mbox_full[0] ), .empty_o ( mbox_empty[0] ), - .usage_o ( mbox_0_to_1_usage ), + .usage_o ( mbox_usage[0] ), .data_i ( mbox_w_data[0] ), .push_i ( mbox_push[0] ), .data_o ( mbox_r_data[1] ), .pop_i ( mbox_pop[1] ) ); - // assign the MSB of the FIFO to the correct usage signal - assign mbox_usage[0] = {mbox_full[0], mbox_0_to_1_usage}; cc_fifo #( - .FALL_THROUGH ( 1'b0 ), - .DEPTH ( MailboxDepth ), - .dtype ( data_t ) + .FallThrough ( 1'b0 ), + .Depth ( MailboxDepth ), + .data_t ( data_t ) ) i_mbox_1_to_0 ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .flush_i ( w_mbox_flush[1] | r_mbox_flush[0] ), .full_o ( mbox_full[1] ), .empty_o ( mbox_empty[1] ), - .usage_o ( mbox_1_to_0_usage ), + .usage_o ( mbox_usage[1] ), .data_i ( mbox_w_data[1] ), .push_i ( mbox_push[1] ), .data_o ( mbox_r_data[0] ), .pop_i ( mbox_pop[0] ) ); - assign mbox_usage[1] = {mbox_full[1], mbox_1_to_0_usage}; for (genvar i = 0; i < 2; i++) begin : gen_irq_conversion if (IrqEdgeTrig) begin : gen_irq_edge @@ -188,6 +185,8 @@ module axi_lite_mailbox #( `ifndef VERILATOR initial begin : proc_check_params mailbox_depth: assert (MailboxDepth > 1) else $fatal(1, "MailboxDepth has to be at least 2"); + mailbox_depth_pow2: assert ((MailboxDepth & (MailboxDepth - 1)) == 0) + else $fatal(1, "MailboxDepth has to be a power of two (usage_t sizing relies on it)."); axi_addr_width: assert (AxiAddrWidth > 0) else $fatal(1, "AxiAddrWidth has to be > 0"); axi_data_width: assert (AxiDataWidth > 0) else $fatal(1, "AxiDataWidth has to be > 0"); end @@ -501,10 +500,11 @@ module axi_lite_mailbox_slave #( .default_idx_i ( '0 ) ); cc_spill_register #( - .T ( b_chan_lite_t ) + .data_t ( b_chan_lite_t ) ) i_b_chan_outp ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .valid_i ( b_valid ), .ready_o ( b_ready ), .data_i ( b_chan ), @@ -527,10 +527,11 @@ module axi_lite_mailbox_slave #( .default_idx_i ( '0 ) ); cc_spill_register #( - .T ( r_chan_lite_t ) + .data_t ( r_chan_lite_t ) ) i_r_chan_outp ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .valid_i ( r_valid ), .ready_o ( r_ready ), .data_i ( r_chan ), diff --git a/src/axi_lite_mux.sv b/src/axi_lite_mux.sv index a8467385b..a6820555f 100644 --- a/src/axi_lite_mux.sv +++ b/src/axi_lite_mux.sv @@ -54,11 +54,12 @@ module axi_lite_mux #( // pass through if only one slave port if (NoSlvPorts == 32'h1) begin : gen_no_mux cc_spill_register #( - .T ( aw_chan_t ), + .data_t ( aw_chan_t ), .Bypass ( ~SpillAw ) ) i_aw_spill_reg ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .valid_i ( slv_reqs_i[0].aw_valid ), .ready_o ( slv_resps_o[0].aw_ready ), .data_i ( slv_reqs_i[0].aw ), @@ -67,11 +68,12 @@ module axi_lite_mux #( .data_o ( mst_req_o.aw ) ); cc_spill_register #( - .T ( w_chan_t ), + .data_t ( w_chan_t ), .Bypass ( ~SpillW ) ) i_w_spill_reg ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .valid_i ( slv_reqs_i[0].w_valid ), .ready_o ( slv_resps_o[0].w_ready ), .data_i ( slv_reqs_i[0].w ), @@ -80,11 +82,12 @@ module axi_lite_mux #( .data_o ( mst_req_o.w ) ); cc_spill_register #( - .T ( b_chan_t ), + .data_t ( b_chan_t ), .Bypass ( ~SpillB ) ) i_b_spill_reg ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .valid_i ( mst_resp_i.b_valid ), .ready_o ( mst_req_o.b_ready ), .data_i ( mst_resp_i.b ), @@ -93,11 +96,12 @@ module axi_lite_mux #( .data_o ( slv_resps_o[0].b ) ); cc_spill_register #( - .T ( ar_chan_t ), + .data_t ( ar_chan_t ), .Bypass ( ~SpillAr ) ) i_ar_spill_reg ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .valid_i ( slv_reqs_i[0].ar_valid ), .ready_o ( slv_resps_o[0].ar_ready ), .data_i ( slv_reqs_i[0].ar ), @@ -106,11 +110,12 @@ module axi_lite_mux #( .data_o ( mst_req_o.ar ) ); cc_spill_register #( - .T ( r_chan_t ), + .data_t ( r_chan_t ), .Bypass ( ~SpillR ) ) i_r_spill_reg ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .valid_i ( mst_resp_i.r_valid ), .ready_o ( mst_req_o.r_ready ), .data_i ( mst_resp_i.r ), @@ -197,13 +202,13 @@ module axi_lite_mux #( end cc_rr_arb_tree #( .NumIn ( NoSlvPorts ), - .DataType ( aw_chan_t ), + .data_t ( aw_chan_t ), .AxiVldRdy ( 1'b1 ), .LockIn ( 1'b1 ) ) i_aw_arbiter ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), - .flush_i( 1'b0 ), + .clr_i ( 1'b0 ), .rr_i ( '0 ), .req_i ( slv_aw_valids ), .gnt_o ( slv_aw_readies ), @@ -249,12 +254,13 @@ module axi_lite_mux #( `FFL(lock_aw_valid_q, lock_aw_valid_d, load_aw_lock, '0, clk_i, rst_ni) cc_fifo #( - .FALL_THROUGH ( FallThrough ), - .DEPTH ( MaxTrans ), - .dtype ( select_t ) + .FallThrough ( FallThrough ), + .Depth ( MaxTrans ), + .data_t ( select_t ) ) i_w_fifo ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .flush_i ( 1'b0 ), .full_o ( w_fifo_full ), .empty_o ( w_fifo_empty ), @@ -266,11 +272,12 @@ module axi_lite_mux #( ); cc_spill_register #( - .T ( aw_chan_t ), + .data_t ( aw_chan_t ), .Bypass ( ~SpillAw ) // Param indicated that we want a spill reg ) i_aw_spill_reg ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .valid_i ( mst_aw_valid ), .ready_o ( mst_aw_ready ), .data_i ( mst_aw_chan ), @@ -292,12 +299,13 @@ module axi_lite_mux #( assign w_fifo_pop = mst_w_valid & mst_w_ready; cc_fifo #( - .FALL_THROUGH ( FallThrough ), - .DEPTH ( MaxTrans ), - .dtype ( select_t ) + .FallThrough ( FallThrough ), + .Depth ( MaxTrans ), + .data_t ( select_t ) ) i_b_fifo ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .flush_i ( 1'b0 ), .full_o ( b_fifo_full ), .empty_o ( b_fifo_empty ), @@ -309,11 +317,12 @@ module axi_lite_mux #( ); cc_spill_register #( - .T ( w_chan_t ), + .data_t ( w_chan_t ), .Bypass ( ~SpillW ) ) i_w_spill_reg ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .valid_i ( mst_w_valid ), .ready_o ( mst_w_ready ), .data_i ( mst_w_chan ), @@ -334,11 +343,12 @@ module axi_lite_mux #( assign b_fifo_pop = mst_b_valid & mst_b_ready; cc_spill_register #( - .T ( b_chan_t ), + .data_t ( b_chan_t ), .Bypass ( ~SpillB ) ) i_b_spill_reg ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .valid_i ( mst_resp_i.b_valid ), .ready_o ( mst_req_o.b_ready ), .data_i ( mst_resp_i.b ), @@ -358,13 +368,13 @@ module axi_lite_mux #( end cc_rr_arb_tree #( .NumIn ( NoSlvPorts ), - .DataType ( ar_chan_t ), + .data_t ( ar_chan_t ), .AxiVldRdy ( 1'b1 ), .LockIn ( 1'b1 ) ) i_ar_arbiter ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), - .flush_i( 1'b0 ), + .clr_i ( 1'b0 ), .rr_i ( '0 ), .req_i ( slv_ar_valids ), .gnt_o ( slv_ar_readies ), @@ -382,12 +392,13 @@ module axi_lite_mux #( assign r_fifo_push = mst_ar_valid & mst_ar_ready; cc_fifo #( - .FALL_THROUGH ( FallThrough ), - .DEPTH ( MaxTrans ), - .dtype ( select_t ) + .FallThrough ( FallThrough ), + .Depth ( MaxTrans ), + .data_t ( select_t ) ) i_r_fifo ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .flush_i ( 1'b0 ), .full_o ( r_fifo_full ), .empty_o ( r_fifo_empty ), @@ -399,11 +410,12 @@ module axi_lite_mux #( ); cc_spill_register #( - .T ( ar_chan_t ), + .data_t ( ar_chan_t ), .Bypass ( ~SpillAr ) ) i_ar_spill_reg ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .valid_i ( mst_ar_valid ), .ready_o ( mst_ar_ready ), .data_i ( mst_ar_chan ), @@ -424,11 +436,12 @@ module axi_lite_mux #( assign r_fifo_pop = mst_r_valid & mst_r_ready; cc_spill_register #( - .T ( r_chan_t ), + .data_t ( r_chan_t ), .Bypass ( ~SpillR ) ) i_r_spill_reg ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .valid_i ( mst_resp_i.r_valid ), .ready_o ( mst_req_o.r_ready ), .data_i ( mst_resp_i.r ), diff --git a/src/axi_lite_regs.sv b/src/axi_lite_regs.sv index b6a8f45fe..bc94d07e8 100644 --- a/src/axi_lite_regs.sv +++ b/src/axi_lite_regs.sv @@ -349,11 +349,12 @@ module axi_lite_regs #( // Add a cycle delay on AXI response, cut all comb paths between slave port inputs and outputs. cc_spill_register #( - .T ( b_chan_lite_t ), + .data_t ( b_chan_lite_t ), .Bypass ( 1'b0 ) ) i_b_spill_register ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .valid_i ( b_valid ), .ready_o ( b_ready ), .data_i ( b_chan ), @@ -364,11 +365,12 @@ module axi_lite_regs #( // Add a cycle delay on AXI response, cut all comb paths between slave port inputs and outputs. cc_spill_register #( - .T ( r_chan_lite_t ), + .data_t ( r_chan_lite_t ), .Bypass ( 1'b0 ) ) i_r_spill_register ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .valid_i ( r_valid ), .ready_o ( r_ready ), .data_i ( r_chan ), diff --git a/src/axi_lite_to_apb.sv b/src/axi_lite_to_apb.sv index 14d5d4f1f..b35d5e0fe 100644 --- a/src/axi_lite_to_apb.sv +++ b/src/axi_lite_to_apb.sv @@ -148,14 +148,14 @@ module axi_lite_to_apb #( cc_rr_arb_tree #( .NumIn ( 32'd2 ), - .DataType ( int_req_t ), + .data_t ( int_req_t ), .ExtPrio ( 1'b0 ), .AxiVldRdy ( 1'b1 ), .LockIn ( 1'b1 ) ) i_req_arb ( .clk_i, .rst_ni, - .flush_i ( '0 ), + .clr_i ( '0 ), .rr_i ( '0 ), .req_i ( axi_req_valid ), .gnt_o ( axi_req_ready ), @@ -168,11 +168,12 @@ module axi_lite_to_apb #( if (PipelineRequest) begin : gen_req_spill cc_spill_register #( - .T ( int_req_t ), + .data_t ( int_req_t ), .Bypass ( 1'b0 ) ) i_req_spill ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .valid_i ( arb_req_valid ), .ready_o ( arb_req_ready ), .data_i ( arb_req ), @@ -182,7 +183,7 @@ module axi_lite_to_apb #( ); end else begin : gen_req_ft_reg cc_fall_through_register #( - .T ( int_req_t ) + .data_t ( int_req_t ) ) i_req_ft_reg ( .clk_i, .rst_ni, @@ -198,11 +199,12 @@ module axi_lite_to_apb #( if (PipelineResponse) begin : gen_resp_spill cc_spill_register #( - .T ( axi_pkg::resp_t ), + .data_t ( axi_pkg::resp_t ), .Bypass ( 1'b0 ) ) i_write_resp_spill ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .valid_i ( apb_wresp_valid ), .ready_o ( apb_wresp_ready ), .data_i ( apb_wresp ), @@ -211,11 +213,12 @@ module axi_lite_to_apb #( .data_o ( axi_bresp ) ); cc_spill_register #( - .T ( int_resp_t ), + .data_t ( int_resp_t ), .Bypass ( 1'b0 ) ) i_read_resp_spill ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .valid_i ( apb_rresp_valid ), .ready_o ( apb_rresp_ready ), .data_i ( apb_rresp ), @@ -225,7 +228,7 @@ module axi_lite_to_apb #( ); end else begin : gen_resp_ft_reg cc_fall_through_register #( - .T ( axi_pkg::resp_t ) + .data_t ( axi_pkg::resp_t ) ) i_write_resp_ft_reg ( .clk_i, .rst_ni, @@ -238,7 +241,7 @@ module axi_lite_to_apb #( .data_o ( axi_bresp ) ); cc_fall_through_register #( - .T ( int_resp_t ) + .data_t ( int_resp_t ) ) i_read_resp_ft_reg ( .clk_i, .rst_ni, @@ -449,10 +452,10 @@ module axi_lite_to_apb_intf #( `AXI_LITE_ASSIGN_FROM_RESP(slv, axi_resp) cc_onehot_to_bin #( - .ONEHOT_WIDTH ( NoApbSlaves ) + .OnehotWidth ( NoApbSlaves ) ) i_onehot_to_bin ( - .onehot ( pselx_o ), - .bin ( apb_sel ) + .onehot_i ( pselx_o ), + .bin_o ( apb_sel ) ); assign paddr_o = apb_req[apb_sel].paddr; diff --git a/src/axi_mux.sv b/src/axi_mux.sv index 16e7bec7d..f194b9cb1 100644 --- a/src/axi_mux.sv +++ b/src/axi_mux.sv @@ -70,11 +70,12 @@ module axi_mux #( // pass through if only one slave port if (NoSlvPorts == 32'h1) begin : gen_no_mux cc_spill_register #( - .T ( mst_aw_chan_t ), + .data_t ( mst_aw_chan_t ), .Bypass ( ~SpillAw ) ) i_aw_spill_reg ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .valid_i ( slv_reqs_i[0].aw_valid ), .ready_o ( slv_resps_o[0].aw_ready ), .data_i ( slv_reqs_i[0].aw ), @@ -83,11 +84,12 @@ module axi_mux #( .data_o ( mst_req_o.aw ) ); cc_spill_register #( - .T ( w_chan_t ), + .data_t ( w_chan_t ), .Bypass ( ~SpillW ) ) i_w_spill_reg ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .valid_i ( slv_reqs_i[0].w_valid ), .ready_o ( slv_resps_o[0].w_ready ), .data_i ( slv_reqs_i[0].w ), @@ -96,11 +98,12 @@ module axi_mux #( .data_o ( mst_req_o.w ) ); cc_spill_register #( - .T ( mst_b_chan_t ), + .data_t ( mst_b_chan_t ), .Bypass ( ~SpillB ) ) i_b_spill_reg ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .valid_i ( mst_resp_i.b_valid ), .ready_o ( mst_req_o.b_ready ), .data_i ( mst_resp_i.b ), @@ -109,11 +112,12 @@ module axi_mux #( .data_o ( slv_resps_o[0].b ) ); cc_spill_register #( - .T ( mst_ar_chan_t ), + .data_t ( mst_ar_chan_t ), .Bypass ( ~SpillAr ) ) i_ar_spill_reg ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .valid_i ( slv_reqs_i[0].ar_valid ), .ready_o ( slv_resps_o[0].ar_ready ), .data_i ( slv_reqs_i[0].ar ), @@ -122,11 +126,12 @@ module axi_mux #( .data_o ( mst_req_o.ar ) ); cc_spill_register #( - .T ( mst_r_chan_t ), + .data_t ( mst_r_chan_t ), .Bypass ( ~SpillR ) ) i_r_spill_reg ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .valid_i ( mst_resp_i.r_valid ), .ready_o ( mst_req_o.r_ready ), .data_i ( mst_resp_i.r ), @@ -262,13 +267,13 @@ module axi_mux #( //-------------------------------------- cc_rr_arb_tree #( .NumIn ( NoSlvPorts ), - .DataType ( mst_aw_chan_t ), + .data_t ( mst_aw_chan_t ), .AxiVldRdy( 1'b1 ), .LockIn ( 1'b1 ) ) i_aw_arbiter ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), - .flush_i( 1'b0 ), + .clr_i ( 1'b0 ), .rr_i ( '0 ), .req_i ( slv_aw_valids ), .gnt_o ( slv_aw_readies ), @@ -314,12 +319,13 @@ module axi_mux #( `FFL(lock_aw_valid_q, lock_aw_valid_d, load_aw_lock, '0, clk_i, rst_ni) cc_fifo #( - .FALL_THROUGH ( FallThrough ), - .DEPTH ( MaxWTrans ), - .dtype ( switch_id_t ) + .FallThrough ( FallThrough ), + .Depth ( MaxWTrans ), + .data_t ( switch_id_t ) ) i_w_fifo ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .flush_i ( 1'b0 ), .full_o ( w_fifo_full ), .empty_o ( w_fifo_empty ), @@ -331,11 +337,12 @@ module axi_mux #( ); cc_spill_register #( - .T ( mst_aw_chan_t ), + .data_t ( mst_aw_chan_t ), .Bypass ( ~SpillAw ) // Param indicated that we want a spill reg ) i_aw_spill_reg ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .valid_i ( mst_aw_valid ), .ready_o ( mst_aw_ready ), .data_i ( mst_aw_chan ), @@ -365,11 +372,12 @@ module axi_mux #( end cc_spill_register #( - .T ( w_chan_t ), + .data_t ( w_chan_t ), .Bypass ( ~SpillW ) ) i_w_spill_reg ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .valid_i ( mst_w_valid ), .ready_o ( mst_w_ready ), .data_i ( mst_w_chan ), @@ -388,11 +396,12 @@ module axi_mux #( assign slv_b_valids = (mst_b_valid) ? (1 << switch_b_id) : '0; cc_spill_register #( - .T ( mst_b_chan_t ), + .data_t ( mst_b_chan_t ), .Bypass ( ~SpillB ) ) i_b_spill_reg ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .valid_i ( mst_resp_i.b_valid ), .ready_o ( mst_req_o.b_ready ), .data_i ( mst_resp_i.b ), @@ -406,13 +415,13 @@ module axi_mux #( //-------------------------------------- cc_rr_arb_tree #( .NumIn ( NoSlvPorts ), - .DataType ( mst_ar_chan_t ), + .data_t ( mst_ar_chan_t ), .AxiVldRdy( 1'b1 ), .LockIn ( 1'b1 ) ) i_ar_arbiter ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), - .flush_i( 1'b0 ), + .clr_i ( 1'b0 ), .rr_i ( '0 ), .req_i ( slv_ar_valids ), .gnt_o ( slv_ar_readies ), @@ -424,11 +433,12 @@ module axi_mux #( ); cc_spill_register #( - .T ( mst_ar_chan_t ), + .data_t ( mst_ar_chan_t ), .Bypass ( ~SpillAr ) ) i_ar_spill_reg ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .valid_i ( ar_valid ), .ready_o ( ar_ready ), .data_i ( mst_ar_chan ), @@ -447,11 +457,12 @@ module axi_mux #( assign slv_r_valids = (mst_r_valid) ? (1 << switch_r_id) : '0; cc_spill_register #( - .T ( mst_r_chan_t ), + .data_t ( mst_r_chan_t ), .Bypass ( ~SpillR ) ) i_r_spill_reg ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .valid_i ( mst_resp_i.r_valid ), .ready_o ( mst_req_o.r_ready ), .data_i ( mst_resp_i.r ), diff --git a/src/axi_serializer.sv b/src/axi_serializer.sv index 1de1f9eed..72ce9c604 100644 --- a/src/axi_serializer.sv +++ b/src/axi_serializer.sv @@ -147,12 +147,13 @@ module axi_serializer #( end cc_fifo #( - .FALL_THROUGH ( 1'b0 ), // No fall-through as response has to come a cycle later anyway - .DEPTH ( MaxReadTxns ), - .dtype ( id_t ) + .FallThrough ( 1'b0 ), // No fall-through as response has to come a cycle later anyway + .Depth ( MaxReadTxns ), + .data_t ( id_t ) ) i_rd_id_fifo ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .flush_i ( 1'b0 ), .data_i ( ar_id ), .push_i ( rd_fifo_push ), @@ -166,12 +167,13 @@ module axi_serializer #( assign rd_fifo_pop = slv_resp_o.r_valid & slv_req_i.r_ready & slv_resp_o.r.last; cc_fifo #( - .FALL_THROUGH ( 1'b0 ), - .DEPTH ( MaxWriteTxns ), - .dtype ( id_t ) + .FallThrough ( 1'b0 ), + .Depth ( MaxWriteTxns ), + .data_t ( id_t ) ) i_wr_id_fifo ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .flush_i ( 1'b0 ), .data_i ( slv_req_i.aw.id ), .push_i ( wr_fifo_push ), diff --git a/src/axi_slave_compare.sv b/src/axi_slave_compare.sv index 976bab3e3..fd91b2a01 100644 --- a/src/axi_slave_compare.sv +++ b/src/axi_slave_compare.sv @@ -91,10 +91,11 @@ module axi_slave_compare #( logic ar_ready_mst; cc_stream_fork #( - .N_OUP ( 32'd2 ) + .NumOup ( 32'd2 ) ) i_stream_fork_aw ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .valid_i ( axi_mst_req_i.aw_valid ), .ready_o ( aw_ready_mst ), .valid_o ( { aw_valid_ref, aw_valid_test } ), @@ -102,10 +103,11 @@ module axi_slave_compare #( ); cc_stream_fork #( - .N_OUP ( 32'd2 ) + .NumOup ( 32'd2 ) ) i_stream_fork_ar ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .valid_i ( axi_mst_req_i.ar_valid ), .ready_o ( ar_ready_mst ), .valid_o ( { ar_valid_ref, ar_valid_test } ), @@ -113,10 +115,11 @@ module axi_slave_compare #( ); cc_stream_fork #( - .N_OUP ( 32'd2 ) + .NumOup ( 32'd2 ) ) i_stream_fork_w ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .valid_i ( axi_mst_req_i.w_valid ), .ready_o ( w_ready_mst ), .valid_o ( { w_valid_ref, w_valid_test } ), diff --git a/src/axi_throttle.sv b/src/axi_throttle.sv index 5b305f1ea..05f006b91 100644 --- a/src/axi_throttle.sv +++ b/src/axi_throttle.sv @@ -61,6 +61,7 @@ module axi_throttle #( ) i_stream_throttle_aw ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .req_valid_i ( req_i.aw_valid ), .req_valid_o ( throttled_aw_valid ), .req_ready_i ( rsp_i.aw_ready ), @@ -76,6 +77,7 @@ module axi_throttle #( ) i_stream_throttle_ar ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .req_valid_i ( req_i.ar_valid ), .req_valid_o ( throttled_ar_valid ), .req_ready_i ( rsp_i.ar_ready ), diff --git a/src/axi_to_axi_lite.sv b/src/axi_to_axi_lite.sv index f1d812f1f..c42120484 100644 --- a/src/axi_to_axi_lite.sv +++ b/src/axi_to_axi_lite.sv @@ -163,12 +163,13 @@ module axi_to_axi_lite_id_reflect #( assign aw_push = mst_req_o.aw_valid & slv_resp_o.aw_ready; assign aw_pop = slv_resp_o.b_valid & mst_req_o.b_ready; cc_fifo #( - .FALL_THROUGH ( FallThrough ), - .DEPTH ( AxiMaxWriteTxns ), - .dtype ( id_t ) + .FallThrough ( FallThrough ), + .Depth ( AxiMaxWriteTxns ), + .data_t ( id_t ) ) i_aw_id_fifo ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .flush_i ( 1'b0 ), .full_o ( aw_full ), .empty_o ( aw_empty ), @@ -183,12 +184,13 @@ module axi_to_axi_lite_id_reflect #( assign ar_push = mst_req_o.ar_valid & slv_resp_o.ar_ready; assign ar_pop = slv_resp_o.r_valid & mst_req_o.r_ready; cc_fifo #( - .FALL_THROUGH ( FallThrough ), - .DEPTH ( AxiMaxReadTxns ), - .dtype ( id_t ) + .FallThrough ( FallThrough ), + .Depth ( AxiMaxReadTxns ), + .data_t ( id_t ) ) i_ar_id_fifo ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .flush_i ( 1'b0 ), .full_o ( ar_full ), .empty_o ( ar_empty ), diff --git a/src/axi_to_detailed_mem.sv b/src/axi_to_detailed_mem.sv index b32238b99..dad69c19d 100644 --- a/src/axi_to_detailed_mem.sv +++ b/src/axi_to_detailed_mem.sv @@ -265,8 +265,8 @@ module axi_to_detailed_mem #( // Arbitrate between reads and writes. cc_stream_mux #( - .DATA_T ( meta_t ), - .N_INP ( 32'd2 ) + .data_t ( meta_t ), + .NumInp ( 32'd2 ) ) i_ax_mux ( .inp_data_i ({wr_meta, rd_meta }), .inp_valid_i ({wr_valid, rd_valid}), @@ -322,10 +322,11 @@ module axi_to_detailed_mem #( // Fork arbitrated stream to meta data, memory requests, and R/B channel selection. cc_stream_fork #( - .N_OUP ( 32'd3 ) + .NumOup ( 32'd3 ) ) i_fork ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .valid_i ( arb_valid ), .ready_o ( arb_ready ), .valid_o ({sel_valid, meta_valid, m2s_req_valid}), @@ -336,12 +337,13 @@ module axi_to_detailed_mem #( assign sel_r = ~meta.write | meta.atop[5]; cc_stream_fifo #( - .FALL_THROUGH ( 1'b1 ), - .DEPTH ( 32'd1 + BufDepth ), - .T ( logic[1:0] ) + .FallThrough ( 1'b1 ), + .Depth ( 32'd1 + BufDepth ), + .data_t ( logic[1:0] ) ) i_sel_buf ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .flush_i ( 1'b0 ), .data_i ({sel_b, sel_r }), .valid_i ( sel_valid ), @@ -353,12 +355,13 @@ module axi_to_detailed_mem #( ); cc_stream_fifo #( - .FALL_THROUGH ( 1'b1 ), - .DEPTH ( 32'd1 + BufDepth ), - .T ( meta_t ) + .FallThrough ( 1'b1 ), + .Depth ( 32'd1 + BufDepth ), + .data_t ( meta_t ) ) i_meta_buf ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .flush_i ( 1'b0 ), .data_i ( meta ), .valid_i ( meta_valid ), @@ -469,7 +472,7 @@ module axi_to_detailed_mem #( // Join memory read data and meta data stream. logic mem_join_valid, mem_join_ready; cc_stream_join #( - .N_INP ( 32'd2 ) + .NumInp ( 32'd2 ) ) i_join ( .inp_valid_i ({m2s_resp_valid, meta_buf_valid}), .inp_ready_o ({m2s_resp_ready, meta_buf_ready}), @@ -479,10 +482,11 @@ module axi_to_detailed_mem #( // Dynamically fork the joined stream to B and R channels. cc_stream_fork_dynamic #( - .N_OUP ( 32'd2 ) + .NumOup ( 32'd2 ) ) i_fork_dynamic ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .valid_i ( mem_join_valid ), .ready_o ( mem_join_ready ), .sel_i ({sel_buf_b, sel_buf_r }), @@ -874,13 +878,14 @@ module mem_stream_to_banks_detailed #( assign bank_req[i].wuser = wuser_i; assign bank_req[i].we = we_i; cc_stream_fifo #( - .FALL_THROUGH ( 1'b1 ), - .DATA_WIDTH ( $bits(req_t) ), - .DEPTH ( OutFifoDepth ), - .T ( req_t ) + .FallThrough ( 1'b1 ), + .DataWidth ( $bits(req_t) ), + .Depth ( OutFifoDepth ), + .data_t ( req_t ) ) i_ft_reg ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .flush_i ( 1'b0 ), .usage_o (), .data_i ( bank_req[i] ), @@ -919,12 +924,13 @@ module mem_stream_to_banks_detailed #( assign zero_strobe_on_input[i] = (strb_i[i*BytesPerBank+:BytesPerBank] == '0); end cc_fifo #( - .FALL_THROUGH ( 1'b0 ), - .DEPTH ( MaxTrans+1 ), - .DATA_WIDTH ( NumBanks ) + .FallThrough ( 1'b0 ), + .Depth ( MaxTrans+1 ), + .DataWidth ( NumBanks ) ) i_dead_write_fifo ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .flush_i ( 1'b0 ), .full_o ( dead_write_fifo_full ), .empty_o ( dead_write_fifo_empty ), @@ -945,12 +951,13 @@ module mem_stream_to_banks_detailed #( // Handle responses. for (genvar i = 0; unsigned'(i) < NumBanks; i++) begin : gen_resp_regs cc_stream_fifo #( - .FALL_THROUGH ( 1'b1 ), - .DATA_WIDTH ( $bits(oup_data_t) + $bits(oup_ruser_t) ), - .DEPTH ( MaxTrans ) + .FallThrough ( 1'b1 ), + .DataWidth ( $bits(oup_data_t) + $bits(oup_ruser_t) ), + .Depth ( MaxTrans ) ) i_ft_reg ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .flush_i ( 1'b0 ), .usage_o (), .data_i ( {bank_rdata_i[i], bank_ruser_i[i]} ), diff --git a/src/axi_to_mem_banked.sv b/src/axi_to_mem_banked.sv index 0525f1c7e..5a8db0a40 100644 --- a/src/axi_to_mem_banked.sv +++ b/src/axi_to_mem_banked.sv @@ -239,11 +239,12 @@ module axi_to_mem_banked #( // Connect for the response data `MemLatency` cycles after a request was made to the xbar. cc_shift_register #( - .dtype ( read_sel_t ), + .data_t ( read_sel_t ), .Depth ( MemLatency ) ) i_shift_reg_rdata_mux ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .d_i ( r_shift_inp ), .d_o ( r_shift_oup ) ); @@ -264,7 +265,8 @@ module axi_to_mem_banked #( ) i_stream_xbar ( .clk_i, .rst_ni, - .flush_i ( 1'b0 ), + .clr_arb_i ( 1'b0 ), + .clr_i ( 1'b0 ), .rr_i ( '0 ), .data_i ( inter_payload ), .sel_i ( inter_sel ), diff --git a/src/axi_to_mem_interleaved.sv b/src/axi_to_mem_interleaved.sv index d3df18905..b2cef75e9 100644 --- a/src/axi_to_mem_interleaved.sv +++ b/src/axi_to_mem_interleaved.sv @@ -221,11 +221,11 @@ module axi_to_mem_interleaved #( // fine-grain arbitration cc_rr_arb_tree #( .NumIn ( 2 ), - .DataType ( mem_req_payload_t ) + .data_t ( mem_req_payload_t ) ) i_rr_arb_tree ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), - .flush_i ( 1'b0 ), + .clr_i ( 1'b0 ), .rr_i ( '0 ), .req_i ( { r_mem_req[i], w_mem_req[i] } ), .gnt_o ( { r_mem_gnt[i], w_mem_gnt[i] } ), @@ -238,11 +238,12 @@ module axi_to_mem_interleaved #( // back-routing store cc_fifo #( - .DATA_WIDTH ( 1 ), - .DEPTH ( BufDepth + 1 ) + .DataWidth ( 1 ), + .Depth ( BufDepth + 1 ) ) i_fifo_v3_response_trgt_store ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .flush_i ( 1'b0 ), .full_o ( fifo_full[i] ), .empty_o ( ), From c268c2b1c086125a959489cee9ffbfb5a291648d Mon Sep 17 00:00:00 2001 From: Luca Colagrande Date: Mon, 27 Jun 2022 15:12:59 +0200 Subject: [PATCH 09/41] axi_xbar: Correct signal names in waveform file --- test/tb_axi_xbar.wave.do | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/tb_axi_xbar.wave.do b/test/tb_axi_xbar.wave.do index 1f19f390c..06cac658e 100644 --- a/test/tb_axi_xbar.wave.do +++ b/test/tb_axi_xbar.wave.do @@ -4,11 +4,11 @@ quietly WaveActivateNextPane {} 0 add wave -noupdate -label Clock /tb_axi_xbar/i_xbar_dut/clk_i add wave -noupdate -label Reset /tb_axi_xbar/i_xbar_dut/rst_ni add wave -noupdate -divider {Slave Ports} -add wave -noupdate /tb_axi_xbar/i_xbar_dut/slv_ports_req_i -add wave -noupdate /tb_axi_xbar/i_xbar_dut/slv_ports_resp_o +add wave -noupdate /tb_axi_xbar/i_xbar_dut/slv_reqs +add wave -noupdate /tb_axi_xbar/i_xbar_dut/slv_resps add wave -noupdate -divider {Master Ports} -add wave -noupdate /tb_axi_xbar/i_xbar_dut/mst_ports_req_o -add wave -noupdate /tb_axi_xbar/i_xbar_dut/mst_ports_resp_i +add wave -noupdate /tb_axi_xbar/i_xbar_dut/mst_reqs +add wave -noupdate /tb_axi_xbar/i_xbar_dut/mst_resps add wave -noupdate -divider {Address Mapping} add wave -noupdate /tb_axi_xbar/i_xbar_dut/addr_map_i add wave -noupdate /tb_axi_xbar/i_xbar_dut/en_default_mst_port_i From b04cb43f1a058623b56298d0e2bf1c994daeb0a7 Mon Sep 17 00:00:00 2001 From: Luca Colagrande Date: Mon, 27 Jun 2022 20:17:21 +0200 Subject: [PATCH 10/41] docs: Correct typos --- doc/axi_demux.md | 2 +- doc/axi_mux.md | 2 +- doc/axi_xbar.md | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/axi_demux.md b/doc/axi_demux.md index ac28fcd99..82a83375b 100644 --- a/doc/axi_demux.md +++ b/doc/axi_demux.md @@ -70,7 +70,7 @@ Setting the `UniqueIds` parameter to `1'b1` reduces the area complexity of the d `2 * 2^AxiLookBits` counters track the number of [in-flight](../doc#in-flight) transactions. That is, for each ID in the (potentially) reduced set of IDs of `AxiLookBits` bits, there is one counter for write transactions and one for read transactions. Each counter can count up to (and including) `MaxTrans`, and there is a register that holds the index of the master port to which a counter is assigned. -When the demultiplexer gets an AW or an AR, it indexes the counters with the AXI ID. If the indexed counter has a value greater than zero and its master port index register is not equal to the index to which the AW or AR is to be sent, a transaction with the same direction and ID is already in flight to another master port. The demultiplexer then stalls the AW or AR. In all other cases, the demultiplexer forwards the AW or AR, increments the value of the indexed counter, and sets the master port index of the counter. A counter is decremented upon a handshake a B respectively last R beat at a slave port. +When the demultiplexer gets an AW or an AR, it indexes the counters with the AXI ID. If the indexed counter has a value greater than zero and its master port index register is not equal to the index to which the AW or AR is to be sent, a transaction with the same direction and ID is already in flight to another master port. The demultiplexer then stalls the AW or AR. In all other cases, the demultiplexer forwards the AW or AR, increments the value of the indexed counter, and sets the master port index of the counter. A counter associated with the AW or AR channel is decremented upon a handshake on the slave port respectively on the B channel or on the R channel in correspondence of the last beat. W beats are routed to the master port defined by the value of `slv_aw_select_i` for the corresponding AW. As the order of the W bursts is given by the order of the AWs, the select signals are stored in a FIFO queue. This FIFO is pushed upon a handshake on the AW slave channel and popped upon a handshake of the last W beat of a burst on a W master channel. diff --git a/doc/axi_mux.md b/doc/axi_mux.md index fc257feb0..0c3641267 100644 --- a/doc/axi_mux.md +++ b/doc/axi_mux.md @@ -4,7 +4,7 @@ The opposite function to the AXI demultiplexer is performed by the AXI Multiplex ![Block-diagram of the AXI 4 Multiplexer Module.](axi_mux.png "Block-diagram of the AXI 4 Multiplexer Module.") -The Multiplexer module is has a simpler structure than the demultiplexer introduced in the previous section. The requests on the AW and AR channels get merged with the same round robin arbitration used for merging the responses in the demultiplexer. One key difference however is the mechanism how the multiplexer determines from which slave port a request came. It uses for this the higher bits of the `axi_id` field of a request. The number of bits can be calculated with: +The Multiplexer module has a simpler structure than the demultiplexer introduced in the previous section. The requests on the AW and AR channels get merged with the same round robin arbitration used for merging the responses in the demultiplexer. One key difference however is the mechanism how the multiplexer determines from which slave port a request came. It uses for this the higher bits of the `axi_id` field of a request. The number of bits can be calculated with: ```systemverilog $clog2(NoSlavePorts) diff --git a/doc/axi_xbar.md b/doc/axi_xbar.md index ef33dda9a..98bdb23a7 100644 --- a/doc/axi_xbar.md +++ b/doc/axi_xbar.md @@ -5,7 +5,7 @@ ## Design Overview -`axi_xbar` is a fully-connected crossbar, which means that each master module that is connected to a *slave port* for of the crossbar has direct wires to all slave modules that are connected to the *master ports* of the crossbar. +`axi_xbar` is a fully-connected crossbar, which means that each master module that is connected to a *slave port* of the crossbar has direct wires to all slave modules that are connected to the *master ports* of the crossbar. A block-diagram of the crossbar is shown below: ![Block-diagram showing the design of the full AXI4 Crossbar.](axi_xbar.png "Block-diagram showing the design of the full AXI4 Crossbar.") @@ -49,7 +49,7 @@ The crossbar is configured through the `Cfg` parameter with a `axi_pkg::xbar_cfg | `LatencyMode` | `enum logic [9:0]` | Latency on the individual channels, defined in detail in section *Pipelining and Latency* below. | | `AxiIdWidthSlvPorts` | `int unsigned` | The AXI ID width of the slave ports. | | `AxiIdUsedSlvPorts` | `int unsigned` | The number of slave port ID bits (starting at the least significant) the crossbar uses to determine the uniqueness of an AXI ID (see section *Ordering and Stalls* below). This value has to be less or equal than `AxiIdWidthSlvPorts`. | -| `UniqueIds` | `bit` | If you can guarantee that the ID of each transaction is always unique among all in-flight transactions in the same direction, setting this parameter to `1'b1` simplifies the crossbar. See the [`axi_demux` documentation](axi_demux#ordering-and-stalls) for details. | +| `UniqueIds` | `bit` | If you can guarantee that the ID of each transaction is always unique among all in-flight transactions in the same direction, setting this parameter to `1'b1` simplifies the crossbar. See the [`axi_demux` documentation](axi_demux.md#ordering-and-stalls) for details. | | `AxiAddrWidth` | `int unsigned` | The AXI address width. | | `AxiDataWidth` | `int unsigned` | The AXI data width. | | `NoAddrRules` | `int unsigned` | The number of address map rules. | From 862efe796060d63cf35f85df74fad0f321e6f16f Mon Sep 17 00:00:00 2001 From: Luca Colagrande Date: Wed, 29 Jun 2022 17:16:32 +0200 Subject: [PATCH 11/41] axi_mcast_xbar: Create copies of original IPs as starting point --- src/axi_mcast_demux.sv | 896 ++++++++++++++++++++++++++++++++++ src/axi_mcast_mux.sv | 598 +++++++++++++++++++++++ src/axi_mcast_xbar.sv | 437 +++++++++++++++++ test/tb_axi_mcast_xbar.sv | 465 ++++++++++++++++++ test/tb_axi_mcast_xbar_pkg.sv | 503 +++++++++++++++++++ 5 files changed, 2899 insertions(+) create mode 100644 src/axi_mcast_demux.sv create mode 100644 src/axi_mcast_mux.sv create mode 100644 src/axi_mcast_xbar.sv create mode 100644 test/tb_axi_mcast_xbar.sv create mode 100644 test/tb_axi_mcast_xbar_pkg.sv diff --git a/src/axi_mcast_demux.sv b/src/axi_mcast_demux.sv new file mode 100644 index 000000000..fc061ff09 --- /dev/null +++ b/src/axi_mcast_demux.sv @@ -0,0 +1,896 @@ +// Copyright (c) 2019 ETH Zurich and University of Bologna. +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. +// +// Authors: +// - Wolfgang Roenninger +// - Andreas Kurth + +`include "common_cells/assertions.svh" +`include "common_cells/registers.svh" + +`ifdef QUESTA +// Derive `TARGET_VSIM`, which is used for tool-specific workarounds in this file, from `QUESTA`, +// which is automatically set in Questa. +`define TARGET_VSIM +`endif + +/// Demultiplex one AXI4+ATOP slave port to multiple AXI4+ATOP master ports. +/// +/// The AW and AR slave channels each have a `select` input to determine to which master port the +/// current request is sent. The `select` can, for example, be driven by an address decoding module +/// to map address ranges to different AXI slaves. +/// +/// ## Design overview +/// +/// ![Block diagram](module.axi_demux.png "Block diagram") +/// +/// Beats on the W channel are routed by demultiplexer according to the selection for the +/// corresponding AW beat. This relies on the AXI property that W bursts must be sent in the same +/// order as AW beats and beats from different W bursts may not be interleaved. +/// +/// Beats on the B and R channel are multiplexed from the master ports to the slave port with +/// a round-robin arbitration tree. +module axi_demux #( + parameter int unsigned AxiIdWidth = 32'd0, + parameter bit AtopSupport = 1'b1, + parameter type aw_chan_t = logic, + parameter type w_chan_t = logic, + parameter type b_chan_t = logic, + parameter type ar_chan_t = logic, + parameter type r_chan_t = logic, + parameter type axi_req_t = logic, + parameter type axi_resp_t = logic, + parameter int unsigned NoMstPorts = 32'd0, + parameter int unsigned MaxTrans = 32'd8, + parameter int unsigned AxiLookBits = 32'd3, + parameter bit UniqueIds = 1'b0, + parameter bit SpillAw = 1'b1, + parameter bit SpillW = 1'b0, + parameter bit SpillB = 1'b0, + 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] +) ( + input logic clk_i, + input logic rst_ni, + input logic test_i, + // Slave Port + input axi_req_t slv_req_i, + input select_t slv_aw_select_i, + input select_t slv_ar_select_i, + output axi_resp_t slv_resp_o, + // Master Ports + output axi_req_t [NoMstPorts-1:0] mst_reqs_o, + input axi_resp_t [NoMstPorts-1:0] mst_resps_i +); + + localparam int unsigned IdCounterWidth = cf_math_pkg::idx_width(MaxTrans); + typedef logic [IdCounterWidth-1:0] id_cnt_t; + + + // pass through if only one master port + if (NoMstPorts == 32'h1) begin : gen_no_demux + spill_register #( + .T ( aw_chan_t ), + .Bypass ( ~SpillAw ) + ) i_aw_spill_reg ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .valid_i ( slv_req_i.aw_valid ), + .ready_o ( slv_resp_o.aw_ready ), + .data_i ( slv_req_i.aw ), + .valid_o ( mst_reqs_o[0].aw_valid ), + .ready_i ( mst_resps_i[0].aw_ready ), + .data_o ( mst_reqs_o[0].aw ) + ); + spill_register #( + .T ( w_chan_t ), + .Bypass ( ~SpillW ) + ) i_w_spill_reg ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .valid_i ( slv_req_i.w_valid ), + .ready_o ( slv_resp_o.w_ready ), + .data_i ( slv_req_i.w ), + .valid_o ( mst_reqs_o[0].w_valid ), + .ready_i ( mst_resps_i[0].w_ready ), + .data_o ( mst_reqs_o[0].w ) + ); + spill_register #( + .T ( b_chan_t ), + .Bypass ( ~SpillB ) + ) i_b_spill_reg ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .valid_i ( mst_resps_i[0].b_valid ), + .ready_o ( mst_reqs_o[0].b_ready ), + .data_i ( mst_resps_i[0].b ), + .valid_o ( slv_resp_o.b_valid ), + .ready_i ( slv_req_i.b_ready ), + .data_o ( slv_resp_o.b ) + ); + spill_register #( + .T ( ar_chan_t ), + .Bypass ( ~SpillAr ) + ) i_ar_spill_reg ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .valid_i ( slv_req_i.ar_valid ), + .ready_o ( slv_resp_o.ar_ready ), + .data_i ( slv_req_i.ar ), + .valid_o ( mst_reqs_o[0].ar_valid ), + .ready_i ( mst_resps_i[0].ar_ready ), + .data_o ( mst_reqs_o[0].ar ) + ); + spill_register #( + .T ( r_chan_t ), + .Bypass ( ~SpillR ) + ) i_r_spill_reg ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .valid_i ( mst_resps_i[0].r_valid ), + .ready_o ( mst_reqs_o[0].r_ready ), + .data_i ( mst_resps_i[0].r ), + .valid_o ( slv_resp_o.r_valid ), + .ready_i ( slv_req_i.r_ready ), + .data_o ( slv_resp_o.r ) + ); + + // other non degenerate cases + end else begin : gen_demux + + //-------------------------------------- + //-------------------------------------- + // Signal Declarations + //-------------------------------------- + //-------------------------------------- + + //-------------------------------------- + // Write Transaction + //-------------------------------------- + // comes from spill register at input + aw_chan_t slv_aw_chan; + select_t slv_aw_select; + + logic slv_aw_valid, slv_aw_valid_chan, slv_aw_valid_sel; + logic slv_aw_ready, slv_aw_ready_chan, slv_aw_ready_sel; + + // AW ID counter + select_t lookup_aw_select; + logic aw_select_occupied, aw_id_cnt_full; + // Upon an ATOP load, inject IDs from the AW into the AR channel + logic atop_inject; + + // W select counter: stores the decision to which master W beats should go + select_t w_select, w_select_q; + logic w_select_valid; + id_cnt_t w_open; + logic w_cnt_up, w_cnt_down; + + // Register which locks the AW valid signal + logic lock_aw_valid_d, lock_aw_valid_q, load_aw_lock; + logic aw_valid, aw_ready; + + // W channel from spill reg + w_chan_t slv_w_chan; + logic slv_w_valid, slv_w_ready; + + // B channles input into the arbitration + b_chan_t [NoMstPorts-1:0] mst_b_chans; + logic [NoMstPorts-1:0] mst_b_valids, mst_b_readies; + + // B channel to spill register + b_chan_t slv_b_chan; + logic slv_b_valid, slv_b_ready; + + //-------------------------------------- + // Read Transaction + //-------------------------------------- + // comes from spill register at input + logic slv_ar_valid, ar_valid_chan, ar_valid_sel; + logic slv_ar_ready, slv_ar_ready_chan, slv_ar_ready_sel; + + // AR ID counter + select_t lookup_ar_select; + logic ar_select_occupied, ar_id_cnt_full; + logic ar_push; + + // Register which locks the AR valid signel + logic lock_ar_valid_d, lock_ar_valid_q, load_ar_lock; + logic ar_valid, ar_ready; + + // R channles input into the arbitration + r_chan_t [NoMstPorts-1:0] mst_r_chans; + logic [NoMstPorts-1:0] mst_r_valids, mst_r_readies; + + // R channel to spill register + r_chan_t slv_r_chan; + logic slv_r_valid, slv_r_ready; + + //-------------------------------------- + //-------------------------------------- + // Channel Control + //-------------------------------------- + //-------------------------------------- + + //-------------------------------------- + // AW Channel + //-------------------------------------- + // spill register at the channel input + spill_register #( + .T ( aw_chan_t ), + .Bypass ( ~SpillAw ) // because module param indicates if we want a spill reg + ) i_aw_channel_spill_reg ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .valid_i ( slv_req_i.aw_valid ), + .ready_o ( slv_aw_ready_chan ), + .data_i ( slv_req_i.aw ), + .valid_o ( slv_aw_valid_chan ), + .ready_i ( slv_aw_ready ), + .data_o ( slv_aw_chan ) + ); + spill_register #( + .T ( select_t ), + .Bypass ( ~SpillAw ) // because module param indicates if we want a spill reg + ) i_aw_select_spill_reg ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .valid_i ( slv_req_i.aw_valid ), + .ready_o ( slv_aw_ready_sel ), + .data_i ( slv_aw_select_i ), + .valid_o ( slv_aw_valid_sel ), + .ready_i ( slv_aw_ready ), + .data_o ( slv_aw_select ) + ); + assign slv_resp_o.aw_ready = slv_aw_ready_chan & slv_aw_ready_sel; + assign slv_aw_valid = slv_aw_valid_chan & slv_aw_valid_sel; + + // Control of the AW handshake + always_comb begin + // AXI Handshakes + slv_aw_ready = 1'b0; + aw_valid = 1'b0; + // `lock_aw_valid`, used to be protocol conform as it is not allowed to deassert + // a valid if there was no corresponding ready. As this process has to be able to inject + // an AXI ID into the counter of the AR channel on an ATOP, there could be a case where + // this process waits on `aw_ready` but in the mean time on the AR channel the counter gets + // full. + lock_aw_valid_d = lock_aw_valid_q; + load_aw_lock = 1'b0; + // AW ID counter and W FIFO + w_cnt_up = 1'b0; + // ATOP injection into ar counter + atop_inject = 1'b0; + // we had an arbitration decision, the valid is locked, wait for the transaction + if (lock_aw_valid_q) begin + aw_valid = 1'b1; + // transaction + if (aw_ready) begin + slv_aw_ready = 1'b1; + lock_aw_valid_d = 1'b0; + load_aw_lock = 1'b1; + // inject the ATOP if necessary + atop_inject = slv_aw_chan.atop[axi_pkg::ATOP_R_RESP] & AtopSupport; + end + end else begin + // An AW can be handled if `i_aw_id_counter` and `i_counter_open_w` are not full. An ATOP that + // requires an R response can be handled if additionally `i_ar_id_counter` is not full (this + // only applies if ATOPs are supported at all). + if (!aw_id_cnt_full && (w_open != {IdCounterWidth{1'b1}}) && + (!(ar_id_cnt_full && slv_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. + // Also stall if previous transmitted AWs still have active W's in flight. + // This prevents deadlocking of the W channel. The counters are there for the + // Handling of the B responses. + if (slv_aw_valid && + ((w_open == '0) || (w_select == slv_aw_select)) && + (!aw_select_occupied || (slv_aw_select == lookup_aw_select))) begin + // connect the handshake + aw_valid = 1'b1; + // push arbitration to the W FIFO regardless, do not wait for the AW transaction + w_cnt_up = 1'b1; + // on AW transaction + if (aw_ready) begin + slv_aw_ready = 1'b1; + atop_inject = slv_aw_chan.atop[axi_pkg::ATOP_R_RESP] & AtopSupport; + // no AW transaction this cycle, lock the decision + end else begin + lock_aw_valid_d = 1'b1; + load_aw_lock = 1'b1; + end + end + end + end + end + + // lock the valid signal, as the selection gets pushed into the W FIFO on first assertion, + // prevent further pushing + `FFLARN(lock_aw_valid_q, lock_aw_valid_d, load_aw_lock, '0, clk_i, rst_ni) + + if (UniqueIds) begin : gen_unique_ids_aw + // If the `UniqueIds` parameter is set, each write transaction has an ID that is unique among + // all in-flight write transactions, or all write transactions with a given ID target the same + // master port as all write transactions with the same ID, or both. This means that the + // signals that are driven by the ID counters if this parameter is not set can instead be + // derived from existing signals. The ID counters can therefore be omitted. + assign lookup_aw_select = slv_aw_select; + assign aw_select_occupied = 1'b0; + assign aw_id_cnt_full = 1'b0; + end else begin : gen_aw_id_counter + axi_demux_id_counters #( + .AxiIdBits ( AxiLookBits ), + .CounterWidth ( IdCounterWidth ), + .mst_port_select_t ( select_t ) + ) i_aw_id_counter ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .lookup_axi_id_i ( slv_aw_chan.id[0+:AxiLookBits] ), + .lookup_mst_select_o ( lookup_aw_select ), + .lookup_mst_select_occupied_o ( aw_select_occupied ), + .full_o ( aw_id_cnt_full ), + .inject_axi_id_i ( '0 ), + .inject_i ( 1'b0 ), + .push_axi_id_i ( slv_aw_chan.id[0+:AxiLookBits] ), + .push_mst_select_i ( slv_aw_select ), + .push_i ( w_cnt_up ), + .pop_axi_id_i ( slv_b_chan.id[0+:AxiLookBits] ), + .pop_i ( slv_b_valid & slv_b_ready ) + ); + // pop from ID counter on outward transaction + end + + // This counter steers the demultiplexer of the W channel. + // `w_select` determines, which handshaking is connected. + // AWs are only forwarded, if the counter is empty, or `w_select_q` is the same as + // `slv_aw_select`. + counter #( + .WIDTH ( IdCounterWidth ), + .STICKY_OVERFLOW ( 1'b0 ) + ) i_counter_open_w ( + .clk_i, + .rst_ni, + .clear_i ( 1'b0 ), + .en_i ( w_cnt_up ^ w_cnt_down ), + .load_i ( 1'b0 ), + .down_i ( w_cnt_down ), + .d_i ( '0 ), + .q_o ( w_open ), + .overflow_o ( /*not used*/ ) + ); + + `FFLARN(w_select_q, slv_aw_select, w_cnt_up, select_t'(0), clk_i, rst_ni) + assign w_select = (|w_open) ? w_select_q : slv_aw_select; + assign w_select_valid = w_cnt_up | (|w_open); + + //-------------------------------------- + // W Channel + //-------------------------------------- + spill_register #( + .T ( w_chan_t ), + .Bypass ( ~SpillW ) + ) i_w_spill_reg( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .valid_i ( slv_req_i.w_valid ), + .ready_o ( slv_resp_o.w_ready ), + .data_i ( slv_req_i.w ), + .valid_o ( slv_w_valid ), + .ready_i ( slv_w_ready ), + .data_o ( slv_w_chan ) + ); + + //-------------------------------------- + // B Channel + //-------------------------------------- + // optional spill register + spill_register #( + .T ( b_chan_t ), + .Bypass ( ~SpillB ) + ) i_b_spill_reg ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .valid_i ( slv_b_valid ), + .ready_o ( slv_b_ready ), + .data_i ( slv_b_chan ), + .valid_o ( slv_resp_o.b_valid ), + .ready_i ( slv_req_i.b_ready ), + .data_o ( slv_resp_o.b ) + ); + + // Arbitration of the different B responses + rr_arb_tree #( + .NumIn ( NoMstPorts ), + .DataType ( b_chan_t ), + .AxiVldRdy( 1'b1 ), + .LockIn ( 1'b1 ) + ) i_b_mux ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .flush_i( 1'b0 ), + .rr_i ( '0 ), + .req_i ( mst_b_valids ), + .gnt_o ( mst_b_readies ), + .data_i ( mst_b_chans ), + .gnt_i ( slv_b_ready ), + .req_o ( slv_b_valid ), + .data_o ( slv_b_chan ), + .idx_o ( ) + ); + + //-------------------------------------- + // AR Channel + //-------------------------------------- + ar_chan_t slv_ar_chan; + select_t slv_ar_select; + spill_register #( + .T ( ar_chan_t ), + .Bypass ( ~SpillAr ) + ) i_ar_chan_spill_reg ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .valid_i ( slv_req_i.ar_valid ), + .ready_o ( slv_ar_ready_chan ), + .data_i ( slv_req_i.ar ), + .valid_o ( ar_valid_chan ), + .ready_i ( slv_ar_ready ), + .data_o ( slv_ar_chan ) + ); + spill_register #( + .T ( select_t ), + .Bypass ( ~SpillAr ) + ) i_ar_sel_spill_reg ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .valid_i ( slv_req_i.ar_valid ), + .ready_o ( slv_ar_ready_sel ), + .data_i ( slv_ar_select_i ), + .valid_o ( ar_valid_sel ), + .ready_i ( slv_ar_ready ), + .data_o ( slv_ar_select ) + ); + assign slv_resp_o.ar_ready = slv_ar_ready_chan & slv_ar_ready_sel; + assign slv_ar_valid = ar_valid_chan & ar_valid_sel; + + // control of the AR handshake + always_comb begin + // AXI Handshakes + slv_ar_ready = 1'b0; + ar_valid = 1'b0; + // `lock_ar_valid`: Used to be protocol conform as it is not allowed to deassert `ar_valid` + // if there was no corresponding `ar_ready`. There is the possibility that an injection + // of a R response from an `atop` from the AW channel can change the occupied flag of the + // `i_ar_id_counter`, even if it was previously empty. This FF prevents the deassertion. + lock_ar_valid_d = lock_ar_valid_q; + load_ar_lock = 1'b0; + // AR id counter + ar_push = 1'b0; + // The process had an arbitration decision in a previous cycle, the valid is locked, + // wait for the AR transaction. + if (lock_ar_valid_q) begin + ar_valid = 1'b1; + // transaction + if (ar_ready) begin + slv_ar_ready = 1'b1; + ar_push = 1'b1; + lock_ar_valid_d = 1'b0; + load_ar_lock = 1'b1; + end + end else begin + // The process can start handling AR transaction if `i_ar_id_counter` has space. + if (!ar_id_cnt_full) begin + // There is a valid AR, so look the ID up. + if (slv_ar_valid && (!ar_select_occupied || + (slv_ar_select == lookup_ar_select))) begin + // connect the AR handshake + ar_valid = 1'b1; + // on transaction + if (ar_ready) begin + slv_ar_ready = 1'b1; + ar_push = 1'b1; + // no transaction this cycle, lock the valid decision! + end else begin + lock_ar_valid_d = 1'b1; + load_ar_lock = 1'b1; + end + end + end + end + end + + // this ff is needed so that ar does not get de-asserted if an atop gets injected + `FFLARN(lock_ar_valid_q, lock_ar_valid_d, load_ar_lock, '0, clk_i, rst_ni) + + if (UniqueIds) begin : gen_unique_ids_ar + // If the `UniqueIds` parameter is set, each read transaction has an ID that is unique among + // all in-flight read transactions, or all read transactions with a given ID target the same + // master port as all read transactions with the same ID, or both. This means that the + // signals that are driven by the ID counters if this parameter is not set can instead be + // derived from existing signals. The ID counters can therefore be omitted. + assign lookup_ar_select = slv_ar_select; + assign ar_select_occupied = 1'b0; + assign ar_id_cnt_full = 1'b0; + end else begin : gen_ar_id_counter + axi_demux_id_counters #( + .AxiIdBits ( AxiLookBits ), + .CounterWidth ( IdCounterWidth ), + .mst_port_select_t ( select_t ) + ) i_ar_id_counter ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .lookup_axi_id_i ( slv_ar_chan.id[0+:AxiLookBits] ), + .lookup_mst_select_o ( lookup_ar_select ), + .lookup_mst_select_occupied_o ( ar_select_occupied ), + .full_o ( ar_id_cnt_full ), + .inject_axi_id_i ( slv_aw_chan.id[0+:AxiLookBits] ), + .inject_i ( atop_inject ), + .push_axi_id_i ( slv_ar_chan.id[0+:AxiLookBits] ), + .push_mst_select_i ( slv_ar_select ), + .push_i ( ar_push ), + .pop_axi_id_i ( slv_r_chan.id[0+:AxiLookBits] ), + .pop_i ( slv_r_valid & slv_r_ready & slv_r_chan.last ) + ); + end + + //-------------------------------------- + // R Channel + //-------------------------------------- + // optional spill register + spill_register #( + .T ( r_chan_t ), + .Bypass ( ~SpillR ) + ) i_r_spill_reg ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .valid_i ( slv_r_valid ), + .ready_o ( slv_r_ready ), + .data_i ( slv_r_chan ), + .valid_o ( slv_resp_o.r_valid ), + .ready_i ( slv_req_i.r_ready ), + .data_o ( slv_resp_o.r ) + ); + + // Arbitration of the different r responses + rr_arb_tree #( + .NumIn ( NoMstPorts ), + .DataType ( r_chan_t ), + .AxiVldRdy( 1'b1 ), + .LockIn ( 1'b1 ) + ) i_r_mux ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .flush_i( 1'b0 ), + .rr_i ( '0 ), + .req_i ( mst_r_valids ), + .gnt_o ( mst_r_readies ), + .data_i ( mst_r_chans ), + .gnt_i ( slv_r_ready ), + .req_o ( slv_r_valid ), + .data_o ( slv_r_chan ), + .idx_o ( ) + ); + + assign ar_ready = ar_valid & mst_resps_i[slv_ar_select].ar_ready; + assign aw_ready = aw_valid & mst_resps_i[slv_aw_select].aw_ready; + + // 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! + always_comb begin + // default assignments + mst_reqs_o = '0; + slv_w_ready = 1'b0; + w_cnt_down = 1'b0; + + for (int unsigned i = 0; i < NoMstPorts; i++) begin + // AW channel + mst_reqs_o[i].aw = slv_aw_chan; + mst_reqs_o[i].aw_valid = 1'b0; + if (aw_valid && (slv_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_select_valid && (w_select == i)) begin + mst_reqs_o[i].w_valid = slv_w_valid; + slv_w_ready = mst_resps_i[i].w_ready; + w_cnt_down = slv_w_valid & mst_resps_i[i].w_ready & slv_w_chan.last; + end + + // B channel + mst_reqs_o[i].b_ready = mst_b_readies[i]; + + // AR channel + mst_reqs_o[i].ar = slv_ar_chan; + mst_reqs_o[i].ar_valid = 1'b0; + if (ar_valid && (slv_ar_select == i)) begin + mst_reqs_o[i].ar_valid = 1'b1; + end + + // R channel + mst_reqs_o[i].r_ready = mst_r_readies[i]; + end + end + // unpack the response B and R channels for the arbitration + 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; + end + + +// Validate parameters. +// pragma translate_off +`ifndef VERILATOR +`ifndef XSIM + initial begin: validate_params + no_mst_ports: assume (NoMstPorts > 0) else + $fatal(1, "The Number of slaves (NoMstPorts) has to be at least 1"); + AXI_ID_BITS: assume (AxiIdWidth >= AxiLookBits) else + $fatal(1, "AxiIdBits has to be equal or smaller than AxiIdWidth."); + end + default disable iff (!rst_ni); + 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.\ + NoMstPorts: %d", slv_aw_select_i, NoMstPorts); + ar_select: assume property( @(posedge clk_i) (slv_req_i.ar_valid |-> + (slv_ar_select_i < NoMstPorts))) else + $fatal(1, "slv_ar_select_i is %d: AR has selected a slave that is not defined.\ + NoMstPorts: %d", slv_ar_select_i, NoMstPorts); + aw_valid_stable: assert property( @(posedge clk_i) (aw_valid && !aw_ready) |=> aw_valid) else + $fatal(1, "aw_valid was deasserted, when aw_ready = 0 in last cycle."); + ar_valid_stable: assert property( @(posedge clk_i) + (ar_valid && !ar_ready) |=> ar_valid) else + $fatal(1, "ar_valid was deasserted, when ar_ready = 0 in last cycle."); + slv_aw_chan_stable: assert property( @(posedge clk_i) (aw_valid && !aw_ready) + |=> $stable(slv_aw_chan)) else + $fatal(1, "slv_aw_chan unstable with valid set."); + slv_aw_select_stable: assert property( @(posedge clk_i) (aw_valid && !aw_ready) + |=> $stable(slv_aw_select)) else + $fatal(1, "slv_aw_select unstable with valid set."); + slv_ar_chan_stable: assert property( @(posedge clk_i) (ar_valid && !ar_ready) + |=> $stable(slv_ar_chan)) else + $fatal(1, "slv_ar_chan unstable with valid set."); + slv_ar_select_stable: assert property( @(posedge clk_i) (ar_valid && !ar_ready) + |=> $stable(slv_ar_select)) else + $fatal(1, "slv_ar_select unstable with valid set."); + internal_ar_select: assert property( @(posedge clk_i) + (ar_valid |-> slv_ar_select < NoMstPorts)) + else $fatal(1, "slv_ar_select illegal while ar_valid."); + internal_aw_select: assert property( @(posedge clk_i) + (aw_valid |-> slv_aw_select < NoMstPorts)) + else $fatal(1, "slv_aw_select illegal while aw_valid."); + w_underflow: assert property( @(posedge clk_i) + ((w_open == '0) && (w_cnt_up ^ w_cnt_down) |-> !w_cnt_down)) else + $fatal(1, "W counter underflowed!"); + `ASSUME(NoAtopAllowed, !AtopSupport && slv_req_i.aw_valid |-> slv_req_i.aw.atop == '0) +`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 #( + 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, + parameter int unsigned AXI_DATA_WIDTH = 32'd0, + parameter int unsigned AXI_USER_WIDTH = 32'd0, + parameter int unsigned NO_MST_PORTS = 32'd3, + parameter int unsigned MAX_TRANS = 32'd8, + parameter int unsigned AXI_LOOK_BITS = 32'd3, + parameter bit UNIQUE_IDS = 1'b0, + parameter bit SPILL_AW = 1'b1, + parameter bit SPILL_W = 1'b0, + parameter bit SPILL_B = 1'b0, + 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 +) ( + input logic clk_i, // Clock + input logic rst_ni, // Asynchronous reset active low + input logic test_i, // Testmode enable + input select_t slv_aw_select_i, // has to be stable, when aw_valid + input 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 +); + + typedef logic [AXI_ID_WIDTH-1:0] id_t; + typedef logic [AXI_ADDR_WIDTH-1:0] addr_t; + typedef logic [AXI_DATA_WIDTH-1:0] data_t; + typedef logic [AXI_DATA_WIDTH/8-1:0] strb_t; + typedef logic [AXI_USER_WIDTH-1:0] user_t; + `AXI_TYPEDEF_AW_CHAN_T(aw_chan_t, addr_t, id_t, user_t) + `AXI_TYPEDEF_W_CHAN_T(w_chan_t, data_t, strb_t, user_t) + `AXI_TYPEDEF_B_CHAN_T(b_chan_t, id_t, user_t) + `AXI_TYPEDEF_AR_CHAN_T(ar_chan_t, addr_t, id_t, user_t) + `AXI_TYPEDEF_R_CHAN_T(r_chan_t, data_t, id_t, user_t) + `AXI_TYPEDEF_REQ_T(axi_req_t, aw_chan_t, w_chan_t, ar_chan_t) + `AXI_TYPEDEF_RESP_T(axi_resp_t, b_chan_t, r_chan_t) + + axi_req_t slv_req; + axi_resp_t slv_resp; + axi_req_t [NO_MST_PORTS-1:0] mst_req; + axi_resp_t [NO_MST_PORTS-1:0] mst_resp; + + `AXI_ASSIGN_TO_REQ(slv_req, slv) + `AXI_ASSIGN_FROM_RESP(slv, slv_resp) + + for (genvar i = 0; i < NO_MST_PORTS; i++) begin : gen_assign_mst_ports + `AXI_ASSIGN_FROM_REQ(mst[i], mst_req[i]) + `AXI_ASSIGN_TO_RESP(mst_resp[i], mst[i]) + end + + axi_demux #( + .AxiIdWidth ( AXI_ID_WIDTH ), // ID Width + .AtopSupport ( ATOP_SUPPORT ), + .aw_chan_t ( aw_chan_t ), // AW Channel Type + .w_chan_t ( w_chan_t ), // W Channel Type + .b_chan_t ( b_chan_t ), // B Channel Type + .ar_chan_t ( ar_chan_t ), // AR Channel Type + .r_chan_t ( r_chan_t ), // R Channel Type + .axi_req_t ( axi_req_t ), + .axi_resp_t ( axi_resp_t ), + .NoMstPorts ( NO_MST_PORTS ), + .MaxTrans ( MAX_TRANS ), + .AxiLookBits ( AXI_LOOK_BITS ), + .UniqueIds ( UNIQUE_IDS ), + .SpillAw ( SPILL_AW ), + .SpillW ( SPILL_W ), + .SpillB ( SPILL_B ), + .SpillAr ( SPILL_AR ), + .SpillR ( SPILL_R ) + ) i_axi_demux ( + .clk_i, // Clock + .rst_ni, // Asynchronous reset active low + .test_i, // Testmode enable + // slave port + .slv_req_i ( slv_req ), + .slv_aw_select_i ( slv_aw_select_i ), + .slv_ar_select_i ( slv_ar_select_i ), + .slv_resp_o ( slv_resp ), + // master port + .mst_reqs_o ( mst_req ), + .mst_resps_i ( mst_resp ) + ); +endmodule diff --git a/src/axi_mcast_mux.sv b/src/axi_mcast_mux.sv new file mode 100644 index 000000000..da17e2b8c --- /dev/null +++ b/src/axi_mcast_mux.sv @@ -0,0 +1,598 @@ +// Copyright (c) 2019 ETH Zurich, University of Bologna +// +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. +// +// Authors: +// - Wolfgang Roenninger +// - Andreas Kurth + +// AXI Multiplexer: This module multiplexes the AXI4 slave ports down to one master port. +// The AXI IDs from the slave ports get extended with the respective slave port index. +// The extension width can be calculated with `$clog2(NoSlvPorts)`. This means the AXI +// ID for the master port has to be this `$clog2(NoSlvPorts)` wider than the ID for the +// slave ports. +// Responses are switched based on these bits. For example, with 4 slave ports +// a response with ID `6'b100110` will be forwarded to slave port 2 (`2'b10`). + +// register macros +`include "common_cells/assertions.svh" +`include "common_cells/registers.svh" + +module axi_mux #( + // AXI parameter and channel types + parameter int unsigned SlvAxiIDWidth = 32'd0, // AXI ID width, slave ports + parameter type slv_aw_chan_t = logic, // AW Channel Type, slave ports + parameter type mst_aw_chan_t = logic, // AW Channel Type, master port + parameter type w_chan_t = logic, // W Channel Type, all ports + parameter type slv_b_chan_t = logic, // B Channel Type, slave ports + parameter type mst_b_chan_t = logic, // B Channel Type, master port + parameter type slv_ar_chan_t = logic, // AR Channel Type, slave ports + parameter type mst_ar_chan_t = logic, // AR Channel Type, master port + parameter type slv_r_chan_t = logic, // R Channel Type, slave ports + parameter type mst_r_chan_t = logic, // R Channel Type, master port + parameter type slv_req_t = logic, // Slave port request type + parameter type slv_resp_t = logic, // Slave port response type + parameter type mst_req_t = logic, // Master ports request type + parameter type mst_resp_t = logic, // Master ports response type + parameter int unsigned NoSlvPorts = 32'd0, // Number of slave ports + // Maximum number of outstanding transactions per write + parameter int unsigned MaxWTrans = 32'd8, + // If enabled, this multiplexer is purely combinatorial + parameter bit FallThrough = 1'b0, + // add spill register on write master ports, adds a cycle latency on write channels + parameter bit SpillAw = 1'b1, + parameter bit SpillW = 1'b0, + parameter bit SpillB = 1'b0, + // add spill register on read master ports, adds a cycle latency on read channels + parameter bit SpillAr = 1'b1, + parameter bit SpillR = 1'b0 +) ( + input logic clk_i, // Clock + input logic rst_ni, // Asynchronous reset active low + input logic test_i, // Test Mode enable + // slave ports (AXI inputs), connect master modules here + input slv_req_t [NoSlvPorts-1:0] slv_reqs_i, + output slv_resp_t [NoSlvPorts-1:0] slv_resps_o, + // master port (AXI outputs), connect slave modules here + output mst_req_t mst_req_o, + input mst_resp_t mst_resp_i +); + + localparam int unsigned MstIdxBits = $clog2(NoSlvPorts); + localparam int unsigned MstAxiIDWidth = SlvAxiIDWidth + MstIdxBits; + + // pass through if only one slave port + if (NoSlvPorts == 32'h1) begin : gen_no_mux + spill_register #( + .T ( mst_aw_chan_t ), + .Bypass ( ~SpillAw ) + ) i_aw_spill_reg ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .valid_i ( slv_reqs_i[0].aw_valid ), + .ready_o ( slv_resps_o[0].aw_ready ), + .data_i ( slv_reqs_i[0].aw ), + .valid_o ( mst_req_o.aw_valid ), + .ready_i ( mst_resp_i.aw_ready ), + .data_o ( mst_req_o.aw ) + ); + spill_register #( + .T ( w_chan_t ), + .Bypass ( ~SpillW ) + ) i_w_spill_reg ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .valid_i ( slv_reqs_i[0].w_valid ), + .ready_o ( slv_resps_o[0].w_ready ), + .data_i ( slv_reqs_i[0].w ), + .valid_o ( mst_req_o.w_valid ), + .ready_i ( mst_resp_i.w_ready ), + .data_o ( mst_req_o.w ) + ); + spill_register #( + .T ( mst_b_chan_t ), + .Bypass ( ~SpillB ) + ) i_b_spill_reg ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .valid_i ( mst_resp_i.b_valid ), + .ready_o ( mst_req_o.b_ready ), + .data_i ( mst_resp_i.b ), + .valid_o ( slv_resps_o[0].b_valid ), + .ready_i ( slv_reqs_i[0].b_ready ), + .data_o ( slv_resps_o[0].b ) + ); + spill_register #( + .T ( mst_ar_chan_t ), + .Bypass ( ~SpillAr ) + ) i_ar_spill_reg ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .valid_i ( slv_reqs_i[0].ar_valid ), + .ready_o ( slv_resps_o[0].ar_ready ), + .data_i ( slv_reqs_i[0].ar ), + .valid_o ( mst_req_o.ar_valid ), + .ready_i ( mst_resp_i.ar_ready ), + .data_o ( mst_req_o.ar ) + ); + spill_register #( + .T ( mst_r_chan_t ), + .Bypass ( ~SpillR ) + ) i_r_spill_reg ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .valid_i ( mst_resp_i.r_valid ), + .ready_o ( mst_req_o.r_ready ), + .data_i ( mst_resp_i.r ), + .valid_o ( slv_resps_o[0].r_valid ), + .ready_i ( slv_reqs_i[0].r_ready ), + .data_o ( slv_resps_o[0].r ) + ); +// Validate parameters. +// pragma translate_off + `ASSERT_INIT(CorrectIdWidthSlvAw, $bits(slv_reqs_i[0].aw.id) == SlvAxiIDWidth) + `ASSERT_INIT(CorrectIdWidthSlvB, $bits(slv_resps_o[0].b.id) == SlvAxiIDWidth) + `ASSERT_INIT(CorrectIdWidthSlvAr, $bits(slv_reqs_i[0].ar.id) == SlvAxiIDWidth) + `ASSERT_INIT(CorrectIdWidthSlvR, $bits(slv_resps_o[0].r.id) == SlvAxiIDWidth) + `ASSERT_INIT(CorrectIdWidthMstAw, $bits(mst_req_o.aw.id) == SlvAxiIDWidth) + `ASSERT_INIT(CorrectIdWidthMstB, $bits(mst_resp_i.b.id) == SlvAxiIDWidth) + `ASSERT_INIT(CorrectIdWidthMstAr, $bits(mst_req_o.ar.id) == SlvAxiIDWidth) + `ASSERT_INIT(CorrectIdWidthMstR, $bits(mst_resp_i.r.id) == SlvAxiIDWidth) +// pragma translate_on + + // other non degenerate cases + end else begin : gen_mux + + typedef logic [MstIdxBits-1:0] switch_id_t; + + // AXI channels between the ID prepend unit and the rest of the multiplexer + mst_aw_chan_t [NoSlvPorts-1:0] slv_aw_chans; + logic [NoSlvPorts-1:0] slv_aw_valids, slv_aw_readies; + w_chan_t [NoSlvPorts-1:0] slv_w_chans; + logic [NoSlvPorts-1:0] slv_w_valids, slv_w_readies; + mst_b_chan_t [NoSlvPorts-1:0] slv_b_chans; + logic [NoSlvPorts-1:0] slv_b_valids, slv_b_readies; + mst_ar_chan_t [NoSlvPorts-1:0] slv_ar_chans; + logic [NoSlvPorts-1:0] slv_ar_valids, slv_ar_readies; + mst_r_chan_t [NoSlvPorts-1:0] slv_r_chans; + logic [NoSlvPorts-1:0] slv_r_valids, slv_r_readies; + + // These signals are all ID prepended + // AW channel + mst_aw_chan_t mst_aw_chan; + logic mst_aw_valid, mst_aw_ready; + + // AW master handshake internal, so that we are able to stall, if w_fifo is full + logic aw_valid, aw_ready; + + // FF to lock the AW valid signal, when a new arbitration decision is made the decision + // gets pushed into the W FIFO, when it now stalls prevent subsequent pushing + // This FF removes AW to W dependency + logic lock_aw_valid_d, lock_aw_valid_q; + logic load_aw_lock; + + // signals for the FIFO that holds the last switching decision of the AW channel + logic w_fifo_full, w_fifo_empty; + logic w_fifo_push, w_fifo_pop; + switch_id_t w_fifo_data; + + // W channel spill reg + w_chan_t mst_w_chan; + logic mst_w_valid, mst_w_ready; + + // master ID in the b_id + switch_id_t switch_b_id; + + // B channel spill reg + mst_b_chan_t mst_b_chan; + logic mst_b_valid; + + // AR channel for when spill is enabled + mst_ar_chan_t mst_ar_chan; + logic ar_valid, ar_ready; + + // master ID in the r_id + switch_id_t switch_r_id; + + // R channel spill reg + mst_r_chan_t mst_r_chan; + logic mst_r_valid; + + //-------------------------------------- + // ID prepend for all slave ports + //-------------------------------------- + for (genvar i = 0; i < NoSlvPorts; i++) begin : gen_id_prepend + axi_id_prepend #( + .NoBus ( 32'd1 ), // one AXI bus per slave port + .AxiIdWidthSlvPort( SlvAxiIDWidth ), + .AxiIdWidthMstPort( MstAxiIDWidth ), + .slv_aw_chan_t ( slv_aw_chan_t ), + .slv_w_chan_t ( w_chan_t ), + .slv_b_chan_t ( slv_b_chan_t ), + .slv_ar_chan_t ( slv_ar_chan_t ), + .slv_r_chan_t ( slv_r_chan_t ), + .mst_aw_chan_t ( mst_aw_chan_t ), + .mst_w_chan_t ( w_chan_t ), + .mst_b_chan_t ( mst_b_chan_t ), + .mst_ar_chan_t ( mst_ar_chan_t ), + .mst_r_chan_t ( mst_r_chan_t ) + ) i_id_prepend ( + .pre_id_i ( switch_id_t'(i) ), + .slv_aw_chans_i ( slv_reqs_i[i].aw ), + .slv_aw_valids_i ( slv_reqs_i[i].aw_valid ), + .slv_aw_readies_o ( slv_resps_o[i].aw_ready ), + .slv_w_chans_i ( slv_reqs_i[i].w ), + .slv_w_valids_i ( slv_reqs_i[i].w_valid ), + .slv_w_readies_o ( slv_resps_o[i].w_ready ), + .slv_b_chans_o ( slv_resps_o[i].b ), + .slv_b_valids_o ( slv_resps_o[i].b_valid ), + .slv_b_readies_i ( slv_reqs_i[i].b_ready ), + .slv_ar_chans_i ( slv_reqs_i[i].ar ), + .slv_ar_valids_i ( slv_reqs_i[i].ar_valid ), + .slv_ar_readies_o ( slv_resps_o[i].ar_ready ), + .slv_r_chans_o ( slv_resps_o[i].r ), + .slv_r_valids_o ( slv_resps_o[i].r_valid ), + .slv_r_readies_i ( slv_reqs_i[i].r_ready ), + .mst_aw_chans_o ( slv_aw_chans[i] ), + .mst_aw_valids_o ( slv_aw_valids[i] ), + .mst_aw_readies_i ( slv_aw_readies[i] ), + .mst_w_chans_o ( slv_w_chans[i] ), + .mst_w_valids_o ( slv_w_valids[i] ), + .mst_w_readies_i ( slv_w_readies[i] ), + .mst_b_chans_i ( slv_b_chans[i] ), + .mst_b_valids_i ( slv_b_valids[i] ), + .mst_b_readies_o ( slv_b_readies[i] ), + .mst_ar_chans_o ( slv_ar_chans[i] ), + .mst_ar_valids_o ( slv_ar_valids[i] ), + .mst_ar_readies_i ( slv_ar_readies[i] ), + .mst_r_chans_i ( slv_r_chans[i] ), + .mst_r_valids_i ( slv_r_valids[i] ), + .mst_r_readies_o ( slv_r_readies[i] ) + ); + end + + //-------------------------------------- + // AW Channel + //-------------------------------------- + rr_arb_tree #( + .NumIn ( NoSlvPorts ), + .DataType ( mst_aw_chan_t ), + .AxiVldRdy( 1'b1 ), + .LockIn ( 1'b1 ) + ) i_aw_arbiter ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .flush_i( 1'b0 ), + .rr_i ( '0 ), + .req_i ( slv_aw_valids ), + .gnt_o ( slv_aw_readies ), + .data_i ( slv_aw_chans ), + .gnt_i ( aw_ready ), + .req_o ( aw_valid ), + .data_o ( mst_aw_chan ), + .idx_o ( ) + ); + + // control of the AW channel + always_comb begin + // default assignments + lock_aw_valid_d = lock_aw_valid_q; + load_aw_lock = 1'b0; + w_fifo_push = 1'b0; + mst_aw_valid = 1'b0; + aw_ready = 1'b0; + // had a downstream stall, be valid and send the AW along + if (lock_aw_valid_q) begin + mst_aw_valid = 1'b1; + // transaction + if (mst_aw_ready) begin + aw_ready = 1'b1; + lock_aw_valid_d = 1'b0; + load_aw_lock = 1'b1; + end + end else begin + if (!w_fifo_full && aw_valid) begin + mst_aw_valid = 1'b1; + w_fifo_push = 1'b1; + if (mst_aw_ready) begin + aw_ready = 1'b1; + end else begin + // go to lock if transaction not in this cycle + lock_aw_valid_d = 1'b1; + load_aw_lock = 1'b1; + end + end + end + end + + `FFLARN(lock_aw_valid_q, lock_aw_valid_d, load_aw_lock, '0, clk_i, rst_ni) + + fifo_v3 #( + .FALL_THROUGH ( FallThrough ), + .DEPTH ( MaxWTrans ), + .dtype ( switch_id_t ) + ) i_w_fifo ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .flush_i ( 1'b0 ), + .testmode_i( test_i ), + .full_o ( w_fifo_full ), + .empty_o ( w_fifo_empty ), + .usage_o ( ), + .data_i ( mst_aw_chan.id[SlvAxiIDWidth+:MstIdxBits] ), + .push_i ( w_fifo_push ), + .data_o ( w_fifo_data ), + .pop_i ( w_fifo_pop ) + ); + + spill_register #( + .T ( mst_aw_chan_t ), + .Bypass ( ~SpillAw ) // Param indicated that we want a spill reg + ) i_aw_spill_reg ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .valid_i ( mst_aw_valid ), + .ready_o ( mst_aw_ready ), + .data_i ( mst_aw_chan ), + .valid_o ( mst_req_o.aw_valid ), + .ready_i ( mst_resp_i.aw_ready ), + .data_o ( mst_req_o.aw ) + ); + + //-------------------------------------- + // W Channel + //-------------------------------------- + // multiplexer + assign mst_w_chan = slv_w_chans[w_fifo_data]; + always_comb begin + // default assignments + mst_w_valid = 1'b0; + slv_w_readies = '0; + w_fifo_pop = 1'b0; + // control + if (!w_fifo_empty) begin + // connect the handshake + mst_w_valid = slv_w_valids[w_fifo_data]; + slv_w_readies[w_fifo_data] = mst_w_ready; + // pop FIFO on a last transaction + w_fifo_pop = slv_w_valids[w_fifo_data] & mst_w_ready & mst_w_chan.last; + end + end + + spill_register #( + .T ( w_chan_t ), + .Bypass ( ~SpillW ) + ) i_w_spill_reg ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .valid_i ( mst_w_valid ), + .ready_o ( mst_w_ready ), + .data_i ( mst_w_chan ), + .valid_o ( mst_req_o.w_valid ), + .ready_i ( mst_resp_i.w_ready ), + .data_o ( mst_req_o.w ) + ); + + //-------------------------------------- + // B Channel + //-------------------------------------- + // replicate B channels + assign slv_b_chans = {NoSlvPorts{mst_b_chan}}; + // control B channel handshake + assign switch_b_id = mst_b_chan.id[SlvAxiIDWidth+:MstIdxBits]; + assign slv_b_valids = (mst_b_valid) ? (1 << switch_b_id) : '0; + + spill_register #( + .T ( mst_b_chan_t ), + .Bypass ( ~SpillB ) + ) i_b_spill_reg ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .valid_i ( mst_resp_i.b_valid ), + .ready_o ( mst_req_o.b_ready ), + .data_i ( mst_resp_i.b ), + .valid_o ( mst_b_valid ), + .ready_i ( slv_b_readies[switch_b_id] ), + .data_o ( mst_b_chan ) + ); + + //-------------------------------------- + // AR Channel + //-------------------------------------- + rr_arb_tree #( + .NumIn ( NoSlvPorts ), + .DataType ( mst_ar_chan_t ), + .AxiVldRdy( 1'b1 ), + .LockIn ( 1'b1 ) + ) i_ar_arbiter ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .flush_i( 1'b0 ), + .rr_i ( '0 ), + .req_i ( slv_ar_valids ), + .gnt_o ( slv_ar_readies ), + .data_i ( slv_ar_chans ), + .gnt_i ( ar_ready ), + .req_o ( ar_valid ), + .data_o ( mst_ar_chan ), + .idx_o ( ) + ); + + spill_register #( + .T ( mst_ar_chan_t ), + .Bypass ( ~SpillAr ) + ) i_ar_spill_reg ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .valid_i ( ar_valid ), + .ready_o ( ar_ready ), + .data_i ( mst_ar_chan ), + .valid_o ( mst_req_o.ar_valid ), + .ready_i ( mst_resp_i.ar_ready ), + .data_o ( mst_req_o.ar ) + ); + + //-------------------------------------- + // R Channel + //-------------------------------------- + // replicate R channels + assign slv_r_chans = {NoSlvPorts{mst_r_chan}}; + // R channel handshake control + assign switch_r_id = mst_r_chan.id[SlvAxiIDWidth+:MstIdxBits]; + assign slv_r_valids = (mst_r_valid) ? (1 << switch_r_id) : '0; + + spill_register #( + .T ( mst_r_chan_t ), + .Bypass ( ~SpillR ) + ) i_r_spill_reg ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .valid_i ( mst_resp_i.r_valid ), + .ready_o ( mst_req_o.r_ready ), + .data_i ( mst_resp_i.r ), + .valid_o ( mst_r_valid ), + .ready_i ( slv_r_readies[switch_r_id] ), + .data_o ( mst_r_chan ) + ); + end + +// pragma translate_off +`ifndef VERILATOR + initial begin + assert (SlvAxiIDWidth > 0) else $fatal(1, "AXI ID width of slave ports must be non-zero!"); + assert (NoSlvPorts > 0) else $fatal(1, "Number of slave ports must be non-zero!"); + assert (MaxWTrans > 0) + else $fatal(1, "Maximum number of outstanding writes must be non-zero!"); + assert (MstAxiIDWidth >= SlvAxiIDWidth + $clog2(NoSlvPorts)) + else $fatal(1, "AXI ID width of master ports must be wide enough to identify slave ports!"); + // Assert ID widths (one slave is sufficient since they all have the same type). + assert ($unsigned($bits(slv_reqs_i[0].aw.id)) == SlvAxiIDWidth) + else $fatal(1, "ID width of AW channel of slave ports does not match parameter!"); + assert ($unsigned($bits(slv_reqs_i[0].ar.id)) == SlvAxiIDWidth) + else $fatal(1, "ID width of AR channel of slave ports does not match parameter!"); + assert ($unsigned($bits(slv_resps_o[0].b.id)) == SlvAxiIDWidth) + else $fatal(1, "ID width of B channel of slave ports does not match parameter!"); + assert ($unsigned($bits(slv_resps_o[0].r.id)) == SlvAxiIDWidth) + else $fatal(1, "ID width of R channel of slave ports does not match parameter!"); + assert ($unsigned($bits(mst_req_o.aw.id)) == MstAxiIDWidth) + else $fatal(1, "ID width of AW channel of master port is wrong!"); + assert ($unsigned($bits(mst_req_o.ar.id)) == MstAxiIDWidth) + else $fatal(1, "ID width of AR channel of master port is wrong!"); + assert ($unsigned($bits(mst_resp_i.b.id)) == MstAxiIDWidth) + else $fatal(1, "ID width of B channel of master port is wrong!"); + assert ($unsigned($bits(mst_resp_i.r.id)) == MstAxiIDWidth) + else $fatal(1, "ID width of R channel of master port is wrong!"); + end +`endif +// pragma translate_on +endmodule + +// interface wrap +`include "axi/assign.svh" +`include "axi/typedef.svh" +module axi_mux_intf #( + parameter int unsigned SLV_AXI_ID_WIDTH = 32'd0, // Synopsys DC requires default value for params + parameter int unsigned MST_AXI_ID_WIDTH = 32'd0, + parameter int unsigned AXI_ADDR_WIDTH = 32'd0, + parameter int unsigned AXI_DATA_WIDTH = 32'd0, + parameter int unsigned AXI_USER_WIDTH = 32'd0, + parameter int unsigned NO_SLV_PORTS = 32'd0, // Number of slave ports + // Maximum number of outstanding transactions per write + parameter int unsigned MAX_W_TRANS = 32'd8, + // if enabled, this multiplexer is purely combinatorial + parameter bit FALL_THROUGH = 1'b0, + // add spill register on write master ports, adds a cycle latency on write channels + parameter bit SPILL_AW = 1'b1, + parameter bit SPILL_W = 1'b0, + parameter bit SPILL_B = 1'b0, + // add spill register on read master ports, adds a cycle latency on read channels + parameter bit SPILL_AR = 1'b1, + parameter bit SPILL_R = 1'b0 +) ( + input logic clk_i, // Clock + input logic rst_ni, // Asynchronous reset active low + input logic test_i, // Testmode enable + AXI_BUS.Slave slv [NO_SLV_PORTS-1:0], // slave ports + AXI_BUS.Master mst // master port +); + + typedef logic [SLV_AXI_ID_WIDTH-1:0] slv_id_t; + typedef logic [MST_AXI_ID_WIDTH-1:0] mst_id_t; + typedef logic [AXI_ADDR_WIDTH -1:0] addr_t; + typedef logic [AXI_DATA_WIDTH-1:0] data_t; + typedef logic [AXI_DATA_WIDTH/8-1:0] strb_t; + typedef logic [AXI_USER_WIDTH-1:0] user_t; + // channels typedef + `AXI_TYPEDEF_AW_CHAN_T(slv_aw_chan_t, addr_t, slv_id_t, user_t) + `AXI_TYPEDEF_AW_CHAN_T(mst_aw_chan_t, addr_t, mst_id_t, user_t) + + `AXI_TYPEDEF_W_CHAN_T(w_chan_t, data_t, strb_t, user_t) + + `AXI_TYPEDEF_B_CHAN_T(slv_b_chan_t, slv_id_t, user_t) + `AXI_TYPEDEF_B_CHAN_T(mst_b_chan_t, mst_id_t, user_t) + + `AXI_TYPEDEF_AR_CHAN_T(slv_ar_chan_t, addr_t, slv_id_t, user_t) + `AXI_TYPEDEF_AR_CHAN_T(mst_ar_chan_t, addr_t, mst_id_t, user_t) + + `AXI_TYPEDEF_R_CHAN_T(slv_r_chan_t, data_t, slv_id_t, user_t) + `AXI_TYPEDEF_R_CHAN_T(mst_r_chan_t, data_t, mst_id_t, user_t) + + `AXI_TYPEDEF_REQ_T(slv_req_t, slv_aw_chan_t, w_chan_t, slv_ar_chan_t) + `AXI_TYPEDEF_RESP_T(slv_resp_t, slv_b_chan_t, slv_r_chan_t) + + `AXI_TYPEDEF_REQ_T(mst_req_t, mst_aw_chan_t, w_chan_t, mst_ar_chan_t) + `AXI_TYPEDEF_RESP_T(mst_resp_t, mst_b_chan_t, mst_r_chan_t) + + slv_req_t [NO_SLV_PORTS-1:0] slv_reqs; + slv_resp_t [NO_SLV_PORTS-1:0] slv_resps; + mst_req_t mst_req; + mst_resp_t mst_resp; + + for (genvar i = 0; i < NO_SLV_PORTS; i++) begin : gen_assign_slv_ports + `AXI_ASSIGN_TO_REQ(slv_reqs[i], slv[i]) + `AXI_ASSIGN_FROM_RESP(slv[i], slv_resps[i]) + end + + `AXI_ASSIGN_FROM_REQ(mst, mst_req) + `AXI_ASSIGN_TO_RESP(mst_resp, mst) + + axi_mux #( + .SlvAxiIDWidth ( SLV_AXI_ID_WIDTH ), + .slv_aw_chan_t ( slv_aw_chan_t ), // AW Channel Type, slave ports + .mst_aw_chan_t ( mst_aw_chan_t ), // AW Channel Type, master port + .w_chan_t ( w_chan_t ), // W Channel Type, all ports + .slv_b_chan_t ( slv_b_chan_t ), // B Channel Type, slave ports + .mst_b_chan_t ( mst_b_chan_t ), // B Channel Type, master port + .slv_ar_chan_t ( slv_ar_chan_t ), // AR Channel Type, slave ports + .mst_ar_chan_t ( mst_ar_chan_t ), // AR Channel Type, master port + .slv_r_chan_t ( slv_r_chan_t ), // R Channel Type, slave ports + .mst_r_chan_t ( mst_r_chan_t ), // R Channel Type, master port + .slv_req_t ( slv_req_t ), + .slv_resp_t ( slv_resp_t ), + .mst_req_t ( mst_req_t ), + .mst_resp_t ( mst_resp_t ), + .NoSlvPorts ( NO_SLV_PORTS ), // Number of slave ports + .MaxWTrans ( MAX_W_TRANS ), + .FallThrough ( FALL_THROUGH ), + .SpillAw ( SPILL_AW ), + .SpillW ( SPILL_W ), + .SpillB ( SPILL_B ), + .SpillAr ( SPILL_AR ), + .SpillR ( SPILL_R ) + ) i_axi_mux ( + .clk_i ( clk_i ), // Clock + .rst_ni ( rst_ni ), // Asynchronous reset active low + .test_i ( test_i ), // Test Mode enable + .slv_reqs_i ( slv_reqs ), + .slv_resps_o ( slv_resps ), + .mst_req_o ( mst_req ), + .mst_resp_i ( mst_resp ) + ); +endmodule diff --git a/src/axi_mcast_xbar.sv b/src/axi_mcast_xbar.sv new file mode 100644 index 000000000..52769a66c --- /dev/null +++ b/src/axi_mcast_xbar.sv @@ -0,0 +1,437 @@ +// Copyright (c) 2019 ETH Zurich and University of Bologna. +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. +// +// Authors: +// - Wolfgang Roenninger +// - Andreas Kurth +// - Florian Zaruba + +/// axi_xbar: 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 +import cf_math_pkg::idx_width; +#( + /// Configuration struct for the crossbar see `axi_pkg` for fields and definitions. + parameter axi_pkg::xbar_cfg_t Cfg = '0, + /// Enable atomic operations support. + parameter bit ATOPs = 1'b1, + /// Connectivity matrix + parameter bit [Cfg.NoSlvPorts-1:0][Cfg.NoMstPorts-1:0] Connectivity = '1, + /// AXI4+ATOP AW channel struct type for the slave ports. + parameter type slv_aw_chan_t = logic, + /// AXI4+ATOP AW channel struct type for the master ports. + parameter type mst_aw_chan_t = logic, + /// AXI4+ATOP W channel struct type for all ports. + parameter type w_chan_t = logic, + /// AXI4+ATOP B channel struct type for the slave ports. + parameter type slv_b_chan_t = logic, + /// AXI4+ATOP B channel struct type for the master ports. + parameter type mst_b_chan_t = logic, + /// AXI4+ATOP AR channel struct type for the slave ports. + parameter type slv_ar_chan_t = logic, + /// AXI4+ATOP AR channel struct type for the master ports. + parameter type mst_ar_chan_t = logic, + /// AXI4+ATOP R channel struct type for the slave ports. + parameter type slv_r_chan_t = logic, + /// AXI4+ATOP R channel struct type for the master ports. + parameter type mst_r_chan_t = logic, + /// AXI4+ATOP request struct type for the slave ports. + parameter type slv_req_t = logic, + /// AXI4+ATOP response struct type for the slave ports. + parameter type slv_resp_t = logic, + /// AXI4+ATOP request struct type for the master ports. + parameter type mst_req_t = logic, + /// AXI4+ATOP response struct type for the master ports + parameter type mst_resp_t = logic, + /// Address rule type for the address decoders from `common_cells:addr_decode`. + /// Example types are provided in `axi_pkg`. + /// Required struct fields: + /// ``` + /// typedef struct packed { + /// int unsigned idx; + /// axi_addr_t start_addr; + /// axi_addr_t end_addr; + /// } rule_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 +) ( + /// Clock, positive edge triggered. + input logic clk_i, + /// Asynchronous reset, active low. + input logic rst_ni, + /// Testmode enable, active high. + input logic test_i, + /// AXI4+ATOP requests to the slave ports. + input slv_req_t [Cfg.NoSlvPorts-1:0] slv_ports_req_i, + /// AXI4+ATOP responses of the slave ports. + output slv_resp_t [Cfg.NoSlvPorts-1:0] slv_ports_resp_o, + /// AXI4+ATOP requests of the master ports. + output mst_req_t [Cfg.NoMstPorts-1:0] mst_ports_req_o, + /// AXI4+ATOP responses to the master ports. + 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. + /// Each master port can have multiple different rules. + 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 tpye for inidvidual address signals + 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 + + // signals from the axi_demuxes, one index more for decode error + slv_req_t [Cfg.NoSlvPorts-1:0][Cfg.NoMstPorts:0] slv_reqs; + slv_resp_t [Cfg.NoSlvPorts-1:0][Cfg.NoMstPorts:0] slv_resps; + + // workaround for issue #133 (problem with vsim 10.6c) + localparam int unsigned cfg_NoMstPorts = Cfg.NoMstPorts; + + // signals into the axi_muxes, are of type slave as the multiplexer extends the ID + slv_req_t [Cfg.NoMstPorts-1:0][Cfg.NoSlvPorts-1:0] mst_reqs; + 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; + + addr_decode #( + .NoIndices ( Cfg.NoMstPorts ), + .NoRules ( Cfg.NoAddrRules ), + .addr_t ( addr_t ), + .rule_t ( rule_t ) + ) i_axi_aw_decode ( + .addr_i ( slv_ports_req_i[i].aw.addr ), + .addr_map_i ( addr_map_i ), + .idx_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] ) + ); + + addr_decode #( + .NoIndices ( Cfg.NoMstPorts ), + .addr_t ( addr_t ), + .NoRules ( Cfg.NoAddrRules ), + .rule_t ( rule_t ) + ) i_axi_ar_decode ( + .addr_i ( slv_ports_req_i[i].ar.addr ), + .addr_map_i ( addr_map_i ), + .idx_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] ) + ); + + assign slv_aw_select = (dec_aw_error) ? + mst_port_idx_t'(Cfg.NoMstPorts) : mst_port_idx_t'(dec_aw); + assign slv_ar_select = (dec_ar_error) ? + mst_port_idx_t'(Cfg.NoMstPorts) : mst_port_idx_t'(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 #( + .AxiIdWidth ( Cfg.AxiIdWidthSlvPorts ), // ID Width + .AtopSupport ( ATOPs ), + .aw_chan_t ( slv_aw_chan_t ), // AW Channel Type + .w_chan_t ( w_chan_t ), // W Channel Type + .b_chan_t ( slv_b_chan_t ), // B Channel Type + .ar_chan_t ( slv_ar_chan_t ), // AR Channel Type + .r_chan_t ( slv_r_chan_t ), // R Channel Type + .axi_req_t ( slv_req_t ), + .axi_resp_t ( slv_resp_t ), + .NoMstPorts ( Cfg.NoMstPorts + 1 ), + .MaxTrans ( Cfg.MaxMstTrans ), + .AxiLookBits ( Cfg.AxiIdUsedSlvPorts ), + .UniqueIds ( Cfg.UniqueIds ), + .SpillAw ( Cfg.LatencyMode[9] ), + .SpillW ( Cfg.LatencyMode[8] ), + .SpillB ( Cfg.LatencyMode[7] ), + .SpillAr ( Cfg.LatencyMode[6] ), + .SpillR ( Cfg.LatencyMode[5] ) + ) i_axi_demux ( + .clk_i, // Clock + .rst_ni, // Asynchronous reset active low + .test_i, // Testmode enable + .slv_req_i ( slv_ports_req_i[i] ), + .slv_aw_select_i ( slv_aw_select ), + .slv_ar_select_i ( slv_ar_select ), + .slv_resp_o ( slv_ports_resp_o[i] ), + .mst_reqs_o ( slv_reqs[i] ), + .mst_resps_i ( slv_resps[i] ) + ); + + axi_err_slv #( + .AxiIdWidth ( Cfg.AxiIdWidthSlvPorts ), + .axi_req_t ( slv_req_t ), + .axi_resp_t ( slv_resp_t ), + .Resp ( axi_pkg::RESP_DECERR ), + .ATOPs ( ATOPs ), + .MaxTrans ( 4 ) // Transactions terminate at this slave, so minimize + // resource consumption by accepting only a few + // transactions at a time. + ) i_axi_err_slv ( + .clk_i, // Clock + .rst_ni, // Asynchronous reset active low + .test_i, // Testmode enable + // slave port + .slv_req_i ( slv_reqs[i][Cfg.NoMstPorts] ), + .slv_resp_o ( slv_resps[i][cfg_NoMstPorts] ) + ); + end + + // cross all channels + for (genvar i = 0; i < Cfg.NoSlvPorts; i++) begin : gen_xbar_slv_cross + for (genvar j = 0; j < Cfg.NoMstPorts; j++) begin : gen_xbar_mst_cross + if (Connectivity[i][j]) begin : gen_connection + axi_multicut #( + .NoCuts ( Cfg.PipelineStages ), + .aw_chan_t ( slv_aw_chan_t ), + .w_chan_t ( w_chan_t ), + .b_chan_t ( slv_b_chan_t ), + .ar_chan_t ( slv_ar_chan_t ), + .r_chan_t ( slv_r_chan_t ), + .axi_req_t ( slv_req_t ), + .axi_resp_t ( slv_resp_t ) + ) i_axi_multicut_xbar_pipeline ( + .clk_i, + .rst_ni, + .slv_req_i ( slv_reqs[i][j] ), + .slv_resp_o ( slv_resps[i][j] ), + .mst_req_o ( mst_reqs[j][i] ), + .mst_resp_i ( mst_resps[j][i] ) + ); + + end else begin : gen_no_connection + assign mst_reqs[j][i] = '0; + axi_err_slv #( + .AxiIdWidth ( Cfg.AxiIdWidthSlvPorts ), + .axi_req_t ( slv_req_t ), + .axi_resp_t ( slv_resp_t ), + .Resp ( axi_pkg::RESP_DECERR ), + .ATOPs ( ATOPs ), + .MaxTrans ( 1 ) + ) i_axi_err_slv ( + .clk_i, + .rst_ni, + .test_i, + .slv_req_i ( slv_reqs[i][j] ), + .slv_resp_o ( slv_resps[i][j] ) + ); + end + end + end + + for (genvar i = 0; i < Cfg.NoMstPorts; i++) begin : gen_mst_port_mux + axi_mux #( + .SlvAxiIDWidth ( Cfg.AxiIdWidthSlvPorts ), // ID width of the slave ports + .slv_aw_chan_t ( slv_aw_chan_t ), // AW Channel Type, slave ports + .mst_aw_chan_t ( mst_aw_chan_t ), // AW Channel Type, master port + .w_chan_t ( w_chan_t ), // W Channel Type, all ports + .slv_b_chan_t ( slv_b_chan_t ), // B Channel Type, slave ports + .mst_b_chan_t ( mst_b_chan_t ), // B Channel Type, master port + .slv_ar_chan_t ( slv_ar_chan_t ), // AR Channel Type, slave ports + .mst_ar_chan_t ( mst_ar_chan_t ), // AR Channel Type, master port + .slv_r_chan_t ( slv_r_chan_t ), // R Channel Type, slave ports + .mst_r_chan_t ( mst_r_chan_t ), // R Channel Type, master port + .slv_req_t ( slv_req_t ), + .slv_resp_t ( slv_resp_t ), + .mst_req_t ( mst_req_t ), + .mst_resp_t ( mst_resp_t ), + .NoSlvPorts ( Cfg.NoSlvPorts ), // Number of Masters for the module + .MaxWTrans ( Cfg.MaxSlvTrans ), + .FallThrough ( Cfg.FallThrough ), + .SpillAw ( Cfg.LatencyMode[4] ), + .SpillW ( Cfg.LatencyMode[3] ), + .SpillB ( Cfg.LatencyMode[2] ), + .SpillAr ( Cfg.LatencyMode[1] ), + .SpillR ( Cfg.LatencyMode[0] ) + ) i_axi_mux ( + .clk_i, // Clock + .rst_ni, // Asynchronous reset active low + .test_i, // Test Mode enable + .slv_reqs_i ( mst_reqs[i] ), + .slv_resps_o ( mst_resps[i] ), + .mst_req_o ( mst_ports_req_o[i] ), + .mst_resp_i ( mst_ports_resp_i[i] ) + ); + end + + // pragma translate_off + `ifndef VERILATOR + `ifndef XSIM + initial begin : check_params + id_slv_req_ports: assert ($bits(slv_ports_req_i[0].aw.id ) == Cfg.AxiIdWidthSlvPorts) else + $fatal(1, $sformatf("Slv_req and aw_chan id width not equal.")); + id_slv_resp_ports: assert ($bits(slv_ports_resp_o[0].r.id) == Cfg.AxiIdWidthSlvPorts) else + $fatal(1, $sformatf("Slv_req and aw_chan id width not equal.")); + end + `endif + `endif + // pragma translate_on +endmodule + +`include "axi/assign.svh" +`include "axi/typedef.svh" + +module axi_xbar_intf +import cf_math_pkg::idx_width; +#( + parameter int unsigned AXI_USER_WIDTH = 0, + 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 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 +); + + localparam int unsigned AxiIdWidthMstPorts = Cfg.AxiIdWidthSlvPorts + $clog2(Cfg.NoSlvPorts); + + typedef logic [AxiIdWidthMstPorts -1:0] id_mst_t; + typedef logic [Cfg.AxiIdWidthSlvPorts -1:0] id_slv_t; + typedef logic [Cfg.AxiAddrWidth -1:0] addr_t; + typedef logic [Cfg.AxiDataWidth -1:0] data_t; + typedef logic [Cfg.AxiDataWidth/8 -1:0] strb_t; + typedef logic [AXI_USER_WIDTH -1:0] user_t; + + `AXI_TYPEDEF_AW_CHAN_T(mst_aw_chan_t, addr_t, id_mst_t, user_t) + `AXI_TYPEDEF_AW_CHAN_T(slv_aw_chan_t, addr_t, id_slv_t, user_t) + `AXI_TYPEDEF_W_CHAN_T(w_chan_t, data_t, strb_t, user_t) + `AXI_TYPEDEF_B_CHAN_T(mst_b_chan_t, id_mst_t, user_t) + `AXI_TYPEDEF_B_CHAN_T(slv_b_chan_t, id_slv_t, user_t) + `AXI_TYPEDEF_AR_CHAN_T(mst_ar_chan_t, addr_t, id_mst_t, user_t) + `AXI_TYPEDEF_AR_CHAN_T(slv_ar_chan_t, addr_t, id_slv_t, user_t) + `AXI_TYPEDEF_R_CHAN_T(mst_r_chan_t, data_t, id_mst_t, user_t) + `AXI_TYPEDEF_R_CHAN_T(slv_r_chan_t, data_t, id_slv_t, user_t) + `AXI_TYPEDEF_REQ_T(mst_req_t, mst_aw_chan_t, w_chan_t, mst_ar_chan_t) + `AXI_TYPEDEF_REQ_T(slv_req_t, slv_aw_chan_t, w_chan_t, slv_ar_chan_t) + `AXI_TYPEDEF_RESP_T(mst_resp_t, mst_b_chan_t, mst_r_chan_t) + `AXI_TYPEDEF_RESP_T(slv_resp_t, slv_b_chan_t, slv_r_chan_t) + + mst_req_t [Cfg.NoMstPorts-1:0] mst_reqs; + mst_resp_t [Cfg.NoMstPorts-1:0] mst_resps; + slv_req_t [Cfg.NoSlvPorts-1:0] slv_reqs; + slv_resp_t [Cfg.NoSlvPorts-1:0] slv_resps; + + for (genvar i = 0; i < Cfg.NoMstPorts; i++) begin : gen_assign_mst + `AXI_ASSIGN_FROM_REQ(mst_ports[i], mst_reqs[i]) + `AXI_ASSIGN_TO_RESP(mst_resps[i], mst_ports[i]) + end + + for (genvar i = 0; i < Cfg.NoSlvPorts; i++) begin : gen_assign_slv + `AXI_ASSIGN_TO_REQ(slv_reqs[i], slv_ports[i]) + `AXI_ASSIGN_FROM_RESP(slv_ports[i], slv_resps[i]) + end + + axi_xbar #( + .Cfg (Cfg), + .ATOPs ( ATOPS ), + .Connectivity ( CONNECTIVITY ), + .slv_aw_chan_t ( slv_aw_chan_t ), + .mst_aw_chan_t ( mst_aw_chan_t ), + .w_chan_t ( w_chan_t ), + .slv_b_chan_t ( slv_b_chan_t ), + .mst_b_chan_t ( mst_b_chan_t ), + .slv_ar_chan_t ( slv_ar_chan_t ), + .mst_ar_chan_t ( mst_ar_chan_t ), + .slv_r_chan_t ( slv_r_chan_t ), + .mst_r_chan_t ( mst_r_chan_t ), + .slv_req_t ( slv_req_t ), + .slv_resp_t ( slv_resp_t ), + .mst_req_t ( mst_req_t ), + .mst_resp_t ( mst_resp_t ), + .rule_t ( rule_t ) + ) i_xbar ( + .clk_i, + .rst_ni, + .test_i, + .slv_ports_req_i (slv_reqs ), + .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 + ); + +endmodule diff --git a/test/tb_axi_mcast_xbar.sv b/test/tb_axi_mcast_xbar.sv new file mode 100644 index 000000000..6056be919 --- /dev/null +++ b/test/tb_axi_mcast_xbar.sv @@ -0,0 +1,465 @@ +// Copyright (c) 2019 ETH Zurich and University of Bologna. +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. +// +// Authors: +// - Wolfgang Roenninger +// - Florian Zaruba +// - Andreas Kurth + +// Directed Random Verification Testbench for `axi_xbar`: The crossbar is instantiated with +// a number of random axi master and slave modules. Each random master executes a fixed number of +// writes and reads over the whole addess map. All masters simultaneously issue transactions +// through the crossbar, thereby saturating it. A monitor, which snoops the transactions of each +// master and slave port and models the crossbar with a network of FIFOs, checks whether each +// transaction follows the expected route. + +`include "axi/typedef.svh" +`include "axi/assign.svh" + +/// Testbench for the module `axi_xbar`. +module tb_axi_xbar #( + /// Number of AXI masters connected to the xbar. (Number of slave ports) + parameter int unsigned TbNumMasters = 32'd6, + /// Number of AXI slaves connected to the xbar. (Number of master ports) + parameter int unsigned TbNumSlaves = 32'd8, + /// Number of write transactions per master. + parameter int unsigned TbNumWrites = 32'd200, + /// Number of read transactions per master. + parameter int unsigned TbNumReads = 32'd200, + /// AXI4+ATOP ID width of the masters connected to the slave ports of the DUT. + /// The ID width of the slaves is calculated depending on the xbar configuration. + parameter int unsigned TbAxiIdWidthMasters = 32'd5, + /// The used ID width of the DUT. + /// Has to be `TbAxiIdWidthMasters >= TbAxiIdUsed`. + parameter int unsigned TbAxiIdUsed = 32'd3, + /// Data width of the AXI channels. + parameter int unsigned TbAxiDataWidth = 32'd64, + /// Pipeline stages in the xbar itself (between demux and mux). + parameter int unsigned TbPipeline = 32'd1, + /// Enable ATOP generation + parameter bit TbEnAtop = 1'b1, + /// Enable exclusive accesses + parameter bit TbEnExcl = 1'b0, + /// Restrict to only unique IDs + parameter bit TbUniqueIds = 1'b0 + +); + + // TB timing parameters + localparam time CyclTime = 10ns; + localparam time ApplTime = 2ns; + localparam time TestTime = 8ns; + + // AXI configuration which is automatically derived. + localparam int unsigned TbAxiIdWidthSlaves = TbAxiIdWidthMasters + $clog2(TbNumMasters); + localparam int unsigned TbAxiAddrWidth = 32'd32; + localparam int unsigned TbAxiStrbWidth = TbAxiDataWidth / 8; + localparam int unsigned TbAxiUserWidth = 5; + // In the bench can change this variables which are set here freely, + localparam axi_pkg::xbar_cfg_t xbar_cfg = '{ + NoSlvPorts: TbNumMasters, + NoMstPorts: TbNumSlaves, + MaxMstTrans: 10, + MaxSlvTrans: 6, + FallThrough: 1'b0, + LatencyMode: axi_pkg::CUT_ALL_AX, + PipelineStages: TbPipeline, + AxiIdWidthSlvPorts: TbAxiIdWidthMasters, + AxiIdUsedSlvPorts: TbAxiIdUsed, + UniqueIds: TbUniqueIds, + AxiAddrWidth: TbAxiAddrWidth, + AxiDataWidth: TbAxiDataWidth, + NoAddrRules: TbNumSlaves + }; + typedef logic [TbAxiIdWidthMasters-1:0] id_mst_t; + typedef logic [TbAxiIdWidthSlaves-1:0] id_slv_t; + typedef logic [TbAxiAddrWidth-1:0] addr_t; + typedef axi_pkg::xbar_rule_32_t rule_t; // Has to be the same width as axi addr + typedef logic [TbAxiDataWidth-1:0] data_t; + typedef logic [TbAxiStrbWidth-1:0] strb_t; + typedef logic [TbAxiUserWidth-1:0] user_t; + + `AXI_TYPEDEF_AW_CHAN_T(aw_chan_mst_t, addr_t, id_mst_t, user_t) + `AXI_TYPEDEF_AW_CHAN_T(aw_chan_slv_t, addr_t, id_slv_t, user_t) + `AXI_TYPEDEF_W_CHAN_T(w_chan_t, data_t, strb_t, user_t) + `AXI_TYPEDEF_B_CHAN_T(b_chan_mst_t, id_mst_t, user_t) + `AXI_TYPEDEF_B_CHAN_T(b_chan_slv_t, id_slv_t, user_t) + + `AXI_TYPEDEF_AR_CHAN_T(ar_chan_mst_t, addr_t, id_mst_t, user_t) + `AXI_TYPEDEF_AR_CHAN_T(ar_chan_slv_t, addr_t, id_slv_t, user_t) + `AXI_TYPEDEF_R_CHAN_T(r_chan_mst_t, data_t, id_mst_t, user_t) + `AXI_TYPEDEF_R_CHAN_T(r_chan_slv_t, data_t, id_slv_t, user_t) + + `AXI_TYPEDEF_REQ_T(mst_req_t, aw_chan_mst_t, w_chan_t, ar_chan_mst_t) + `AXI_TYPEDEF_RESP_T(mst_resp_t, b_chan_mst_t, r_chan_mst_t) + `AXI_TYPEDEF_REQ_T(slv_req_t, aw_chan_slv_t, w_chan_t, ar_chan_slv_t) + `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(); + + function rule_t [xbar_cfg.NoAddrRules-1:0] addr_map_gen (); + for (int unsigned i = 0; i < xbar_cfg.NoAddrRules; i++) begin + addr_map_gen[i] = rule_t'{ + idx: unsigned'(i), + start_addr: i * 32'h0000_2000, + end_addr: (i+1) * 32'h0000_2000, + default: '0 + }; + end + endfunction + + typedef axi_test::axi_rand_master #( + // AXI interface parameters + .AW ( TbAxiAddrWidth ), + .DW ( TbAxiDataWidth ), + .IW ( TbAxiIdWidthMasters ), + .UW ( TbAxiUserWidth ), + // Stimuli application and test time + .TA ( ApplTime ), + .TT ( TestTime ), + // Maximum number of read and write transactions in flight + .MAX_READ_TXNS ( 20 ), + .MAX_WRITE_TXNS ( 20 ), + .AXI_EXCLS ( TbEnExcl ), + .AXI_ATOPS ( TbEnAtop ), + .UNIQUE_IDS ( TbUniqueIds ) + ) axi_rand_master_t; + typedef axi_test::axi_rand_slave #( + // AXI interface parameters + .AW ( TbAxiAddrWidth ), + .DW ( TbAxiDataWidth ), + .IW ( TbAxiIdWidthSlaves ), + .UW ( TbAxiUserWidth ), + // Stimuli application and test time + .TA ( ApplTime ), + .TT ( TestTime ) + ) axi_rand_slave_t; + + // ------------- + // DUT signals + // ------------- + logic clk; + // DUT signals + logic rst_n; + logic [TbNumMasters-1:0] end_of_sim; + + // master structs + mst_req_t [TbNumMasters-1:0] masters_req; + mst_resp_t [TbNumMasters-1:0] masters_resp; + + // slave structs + slv_req_t [TbNumSlaves-1:0] slaves_req; + slv_resp_t [TbNumSlaves-1:0] slaves_resp; + + // ------------------------------- + // AXI Interfaces + // ------------------------------- + AXI_BUS #( + .AXI_ADDR_WIDTH ( TbAxiAddrWidth ), + .AXI_DATA_WIDTH ( TbAxiDataWidth ), + .AXI_ID_WIDTH ( TbAxiIdWidthMasters ), + .AXI_USER_WIDTH ( TbAxiUserWidth ) + ) master [TbNumMasters-1:0] (); + AXI_BUS_DV #( + .AXI_ADDR_WIDTH ( TbAxiAddrWidth ), + .AXI_DATA_WIDTH ( TbAxiDataWidth ), + .AXI_ID_WIDTH ( TbAxiIdWidthMasters ), + .AXI_USER_WIDTH ( TbAxiUserWidth ) + ) master_dv [TbNumMasters-1:0] (clk); + AXI_BUS_DV #( + .AXI_ADDR_WIDTH ( TbAxiAddrWidth ), + .AXI_DATA_WIDTH ( TbAxiDataWidth ), + .AXI_ID_WIDTH ( TbAxiIdWidthMasters ), + .AXI_USER_WIDTH ( TbAxiUserWidth ) + ) master_monitor_dv [TbNumMasters-1:0] (clk); + for (genvar i = 0; i < TbNumMasters; i++) begin : gen_conn_dv_masters + `AXI_ASSIGN (master[i], master_dv[i]) + `AXI_ASSIGN_TO_REQ(masters_req[i], master[i]) + `AXI_ASSIGN_TO_RESP(masters_resp[i], master[i]) + end + + AXI_BUS #( + .AXI_ADDR_WIDTH ( TbAxiAddrWidth ), + .AXI_DATA_WIDTH ( TbAxiDataWidth ), + .AXI_ID_WIDTH ( TbAxiIdWidthSlaves ), + .AXI_USER_WIDTH ( TbAxiUserWidth ) + ) slave [TbNumSlaves-1:0] (); + AXI_BUS_DV #( + .AXI_ADDR_WIDTH ( TbAxiAddrWidth ), + .AXI_DATA_WIDTH ( TbAxiDataWidth ), + .AXI_ID_WIDTH ( TbAxiIdWidthSlaves ), + .AXI_USER_WIDTH ( TbAxiUserWidth ) + ) slave_dv [TbNumSlaves-1:0](clk); + AXI_BUS_DV #( + .AXI_ADDR_WIDTH ( TbAxiAddrWidth ), + .AXI_DATA_WIDTH ( TbAxiDataWidth ), + .AXI_ID_WIDTH ( TbAxiIdWidthSlaves ), + .AXI_USER_WIDTH ( TbAxiUserWidth ) + ) slave_monitor_dv [TbNumSlaves-1:0](clk); + for (genvar i = 0; i < TbNumSlaves; i++) begin : gen_conn_dv_slaves + `AXI_ASSIGN(slave_dv[i], slave[i]) + `AXI_ASSIGN_TO_REQ(slaves_req[i], slave[i]) + `AXI_ASSIGN_TO_RESP(slaves_resp[i], slave[i]) + end + // ------------------------------- + // AXI Rand Masters and Slaves + // ------------------------------- + // Masters control simulation run time + axi_rand_master_t axi_rand_master [TbNumMasters]; + for (genvar i = 0; i < TbNumMasters; i++) begin : gen_rand_master + initial begin + 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.NoAddrRules-1].end_addr, + axi_pkg::DEVICE_NONBUFFERABLE); + axi_rand_master[i].reset(); + @(posedge rst_n); + axi_rand_master[i].run(TbNumReads, TbNumWrites); + end_of_sim[i] <= 1'b1; + end + end + + axi_rand_slave_t axi_rand_slave [TbNumSlaves]; + for (genvar i = 0; i < TbNumSlaves; i++) begin : gen_rand_slave + initial begin + axi_rand_slave[i] = new( slave_dv[i] ); + axi_rand_slave[i].reset(); + @(posedge rst_n); + axi_rand_slave[i].run(); + end + end + + initial begin : proc_monitor + static tb_axi_xbar_pkg::axi_xbar_monitor #( + .AxiAddrWidth ( TbAxiAddrWidth ), + .AxiDataWidth ( TbAxiDataWidth ), + .AxiIdWidthMasters ( TbAxiIdWidthMasters ), + .AxiIdWidthSlaves ( TbAxiIdWidthSlaves ), + .AxiUserWidth ( TbAxiUserWidth ), + .NoMasters ( TbNumMasters ), + .NoSlaves ( TbNumSlaves ), + .NoAddrRules ( xbar_cfg.NoAddrRules ), + .rule_t ( rule_t ), + .AddrMap ( AddrMap ), + .TimeTest ( TestTime ) + ) monitor = new( master_monitor_dv, slave_monitor_dv ); + fork + monitor.run(); + do begin + #TestTime; + if(end_of_sim == '1) begin + monitor.print_result(); + $stop(); + end + @(posedge clk); + end while (1'b1); + join + end + + //----------------------------------- + // Clock generator + //----------------------------------- + clk_rst_gen #( + .ClkPeriod ( CyclTime ), + .RstClkCycles ( 5 ) + ) i_clk_gen ( + .clk_o (clk), + .rst_no(rst_n) + ); + + //----------------------------------- + // DUT + //----------------------------------- + axi_xbar_intf #( + .AXI_USER_WIDTH ( TbAxiUserWidth ), + .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 ) + ); + + // logger for master modules + for (genvar i = 0; i < TbNumMasters; i++) begin : gen_master_logger + axi_chan_logger #( + .TestTime ( TestTime ), // Time after clock, where sampling happens + .LoggerName( $sformatf("axi_logger_master_%0d", i)), + .aw_chan_t ( aw_chan_mst_t ), // axi AW type + .w_chan_t ( w_chan_t ), // axi W type + .b_chan_t ( b_chan_mst_t ), // axi B type + .ar_chan_t ( ar_chan_mst_t ), // axi AR type + .r_chan_t ( r_chan_mst_t ) // axi R type + ) i_mst_channel_logger ( + .clk_i ( clk ), // Clock + .rst_ni ( rst_n ), // Asynchronous reset active low, when `1'b0` no sampling + .end_sim_i ( &end_of_sim ), + // AW channel + .aw_chan_i ( masters_req[i].aw ), + .aw_valid_i ( masters_req[i].aw_valid ), + .aw_ready_i ( masters_resp[i].aw_ready ), + // W channel + .w_chan_i ( masters_req[i].w ), + .w_valid_i ( masters_req[i].w_valid ), + .w_ready_i ( masters_resp[i].w_ready ), + // B channel + .b_chan_i ( masters_resp[i].b ), + .b_valid_i ( masters_resp[i].b_valid ), + .b_ready_i ( masters_req[i].b_ready ), + // AR channel + .ar_chan_i ( masters_req[i].ar ), + .ar_valid_i ( masters_req[i].ar_valid ), + .ar_ready_i ( masters_resp[i].ar_ready ), + // R channel + .r_chan_i ( masters_resp[i].r ), + .r_valid_i ( masters_resp[i].r_valid ), + .r_ready_i ( masters_req[i].r_ready ) + ); + end + // logger for slave modules + for (genvar i = 0; i < TbNumSlaves; i++) begin : gen_slave_logger + axi_chan_logger #( + .TestTime ( TestTime ), // Time after clock, where sampling happens + .LoggerName( $sformatf("axi_logger_slave_%0d",i)), + .aw_chan_t ( aw_chan_slv_t ), // axi AW type + .w_chan_t ( w_chan_t ), // axi W type + .b_chan_t ( b_chan_slv_t ), // axi B type + .ar_chan_t ( ar_chan_slv_t ), // axi AR type + .r_chan_t ( r_chan_slv_t ) // axi R type + ) i_slv_channel_logger ( + .clk_i ( clk ), // Clock + .rst_ni ( rst_n ), // Asynchronous reset active low, when `1'b0` no sampling + .end_sim_i ( &end_of_sim ), + // AW channel + .aw_chan_i ( slaves_req[i].aw ), + .aw_valid_i ( slaves_req[i].aw_valid ), + .aw_ready_i ( slaves_resp[i].aw_ready ), + // W channel + .w_chan_i ( slaves_req[i].w ), + .w_valid_i ( slaves_req[i].w_valid ), + .w_ready_i ( slaves_resp[i].w_ready ), + // B channel + .b_chan_i ( slaves_resp[i].b ), + .b_valid_i ( slaves_resp[i].b_valid ), + .b_ready_i ( slaves_req[i].b_ready ), + // AR channel + .ar_chan_i ( slaves_req[i].ar ), + .ar_valid_i ( slaves_req[i].ar_valid ), + .ar_ready_i ( slaves_resp[i].ar_ready ), + // R channel + .r_chan_i ( slaves_resp[i].r ), + .r_valid_i ( slaves_resp[i].r_valid ), + .r_ready_i ( slaves_req[i].r_ready ) + ); + end + + + for (genvar i = 0; i < TbNumMasters; i++) begin : gen_connect_master_monitor + assign master_monitor_dv[i].aw_id = master[i].aw_id ; + assign master_monitor_dv[i].aw_addr = master[i].aw_addr ; + assign master_monitor_dv[i].aw_len = master[i].aw_len ; + assign master_monitor_dv[i].aw_size = master[i].aw_size ; + assign master_monitor_dv[i].aw_burst = master[i].aw_burst ; + assign master_monitor_dv[i].aw_lock = master[i].aw_lock ; + assign master_monitor_dv[i].aw_cache = master[i].aw_cache ; + assign master_monitor_dv[i].aw_prot = master[i].aw_prot ; + assign master_monitor_dv[i].aw_qos = master[i].aw_qos ; + assign master_monitor_dv[i].aw_region = master[i].aw_region; + assign master_monitor_dv[i].aw_atop = master[i].aw_atop ; + assign master_monitor_dv[i].aw_user = master[i].aw_user ; + assign master_monitor_dv[i].aw_valid = master[i].aw_valid ; + assign master_monitor_dv[i].aw_ready = master[i].aw_ready ; + assign master_monitor_dv[i].w_data = master[i].w_data ; + assign master_monitor_dv[i].w_strb = master[i].w_strb ; + assign master_monitor_dv[i].w_last = master[i].w_last ; + assign master_monitor_dv[i].w_user = master[i].w_user ; + assign master_monitor_dv[i].w_valid = master[i].w_valid ; + assign master_monitor_dv[i].w_ready = master[i].w_ready ; + assign master_monitor_dv[i].b_id = master[i].b_id ; + assign master_monitor_dv[i].b_resp = master[i].b_resp ; + assign master_monitor_dv[i].b_user = master[i].b_user ; + assign master_monitor_dv[i].b_valid = master[i].b_valid ; + assign master_monitor_dv[i].b_ready = master[i].b_ready ; + assign master_monitor_dv[i].ar_id = master[i].ar_id ; + assign master_monitor_dv[i].ar_addr = master[i].ar_addr ; + assign master_monitor_dv[i].ar_len = master[i].ar_len ; + assign master_monitor_dv[i].ar_size = master[i].ar_size ; + assign master_monitor_dv[i].ar_burst = master[i].ar_burst ; + assign master_monitor_dv[i].ar_lock = master[i].ar_lock ; + assign master_monitor_dv[i].ar_cache = master[i].ar_cache ; + assign master_monitor_dv[i].ar_prot = master[i].ar_prot ; + assign master_monitor_dv[i].ar_qos = master[i].ar_qos ; + assign master_monitor_dv[i].ar_region = master[i].ar_region; + assign master_monitor_dv[i].ar_user = master[i].ar_user ; + assign master_monitor_dv[i].ar_valid = master[i].ar_valid ; + assign master_monitor_dv[i].ar_ready = master[i].ar_ready ; + assign master_monitor_dv[i].r_id = master[i].r_id ; + assign master_monitor_dv[i].r_data = master[i].r_data ; + assign master_monitor_dv[i].r_resp = master[i].r_resp ; + assign master_monitor_dv[i].r_last = master[i].r_last ; + assign master_monitor_dv[i].r_user = master[i].r_user ; + assign master_monitor_dv[i].r_valid = master[i].r_valid ; + assign master_monitor_dv[i].r_ready = master[i].r_ready ; + end + for (genvar i = 0; i < TbNumSlaves; i++) begin : gen_connect_slave_monitor + assign slave_monitor_dv[i].aw_id = slave[i].aw_id ; + assign slave_monitor_dv[i].aw_addr = slave[i].aw_addr ; + assign slave_monitor_dv[i].aw_len = slave[i].aw_len ; + assign slave_monitor_dv[i].aw_size = slave[i].aw_size ; + assign slave_monitor_dv[i].aw_burst = slave[i].aw_burst ; + assign slave_monitor_dv[i].aw_lock = slave[i].aw_lock ; + assign slave_monitor_dv[i].aw_cache = slave[i].aw_cache ; + assign slave_monitor_dv[i].aw_prot = slave[i].aw_prot ; + assign slave_monitor_dv[i].aw_qos = slave[i].aw_qos ; + assign slave_monitor_dv[i].aw_region = slave[i].aw_region; + assign slave_monitor_dv[i].aw_atop = slave[i].aw_atop ; + assign slave_monitor_dv[i].aw_user = slave[i].aw_user ; + assign slave_monitor_dv[i].aw_valid = slave[i].aw_valid ; + assign slave_monitor_dv[i].aw_ready = slave[i].aw_ready ; + assign slave_monitor_dv[i].w_data = slave[i].w_data ; + assign slave_monitor_dv[i].w_strb = slave[i].w_strb ; + assign slave_monitor_dv[i].w_last = slave[i].w_last ; + assign slave_monitor_dv[i].w_user = slave[i].w_user ; + assign slave_monitor_dv[i].w_valid = slave[i].w_valid ; + assign slave_monitor_dv[i].w_ready = slave[i].w_ready ; + assign slave_monitor_dv[i].b_id = slave[i].b_id ; + assign slave_monitor_dv[i].b_resp = slave[i].b_resp ; + assign slave_monitor_dv[i].b_user = slave[i].b_user ; + assign slave_monitor_dv[i].b_valid = slave[i].b_valid ; + assign slave_monitor_dv[i].b_ready = slave[i].b_ready ; + assign slave_monitor_dv[i].ar_id = slave[i].ar_id ; + assign slave_monitor_dv[i].ar_addr = slave[i].ar_addr ; + assign slave_monitor_dv[i].ar_len = slave[i].ar_len ; + assign slave_monitor_dv[i].ar_size = slave[i].ar_size ; + assign slave_monitor_dv[i].ar_burst = slave[i].ar_burst ; + assign slave_monitor_dv[i].ar_lock = slave[i].ar_lock ; + assign slave_monitor_dv[i].ar_cache = slave[i].ar_cache ; + assign slave_monitor_dv[i].ar_prot = slave[i].ar_prot ; + assign slave_monitor_dv[i].ar_qos = slave[i].ar_qos ; + assign slave_monitor_dv[i].ar_region = slave[i].ar_region; + assign slave_monitor_dv[i].ar_user = slave[i].ar_user ; + assign slave_monitor_dv[i].ar_valid = slave[i].ar_valid ; + assign slave_monitor_dv[i].ar_ready = slave[i].ar_ready ; + assign slave_monitor_dv[i].r_id = slave[i].r_id ; + assign slave_monitor_dv[i].r_data = slave[i].r_data ; + assign slave_monitor_dv[i].r_resp = slave[i].r_resp ; + assign slave_monitor_dv[i].r_last = slave[i].r_last ; + assign slave_monitor_dv[i].r_user = slave[i].r_user ; + assign slave_monitor_dv[i].r_valid = slave[i].r_valid ; + assign slave_monitor_dv[i].r_ready = slave[i].r_ready ; + end +endmodule diff --git a/test/tb_axi_mcast_xbar_pkg.sv b/test/tb_axi_mcast_xbar_pkg.sv new file mode 100644 index 000000000..fb7098998 --- /dev/null +++ b/test/tb_axi_mcast_xbar_pkg.sv @@ -0,0 +1,503 @@ +// Copyright (c) 2019 ETH Zurich and University of Bologna. +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. +// +// Authors: +// - Florian Zaruba +// - Wolfgang Roenninger + +// `axi_xbar_monitor` implements an AXI bus monitor that is tuned for the AXI crossbar. +// It snoops on each of the slaves and master ports of the crossbar and +// populates FIFOs and ID queues to validate that no AXI beats get +// lost or sent to the wrong destination. + +package tb_axi_xbar_pkg; + class axi_xbar_monitor #( + parameter int unsigned AxiAddrWidth, + parameter int unsigned AxiDataWidth, + parameter int unsigned AxiIdWidthMasters, + parameter int unsigned AxiIdWidthSlaves, + parameter int unsigned AxiUserWidth, + parameter int unsigned NoMasters, + parameter int unsigned NoSlaves, + parameter int unsigned NoAddrRules, + parameter type rule_t, + parameter rule_t [NoAddrRules-1:0] AddrMap, + // Stimuli application and test time + parameter time TimeTest + ); + typedef logic [AxiIdWidthMasters-1:0] mst_axi_id_t; + typedef logic [AxiIdWidthSlaves-1:0] slv_axi_id_t; + typedef logic [AxiAddrWidth-1:0] axi_addr_t; + + typedef logic [$clog2(NoMasters)-1:0] idx_mst_t; + typedef int unsigned idx_slv_t; // from rule_t + + typedef struct packed { + mst_axi_id_t mst_axi_id; + logic last; + } master_exp_t; + typedef struct packed { + slv_axi_id_t slv_axi_id; + axi_addr_t slv_axi_addr; + axi_pkg::len_t slv_axi_len; + } exp_ax_t; + typedef struct packed { + slv_axi_id_t slv_axi_id; + logic last; + } slave_exp_t; + + typedef rand_id_queue_pkg::rand_id_queue #( + .data_t ( master_exp_t ), + .ID_WIDTH ( AxiIdWidthMasters ) + ) master_exp_queue_t; + typedef rand_id_queue_pkg::rand_id_queue #( + .data_t ( exp_ax_t ), + .ID_WIDTH ( AxiIdWidthSlaves ) + ) ax_queue_t; + + typedef rand_id_queue_pkg::rand_id_queue #( + .data_t ( slave_exp_t ), + .ID_WIDTH ( AxiIdWidthSlaves ) + ) slave_exp_queue_t; + + //----------------------------------------- + // Monitoring virtual interfaces + //----------------------------------------- + virtual AXI_BUS_DV #( + .AXI_ADDR_WIDTH ( AxiAddrWidth ), + .AXI_DATA_WIDTH ( AxiDataWidth ), + .AXI_ID_WIDTH ( AxiIdWidthMasters ), + .AXI_USER_WIDTH ( AxiUserWidth ) + ) masters_axi [NoMasters-1:0]; + virtual AXI_BUS_DV #( + .AXI_ADDR_WIDTH ( AxiAddrWidth ), + .AXI_DATA_WIDTH ( AxiDataWidth ), + .AXI_ID_WIDTH ( AxiIdWidthSlaves ), + .AXI_USER_WIDTH ( AxiUserWidth ) + ) slaves_axi [NoSlaves-1:0]; + //----------------------------------------- + // Queues and FIFOs to hold the expected ids + //----------------------------------------- + // Write transactions + ax_queue_t exp_aw_queue [NoSlaves-1:0]; + slave_exp_t exp_w_fifo [NoSlaves-1:0][$]; + slave_exp_t act_w_fifo [NoSlaves-1:0][$]; + master_exp_queue_t exp_b_queue [NoMasters-1:0]; + + // Read transactions + ax_queue_t exp_ar_queue [NoSlaves-1:0]; + master_exp_queue_t exp_r_queue [NoMasters-1:0]; + + //----------------------------------------- + // Bookkeeping + //----------------------------------------- + longint unsigned tests_expected; + longint unsigned tests_conducted; + longint unsigned tests_failed; + semaphore cnt_sem; + + //----------------------------------------- + // Constructor + //----------------------------------------- + function new( + virtual AXI_BUS_DV #( + .AXI_ADDR_WIDTH ( AxiAddrWidth ), + .AXI_DATA_WIDTH ( AxiDataWidth ), + .AXI_ID_WIDTH ( AxiIdWidthMasters ), + .AXI_USER_WIDTH ( AxiUserWidth ) + ) axi_masters_vif [NoMasters-1:0], + virtual AXI_BUS_DV #( + .AXI_ADDR_WIDTH ( AxiAddrWidth ), + .AXI_DATA_WIDTH ( AxiDataWidth ), + .AXI_ID_WIDTH ( AxiIdWidthSlaves ), + .AXI_USER_WIDTH ( AxiUserWidth ) + ) axi_slaves_vif [NoSlaves-1:0] + ); + begin + this.masters_axi = axi_masters_vif; + this.slaves_axi = axi_slaves_vif; + this.tests_expected = 0; + this.tests_conducted = 0; + this.tests_failed = 0; + for (int unsigned i = 0; i < NoMasters; i++) begin + this.exp_b_queue[i] = new; + this.exp_r_queue[i] = new; + end + for (int unsigned i = 0; i < NoSlaves; i++) begin + this.exp_aw_queue[i] = new; + this.exp_ar_queue[i] = new; + end + this.cnt_sem = new(1); + end + endfunction + + // when start the testing + task cycle_start; + #TimeTest; + endtask + + // when is cycle finished + task cycle_end; + @(posedge masters_axi[0].clk_i); + endtask + + // This task monitors a slave ports of the crossbar. Every time an AW beat is seen + // it populates an id queue at the right master port (if there is no expected decode error), + // populates the expected b response in its own id_queue and in case when 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); + idx_slv_t to_slave_idx; + exp_ax_t exp_aw; + slv_axi_id_t exp_aw_id; + bit decerr; + + master_exp_t exp_b; + + if (masters_axi[i].aw_valid && masters_axi[i].aw_ready) begin + // check if it should go to a decerror + decerr = 1'b1; + for (int unsigned j = 0; j < NoAddrRules; j++) begin + if ((masters_axi[i].aw_addr >= AddrMap[j].start_addr) && + (masters_axi[i].aw_addr < AddrMap[j].end_addr)) begin + to_slave_idx = idx_slv_t'(AddrMap[j].idx); + decerr = 1'b0; + end + end + // send the exp aw beat down into the queue of the slave when no decerror + if (!decerr) begin + exp_aw_id = {idx_mst_t'(i), masters_axi[i].aw_id}; + // $display("Test exp aw_id: %b",exp_aw_id); + exp_aw = '{slv_axi_id: exp_aw_id, + slv_axi_addr: masters_axi[i].aw_addr, + slv_axi_len: masters_axi[i].aw_len }; + this.exp_aw_queue[to_slave_idx].push(exp_aw_id, exp_aw); + incr_expected_tests(3); + $display("%0tns > Master %0d: AW to Slave %0d: Axi ID: %b", + $time, i, to_slave_idx, masters_axi[i].aw_id); + end else begin + $display("%0tns > Master %0d: AW to Decerror: Axi ID: %b", + $time, i, to_slave_idx, masters_axi[i].aw_id); + end + // populate the expected b queue anyway + exp_b = '{mst_axi_id: masters_axi[i].aw_id, last: 1'b1}; + this.exp_b_queue[i].push(masters_axi[i].aw_id, exp_b); + incr_expected_tests(1); + $display(" Expect B response."); + // inject expected r beats on this id, if it is an atop + if(masters_axi[i].aw_atop[5]) begin + // push the required r beats into the right fifo (reuse the exp_b variable) + $display(" Expect R response, len: %0d.", masters_axi[i].aw_len); + for (int unsigned j = 0; j <= masters_axi[i].aw_len; j++) begin + exp_b = (j == masters_axi[i].aw_len) ? + '{mst_axi_id: masters_axi[i].aw_id, last: 1'b1} : + '{mst_axi_id: masters_axi[i].aw_id, last: 1'b0}; + this.exp_r_queue[i].push(masters_axi[i].aw_id, exp_b); + incr_expected_tests(1); + end + end + end + endtask : monitor_mst_aw + + // This task monitors a slave port of the crossbar. Every time there is an AW vector it + // gets checked for its contents and if it was expected. The task then pushes an expected + // amount of W beats in the respective fifo. Emphasis of the last flag. + task automatic monitor_slv_aw(input int unsigned i); + exp_ax_t exp_aw; + slave_exp_t exp_slv_w; + // $display("%0t > Was triggered: aw_valid %b, aw_ready: %b", + // $time(), slaves_axi[i].aw_valid, slaves_axi[i].aw_ready); + if (slaves_axi[i].aw_valid && slaves_axi[i].aw_ready) begin + // test if the aw beat was expected + exp_aw = this.exp_aw_queue[i].pop_id(slaves_axi[i].aw_id); + $display("%0tns > Slave %0d: AW Axi ID: %b", + $time, i, slaves_axi[i].aw_id); + if (exp_aw.slv_axi_id != slaves_axi[i].aw_id) begin + incr_failed_tests(1); + $warning("Slave %0d: Unexpected AW with ID: %b", i, slaves_axi[i].aw_id); + end + if (exp_aw.slv_axi_addr != slaves_axi[i].aw_addr) begin + incr_failed_tests(1); + $warning("Slave %0d: Unexpected AW with ID: %b and ADDR: %h, exp: %h", + i, slaves_axi[i].aw_id, slaves_axi[i].aw_addr, exp_aw.slv_axi_addr); + end + if (exp_aw.slv_axi_len != slaves_axi[i].aw_len) begin + incr_failed_tests(1); + $warning("Slave %0d: Unexpected AW with ID: %b and LEN: %h, exp: %h", + i, slaves_axi[i].aw_id, slaves_axi[i].aw_len, exp_aw.slv_axi_len); + end + incr_conducted_tests(3); + + // push the required w beats into the right fifo + incr_expected_tests(slaves_axi[i].aw_len + 1); + for (int unsigned j = 0; j <= slaves_axi[i].aw_len; j++) begin + exp_slv_w = (j == slaves_axi[i].aw_len) ? + '{slv_axi_id: slaves_axi[i].aw_id, last: 1'b1} : + '{slv_axi_id: slaves_axi[i].aw_id, last: 1'b0}; + this.exp_w_fifo[i].push_back(exp_slv_w); + end + end + endtask : monitor_slv_aw + + // This task just pushes every W beat that gets sent on a master port in its respective fifo. + task automatic monitor_slv_w(input int unsigned i); + slave_exp_t act_slv_w; + if (slaves_axi[i].w_valid && slaves_axi[i].w_ready) begin + // $display("%0t > W beat on Slave %0d, last flag: %b", $time, i, slaves_axi[i].w_last); + act_slv_w = '{last: slaves_axi[i].w_last , default:'0}; + this.act_w_fifo[i].push_back(act_slv_w); + end + endtask : monitor_slv_w + + // This task compares the expected and actual W beats on a master port. The reason that + // this is not done in `monitor_slv_w` is that there can be per protocol W beats on the + // channel, before AW is sent to the slave. + task automatic check_slv_w(input int unsigned i); + slave_exp_t exp_w, act_w; + while (this.exp_w_fifo[i].size() != 0 && this.act_w_fifo[i].size() != 0) begin + + exp_w = this.exp_w_fifo[i].pop_front(); + act_w = this.act_w_fifo[i].pop_front(); + // do the check + incr_conducted_tests(1); + if(exp_w.last != act_w.last) begin + incr_failed_tests(1); + $warning("Slave %d: unexpected W beat last flag %b, expected: %b.", + i, act_w.last, exp_w.last); + end + end + endtask : check_slv_w + + // This task checks if a B response is allowed on a slave port of the crossbar. + task automatic monitor_mst_b(input int unsigned i); + master_exp_t exp_b; + mst_axi_id_t axi_b_id; + if (masters_axi[i].b_valid && masters_axi[i].b_ready) begin + incr_conducted_tests(1); + axi_b_id = masters_axi[i].b_id; + $display("%0tns > Master %0d: Got last B with id: %b", + $time, i, axi_b_id); + if (this.exp_b_queue[i].is_empty()) begin + incr_failed_tests(1); + $warning("Master %d: unexpected B beat with ID: %b detected!", i, axi_b_id); + end else begin + exp_b = this.exp_b_queue[i].pop_id(axi_b_id); + if (axi_b_id != exp_b.mst_axi_id) begin + incr_failed_tests(1); + $warning("Master: %d got unexpected B with ID: %b", i, axi_b_id); + end + end + end + endtask : monitor_mst_b + + // This task monitors the AR channel of a slave port of the crossbar. For each AR it populates + // the corresponding ID queue with the number of r beats indicated on the `ar_len` field. + // Emphasis on the last flag. We will detect reordering, if the last flags do not match, + // as each `random` burst tend to have a different length. + task automatic monitor_mst_ar(input int unsigned i); + mst_axi_id_t mst_axi_id; + axi_addr_t mst_axi_addr; + axi_pkg::len_t mst_axi_len; + + idx_slv_t exp_slv_idx; + slv_axi_id_t exp_slv_axi_id; + exp_ax_t exp_slv_ar; + master_exp_t exp_mst_r; + + logic exp_decerr; + + if (masters_axi[i].ar_valid && masters_axi[i].ar_ready) begin + exp_decerr = 1'b1; + mst_axi_id = masters_axi[i].ar_id; + mst_axi_addr = masters_axi[i].ar_addr; + mst_axi_len = masters_axi[i].ar_len; + exp_slv_axi_id = {idx_mst_t'(i), mst_axi_id}; + exp_slv_idx = '0; + for (int unsigned j = 0; j < NoAddrRules; j++) begin + if ((mst_axi_addr >= AddrMap[j].start_addr) && (mst_axi_addr < AddrMap[j].end_addr)) begin + exp_slv_idx = AddrMap[j].idx; + exp_decerr = 1'b0; + end + end + if (exp_decerr) begin + $display("%0tns > Master %0d: AR to Decerror: Axi ID: %b", + $time, i, mst_axi_id); + end else begin + $display("%0tns > Master %0d: AR to Slave %0d: Axi ID: %b", + $time, i, exp_slv_idx, mst_axi_id); + // push the expected vectors AW for exp_slv + exp_slv_ar = '{slv_axi_id: exp_slv_axi_id, + slv_axi_addr: mst_axi_addr, + slv_axi_len: mst_axi_len }; + //$display("Expected Slv Axi Id is: %b", exp_slv_axi_id); + this.exp_ar_queue[exp_slv_idx].push(exp_slv_axi_id, exp_slv_ar); + incr_expected_tests(1); + end + // push the required r beats into the right fifo + $display(" Expect R response, len: %0d.", masters_axi[i].ar_len); + for (int unsigned j = 0; j <= mst_axi_len; j++) begin + exp_mst_r = (j == mst_axi_len) ? '{mst_axi_id: mst_axi_id, last: 1'b1} : + '{mst_axi_id: mst_axi_id, last: 1'b0}; + this.exp_r_queue[i].push(mst_axi_id, exp_mst_r); + incr_expected_tests(1); + end + end + endtask : monitor_mst_ar + + // This task monitors a master port of the crossbar and checks if a transmitted AR beat was + // expected. + task automatic monitor_slv_ar(input int unsigned i); + exp_ax_t exp_slv_ar; + slv_axi_id_t slv_axi_id; + if (slaves_axi[i].ar_valid && slaves_axi[i].ar_ready) begin + incr_conducted_tests(1); + slv_axi_id = slaves_axi[i].ar_id; + if (this.exp_ar_queue[i].is_empty()) begin + incr_failed_tests(1); + end else begin + // check that the ids are the same + exp_slv_ar = this.exp_ar_queue[i].pop_id(slv_axi_id); + $display("%0tns > Slave %0d: AR Axi ID: %b", $time, i, slv_axi_id); + if (exp_slv_ar.slv_axi_id != slv_axi_id) begin + incr_failed_tests(1); + $warning("Slave %d: Unexpected AR with ID: %b", i, slv_axi_id); + end + end + end + endtask : monitor_slv_ar + + // This task does the R channel monitoring on a slave port. It compares the last flags, + // which are determined by the sequence of previously sent AR vectors. + task automatic monitor_mst_r(input int unsigned i); + master_exp_t exp_mst_r; + mst_axi_id_t mst_axi_r_id; + logic mst_axi_r_last; + if (masters_axi[i].r_valid && masters_axi[i].r_ready) begin + incr_conducted_tests(1); + mst_axi_r_id = masters_axi[i].r_id; + mst_axi_r_last = masters_axi[i].r_last; + if (mst_axi_r_last) begin + $display("%0tns > Master %0d: Got last R with id: %b", + $time, i, mst_axi_r_id); + end + if (this.exp_r_queue[i].is_empty()) begin + incr_failed_tests(1); + $warning("Master %d: unexpected R beat with ID: %b detected!", i, mst_axi_r_id); + end else begin + exp_mst_r = this.exp_r_queue[i].pop_id(mst_axi_r_id); + if (mst_axi_r_id != exp_mst_r.mst_axi_id) begin + incr_failed_tests(1); + $warning("Master: %d got unexpected R with ID: %b", i, mst_axi_r_id); + end + if (mst_axi_r_last != exp_mst_r.last) begin + incr_failed_tests(1); + $warning("Master: %d got unexpected R with ID: %b and last flag: %b", + i, mst_axi_r_id, mst_axi_r_last); + end + end + end + endtask : monitor_mst_r + + // Some tasks to manage bookkeeping of the tests conducted. + task incr_expected_tests(input int unsigned times); + cnt_sem.get(); + this.tests_expected += times; + cnt_sem.put(); + endtask : incr_expected_tests + + task incr_conducted_tests(input int unsigned times); + cnt_sem.get(); + this.tests_conducted += times; + cnt_sem.put(); + endtask : incr_conducted_tests + + task incr_failed_tests(input int unsigned times); + cnt_sem.get(); + this.tests_failed += times; + cnt_sem.put(); + endtask : incr_failed_tests + + // This task invokes the various monitoring tasks. It first forks in two, spitting + // the tasks that should continuously run and the ones that get invoked every clock cycle. + // For the tasks every clock cycle all processes that only push something in the fifo's and + // Queues get run. When they are finished the processes that pop something get run. + task run(); + Continous: fork + begin + do begin + cycle_start(); + // at every cycle span some monitoring processes + // execute all processes that put something into the queues + PushMon: fork + proc_mst_aw: begin + for (int unsigned i = 0; i < NoMasters; i++) begin + monitor_mst_aw(i); + end + end + proc_mst_ar: begin + for (int unsigned i = 0; i < NoMasters; i++) begin + monitor_mst_ar(i); + end + end + join : PushMon + // this one pops and pushes something + proc_slv_aw: begin + for (int unsigned i = 0; i < NoSlaves; i++) begin + monitor_slv_aw(i); + end + end + proc_slv_w: begin + for (int unsigned i = 0; i < NoSlaves; i++) begin + monitor_slv_w(i); + end + end + // These only pop somethong from the queses + PopMon: fork + proc_mst_b: begin + for (int unsigned i = 0; i < NoMasters; i++) begin + monitor_mst_b(i); + end + end + proc_slv_ar: begin + for (int unsigned i = 0; i < NoSlaves; i++) begin + monitor_slv_ar(i); + end + end + proc_mst_r: begin + for (int unsigned i = 0; i < NoMasters; i++) begin + monitor_mst_r(i); + end + end + join : PopMon + // check the slave W fifos last + proc_check_slv_w: begin + for (int unsigned i = 0; i < NoSlaves; i++) begin + check_slv_w(i); + end + end + cycle_end(); + end while (1'b1); + end + join + endtask : run + + task print_result(); + $info("Simulation has ended!"); + $display("Tests Expected: %d", this.tests_expected); + $display("Tests Conducted: %d", this.tests_conducted); + $display("Tests Failed: %d", this.tests_failed); + if(tests_failed > 0) begin + $error("Simulation encountered unexpected Transactions!!!!!!"); + end + if(tests_conducted == 0) begin + $error("Simulation did not conduct any tests!"); + end + endtask : print_result + endclass : axi_xbar_monitor +endpackage From 9382729e14862eafdf44def65ebcb5e6e96c305c Mon Sep 17 00:00:00 2001 From: Luca Colagrande Date: Fri, 23 Jan 2026 11:30:15 +0100 Subject: [PATCH 12/41] axi_mcast_xbar: Add basic multicast logic --- Bender.yml | 10 + scripts/run_vsim.sh | 26 + src/axi_mcast_demux.sv | 319 +++++++--- src/axi_mcast_mux.sv | 2 +- src/axi_mcast_xbar.sv | 198 +++---- src/axi_pkg.sv | 12 + src/axi_test.sv | 47 +- test/axi_synth_bench.sv | 1023 +++++++++++++++++++++++++++++++++ test/tb_axi_mcast_xbar.sv | 80 ++- test/tb_axi_mcast_xbar_pkg.sv | 133 +++-- 10 files changed, 1601 insertions(+), 249 deletions(-) diff --git a/Bender.yml b/Bender.yml index dc6559d30..9d975f0ab 100644 --- a/Bender.yml +++ b/Bender.yml @@ -71,6 +71,7 @@ sources: - src/axi_lite_to_axi.sv - src/axi_modify_address.sv - src/axi_mux.sv + - src/axi_mcast_mux.sv - src/axi_rw_join.sv - src/axi_rw_split.sv - src/axi_serializer.sv @@ -81,6 +82,7 @@ sources: - src/axi_burst_splitter.sv - src/axi_cdc.sv - src/axi_demux.sv + - src/axi_mcast_demux.sv - src/axi_err_slv.sv - src/axi_dw_converter.sv - src/axi_from_mem.sv @@ -95,6 +97,8 @@ sources: - src/axi_iw_converter.sv - src/axi_lite_xbar.sv - src/axi_xbar_unmuxed.sv + - src/axi_xbar.sv + - src/axi_mcast_xbar.sv - src/axi_to_mem_banked.sv - src/axi_to_mem_interleaved.sv - src/axi_to_mem_split.sv @@ -107,6 +111,10 @@ sources: files: - test/axi_synth_bench.sv + - target: gf12 + files: + - test/axi_synth_bench.sv + - target: simulation files: - src/axi_chan_compare.sv @@ -119,6 +127,7 @@ sources: # Level 0 - test/tb_axi_dw_pkg.sv - test/tb_axi_xbar_pkg.sv + - test/tb_axi_mcast_xbar_pkg.sv # Level 1 - test/tb_axi_addr_test.sv - test/tb_axi_atop_filter.sv @@ -143,3 +152,4 @@ sources: - test/tb_axi_to_axi_lite.sv - test/tb_axi_to_mem_banked.sv - test/tb_axi_xbar.sv + - test/tb_axi_mcast_xbar.sv diff --git a/scripts/run_vsim.sh b/scripts/run_vsim.sh index aaf8c3f22..9d1228dc2 100755 --- a/scripts/run_vsim.sh +++ b/scripts/run_vsim.sh @@ -241,6 +241,32 @@ exec_test() { done done ;; + axi_mcast_xbar) + for GEN_ATOP in 0 1; do + for NUM_MST in 1 6; do + for NUM_SLV in 2 9; do + for MST_ID_USE in 3 5; do + MST_ID=5 + for DATA_WIDTH in 64 256; do + for PIPE in 0 1; do + for UNIQUE_IDS in 0 1; do + call_vsim tb_axi_mcast_xbar -t 1ns -voptargs="+acc" \ + -gTbNumMasters=$NUM_MST \ + -gTbNumSlaves=$NUM_SLV \ + -gTbAxiIdWidthMasters=$MST_ID \ + -gTbAxiIdUsed=$MST_ID_USE \ + -gTbAxiDataWidth=$DATA_WIDTH \ + -gTbPipeline=$PIPE \ + -gTbEnAtop=$GEN_ATOP \ + -gTbUniqueIds=$UNIQUE_IDS + done + done + done + done + done + done + done + ;; *) call_vsim tb_$1 -t 1ns -coverage -voptargs="+acc +cover=bcesfx" ;; diff --git a/src/axi_mcast_demux.sv b/src/axi_mcast_demux.sv index fc061ff09..c816a7808 100644 --- a/src/axi_mcast_demux.sv +++ b/src/axi_mcast_demux.sv @@ -1,4 +1,4 @@ -// Copyright (c) 2019 ETH Zurich and University of Bologna. +// Copyright (c) 2022 ETH Zurich and University of Bologna. // Copyright and related rights are licensed under the Solderpad Hardware // License, Version 0.51 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at @@ -9,8 +9,9 @@ // specific language governing permissions and limitations under the License. // // Authors: -// - Wolfgang Roenninger -// - Andreas Kurth +// - Luca Colagrande +// Based on: +// - axi_demux.sv `include "common_cells/assertions.svh" `include "common_cells/registers.svh" @@ -37,9 +38,10 @@ /// /// Beats on the B and R channel are multiplexed from the master ports to the slave port with /// a round-robin arbitration tree. -module axi_demux #( +module axi_mcast_demux #( parameter int unsigned AxiIdWidth = 32'd0, parameter bit AtopSupport = 1'b1, + parameter type aw_addr_t = logic, parameter type aw_chan_t = logic, parameter type w_chan_t = logic, parameter type b_chan_t = logic, @@ -57,20 +59,27 @@ 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 int unsigned IdxSelectWidth = (NoMstPorts > 32'd1) ? $clog2(NoMstPorts) : 32'd1, + parameter type idx_select_t = logic [IdxSelectWidth-1:0], + parameter type mask_select_t = logic [NoMstPorts-1:0], + // Multi-address type (represents a set of addresses) + parameter type aw_multi_addr_t = struct packed { + aw_addr_t aw_addr; + aw_addr_t aw_mask; + } ) ( - input logic clk_i, - input logic rst_ni, - input logic test_i, + input logic clk_i, + input logic rst_ni, + input logic test_i, // Slave Port - input axi_req_t slv_req_i, - input select_t slv_aw_select_i, - input select_t slv_ar_select_i, - output axi_resp_t slv_resp_o, + input axi_req_t slv_req_i, + input mask_select_t slv_aw_select_i, + input idx_select_t slv_ar_select_i, + input aw_multi_addr_t [NoMstPorts-1:0] slv_aw_mcast_i, + output axi_resp_t slv_resp_o, // Master Ports - output axi_req_t [NoMstPorts-1:0] mst_reqs_o, - input axi_resp_t [NoMstPorts-1:0] mst_resps_i + output axi_req_t [NoMstPorts-1:0] mst_reqs_o, + input axi_resp_t [NoMstPorts-1:0] mst_resps_i ); localparam int unsigned IdCounterWidth = cf_math_pkg::idx_width(MaxTrans); @@ -158,20 +167,33 @@ module axi_demux #( // Write Transaction //-------------------------------------- // comes from spill register at input - aw_chan_t slv_aw_chan; - select_t slv_aw_select; + aw_chan_t slv_aw_chan; + mask_select_t slv_aw_select; + aw_multi_addr_t [NoMstPorts-1:0] slv_aw_mcast; - logic slv_aw_valid, slv_aw_valid_chan, slv_aw_valid_sel; - logic slv_aw_ready, slv_aw_ready_chan, slv_aw_ready_sel; + logic slv_aw_valid, slv_aw_valid_chan, slv_aw_valid_sel, slv_aw_valid_mcast; + logic slv_aw_ready, slv_aw_ready_chan, slv_aw_ready_sel, slv_aw_ready_mcast; + + // AW channel to slave ports + logic [NoMstPorts-1:0] mst_aw_valids, mst_aw_readies; // AW ID counter - select_t lookup_aw_select; + mask_select_t lookup_aw_select; logic aw_select_occupied, aw_id_cnt_full; + logic aw_any_outstanding_unicast_trx; + logic aw_any_outstanding_trx; // Upon an ATOP load, inject IDs from the AW into the AR channel logic atop_inject; + // Multicast logic + logic aw_is_multicast; + logic outstanding_multicast; + logic multicast_stall; + mask_select_t multicast_select_q, multicast_select_d; + logic multicast_select_load; + logic [$clog2(NoMstPorts)+1-1:0] aw_select_popcount; - // W select counter: stores the decision to which master W beats should go - select_t w_select, w_select_q; + // W select counter: stores the decision to which masters W beats should go + mask_select_t w_select, w_select_q; logic w_select_valid; id_cnt_t w_open; logic w_cnt_up, w_cnt_down; @@ -184,13 +206,20 @@ module axi_demux #( w_chan_t slv_w_chan; logic slv_w_valid, slv_w_ready; - // B channles input into the arbitration + // W channel to slave ports + logic [NoMstPorts-1:0] mst_w_valids, mst_w_readies; + + // B channels input into the arbitration (unicast transactions) + // or join module (multicast transactions) b_chan_t [NoMstPorts-1:0] mst_b_chans; logic [NoMstPorts-1:0] mst_b_valids, mst_b_readies; + logic [NoMstPorts-1:0] mst_b_readies_arb, mst_b_readies_join; // B channel to spill register b_chan_t slv_b_chan; logic slv_b_valid, slv_b_ready; + b_chan_t slv_b_chan_arb, slv_b_chan_join; + logic slv_b_valid_arb, slv_b_valid_join; //-------------------------------------- // Read Transaction @@ -200,7 +229,7 @@ module axi_demux #( logic slv_ar_ready, slv_ar_ready_chan, slv_ar_ready_sel; // AR ID counter - select_t lookup_ar_select; + idx_select_t lookup_ar_select; logic ar_select_occupied, ar_id_cnt_full; logic ar_push; @@ -240,7 +269,7 @@ module axi_demux #( .data_o ( slv_aw_chan ) ); spill_register #( - .T ( select_t ), + .T ( mask_select_t ), .Bypass ( ~SpillAw ) // because module param indicates if we want a spill reg ) i_aw_select_spill_reg ( .clk_i ( clk_i ), @@ -252,8 +281,21 @@ module axi_demux #( .ready_i ( slv_aw_ready ), .data_o ( slv_aw_select ) ); - assign slv_resp_o.aw_ready = slv_aw_ready_chan & slv_aw_ready_sel; - assign slv_aw_valid = slv_aw_valid_chan & slv_aw_valid_sel; + spill_register #( + .T ( aw_multi_addr_t [NoMstPorts-1:0] ), + .Bypass ( ~SpillAw ) // because module param indicates if we want a spill reg + ) i_aw_mcast_spill_reg ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .valid_i ( slv_req_i.aw_valid ), + .ready_o ( slv_aw_ready_mcast ), + .data_i ( slv_aw_mcast_i ), + .valid_o ( slv_aw_valid_mcast ), + .ready_i ( slv_aw_ready ), + .data_o ( slv_aw_mcast ) + ); + assign slv_resp_o.aw_ready = slv_aw_ready_chan & slv_aw_ready_sel & slv_aw_ready_mcast; + assign slv_aw_valid = slv_aw_valid_chan & slv_aw_valid_sel & slv_aw_valid_mcast; // Control of the AW handshake always_comb begin @@ -295,7 +337,8 @@ module axi_demux #( // Handling of the B responses. if (slv_aw_valid && ((w_open == '0) || (w_select == slv_aw_select)) && - (!aw_select_occupied || (slv_aw_select == lookup_aw_select))) begin + (!aw_select_occupied || (slv_aw_select == lookup_aw_select)) && + !multicast_stall) begin // connect the handshake aw_valid = 1'b1; // push arbitration to the W FIFO regardless, do not wait for the AW transaction @@ -318,6 +361,75 @@ module axi_demux #( // prevent further pushing `FFLARN(lock_aw_valid_q, lock_aw_valid_d, load_aw_lock, '0, clk_i, rst_ni) + /// Multicast logic + + // Popcount to identify multicast requests + popcount #(NoMstPorts) i_aw_select_popcount ( + .data_i (slv_aw_select), + .popcount_o(aw_select_popcount) + ); + + // While there can be multiple outstanding write transactions, i.e. + // multiple AWs can be accepted before the corresponding Bs are returned, + // in the case of multicast transactions this would require the need + // for additional (possibly expensive) hardware. + // The reason is that multicast transactions require merging multiple B + // responses arriving on different master ports. To know which master ports + // need to be merged we need to register the select signal of the + // write transaction. And if we allow multiple outstanding transactions + // we need to register the select signal of each, and we need a big + // associative (by ID) table for this. And actually this still allows + // deadlocks to occur, e.g. if two multicast transactions A and B are partially + // reordered, i.e. some masters respond to A first and some to B. + // If we restrict the outstanding transactions to a single ID then ordering is + // guaranteed, but we anyways need a FIFO to store the selects. + // So for the moment we disallow multiple outstanding transactions in presence + // of a multicast. This means stall an AW request if: + // - there is an outstanding multicast transaction or + // - if the request is a multicast, until there are no more outstanding transactions + assign aw_is_multicast = aw_select_popcount > 1; + assign outstanding_multicast = |multicast_select_q; + assign aw_any_outstanding_trx = aw_any_outstanding_unicast_trx || outstanding_multicast; + assign multicast_stall = outstanding_multicast || (aw_is_multicast && aw_any_outstanding_trx); + + // Keep track of which B responses need to be returned to complete the multicast + `FFLARN(multicast_select_q, multicast_select_d, multicast_select_load, '0, clk_i, rst_ni) + + // Logic to update multicast_select_q. Loads the register upon the AW handshake + // of a multicast transaction. Successively clears it upon the "joined" B handshake + always_comb begin + multicast_select_d = multicast_select_q; + multicast_select_load = 1'b0; + + unique if (aw_is_multicast && aw_valid && aw_ready) begin + multicast_select_d = slv_aw_select; + multicast_select_load = 1'b1; + end else if (outstanding_multicast && slv_b_valid && slv_b_ready) begin + multicast_select_d = '0; + multicast_select_load = 1'b1; + end else begin + multicast_select_d = multicast_select_q; + multicast_select_load = 1'b0; + end + end + + // When a multicast occurs, the upstream valid signals need to + // be forwarded to multiple master ports. + // Proper stream forking is necessary to avoid protocol violations + stream_fork_dynamic #( + .N_OUP(NoMstPorts) + ) i_aw_stream_fork_dynamic ( + .clk_i (clk_i), + .rst_ni (rst_ni), + .valid_i (aw_valid), + .ready_o (aw_ready), + .sel_i (slv_aw_select), + .sel_valid_i(slv_aw_valid_sel), + .sel_ready_o(), + .valid_o (mst_aw_valids), + .ready_i (mst_aw_readies) + ); + if (UniqueIds) begin : gen_unique_ids_aw // If the `UniqueIds` parameter is set, each write transaction has an ID that is unique among // all in-flight write transactions, or all write transactions with a given ID target the same @@ -326,12 +438,34 @@ module axi_demux #( // derived from existing signals. The ID counters can therefore be omitted. assign lookup_aw_select = slv_aw_select; assign aw_select_occupied = 1'b0; - assign aw_id_cnt_full = 1'b0; + + // We still need a (single) counter to keep track of any outstanding transactions + axi_mcast_demux_id_counters #( + .AxiIdBits ( 0 ), + .CounterWidth ( IdCounterWidth ), + .mst_port_select_t ( idx_select_t ) + ) i_aw_id_counter ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .lookup_axi_id_i ( '0 ), + .lookup_mst_select_o ( /* Not used */ ), + .lookup_mst_select_occupied_o ( /* Not used */ ), + .full_o ( aw_id_cnt_full ), + .inject_axi_id_i ( '0 ), + .inject_i ( 1'b0 ), + .push_axi_id_i ( '0 ), + .push_mst_select_i ( '0 ), + .push_i ( w_cnt_up && !aw_is_multicast ), + .pop_axi_id_i ( '0 ), + .pop_i ( slv_b_valid & slv_b_ready & ~outstanding_multicast ), + .any_outstanding_trx_o ( aw_any_outstanding_unicast_trx ) + ); + end else begin : gen_aw_id_counter - axi_demux_id_counters #( + axi_mcast_demux_id_counters #( .AxiIdBits ( AxiLookBits ), .CounterWidth ( IdCounterWidth ), - .mst_port_select_t ( select_t ) + .mst_port_select_t ( mask_select_t ) ) i_aw_id_counter ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), @@ -343,9 +477,10 @@ module axi_demux #( .inject_i ( 1'b0 ), .push_axi_id_i ( slv_aw_chan.id[0+:AxiLookBits] ), .push_mst_select_i ( slv_aw_select ), - .push_i ( w_cnt_up ), + .push_i ( w_cnt_up && !aw_is_multicast ), .pop_axi_id_i ( slv_b_chan.id[0+:AxiLookBits] ), - .pop_i ( slv_b_valid & slv_b_ready ) + .pop_i ( slv_b_valid & slv_b_ready & ~outstanding_multicast ), + .any_outstanding_trx_o ( aw_any_outstanding_unicast_trx ) ); // pop from ID counter on outward transaction end @@ -369,9 +504,10 @@ module axi_demux #( .overflow_o ( /*not used*/ ) ); - `FFLARN(w_select_q, slv_aw_select, w_cnt_up, select_t'(0), clk_i, rst_ni) + `FFLARN(w_select_q, slv_aw_select, w_cnt_up, mask_select_t'(0), clk_i, rst_ni) assign w_select = (|w_open) ? w_select_q : slv_aw_select; assign w_select_valid = w_cnt_up | (|w_open); + assign w_cnt_down = slv_w_valid & slv_w_ready & slv_w_chan.last; //-------------------------------------- // W Channel @@ -390,6 +526,23 @@ module axi_demux #( .data_o ( slv_w_chan ) ); + // When a multicast occurs, the upstream valid signals need to + // be forwarded to multiple master ports. + // Proper stream forking is necessary to avoid protocol violations + stream_fork_dynamic #( + .N_OUP(NoMstPorts) + ) i_w_stream_fork_dynamic ( + .clk_i (clk_i), + .rst_ni (rst_ni), + .valid_i (slv_w_valid), + .ready_o (slv_w_ready), + .sel_i (w_select), + .sel_valid_i(w_select_valid), + .sel_ready_o(), + .valid_o (mst_w_valids), + .ready_i (mst_w_readies) + ); + //-------------------------------------- // B Channel //-------------------------------------- @@ -419,20 +572,36 @@ module axi_demux #( .rst_ni ( rst_ni ), .flush_i( 1'b0 ), .rr_i ( '0 ), - .req_i ( mst_b_valids ), - .gnt_o ( mst_b_readies ), + .req_i ( mst_b_valids & {NoMstPorts{!outstanding_multicast}} ), + .gnt_o ( mst_b_readies_arb ), .data_i ( mst_b_chans ), .gnt_i ( slv_b_ready ), - .req_o ( slv_b_valid ), - .data_o ( slv_b_chan ), + .req_o ( slv_b_valid_arb ), + .data_o ( slv_b_chan_arb ), .idx_o ( ) ); + // Streams must be joined instead of arbitrated when multicast + stream_join_dynamic #(NoMstPorts) i_b_stream_join ( + .inp_valid_i(mst_b_valids & {NoMstPorts{outstanding_multicast}}), + .inp_ready_o(mst_b_readies_join), + .sel_i (multicast_select_q), + .oup_valid_o(slv_b_valid_join), + .oup_ready_i(slv_b_ready) + ); + // TODO colluca: merge B channels appropriately + assign slv_b_chan_join = mst_b_chans[0]; + + // Mux output of arbiter and stream_join_dynamic modules + assign mst_b_readies = mst_b_readies_arb | mst_b_readies_join; + assign slv_b_valid = slv_b_valid_arb | slv_b_valid_join; + assign slv_b_chan = outstanding_multicast ? slv_b_chan_join : slv_b_chan_arb; + //-------------------------------------- // AR Channel //-------------------------------------- ar_chan_t slv_ar_chan; - select_t slv_ar_select; + idx_select_t slv_ar_select; spill_register #( .T ( ar_chan_t ), .Bypass ( ~SpillAr ) @@ -447,7 +616,7 @@ module axi_demux #( .data_o ( slv_ar_chan ) ); spill_register #( - .T ( select_t ), + .T ( idx_select_t ), .Bypass ( ~SpillAr ) ) i_ar_sel_spill_reg ( .clk_i ( clk_i ), @@ -524,7 +693,7 @@ module axi_demux #( axi_demux_id_counters #( .AxiIdBits ( AxiLookBits ), .CounterWidth ( IdCounterWidth ), - .mst_port_select_t ( select_t ) + .mst_port_select_t ( idx_select_t ) ) i_ar_id_counter ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), @@ -580,33 +749,24 @@ module axi_demux #( .idx_o ( ) ); - assign ar_ready = ar_valid & mst_resps_i[slv_ar_select].ar_ready; - assign aw_ready = aw_valid & mst_resps_i[slv_aw_select].aw_ready; + assign ar_ready = ar_valid & mst_resps_i[slv_ar_select].ar_ready; // 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; - slv_w_ready = 1'b0; - w_cnt_down = 1'b0; for (int unsigned i = 0; i < NoMstPorts; i++) begin // AW channel - mst_reqs_o[i].aw = slv_aw_chan; - mst_reqs_o[i].aw_valid = 1'b0; - if (aw_valid && (slv_aw_select == i)) begin - mst_reqs_o[i].aw_valid = 1'b1; - end + mst_reqs_o[i].aw = slv_aw_chan; + mst_reqs_o[i].aw.addr = slv_aw_mcast[i].aw_addr; + mst_reqs_o[i].aw.user.mcast = slv_aw_mcast[i].aw_mask; + mst_reqs_o[i].aw_valid = mst_aw_valids[i]; // W channel mst_reqs_o[i].w = slv_w_chan; - mst_reqs_o[i].w_valid = 1'b0; - if (w_select_valid && (w_select == i)) begin - mst_reqs_o[i].w_valid = slv_w_valid; - slv_w_ready = mst_resps_i[i].w_ready; - w_cnt_down = slv_w_valid & mst_resps_i[i].w_ready & slv_w_chan.last; - end + mst_reqs_o[i].w_valid = mst_w_valids[i]; // B channel mst_reqs_o[i].b_ready = mst_b_readies[i]; @@ -622,12 +782,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, W, R and B 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_w_readies[i] = mst_resps_i[i].w_ready; + assign mst_aw_readies[i] = mst_resps_i[i].aw_ready; end @@ -640,12 +802,10 @@ module axi_demux #( $fatal(1, "The Number of slaves (NoMstPorts) has to be at least 1"); AXI_ID_BITS: assume (AxiIdWidth >= AxiLookBits) else $fatal(1, "AxiIdBits has to be equal or smaller than AxiIdWidth."); + aw_addr_bits: assume ($bits(slv_aw_mcast_i[0].aw_addr) == $bits(slv_req_i.aw.addr)) else + $fatal(1, "aw_addr_t must be the type of slv_req_i.aw.addr"); end default disable iff (!rst_ni); - 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.\ - NoMstPorts: %d", slv_aw_select_i, NoMstPorts); ar_select: assume property( @(posedge clk_i) (slv_req_i.ar_valid |-> (slv_ar_select_i < NoMstPorts))) else $fatal(1, "slv_ar_select_i is %d: AR has selected a slave that is not defined.\ @@ -670,9 +830,6 @@ module axi_demux #( internal_ar_select: assert property( @(posedge clk_i) (ar_valid |-> slv_ar_select < NoMstPorts)) else $fatal(1, "slv_ar_select illegal while ar_valid."); - internal_aw_select: assert property( @(posedge clk_i) - (aw_valid |-> slv_aw_select < NoMstPorts)) - else $fatal(1, "slv_aw_select illegal while aw_valid."); w_underflow: assert property( @(posedge clk_i) ((w_open == '0) && (w_cnt_up ^ w_cnt_down) |-> !w_cnt_down)) else $fatal(1, "W counter underflowed!"); @@ -683,7 +840,7 @@ module axi_demux #( end endmodule -module axi_demux_id_counters #( +module axi_mcast_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, @@ -705,7 +862,9 @@ module axi_demux_id_counters #( input logic inject_i, // pop input logic [AxiIdBits-1:0] pop_axi_id_i, - input logic pop_i + input logic pop_i, + // outstanding transactions + output logic any_outstanding_trx_o ); localparam int unsigned NoCounters = 2**AxiIdBits; typedef logic [CounterWidth-1:0] cnt_t; @@ -728,6 +887,11 @@ module axi_demux_id_counters #( 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; + //----------------------------------- + // Status + //----------------------------------- + assign any_outstanding_trx_o = |occupied; + // counters for (genvar i = 0; i < NoCounters; i++) begin : gen_counters logic cnt_en, cnt_down, overflow; @@ -807,7 +971,7 @@ 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, @@ -824,19 +988,26 @@ module axi_demux_intf #( 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 idx_select_t = logic [SELECT_WIDTH-1:0], + parameter type mask_select_t = logic [NO_MST_PORTS-1:0], + parameter type addr_t = logic [AXI_ADDR_WIDTH-1:0], + // Multi-address type (represents a set of addresses) + parameter type aw_multi_addr_t = struct packed { + addr_t aw_addr; + addr_t aw_mask; + } ) ( input logic clk_i, // Clock input logic rst_ni, // Asynchronous reset active low input logic test_i, // Testmode enable - input select_t slv_aw_select_i, // has to be stable, when aw_valid - input select_t slv_ar_select_i, // has to be stable, when ar_valid + input mask_select_t slv_aw_select_i, // has to be stable, when aw_valid + input idx_select_t slv_ar_select_i, // has to be stable, when ar_valid + input aw_multi_addr_t [NO_MST_PORTS-1:0] slv_aw_mcast_i, AXI_BUS.Slave slv, // slave port AXI_BUS.Master mst [NO_MST_PORTS-1:0] // master ports ); typedef logic [AXI_ID_WIDTH-1:0] id_t; - typedef logic [AXI_ADDR_WIDTH-1:0] addr_t; typedef logic [AXI_DATA_WIDTH-1:0] data_t; typedef logic [AXI_DATA_WIDTH/8-1:0] strb_t; typedef logic [AXI_USER_WIDTH-1:0] user_t; @@ -861,9 +1032,10 @@ 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_addr_t ( addr_t ), // AW Address Type .aw_chan_t ( aw_chan_t ), // AW Channel Type .w_chan_t ( w_chan_t ), // W Channel Type .b_chan_t ( b_chan_t ), // B Channel Type @@ -888,6 +1060,7 @@ module axi_demux_intf #( .slv_req_i ( slv_req ), .slv_aw_select_i ( slv_aw_select_i ), .slv_ar_select_i ( slv_ar_select_i ), + .slv_aw_mcast_i ( slv_aw_mcast_i ), .slv_resp_o ( slv_resp ), // master port .mst_reqs_o ( mst_req ), diff --git a/src/axi_mcast_mux.sv b/src/axi_mcast_mux.sv index da17e2b8c..358cef8b7 100644 --- a/src/axi_mcast_mux.sv +++ b/src/axi_mcast_mux.sv @@ -25,7 +25,7 @@ `include "common_cells/assertions.svh" `include "common_cells/registers.svh" -module axi_mux #( +module axi_mcast_mux #( // AXI parameter and channel types parameter int unsigned SlvAxiIDWidth = 32'd0, // AXI ID width, slave ports parameter type slv_aw_chan_t = logic, // AW Channel Type, slave ports diff --git a/src/axi_mcast_xbar.sv b/src/axi_mcast_xbar.sv index 52769a66c..d95a07d54 100644 --- a/src/axi_mcast_xbar.sv +++ b/src/axi_mcast_xbar.sv @@ -1,4 +1,4 @@ -// Copyright (c) 2019 ETH Zurich and University of Bologna. +// Copyright (c) 2022 ETH Zurich and University of Bologna. // Copyright and related rights are licensed under the Solderpad Hardware // License, Version 0.51 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at @@ -9,13 +9,14 @@ // specific language governing permissions and limitations under the License. // // Authors: -// - Wolfgang Roenninger -// - Andreas Kurth -// - Florian Zaruba +// - Luca Colagrande +// Based on: +// - axi_xbar.sv -/// axi_xbar: 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 +// 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_mcast_xbar import cf_math_pkg::idx_width; #( /// Configuration struct for the crossbar see `axi_pkg` for fields and definitions. @@ -60,11 +61,17 @@ import cf_math_pkg::idx_width; /// axi_addr_t end_addr; /// } rule_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 + 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 ) ( /// Clock, positive edge triggered. input logic clk_i, @@ -82,24 +89,12 @@ 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. - /// Each master port can have multiple different rules. - 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 + + input ar_rule_t [Cfg.NoAddrRules-1:0] ar_addr_map_i, + input aw_rule_t [Cfg.NoAddrRules-1:0] aw_addr_map_i ); - // Address tpye for inidvidual address signals + // Address type for individual address signals typedef logic [Cfg.AxiAddrWidth-1:0] addr_t; // to account for the decoding error slave `ifdef VCS @@ -109,6 +104,12 @@ import cf_math_pkg::idx_width; `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; + + typedef struct packed { + addr_t addr; + addr_t mask; + } multi_addr_t; // signals from the axi_demuxes, one index more for decode error slv_req_t [Cfg.NoSlvPorts-1:0][Cfg.NoMstPorts:0] slv_reqs; @@ -123,80 +124,66 @@ import cf_math_pkg::idx_width; for (genvar i = 0; i < Cfg.NoSlvPorts; i++) begin : gen_slv_port_demux `ifdef VCS - logic [MstPortsIdxWidth-1:0] dec_aw, dec_ar; + logic [MstPortsIdxWidth-1:0] dec_ar_select; `else - logic [idx_width(Cfg.NoMstPorts)-1:0] dec_aw, dec_ar; + logic [idx_width(Cfg.NoMstPorts)-1:0] dec_ar_select; `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_select; + addr_t [Cfg.NoMstPorts-1:0] dec_aw_addr, dec_aw_mask; + logic dec_aw_valid, dec_aw_error; + logic dec_ar_valid, dec_ar_error; + mst_port_mask_t slv_aw_select; + mst_port_idx_t slv_ar_select; + addr_t [Cfg.NoMstPorts:0] slv_aw_addr, slv_aw_mask; + multi_addr_t [Cfg.NoMstPorts:0] slv_aw_mcast; - addr_decode #( - .NoIndices ( Cfg.NoMstPorts ), - .NoRules ( Cfg.NoAddrRules ), - .addr_t ( addr_t ), - .rule_t ( rule_t ) + multiaddr_decode #( + .NoRules(Cfg.NoMstPorts), + .addr_t (addr_t), + .rule_t (aw_rule_t) ) i_axi_aw_decode ( - .addr_i ( slv_ports_req_i[i].aw.addr ), - .addr_map_i ( addr_map_i ), - .idx_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] ) + .addr_i (slv_ports_req_i[i].aw.addr), + .mask_i (slv_ports_req_i[i].aw.user.mcast), + .addr_map_i (aw_addr_map_i), + .select_o (dec_aw_select), + .addr_o (dec_aw_addr), + .mask_o (dec_aw_mask), + .dec_valid_o(dec_aw_valid), + .dec_error_o(dec_aw_error) ); addr_decode #( .NoIndices ( Cfg.NoMstPorts ), .addr_t ( addr_t ), .NoRules ( Cfg.NoAddrRules ), - .rule_t ( rule_t ) + .rule_t ( ar_rule_t ) ) i_axi_ar_decode ( .addr_i ( slv_ports_req_i[i].ar.addr ), - .addr_map_i ( addr_map_i ), - .idx_o ( dec_ar ), + .addr_map_i ( ar_addr_map_i ), + .idx_o ( dec_ar_select ), .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] ) + .en_default_idx_i ( '0 ), + .default_idx_i ( '0 ) ); 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_select}; assign slv_ar_select = (dec_ar_error) ? - mst_port_idx_t'(Cfg.NoMstPorts) : mst_port_idx_t'(dec_ar); + mst_port_idx_t'(Cfg.NoMstPorts) : mst_port_idx_t'(dec_ar_select); + assign slv_aw_addr = {'0, dec_aw_addr}; + assign slv_aw_mask = {'0, dec_aw_mask}; + + // Zip slv_aw_addr and slv_aw_mask into one array of structs + for (genvar mst_idx = 0; mst_idx <= Cfg.NoMstPorts; mst_idx++) begin : gen_aw_mcast + assign slv_aw_mcast[mst_idx].addr = slv_aw_addr[mst_idx]; + assign slv_aw_mcast[mst_idx].mask = slv_aw_mask[mst_idx]; + end - // 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_addr_t ( addr_t ), // AW Address Type .aw_chan_t ( slv_aw_chan_t ), // AW Channel Type .w_chan_t ( w_chan_t ), // W Channel Type .b_chan_t ( slv_b_chan_t ), // B Channel Type @@ -220,6 +207,7 @@ import cf_math_pkg::idx_width; .slv_req_i ( slv_ports_req_i[i] ), .slv_aw_select_i ( slv_aw_select ), .slv_ar_select_i ( slv_ar_select ), + .slv_aw_mcast_i ( slv_aw_mcast ), .slv_resp_o ( slv_ports_resp_o[i] ), .mst_reqs_o ( slv_reqs[i] ), .mst_resps_i ( slv_resps[i] ) @@ -329,6 +317,10 @@ import cf_math_pkg::idx_width; $fatal(1, $sformatf("Slv_req and aw_chan id width not equal.")); id_slv_resp_ports: assert ($bits(slv_ports_resp_o[0].r.id) == Cfg.AxiIdWidthSlvPorts) else $fatal(1, $sformatf("Slv_req and aw_chan id width not equal.")); + addr_slv_req_ports: assert ($bits(slv_ports_req_i[0].aw.addr) == Cfg.AxiAddrWidth) else + $fatal(1, $sformatf("Slv_req and aw_addr width not equal.")); + addr_mst_req_ports: assert ($bits(mst_ports_req_o[0].aw.addr) == Cfg.AxiAddrWidth) else + $fatal(1, $sformatf("Mst_req and aw_addr width not equal.")); end `endif `endif @@ -338,31 +330,23 @@ 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, 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 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 + parameter type ar_rule_t = axi_pkg::xbar_rule_64_t, + parameter type aw_rule_t = axi_pkg::xbar_mask_rule_64_t ) ( 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 ar_rule_t [Cfg.NoAddrRules-1:0] ar_addr_map_i, + input aw_rule_t [Cfg.NoAddrRules-1:0] aw_addr_map_i ); localparam int unsigned AxiIdWidthMstPorts = Cfg.AxiIdWidthSlvPorts + $clog2(Cfg.NoSlvPorts); @@ -373,9 +357,13 @@ import cf_math_pkg::idx_width; typedef logic [Cfg.AxiDataWidth -1:0] data_t; typedef logic [Cfg.AxiDataWidth/8 -1:0] strb_t; typedef logic [AXI_USER_WIDTH -1:0] user_t; + // AW channel adds multicast mask to USER signals + typedef struct packed { + addr_t mcast; + } aw_user_t; - `AXI_TYPEDEF_AW_CHAN_T(mst_aw_chan_t, addr_t, id_mst_t, user_t) - `AXI_TYPEDEF_AW_CHAN_T(slv_aw_chan_t, addr_t, id_slv_t, user_t) + `AXI_TYPEDEF_AW_CHAN_T(mst_aw_chan_t, addr_t, id_mst_t, aw_user_t) + `AXI_TYPEDEF_AW_CHAN_T(slv_aw_chan_t, addr_t, id_slv_t, aw_user_t) `AXI_TYPEDEF_W_CHAN_T(w_chan_t, data_t, strb_t, user_t) `AXI_TYPEDEF_B_CHAN_T(mst_b_chan_t, id_mst_t, user_t) `AXI_TYPEDEF_B_CHAN_T(slv_b_chan_t, id_slv_t, user_t) @@ -403,7 +391,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 ), @@ -420,18 +408,18 @@ import cf_math_pkg::idx_width; .slv_resp_t ( slv_resp_t ), .mst_req_t ( mst_req_t ), .mst_resp_t ( mst_resp_t ), - .rule_t ( rule_t ) + .ar_rule_t ( ar_rule_t ), + .aw_rule_t ( aw_rule_t ) ) i_xbar ( .clk_i, .rst_ni, .test_i, - .slv_ports_req_i (slv_reqs ), - .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 + .slv_ports_req_i (slv_reqs), + .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 ); endmodule diff --git a/src/axi_pkg.sv b/src/axi_pkg.sv index f14d6c36e..c7a974383 100644 --- a/src/axi_pkg.sv +++ b/src/axi_pkg.sv @@ -528,6 +528,12 @@ package axi_pkg; logic [63:0] end_addr; } xbar_rule_64_t; + /// Commonly used rule types for `axi_xbar` (64-bit addresses). + typedef struct packed { + logic [63:0] addr; + logic [63:0] mask; + } xbar_mask_rule_64_t; + /// Commonly used rule types for `axi_xbar` (32-bit addresses). typedef struct packed { int unsigned idx; @@ -535,6 +541,12 @@ package axi_pkg; logic [31:0] end_addr; } xbar_rule_32_t; + /// Commonly used rule types for `axi_xbar` (32-bit addresses). + typedef struct packed { + logic [31:0] addr; + logic [31:0] mask; + } xbar_mask_rule_32_t; + // Return either the argument minus 1 or 0 if 0; useful for IO vector width declaration function automatic integer unsigned iomsb (input integer unsigned width); return (width != 32'd0) ? unsigned'(width-1) : 32'd0; diff --git a/src/axi_test.sv b/src/axi_test.sv index a782422c2..1c27cfc5e 100644 --- a/src/axi_test.sv +++ b/src/axi_test.sv @@ -15,6 +15,7 @@ // - Fabian Schuiki // - Thomas Benz // - Matheus Cavalcante +// - Luca Colagrande /// A set of testbench utilities for AXI interfaces. @@ -710,6 +711,8 @@ package axi_test; parameter bit UNIQUE_IDS = 1'b0, // guarantee that the ID of each transaction is // unique among all in-flight transactions in the // same direction + // Custom features + parameter bit ENABLE_MULTICAST = 1'b0, // Dependent parameters, do not override. parameter int AXI_STRB_WIDTH = DW/8, parameter int N_AXI_IDS = 2**IW, @@ -770,6 +773,8 @@ package axi_test; } traffic_shape[$]; int unsigned max_cprob; + int unsigned mcast_prob; + function new( virtual AXI_BUS_DV #( .AXI_ADDR_WIDTH(AW), @@ -808,6 +813,13 @@ package axi_test; atop_resp_r = '0; endfunction + // Sets the probability to generate a transaction with a non-zero multicast mask. + // `prob` should be a percentage, as Questa 2022.3 doesn't support real types + // in SystemVerilog `dist` constraints. + function void set_multicast_probability(int unsigned prob); + mcast_prob = prob; + endfunction + function void add_memory_region(input addr_t addr_begin, input addr_t addr_end, input mem_type_t mem_type); mem_map.push_back({addr_begin, addr_end, mem_type}); endfunction @@ -867,6 +879,8 @@ package axi_test; automatic int unsigned mem_region_idx; automatic mem_region_t mem_region; automatic int cprob; + automatic bit mcast; + automatic addr_t mcast_mask; // No memory regions defined if (mem_map.size() == 0) begin @@ -892,6 +906,7 @@ package axi_test; // Determine memory type. ax_beat.ax_cache = is_read ? axi_pkg::get_arcache(mem_region.mem_type) : axi_pkg::get_awcache(mem_region.mem_type); // Randomize beat size. + // TODO colluca: how do we handle traffic shaping w/ multicast? if (TRAFFIC_SHAPING) begin rand_success = std::randomize(cprob) with { cprob >= 0; cprob < max_cprob; @@ -964,6 +979,15 @@ package axi_test; ax_beat.ax_addr = axi_pkg::aligned_addr(addr, axi_pkg::size_t'(SIZE_ALIGN) ); rand_success = std::randomize(id); assert(rand_success); rand_success = std::randomize(qos); assert(rand_success); + // Randomize multicast mask. + if (ENABLE_MULTICAST && !is_read) begin + rand_success = std::randomize(mcast, mcast_mask) with { + mcast dist {0 := (100 - mcast_prob), 1 := mcast_prob}; + !mcast -> mcast_mask == 0; + mcast -> mcast_mask != 0; + }; assert(rand_success); + ax_beat.ax_user = mcast_mask; + end // The random ID *must* be legalized with `legalize_id()` before the beat is sent! This is // currently done in the functions `create_aws()` and `send_ars()`. ax_beat.ax_id = id; @@ -981,6 +1005,11 @@ package axi_test; $warning("ATOP suppressed because INCR bursts are disabled!"); beat.ax_atop[5:4] = 2'b00; end + if (beat.ax_atop[5:4] != 2'b00 && beat.ax_user != '0) begin + // We can emit ATOPs only if current burst is not a multicast. + $warning("ATOP suppressed because burst is a multicast!"); + beat.ax_atop[5:4] = 2'b00; + end if (beat.ax_atop[5:4] != 2'b00) begin // ATOP // Determine `ax_atop`. if (beat.ax_atop[5:4] == axi_pkg::ATOP_ATOMICSTORE || @@ -2613,7 +2642,8 @@ module axi_chan_logger #( parameter type w_chan_t = logic, // axi W type parameter type b_chan_t = logic, // axi B type parameter type ar_chan_t = logic, // axi AR type - parameter type r_chan_t = logic // axi R type + parameter type r_chan_t = logic, // axi R type + parameter bit ENABLE_MULTICAST = 1'b0 ) ( input logic clk_i, // Clock input logic rst_ni, // Asynchronous reset active low, when `1'b0` no sampling @@ -2643,6 +2673,10 @@ module axi_chan_logger #( localparam int unsigned IdWidth = $bits(aw_chan_i.id); localparam int unsigned NoIds = 2**IdWidth; + // addr width from channel + localparam int unsigned AddrWidth = $bits(aw_chan_i.addr); + typedef logic [AddrWidth-1:0] addr_t; + // queues for writes and reads aw_chan_t aw_queue[$]; w_chan_t w_queue[$]; @@ -2656,6 +2690,8 @@ module axi_chan_logger #( automatic int fd; automatic string log_file; automatic string log_str; + automatic addr_t aw_mcast_mask; + automatic addr_t aw_addr; // only execute when reset is high if (rst_ni) begin // AW channel @@ -2664,8 +2700,13 @@ module axi_chan_logger #( log_file = $sformatf("./axi_log/%s/write.log", LoggerName); fd = $fopen(log_file, "a"); if (fd) begin - log_str = $sformatf("%0t> ID: %h AW on channel: LEN: %d, ATOP: %b", - $time, aw_chan_i.id, aw_chan_i.len, aw_chan_i.atop); + aw_addr = aw_chan_i.addr; + if (ENABLE_MULTICAST) begin + aw_mcast_mask = aw_chan_i.user[AddrWidth-1:0]; + for (int i = 0; i < AddrWidth; i++) if (aw_mcast_mask[i]) aw_addr[i] = 1'bx; + end + log_str = $sformatf("%0t> ID: %h AW on channel: LEN: %d, ATOP: %b, ADDR: %b", + $time, aw_chan_i.id, aw_chan_i.len, aw_chan_i.atop, aw_addr); $fdisplay(fd, log_str); $fclose(fd); end diff --git a/test/axi_synth_bench.sv b/test/axi_synth_bench.sv index e5caff06f..34f4a87f4 100644 --- a/test/axi_synth_bench.sv +++ b/test/axi_synth_bench.sv @@ -13,6 +13,7 @@ // - Andreas Kurth // - Fabian Schuiki // - Michael Rogenmoser +// - Luca Colagrande /// A synthesis test bench which instantiates various adapter variants. module axi_synth_bench ( @@ -786,3 +787,1025 @@ module synth_axi_lite_dw_converter #( ); endmodule + + +module synth_axi_xbar #( + parameter int unsigned NoSlvMst = 32'd8, // Max 16, as the addr rules defined below + parameter bit EnableMulticast = 0, + parameter bit UniqueIds = 0, + parameter axi_pkg::xbar_latency_e LatencyMode = axi_pkg::NO_LATENCY, + // axi configuration + parameter int unsigned AxiIdWidthMasters = 4, + parameter int unsigned AxiIdUsed = 3, // Has to be <= AxiIdWidthMasters + parameter int unsigned AxiIdWidthSlaves = AxiIdWidthMasters + $clog2(NoSlvMst), + parameter int unsigned AxiAddrWidth = 32, // Axi Address Width + parameter int unsigned AxiDataWidth = 32, // Axi Data Width + parameter int unsigned AxiStrbWidth = AxiDataWidth / 8, + parameter int unsigned AxiUserWidth = 1, + parameter int unsigned AxiAwUserWidth = EnableMulticast ? AxiAddrWidth : 1, + // axi types + parameter type id_mst_t = logic [AxiIdWidthSlaves-1:0], + parameter type id_slv_t = logic [AxiIdWidthMasters-1:0], + parameter type addr_t = logic [AxiAddrWidth-1:0], + parameter type data_t = logic [AxiDataWidth-1:0], + parameter type strb_t = logic [AxiStrbWidth-1:0], + parameter type user_t = logic [AxiUserWidth-1:0], + parameter type aw_user_t = struct packed {logic [AxiAwUserWidth-1:0] mcast;} +) ( + input logic clk_i, + input logic rst_ni, + + /*********************************** + /* Slave ports request inputs + ***********************************/ + + // AW + input id_slv_t [NoSlvMst-1:0] slv_aw_id, + input addr_t [NoSlvMst-1:0] slv_aw_addr, + input axi_pkg::len_t [NoSlvMst-1:0] slv_aw_len, + input axi_pkg::size_t [NoSlvMst-1:0] slv_aw_size, + input axi_pkg::burst_t [NoSlvMst-1:0] slv_aw_burst, + input logic [NoSlvMst-1:0] slv_aw_lock, + input axi_pkg::cache_t [NoSlvMst-1:0] slv_aw_cache, + input axi_pkg::prot_t [NoSlvMst-1:0] slv_aw_prot, + input axi_pkg::qos_t [NoSlvMst-1:0] slv_aw_qos, + input axi_pkg::region_t [NoSlvMst-1:0] slv_aw_region, + input axi_pkg::atop_t [NoSlvMst-1:0] slv_aw_atop, + input aw_user_t [NoSlvMst-1:0] slv_aw_user, + input logic [NoSlvMst-1:0] slv_aw_valid, + // W + input data_t [NoSlvMst-1:0] slv_w_data, + input strb_t [NoSlvMst-1:0] slv_w_strb, + input logic [NoSlvMst-1:0] slv_w_last, + input user_t [NoSlvMst-1:0] slv_w_user, + input logic [NoSlvMst-1:0] slv_w_valid, + // B + input logic [NoSlvMst-1:0] slv_b_ready, + // AR + input id_slv_t [NoSlvMst-1:0] slv_ar_id, + input addr_t [NoSlvMst-1:0] slv_ar_addr, + input axi_pkg::len_t [NoSlvMst-1:0] slv_ar_len, + input axi_pkg::size_t [NoSlvMst-1:0] slv_ar_size, + input axi_pkg::burst_t [NoSlvMst-1:0] slv_ar_burst, + input logic [NoSlvMst-1:0] slv_ar_lock, + input axi_pkg::cache_t [NoSlvMst-1:0] slv_ar_cache, + input axi_pkg::prot_t [NoSlvMst-1:0] slv_ar_prot, + input axi_pkg::qos_t [NoSlvMst-1:0] slv_ar_qos, + input axi_pkg::region_t [NoSlvMst-1:0] slv_ar_region, + input user_t [NoSlvMst-1:0] slv_ar_user, + input logic [NoSlvMst-1:0] slv_ar_valid, + // R + input logic [NoSlvMst-1:0] slv_r_ready, + + /*********************************** + /* Slave ports response outputs + ***********************************/ + + // AW + output logic [NoSlvMst-1:0] slv_aw_ready, + // AR + output logic [NoSlvMst-1:0] slv_ar_ready, + // W + output logic [NoSlvMst-1:0] slv_w_ready, + // B + output logic [NoSlvMst-1:0] slv_b_valid, + output id_slv_t [NoSlvMst-1:0] slv_b_id, + output axi_pkg::resp_t [NoSlvMst-1:0] slv_b_resp, + output user_t [NoSlvMst-1:0] slv_b_user, + // R + output logic [NoSlvMst-1:0] slv_r_valid, + output id_slv_t [NoSlvMst-1:0] slv_r_id, + output data_t [NoSlvMst-1:0] slv_r_data, + output axi_pkg::resp_t [NoSlvMst-1:0] slv_r_resp, + output logic [NoSlvMst-1:0] slv_r_last, + output user_t [NoSlvMst-1:0] slv_r_user, + + /*********************************** + /* Master ports request outputs + ***********************************/ + + // AW + output id_mst_t [NoSlvMst-1:0] mst_aw_id, + output addr_t [NoSlvMst-1:0] mst_aw_addr, + output axi_pkg::len_t [NoSlvMst-1:0] mst_aw_len, + output axi_pkg::size_t [NoSlvMst-1:0] mst_aw_size, + output axi_pkg::burst_t [NoSlvMst-1:0] mst_aw_burst, + output logic [NoSlvMst-1:0] mst_aw_lock, + output axi_pkg::cache_t [NoSlvMst-1:0] mst_aw_cache, + output axi_pkg::prot_t [NoSlvMst-1:0] mst_aw_prot, + output axi_pkg::qos_t [NoSlvMst-1:0] mst_aw_qos, + output axi_pkg::region_t [NoSlvMst-1:0] mst_aw_region, + output axi_pkg::atop_t [NoSlvMst-1:0] mst_aw_atop, + output aw_user_t [NoSlvMst-1:0] mst_aw_user, + output logic [NoSlvMst-1:0] mst_aw_valid, + // W + output data_t [NoSlvMst-1:0] mst_w_data, + output strb_t [NoSlvMst-1:0] mst_w_strb, + output logic [NoSlvMst-1:0] mst_w_last, + output user_t [NoSlvMst-1:0] mst_w_user, + output logic [NoSlvMst-1:0] mst_w_valid, + // B + output logic [NoSlvMst-1:0] mst_b_ready, + // AR + output id_mst_t [NoSlvMst-1:0] mst_ar_id, + output addr_t [NoSlvMst-1:0] mst_ar_addr, + output axi_pkg::len_t [NoSlvMst-1:0] mst_ar_len, + output axi_pkg::size_t [NoSlvMst-1:0] mst_ar_size, + output axi_pkg::burst_t [NoSlvMst-1:0] mst_ar_burst, + output logic [NoSlvMst-1:0] mst_ar_lock, + output axi_pkg::cache_t [NoSlvMst-1:0] mst_ar_cache, + output axi_pkg::prot_t [NoSlvMst-1:0] mst_ar_prot, + output axi_pkg::qos_t [NoSlvMst-1:0] mst_ar_qos, + output axi_pkg::region_t [NoSlvMst-1:0] mst_ar_region, + output user_t [NoSlvMst-1:0] mst_ar_user, + output logic [NoSlvMst-1:0] mst_ar_valid, + // R + output logic [NoSlvMst-1:0] mst_r_ready, + + /*********************************** + /* Master ports response inputs + ***********************************/ + + // AW + input logic [NoSlvMst-1:0] mst_aw_ready, + // AR + input logic [NoSlvMst-1:0] mst_ar_ready, + // W + input logic [NoSlvMst-1:0] mst_w_ready, + // B + input logic [NoSlvMst-1:0] mst_b_valid, + input id_mst_t [NoSlvMst-1:0] mst_b_id, + input axi_pkg::resp_t [NoSlvMst-1:0] mst_b_resp, + input user_t [NoSlvMst-1:0] mst_b_user, + // R + input logic [NoSlvMst-1:0] mst_r_valid, + input id_mst_t [NoSlvMst-1:0] mst_r_id, + input data_t [NoSlvMst-1:0] mst_r_data, + input axi_pkg::resp_t [NoSlvMst-1:0] mst_r_resp, + input logic [NoSlvMst-1:0] mst_r_last, + input user_t [NoSlvMst-1:0] mst_r_user + +); + + localparam axi_pkg::xbar_cfg_t xbar_cfg = '{ + NoSlvPorts: NoSlvMst, + NoMstPorts: NoSlvMst, + MaxMstTrans: 10, + MaxSlvTrans: 6, + FallThrough: 1'b0, + LatencyMode: LatencyMode, + PipelineStages: 0, + AxiIdWidthSlvPorts: AxiIdWidthMasters, + AxiIdUsedSlvPorts: AxiIdUsed, + UniqueIds: UniqueIds, + AxiAddrWidth: AxiAddrWidth, + AxiDataWidth: AxiDataWidth, + NoAddrRules: NoSlvMst + }; + + typedef axi_pkg::xbar_mask_rule_32_t aw_rule_t; // Has to be the same width as axi addr + typedef axi_pkg::xbar_rule_32_t ar_rule_t; // Has to be the same width as axi addr + + `AXI_TYPEDEF_AW_CHAN_T(mst_aw_chan_t, addr_t, id_mst_t, aw_user_t) + `AXI_TYPEDEF_AW_CHAN_T(slv_aw_chan_t, addr_t, id_slv_t, aw_user_t) + `AXI_TYPEDEF_W_CHAN_T(w_chan_t, data_t, strb_t, user_t) + `AXI_TYPEDEF_B_CHAN_T(mst_b_chan_t, id_mst_t, user_t) + `AXI_TYPEDEF_B_CHAN_T(slv_b_chan_t, id_slv_t, user_t) + + `AXI_TYPEDEF_AR_CHAN_T(mst_ar_chan_t, addr_t, id_mst_t, user_t) + `AXI_TYPEDEF_AR_CHAN_T(slv_ar_chan_t, addr_t, id_slv_t, user_t) + `AXI_TYPEDEF_R_CHAN_T(mst_r_chan_t, data_t, id_mst_t, user_t) + `AXI_TYPEDEF_R_CHAN_T(slv_r_chan_t, data_t, id_slv_t, user_t) + + `AXI_TYPEDEF_REQ_T(mst_req_t, mst_aw_chan_t, w_chan_t, mst_ar_chan_t) + `AXI_TYPEDEF_RESP_T(mst_resp_t, mst_b_chan_t, mst_r_chan_t) + `AXI_TYPEDEF_REQ_T(slv_req_t, slv_aw_chan_t, w_chan_t, slv_ar_chan_t) + `AXI_TYPEDEF_RESP_T(slv_resp_t, slv_b_chan_t, slv_r_chan_t) + + // Each slave has its own address range: + localparam ar_rule_t [xbar_cfg.NoAddrRules-1:0] ar_addr_map = ar_addr_map_gen(); + localparam aw_rule_t [xbar_cfg.NoAddrRules-1:0] aw_addr_map = aw_addr_map_gen(); + + function ar_rule_t [xbar_cfg.NoAddrRules-1:0] ar_addr_map_gen (); + for (int unsigned i = 0; i < xbar_cfg.NoAddrRules; i++) begin + ar_addr_map_gen[i] = ar_rule_t'{ + idx: unsigned'(i), + start_addr: i * 32'h0000_2000, + end_addr: (i+1) * 32'h0000_2000, + default: '0 + }; + end + endfunction + + function aw_rule_t [xbar_cfg.NoAddrRules-1:0] aw_addr_map_gen (); + for (int unsigned i = 0; i < xbar_cfg.NoAddrRules; i++) begin + aw_addr_map_gen[i] = aw_rule_t'{ + addr: i * 32'h0000_2000, + mask: 32'h0000_1FFF, + default: '0 + }; + end + endfunction + + slv_req_t [NoSlvMst-1:0] slv_reqs; + mst_req_t [NoSlvMst-1:0] mst_reqs; + slv_resp_t [NoSlvMst-1:0] slv_resps; + mst_resp_t [NoSlvMst-1:0] mst_resps; + + // Connect XBAR interfaces + generate + for (genvar i = 0; i < NoSlvMst; i++) begin : g_connect_slv_port + // Request + assign slv_reqs[i].aw.id = slv_aw_id[i]; + assign slv_reqs[i].aw.addr = slv_aw_addr[i]; + assign slv_reqs[i].aw.len = slv_aw_len[i]; + assign slv_reqs[i].aw.size = slv_aw_size[i]; + assign slv_reqs[i].aw.burst = slv_aw_burst[i]; + assign slv_reqs[i].aw.lock = slv_aw_lock[i]; + assign slv_reqs[i].aw.cache = slv_aw_cache[i]; + assign slv_reqs[i].aw.prot = slv_aw_prot[i]; + assign slv_reqs[i].aw.qos = slv_aw_qos[i]; + assign slv_reqs[i].aw.region = slv_aw_region[i]; + assign slv_reqs[i].aw.atop = slv_aw_atop[i]; + assign slv_reqs[i].aw.user = slv_aw_user[i]; + assign slv_reqs[i].aw_valid = slv_aw_valid[i]; + assign slv_reqs[i].w.data = slv_w_data[i]; + assign slv_reqs[i].w.strb = slv_w_strb[i]; + assign slv_reqs[i].w.last = slv_w_last[i]; + assign slv_reqs[i].w.user = slv_w_user[i]; + assign slv_reqs[i].w_valid = slv_w_valid[i]; + assign slv_reqs[i].b_ready = slv_b_ready[i]; + assign slv_reqs[i].ar.id = slv_ar_id[i]; + assign slv_reqs[i].ar.addr = slv_ar_addr[i]; + assign slv_reqs[i].ar.len = slv_ar_len[i]; + assign slv_reqs[i].ar.size = slv_ar_size[i]; + assign slv_reqs[i].ar.burst = slv_ar_burst[i]; + assign slv_reqs[i].ar.lock = slv_ar_lock[i]; + assign slv_reqs[i].ar.cache = slv_ar_cache[i]; + assign slv_reqs[i].ar.prot = slv_ar_prot[i]; + assign slv_reqs[i].ar.qos = slv_ar_qos[i]; + assign slv_reqs[i].ar.region = slv_ar_region[i]; + assign slv_reqs[i].ar.user = slv_ar_user[i]; + assign slv_reqs[i].ar_valid = slv_ar_valid[i]; + assign slv_reqs[i].r_ready = slv_r_ready[i]; + // Response + assign slv_aw_ready[i] = slv_resps[i].aw_ready; + assign slv_ar_ready[i] = slv_resps[i].ar_ready; + assign slv_w_ready[i] = slv_resps[i].w_ready; + assign slv_b_valid[i] = slv_resps[i].b_valid; + assign slv_b_id[i] = slv_resps[i].b.id; + assign slv_b_resp[i] = slv_resps[i].b.resp; + assign slv_b_user[i] = slv_resps[i].b.user; + assign slv_r_valid[i] = slv_resps[i].r_valid; + assign slv_r_id[i] = slv_resps[i].r.id; + assign slv_r_data[i] = slv_resps[i].r.data; + assign slv_r_resp[i] = slv_resps[i].r.resp; + assign slv_r_last[i] = slv_resps[i].r.last; + assign slv_r_user[i] = slv_resps[i].r.user; + end + + for (genvar i = 0; i < NoSlvMst; i++) begin : g_connect_mst_port + // Request + assign mst_aw_id[i] = mst_reqs[i].aw.id; + assign mst_aw_addr[i] = mst_reqs[i].aw.addr; + assign mst_aw_len[i] = mst_reqs[i].aw.len; + assign mst_aw_size[i] = mst_reqs[i].aw.size; + assign mst_aw_burst[i] = mst_reqs[i].aw.burst; + assign mst_aw_lock[i] = mst_reqs[i].aw.lock; + assign mst_aw_cache[i] = mst_reqs[i].aw.cache; + assign mst_aw_prot[i] = mst_reqs[i].aw.prot; + assign mst_aw_qos[i] = mst_reqs[i].aw.qos; + assign mst_aw_region[i] = mst_reqs[i].aw.region; + assign mst_aw_atop[i] = mst_reqs[i].aw.atop; + assign mst_aw_user[i] = mst_reqs[i].aw.user; + assign mst_aw_valid[i] = mst_reqs[i].aw_valid; + assign mst_w_data[i] = mst_reqs[i].w.data; + assign mst_w_strb[i] = mst_reqs[i].w.strb; + assign mst_w_last[i] = mst_reqs[i].w.last; + assign mst_w_user[i] = mst_reqs[i].w.user; + assign mst_w_valid[i] = mst_reqs[i].w_valid; + assign mst_b_ready[i] = mst_reqs[i].b_ready; + assign mst_ar_id[i] = mst_reqs[i].ar.id; + assign mst_ar_addr[i] = mst_reqs[i].ar.addr; + assign mst_ar_len[i] = mst_reqs[i].ar.len; + assign mst_ar_size[i] = mst_reqs[i].ar.size; + assign mst_ar_burst[i] = mst_reqs[i].ar.burst; + assign mst_ar_lock[i] = mst_reqs[i].ar.lock; + assign mst_ar_cache[i] = mst_reqs[i].ar.cache; + assign mst_ar_prot[i] = mst_reqs[i].ar.prot; + assign mst_ar_qos[i] = mst_reqs[i].ar.qos; + assign mst_ar_region[i] = mst_reqs[i].ar.region; + assign mst_ar_user[i] = mst_reqs[i].ar.user; + assign mst_ar_valid[i] = mst_reqs[i].ar_valid; + assign mst_r_ready[i] = mst_reqs[i].r_ready; + // Response + assign mst_resps[i].aw_ready = mst_aw_ready[i]; + assign mst_resps[i].ar_ready = mst_ar_ready[i]; + assign mst_resps[i].w_ready = mst_w_ready[i]; + assign mst_resps[i].b_valid = mst_b_valid[i]; + assign mst_resps[i].b.id = mst_b_id[i]; + assign mst_resps[i].b.resp = mst_b_resp[i]; + assign mst_resps[i].b.user = mst_b_user[i]; + assign mst_resps[i].r_valid = mst_r_valid[i]; + assign mst_resps[i].r.id = mst_r_id[i]; + assign mst_resps[i].r.data = mst_r_data[i]; + assign mst_resps[i].r.resp = mst_r_resp[i]; + assign mst_resps[i].r.last = mst_r_last[i]; + assign mst_resps[i].r.user = mst_r_user[i]; + end + endgenerate + + if (EnableMulticast) begin : g_multicast + axi_mcast_xbar #( + .Cfg (xbar_cfg), + .slv_aw_chan_t(slv_aw_chan_t), + .mst_aw_chan_t(mst_aw_chan_t), + .w_chan_t (w_chan_t), + .slv_b_chan_t (slv_b_chan_t), + .mst_b_chan_t (mst_b_chan_t), + .slv_ar_chan_t(slv_ar_chan_t), + .mst_ar_chan_t(mst_ar_chan_t), + .slv_r_chan_t (slv_r_chan_t), + .mst_r_chan_t (mst_r_chan_t), + .slv_req_t (slv_req_t), + .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) + ) i_xbar_dut ( + .clk_i (clk_i), + .rst_ni (rst_ni), + .test_i ('0), + .slv_ports_req_i (slv_reqs), + .slv_ports_resp_o (slv_resps), + .mst_ports_req_o (mst_reqs), + .mst_ports_resp_i (mst_resps), + .ar_addr_map_i (ar_addr_map), + .aw_addr_map_i (aw_addr_map) + ); + end else begin : g_no_multicast + axi_xbar #( + .Cfg (xbar_cfg), + .slv_aw_chan_t(slv_aw_chan_t), + .mst_aw_chan_t(mst_aw_chan_t), + .w_chan_t (w_chan_t), + .slv_b_chan_t (slv_b_chan_t), + .mst_b_chan_t (mst_b_chan_t), + .slv_ar_chan_t(slv_ar_chan_t), + .mst_ar_chan_t(mst_ar_chan_t), + .slv_r_chan_t (slv_r_chan_t), + .mst_r_chan_t (mst_r_chan_t), + .slv_req_t (slv_req_t), + .slv_resp_t (slv_resp_t), + .mst_req_t (mst_req_t), + .mst_resp_t (mst_resp_t), + .rule_t (ar_rule_t) + ) i_xbar_dut ( + .clk_i (clk_i), + .rst_ni (rst_ni), + .test_i ('0), + .slv_ports_req_i (slv_reqs), + .slv_ports_resp_o (slv_resps), + .mst_ports_req_o (mst_reqs), + .mst_ports_resp_i (mst_resps), + .addr_map_i (ar_addr_map), + .en_default_mst_port_i('0), + .default_mst_port_i ('0) + ); + end + +endmodule + +module synth_axi_demux import axi_pkg::*; #( + parameter int unsigned NoMstPorts = 32'd8, + parameter bit UniqueIds = 0, + parameter xbar_latency_e LatencyMode = NO_LATENCY, + // axi configuration + parameter int unsigned AxiIdWidthMasters = 4, + parameter int unsigned AxiIdUsed = 3, // Has to be <= AxiIdWidthMasters + parameter int unsigned AxiAddrWidth = 32, // Axi Address Width + parameter int unsigned AxiDataWidth = 32, // Axi Data Width + parameter int unsigned AxiStrbWidth = AxiDataWidth / 8, + parameter int unsigned AxiUserWidth = 1, + // axi types + parameter type id_t = logic [AxiIdWidthMasters-1:0], + parameter type addr_t = logic [AxiAddrWidth-1:0], + parameter type data_t = logic [AxiDataWidth-1:0], + parameter type strb_t = logic [AxiStrbWidth-1:0], + parameter type user_t = logic [AxiUserWidth-1:0], + // select signal types + parameter int unsigned SelectWidth = (NoMstPorts > 32'd1) ? $clog2(NoMstPorts) : 32'd1, + parameter type select_t = logic [SelectWidth-1:0] +) ( + input logic clk_i, + input logic rst_ni, + + // Select signals + input select_t slv_aw_select_i, + input select_t slv_ar_select_i, + + /*********************************** + /* Slave ports request inputs + ***********************************/ + + // AW + input id_t slv_aw_id, + input addr_t slv_aw_addr, + input axi_pkg::len_t slv_aw_len, + input axi_pkg::size_t slv_aw_size, + input axi_pkg::burst_t slv_aw_burst, + input logic slv_aw_lock, + input axi_pkg::cache_t slv_aw_cache, + input axi_pkg::prot_t slv_aw_prot, + input axi_pkg::qos_t slv_aw_qos, + input axi_pkg::region_t slv_aw_region, + input axi_pkg::atop_t slv_aw_atop, + input user_t slv_aw_user, + input logic slv_aw_valid, + // W + input data_t slv_w_data, + input strb_t slv_w_strb, + input logic slv_w_last, + input user_t slv_w_user, + input logic slv_w_valid, + // B + input logic slv_b_ready, + // AR + input id_t slv_ar_id, + input addr_t slv_ar_addr, + input axi_pkg::len_t slv_ar_len, + input axi_pkg::size_t slv_ar_size, + input axi_pkg::burst_t slv_ar_burst, + input logic slv_ar_lock, + input axi_pkg::cache_t slv_ar_cache, + input axi_pkg::prot_t slv_ar_prot, + input axi_pkg::qos_t slv_ar_qos, + input axi_pkg::region_t slv_ar_region, + input user_t slv_ar_user, + input logic slv_ar_valid, + // R + input logic slv_r_ready, + + /*********************************** + /* Slave ports response outputs + ***********************************/ + + // AW + output logic slv_aw_ready, + // AR + output logic slv_ar_ready, + // W + output logic slv_w_ready, + // B + output logic slv_b_valid, + output id_t slv_b_id, + output axi_pkg::resp_t slv_b_resp, + output user_t slv_b_user, + // R + output logic slv_r_valid, + output id_t slv_r_id, + output data_t slv_r_data, + output axi_pkg::resp_t slv_r_resp, + output logic slv_r_last, + output user_t slv_r_user, + + /*********************************** + /* Master ports request outputs + ***********************************/ + + // AW + output id_t [NoMstPorts-1:0] mst_aw_id, + output addr_t [NoMstPorts-1:0] mst_aw_addr, + output axi_pkg::len_t [NoMstPorts-1:0] mst_aw_len, + output axi_pkg::size_t [NoMstPorts-1:0] mst_aw_size, + output axi_pkg::burst_t [NoMstPorts-1:0] mst_aw_burst, + output logic [NoMstPorts-1:0] mst_aw_lock, + output axi_pkg::cache_t [NoMstPorts-1:0] mst_aw_cache, + output axi_pkg::prot_t [NoMstPorts-1:0] mst_aw_prot, + output axi_pkg::qos_t [NoMstPorts-1:0] mst_aw_qos, + output axi_pkg::region_t [NoMstPorts-1:0] mst_aw_region, + output axi_pkg::atop_t [NoMstPorts-1:0] mst_aw_atop, + output user_t [NoMstPorts-1:0] mst_aw_user, + output logic [NoMstPorts-1:0] mst_aw_valid, + // W + output data_t [NoMstPorts-1:0] mst_w_data, + output strb_t [NoMstPorts-1:0] mst_w_strb, + output logic [NoMstPorts-1:0] mst_w_last, + output user_t [NoMstPorts-1:0] mst_w_user, + output logic [NoMstPorts-1:0] mst_w_valid, + // B + output logic [NoMstPorts-1:0] mst_b_ready, + // AR + output id_t [NoMstPorts-1:0] mst_ar_id, + output addr_t [NoMstPorts-1:0] mst_ar_addr, + output axi_pkg::len_t [NoMstPorts-1:0] mst_ar_len, + output axi_pkg::size_t [NoMstPorts-1:0] mst_ar_size, + output axi_pkg::burst_t [NoMstPorts-1:0] mst_ar_burst, + output logic [NoMstPorts-1:0] mst_ar_lock, + output axi_pkg::cache_t [NoMstPorts-1:0] mst_ar_cache, + output axi_pkg::prot_t [NoMstPorts-1:0] mst_ar_prot, + output axi_pkg::qos_t [NoMstPorts-1:0] mst_ar_qos, + output axi_pkg::region_t [NoMstPorts-1:0] mst_ar_region, + output user_t [NoMstPorts-1:0] mst_ar_user, + output logic [NoMstPorts-1:0] mst_ar_valid, + // R + output logic [NoMstPorts-1:0] mst_r_ready, + + /*********************************** + /* Master ports response inputs + ***********************************/ + + // AW + input logic [NoMstPorts-1:0] mst_aw_ready, + // AR + input logic [NoMstPorts-1:0] mst_ar_ready, + // W + input logic [NoMstPorts-1:0] mst_w_ready, + // B + input logic [NoMstPorts-1:0] mst_b_valid, + input id_t [NoMstPorts-1:0] mst_b_id, + input axi_pkg::resp_t [NoMstPorts-1:0] mst_b_resp, + input user_t [NoMstPorts-1:0] mst_b_user, + // R + input logic [NoMstPorts-1:0] mst_r_valid, + input id_t [NoMstPorts-1:0] mst_r_id, + input data_t [NoMstPorts-1:0] mst_r_data, + input axi_pkg::resp_t [NoMstPorts-1:0] mst_r_resp, + input logic [NoMstPorts-1:0] mst_r_last, + input user_t [NoMstPorts-1:0] mst_r_user + +); + + `AXI_TYPEDEF_AW_CHAN_T(aw_chan_t, addr_t, id_t, user_t) + `AXI_TYPEDEF_W_CHAN_T(w_chan_t, data_t, strb_t, user_t) + `AXI_TYPEDEF_B_CHAN_T(b_chan_t, id_t, user_t) + + `AXI_TYPEDEF_AR_CHAN_T(ar_chan_t, addr_t, id_t, user_t) + `AXI_TYPEDEF_R_CHAN_T(r_chan_t, data_t, id_t, user_t) + + `AXI_TYPEDEF_REQ_T(req_t, aw_chan_t, w_chan_t, ar_chan_t) + `AXI_TYPEDEF_RESP_T(resp_t, b_chan_t, r_chan_t) + + req_t slv_req; + req_t [NoMstPorts-1:0] mst_reqs; + resp_t slv_resp; + resp_t [NoMstPorts-1:0] mst_resps; + + // Connect XBAR interfaces + assign slv_req.aw.id = slv_aw_id; + assign slv_req.aw.addr = slv_aw_addr; + assign slv_req.aw.len = slv_aw_len; + assign slv_req.aw.size = slv_aw_size; + assign slv_req.aw.burst = slv_aw_burst; + assign slv_req.aw.lock = slv_aw_lock; + assign slv_req.aw.cache = slv_aw_cache; + assign slv_req.aw.prot = slv_aw_prot; + assign slv_req.aw.qos = slv_aw_qos; + assign slv_req.aw.region = slv_aw_region; + assign slv_req.aw.atop = slv_aw_atop; + assign slv_req.aw.user = slv_aw_user; + assign slv_req.aw_valid = slv_aw_valid; + assign slv_req.w.data = slv_w_data; + assign slv_req.w.strb = slv_w_strb; + assign slv_req.w.last = slv_w_last; + assign slv_req.w.user = slv_w_user; + assign slv_req.w_valid = slv_w_valid; + assign slv_req.b_ready = slv_b_ready; + assign slv_req.ar.id = slv_ar_id; + assign slv_req.ar.addr = slv_ar_addr; + assign slv_req.ar.len = slv_ar_len; + assign slv_req.ar.size = slv_ar_size; + assign slv_req.ar.burst = slv_ar_burst; + assign slv_req.ar.lock = slv_ar_lock; + assign slv_req.ar.cache = slv_ar_cache; + assign slv_req.ar.prot = slv_ar_prot; + assign slv_req.ar.qos = slv_ar_qos; + assign slv_req.ar.region = slv_ar_region; + assign slv_req.ar.user = slv_ar_user; + assign slv_req.ar_valid = slv_ar_valid; + assign slv_req.r_ready = slv_r_ready; + // Response + assign slv_aw_ready = slv_resp.aw_ready; + assign slv_ar_ready = slv_resp.ar_ready; + assign slv_w_ready = slv_resp.w_ready; + assign slv_b_valid = slv_resp.b_valid; + assign slv_b_id = slv_resp.b.id; + assign slv_b_resp = slv_resp.b.resp; + assign slv_b_user = slv_resp.b.user; + assign slv_r_valid = slv_resp.r_valid; + assign slv_r_id = slv_resp.r.id; + assign slv_r_data = slv_resp.r.data; + assign slv_r_resp = slv_resp.r.resp; + assign slv_r_last = slv_resp.r.last; + assign slv_r_user = slv_resp.r.user; + + generate + for (genvar i = 0; i < NoMstPorts; i++) begin : g_connect_mst_port + // Request + assign mst_aw_id[i] = mst_reqs[i].aw.id; + assign mst_aw_addr[i] = mst_reqs[i].aw.addr; + assign mst_aw_len[i] = mst_reqs[i].aw.len; + assign mst_aw_size[i] = mst_reqs[i].aw.size; + assign mst_aw_burst[i] = mst_reqs[i].aw.burst; + assign mst_aw_lock[i] = mst_reqs[i].aw.lock; + assign mst_aw_cache[i] = mst_reqs[i].aw.cache; + assign mst_aw_prot[i] = mst_reqs[i].aw.prot; + assign mst_aw_qos[i] = mst_reqs[i].aw.qos; + assign mst_aw_region[i] = mst_reqs[i].aw.region; + assign mst_aw_atop[i] = mst_reqs[i].aw.atop; + assign mst_aw_user[i] = mst_reqs[i].aw.user; + assign mst_aw_valid[i] = mst_reqs[i].aw_valid; + assign mst_w_data[i] = mst_reqs[i].w.data; + assign mst_w_strb[i] = mst_reqs[i].w.strb; + assign mst_w_last[i] = mst_reqs[i].w.last; + assign mst_w_user[i] = mst_reqs[i].w.user; + assign mst_w_valid[i] = mst_reqs[i].w_valid; + assign mst_b_ready[i] = mst_reqs[i].b_ready; + assign mst_ar_id[i] = mst_reqs[i].ar.id; + assign mst_ar_addr[i] = mst_reqs[i].ar.addr; + assign mst_ar_len[i] = mst_reqs[i].ar.len; + assign mst_ar_size[i] = mst_reqs[i].ar.size; + assign mst_ar_burst[i] = mst_reqs[i].ar.burst; + assign mst_ar_lock[i] = mst_reqs[i].ar.lock; + assign mst_ar_cache[i] = mst_reqs[i].ar.cache; + assign mst_ar_prot[i] = mst_reqs[i].ar.prot; + assign mst_ar_qos[i] = mst_reqs[i].ar.qos; + assign mst_ar_region[i] = mst_reqs[i].ar.region; + assign mst_ar_user[i] = mst_reqs[i].ar.user; + assign mst_ar_valid[i] = mst_reqs[i].ar_valid; + assign mst_r_ready[i] = mst_reqs[i].r_ready; + // Response + assign mst_resps[i].aw_ready = mst_aw_ready[i]; + assign mst_resps[i].ar_ready = mst_ar_ready[i]; + assign mst_resps[i].w_ready = mst_w_ready[i]; + assign mst_resps[i].b_valid = mst_b_valid[i]; + assign mst_resps[i].b.id = mst_b_id[i]; + assign mst_resps[i].b.resp = mst_b_resp[i]; + assign mst_resps[i].b.user = mst_b_user[i]; + assign mst_resps[i].r_valid = mst_r_valid[i]; + assign mst_resps[i].r.id = mst_r_id[i]; + assign mst_resps[i].r.data = mst_r_data[i]; + assign mst_resps[i].r.resp = mst_r_resp[i]; + assign mst_resps[i].r.last = mst_r_last[i]; + assign mst_resps[i].r.user = mst_r_user[i]; + end + endgenerate + + axi_demux #( + .AxiIdWidth (AxiIdWidthMasters), + .AtopSupport(1'b0), + .aw_chan_t (aw_chan_t), + .w_chan_t (w_chan_t), + .b_chan_t (b_chan_t), + .ar_chan_t (ar_chan_t), + .r_chan_t (r_chan_t), + .axi_req_t (req_t), + .axi_resp_t (resp_t), + .NoMstPorts (NoMstPorts), + .MaxTrans (10), + .AxiLookBits(AxiIdUsed), + .UniqueIds (UniqueIds), + .SpillAw (LatencyMode[9]), + .SpillW (LatencyMode[8]), + .SpillB (LatencyMode[7]), + .SpillAr (LatencyMode[6]), + .SpillR (LatencyMode[5]) + ) i_axi_demux ( + .clk_i (clk_i), + .rst_ni (rst_ni), + .test_i ('0), + .slv_req_i (slv_req), + .slv_aw_select_i(slv_aw_select_i), + .slv_ar_select_i(slv_ar_select_i), + .slv_resp_o (slv_resp), + .mst_reqs_o (mst_reqs), + .mst_resps_i (mst_resps) + ); +endmodule + +module synth_axi_mcast_demux import axi_pkg::*; #( + parameter int unsigned NoMstPorts = 32'd8, + parameter bit UniqueIds = 0, + parameter xbar_latency_e LatencyMode = NO_LATENCY, + // axi configuration + parameter int unsigned AxiIdWidthMasters = 4, + parameter int unsigned AxiIdUsed = 3, // Has to be <= AxiIdWidthMasters + parameter int unsigned AxiAddrWidth = 32, // Axi Address Width + parameter int unsigned AxiDataWidth = 32, // Axi Data Width + parameter int unsigned AxiStrbWidth = AxiDataWidth / 8, + parameter int unsigned AxiUserWidth = 32, + // axi types + parameter type id_t = logic [AxiIdWidthMasters-1:0], + parameter type addr_t = logic [AxiAddrWidth-1:0], + parameter type data_t = logic [AxiDataWidth-1:0], + parameter type strb_t = logic [AxiStrbWidth-1:0], + parameter type user_t = logic [AxiUserWidth-1:0], + // select signal types + parameter int unsigned IdxSelectWidth = (NoMstPorts > 32'd1) ? $clog2(NoMstPorts) : 32'd1, + parameter type idx_select_t = logic [IdxSelectWidth-1:0], + parameter type mask_select_t = logic [NoMstPorts-1:0], + parameter type multi_addr_t = struct packed { + addr_t aw_addr; + addr_t aw_mask; + } +) ( + input logic clk_i, + input logic rst_ni, + + // Address decoder signals + input mask_select_t slv_aw_select_i, + input idx_select_t slv_ar_select_i, + input multi_addr_t [NoMstPorts-1:0] slv_aw_mcast_i, + + /*********************************** + /* Slave ports request inputs + ***********************************/ + + // AW + input id_t slv_aw_id, + input addr_t slv_aw_addr, + input axi_pkg::len_t slv_aw_len, + input axi_pkg::size_t slv_aw_size, + input axi_pkg::burst_t slv_aw_burst, + input logic slv_aw_lock, + input axi_pkg::cache_t slv_aw_cache, + input axi_pkg::prot_t slv_aw_prot, + input axi_pkg::qos_t slv_aw_qos, + input axi_pkg::region_t slv_aw_region, + input axi_pkg::atop_t slv_aw_atop, + input user_t slv_aw_user, + input logic slv_aw_valid, + // W + input data_t slv_w_data, + input strb_t slv_w_strb, + input logic slv_w_last, + input user_t slv_w_user, + input logic slv_w_valid, + // B + input logic slv_b_ready, + // AR + input id_t slv_ar_id, + input addr_t slv_ar_addr, + input axi_pkg::len_t slv_ar_len, + input axi_pkg::size_t slv_ar_size, + input axi_pkg::burst_t slv_ar_burst, + input logic slv_ar_lock, + input axi_pkg::cache_t slv_ar_cache, + input axi_pkg::prot_t slv_ar_prot, + input axi_pkg::qos_t slv_ar_qos, + input axi_pkg::region_t slv_ar_region, + input user_t slv_ar_user, + input logic slv_ar_valid, + // R + input logic slv_r_ready, + + /*********************************** + /* Slave ports response outputs + ***********************************/ + + // AW + output logic slv_aw_ready, + // AR + output logic slv_ar_ready, + // W + output logic slv_w_ready, + // B + output logic slv_b_valid, + output id_t slv_b_id, + output axi_pkg::resp_t slv_b_resp, + output user_t slv_b_user, + // R + output logic slv_r_valid, + output id_t slv_r_id, + output data_t slv_r_data, + output axi_pkg::resp_t slv_r_resp, + output logic slv_r_last, + output user_t slv_r_user, + + /*********************************** + /* Master ports request outputs + ***********************************/ + + // AW + output id_t [NoMstPorts-1:0] mst_aw_id, + output addr_t [NoMstPorts-1:0] mst_aw_addr, + output axi_pkg::len_t [NoMstPorts-1:0] mst_aw_len, + output axi_pkg::size_t [NoMstPorts-1:0] mst_aw_size, + output axi_pkg::burst_t [NoMstPorts-1:0] mst_aw_burst, + output logic [NoMstPorts-1:0] mst_aw_lock, + output axi_pkg::cache_t [NoMstPorts-1:0] mst_aw_cache, + output axi_pkg::prot_t [NoMstPorts-1:0] mst_aw_prot, + output axi_pkg::qos_t [NoMstPorts-1:0] mst_aw_qos, + output axi_pkg::region_t [NoMstPorts-1:0] mst_aw_region, + output axi_pkg::atop_t [NoMstPorts-1:0] mst_aw_atop, + output user_t [NoMstPorts-1:0] mst_aw_user, + output logic [NoMstPorts-1:0] mst_aw_valid, + // W + output data_t [NoMstPorts-1:0] mst_w_data, + output strb_t [NoMstPorts-1:0] mst_w_strb, + output logic [NoMstPorts-1:0] mst_w_last, + output user_t [NoMstPorts-1:0] mst_w_user, + output logic [NoMstPorts-1:0] mst_w_valid, + // B + output logic [NoMstPorts-1:0] mst_b_ready, + // AR + output id_t [NoMstPorts-1:0] mst_ar_id, + output addr_t [NoMstPorts-1:0] mst_ar_addr, + output axi_pkg::len_t [NoMstPorts-1:0] mst_ar_len, + output axi_pkg::size_t [NoMstPorts-1:0] mst_ar_size, + output axi_pkg::burst_t [NoMstPorts-1:0] mst_ar_burst, + output logic [NoMstPorts-1:0] mst_ar_lock, + output axi_pkg::cache_t [NoMstPorts-1:0] mst_ar_cache, + output axi_pkg::prot_t [NoMstPorts-1:0] mst_ar_prot, + output axi_pkg::qos_t [NoMstPorts-1:0] mst_ar_qos, + output axi_pkg::region_t [NoMstPorts-1:0] mst_ar_region, + output user_t [NoMstPorts-1:0] mst_ar_user, + output logic [NoMstPorts-1:0] mst_ar_valid, + // R + output logic [NoMstPorts-1:0] mst_r_ready, + + /*********************************** + /* Master ports response inputs + ***********************************/ + + // AW + input logic [NoMstPorts-1:0] mst_aw_ready, + // AR + input logic [NoMstPorts-1:0] mst_ar_ready, + // W + input logic [NoMstPorts-1:0] mst_w_ready, + // B + input logic [NoMstPorts-1:0] mst_b_valid, + input id_t [NoMstPorts-1:0] mst_b_id, + input axi_pkg::resp_t [NoMstPorts-1:0] mst_b_resp, + input user_t [NoMstPorts-1:0] mst_b_user, + // R + input logic [NoMstPorts-1:0] mst_r_valid, + input id_t [NoMstPorts-1:0] mst_r_id, + input data_t [NoMstPorts-1:0] mst_r_data, + input axi_pkg::resp_t [NoMstPorts-1:0] mst_r_resp, + input logic [NoMstPorts-1:0] mst_r_last, + input user_t [NoMstPorts-1:0] mst_r_user + +); + + typedef struct packed { + logic [AxiUserWidth-1:0] mcast; + } aw_user_t; + + `AXI_TYPEDEF_AW_CHAN_T(mst_aw_chan_t, addr_t, id_t, aw_user_t) + `AXI_TYPEDEF_AW_CHAN_T(slv_aw_chan_t, addr_t, id_t, aw_user_t) + `AXI_TYPEDEF_W_CHAN_T(w_chan_t, data_t, strb_t, user_t) + `AXI_TYPEDEF_B_CHAN_T(mst_b_chan_t, id_t, user_t) + `AXI_TYPEDEF_B_CHAN_T(slv_b_chan_t, id_t, user_t) + + `AXI_TYPEDEF_AR_CHAN_T(mst_ar_chan_t, addr_t, id_t, user_t) + `AXI_TYPEDEF_AR_CHAN_T(slv_ar_chan_t, addr_t, id_t, user_t) + `AXI_TYPEDEF_R_CHAN_T(mst_r_chan_t, data_t, id_t, user_t) + `AXI_TYPEDEF_R_CHAN_T(slv_r_chan_t, data_t, id_t, user_t) + + `AXI_TYPEDEF_REQ_T(mst_req_t, mst_aw_chan_t, w_chan_t, mst_ar_chan_t) + `AXI_TYPEDEF_RESP_T(mst_resp_t, mst_b_chan_t, mst_r_chan_t) + `AXI_TYPEDEF_REQ_T(slv_req_t, slv_aw_chan_t, w_chan_t, slv_ar_chan_t) + `AXI_TYPEDEF_RESP_T(slv_resp_t, slv_b_chan_t, slv_r_chan_t) + + slv_req_t slv_req; + mst_req_t [NoMstPorts-1:0] mst_reqs; + slv_resp_t slv_resp; + mst_resp_t [NoMstPorts-1:0] mst_resps; + + // Connect XBAR interfaces + assign slv_req.aw.id = slv_aw_id; + assign slv_req.aw.addr = slv_aw_addr; + assign slv_req.aw.len = slv_aw_len; + assign slv_req.aw.size = slv_aw_size; + assign slv_req.aw.burst = slv_aw_burst; + assign slv_req.aw.lock = slv_aw_lock; + assign slv_req.aw.cache = slv_aw_cache; + assign slv_req.aw.prot = slv_aw_prot; + assign slv_req.aw.qos = slv_aw_qos; + assign slv_req.aw.region = slv_aw_region; + assign slv_req.aw.atop = slv_aw_atop; + assign slv_req.aw.user = slv_aw_user; + assign slv_req.aw_valid = slv_aw_valid; + assign slv_req.w.data = slv_w_data; + assign slv_req.w.strb = slv_w_strb; + assign slv_req.w.last = slv_w_last; + assign slv_req.w.user = slv_w_user; + assign slv_req.w_valid = slv_w_valid; + assign slv_req.b_ready = slv_b_ready; + assign slv_req.ar.id = slv_ar_id; + assign slv_req.ar.addr = slv_ar_addr; + assign slv_req.ar.len = slv_ar_len; + assign slv_req.ar.size = slv_ar_size; + assign slv_req.ar.burst = slv_ar_burst; + assign slv_req.ar.lock = slv_ar_lock; + assign slv_req.ar.cache = slv_ar_cache; + assign slv_req.ar.prot = slv_ar_prot; + assign slv_req.ar.qos = slv_ar_qos; + assign slv_req.ar.region = slv_ar_region; + assign slv_req.ar.user = slv_ar_user; + assign slv_req.ar_valid = slv_ar_valid; + assign slv_req.r_ready = slv_r_ready; + // Response + assign slv_aw_ready = slv_resp.aw_ready; + assign slv_ar_ready = slv_resp.ar_ready; + assign slv_w_ready = slv_resp.w_ready; + assign slv_b_valid = slv_resp.b_valid; + assign slv_b_id = slv_resp.b.id; + assign slv_b_resp = slv_resp.b.resp; + assign slv_b_user = slv_resp.b.user; + assign slv_r_valid = slv_resp.r_valid; + assign slv_r_id = slv_resp.r.id; + assign slv_r_data = slv_resp.r.data; + assign slv_r_resp = slv_resp.r.resp; + assign slv_r_last = slv_resp.r.last; + assign slv_r_user = slv_resp.r.user; + + generate + for (genvar i = 0; i < NoMstPorts; i++) begin : g_connect_mst_port + // Request + assign mst_aw_id[i] = mst_reqs[i].aw.id; + assign mst_aw_addr[i] = mst_reqs[i].aw.addr; + assign mst_aw_len[i] = mst_reqs[i].aw.len; + assign mst_aw_size[i] = mst_reqs[i].aw.size; + assign mst_aw_burst[i] = mst_reqs[i].aw.burst; + assign mst_aw_lock[i] = mst_reqs[i].aw.lock; + assign mst_aw_cache[i] = mst_reqs[i].aw.cache; + assign mst_aw_prot[i] = mst_reqs[i].aw.prot; + assign mst_aw_qos[i] = mst_reqs[i].aw.qos; + assign mst_aw_region[i] = mst_reqs[i].aw.region; + assign mst_aw_atop[i] = mst_reqs[i].aw.atop; + assign mst_aw_user[i] = mst_reqs[i].aw.user; + assign mst_aw_valid[i] = mst_reqs[i].aw_valid; + assign mst_w_data[i] = mst_reqs[i].w.data; + assign mst_w_strb[i] = mst_reqs[i].w.strb; + assign mst_w_last[i] = mst_reqs[i].w.last; + assign mst_w_user[i] = mst_reqs[i].w.user; + assign mst_w_valid[i] = mst_reqs[i].w_valid; + assign mst_b_ready[i] = mst_reqs[i].b_ready; + assign mst_ar_id[i] = mst_reqs[i].ar.id; + assign mst_ar_addr[i] = mst_reqs[i].ar.addr; + assign mst_ar_len[i] = mst_reqs[i].ar.len; + assign mst_ar_size[i] = mst_reqs[i].ar.size; + assign mst_ar_burst[i] = mst_reqs[i].ar.burst; + assign mst_ar_lock[i] = mst_reqs[i].ar.lock; + assign mst_ar_cache[i] = mst_reqs[i].ar.cache; + assign mst_ar_prot[i] = mst_reqs[i].ar.prot; + assign mst_ar_qos[i] = mst_reqs[i].ar.qos; + assign mst_ar_region[i] = mst_reqs[i].ar.region; + assign mst_ar_user[i] = mst_reqs[i].ar.user; + assign mst_ar_valid[i] = mst_reqs[i].ar_valid; + assign mst_r_ready[i] = mst_reqs[i].r_ready; + // Response + assign mst_resps[i].aw_ready = mst_aw_ready[i]; + assign mst_resps[i].ar_ready = mst_ar_ready[i]; + assign mst_resps[i].w_ready = mst_w_ready[i]; + assign mst_resps[i].b_valid = mst_b_valid[i]; + assign mst_resps[i].b.id = mst_b_id[i]; + assign mst_resps[i].b.resp = mst_b_resp[i]; + assign mst_resps[i].b.user = mst_b_user[i]; + assign mst_resps[i].r_valid = mst_r_valid[i]; + assign mst_resps[i].r.id = mst_r_id[i]; + assign mst_resps[i].r.data = mst_r_data[i]; + assign mst_resps[i].r.resp = mst_r_resp[i]; + assign mst_resps[i].r.last = mst_r_last[i]; + assign mst_resps[i].r.user = mst_r_user[i]; + end + endgenerate + + axi_mcast_demux #( + .AxiIdWidth (AxiIdWidthMasters), + .AtopSupport(1'b0), + .aw_addr_t (addr_t), + .aw_chan_t (slv_aw_chan_t), + .w_chan_t (w_chan_t), + .b_chan_t (slv_b_chan_t), + .ar_chan_t (slv_ar_chan_t), + .r_chan_t (slv_r_chan_t), + .axi_req_t (slv_req_t), + .axi_resp_t (slv_resp_t), + .NoMstPorts (NoMstPorts), + .MaxTrans (10), + .AxiLookBits(AxiIdUsed), + .UniqueIds (UniqueIds), + .SpillAw (LatencyMode[9]), + .SpillW (LatencyMode[8]), + .SpillB (LatencyMode[7]), + .SpillAr (LatencyMode[6]), + .SpillR (LatencyMode[5]) + ) i_axi_mcast_demux ( + .clk_i (clk_i), + .rst_ni (rst_ni), + .test_i ('0), + .slv_req_i (slv_req), + .slv_aw_select_i(slv_aw_select_i), + .slv_ar_select_i(slv_ar_select_i), + .slv_aw_mcast_i (slv_aw_mcast_i), + .slv_resp_o (slv_resp), + .mst_reqs_o (mst_reqs), + .mst_resps_i (mst_resps) + ); + +endmodule diff --git a/test/tb_axi_mcast_xbar.sv b/test/tb_axi_mcast_xbar.sv index 6056be919..f86d71a7a 100644 --- a/test/tb_axi_mcast_xbar.sv +++ b/test/tb_axi_mcast_xbar.sv @@ -1,4 +1,4 @@ -// Copyright (c) 2019 ETH Zurich and University of Bologna. +// Copyright (c) 2022 ETH Zurich and University of Bologna. // Copyright and related rights are licensed under the Solderpad Hardware // License, Version 0.51 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at @@ -9,9 +9,9 @@ // specific language governing permissions and limitations under the License. // // Authors: -// - Wolfgang Roenninger -// - Florian Zaruba -// - Andreas Kurth +// - Luca Colagrande +// Based on: +// - tb_axi_xbar.sv // Directed Random Verification Testbench for `axi_xbar`: The crossbar is instantiated with // a number of random axi master and slave modules. Each random master executes a fixed number of @@ -23,8 +23,8 @@ `include "axi/typedef.svh" `include "axi/assign.svh" -/// Testbench for the module `axi_xbar`. -module tb_axi_xbar #( +/// Testbench for the module `axi_mcast_xbar`. +module tb_axi_mcast_xbar #( /// Number of AXI masters connected to the xbar. (Number of slave ports) parameter int unsigned TbNumMasters = 32'd6, /// Number of AXI slaves connected to the xbar. (Number of master ports) @@ -48,8 +48,7 @@ module tb_axi_xbar #( /// Enable exclusive accesses parameter bit TbEnExcl = 1'b0, /// Restrict to only unique IDs - parameter bit TbUniqueIds = 1'b0 - + parameter bit TbUniqueIds = 1'b0 ); // TB timing parameters @@ -61,7 +60,7 @@ module tb_axi_xbar #( localparam int unsigned TbAxiIdWidthSlaves = TbAxiIdWidthMasters + $clog2(TbNumMasters); localparam int unsigned TbAxiAddrWidth = 32'd32; localparam int unsigned TbAxiStrbWidth = TbAxiDataWidth / 8; - localparam int unsigned TbAxiUserWidth = 5; + localparam int unsigned TbAxiUserWidth = TbAxiAddrWidth; // In the bench can change this variables which are set here freely, localparam axi_pkg::xbar_cfg_t xbar_cfg = '{ NoSlvPorts: TbNumMasters, @@ -69,7 +68,7 @@ module tb_axi_xbar #( MaxMstTrans: 10, MaxSlvTrans: 6, FallThrough: 1'b0, - LatencyMode: axi_pkg::CUT_ALL_AX, + LatencyMode: axi_pkg::CUT_ALL_PORTS, PipelineStages: TbPipeline, AxiIdWidthSlvPorts: TbAxiIdWidthMasters, AxiIdUsedSlvPorts: TbAxiIdUsed, @@ -81,7 +80,15 @@ module tb_axi_xbar #( typedef logic [TbAxiIdWidthMasters-1:0] id_mst_t; typedef logic [TbAxiIdWidthSlaves-1:0] id_slv_t; typedef logic [TbAxiAddrWidth-1:0] addr_t; - typedef axi_pkg::xbar_rule_32_t rule_t; // Has to be the same width as axi addr + typedef struct packed { + addr_t addr; + addr_t mask; + } aw_rule_t; + typedef struct packed { + int unsigned idx; + addr_t start_addr; + addr_t end_addr; + } ar_rule_t; typedef logic [TbAxiDataWidth-1:0] data_t; typedef logic [TbAxiStrbWidth-1:0] strb_t; typedef logic [TbAxiUserWidth-1:0] user_t; @@ -103,11 +110,12 @@ module tb_axi_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 ar_rule_t [xbar_cfg.NoAddrRules-1:0] ArAddrMap = ar_addr_map_gen(); + localparam aw_rule_t [xbar_cfg.NoAddrRules-1:0] AwAddrMap = aw_addr_map_gen(); - function rule_t [xbar_cfg.NoAddrRules-1:0] addr_map_gen (); + function ar_rule_t [xbar_cfg.NoAddrRules-1:0] ar_addr_map_gen (); for (int unsigned i = 0; i < xbar_cfg.NoAddrRules; i++) begin - addr_map_gen[i] = rule_t'{ + ar_addr_map_gen[i] = ar_rule_t'{ idx: unsigned'(i), start_addr: i * 32'h0000_2000, end_addr: (i+1) * 32'h0000_2000, @@ -116,6 +124,16 @@ module tb_axi_xbar #( end endfunction + function aw_rule_t [xbar_cfg.NoAddrRules-1:0] aw_addr_map_gen (); + for (int unsigned i = 0; i < xbar_cfg.NoAddrRules; i++) begin + aw_addr_map_gen[i] = aw_rule_t'{ + addr: i * 32'h0000_2000, + mask: 32'h0000_1FFF, + default: '0 + }; + end + endfunction + typedef axi_test::axi_rand_master #( // AXI interface parameters .AW ( TbAxiAddrWidth ), @@ -130,7 +148,8 @@ module tb_axi_xbar #( .MAX_WRITE_TXNS ( 20 ), .AXI_EXCLS ( TbEnExcl ), .AXI_ATOPS ( TbEnAtop ), - .UNIQUE_IDS ( TbUniqueIds ) + .UNIQUE_IDS ( TbUniqueIds ), + .ENABLE_MULTICAST( 1 ) ) axi_rand_master_t; typedef axi_test::axi_rand_slave #( // AXI interface parameters @@ -218,9 +237,10 @@ module tb_axi_xbar #( initial begin 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.NoAddrRules-1].end_addr, + axi_rand_master[i].add_memory_region(ArAddrMap[0].start_addr, + ArAddrMap[xbar_cfg.NoAddrRules-1].end_addr, axi_pkg::DEVICE_NONBUFFERABLE); + axi_rand_master[i].set_multicast_probability(0.5); axi_rand_master[i].reset(); @(posedge rst_n); axi_rand_master[i].run(TbNumReads, TbNumWrites); @@ -239,7 +259,7 @@ module tb_axi_xbar #( end initial begin : proc_monitor - static tb_axi_xbar_pkg::axi_xbar_monitor #( + static tb_axi_mcast_xbar_pkg::axi_mcast_xbar_monitor #( .AxiAddrWidth ( TbAxiAddrWidth ), .AxiDataWidth ( TbAxiDataWidth ), .AxiIdWidthMasters ( TbAxiIdWidthMasters ), @@ -248,8 +268,10 @@ module tb_axi_xbar #( .NoMasters ( TbNumMasters ), .NoSlaves ( TbNumSlaves ), .NoAddrRules ( xbar_cfg.NoAddrRules ), - .rule_t ( rule_t ), - .AddrMap ( AddrMap ), + .ar_rule_t ( ar_rule_t ), + .aw_rule_t ( aw_rule_t ), + .ArAddrMap ( ArAddrMap ), + .AwAddrMap ( AwAddrMap ), .TimeTest ( TestTime ) ) monitor = new( master_monitor_dv, slave_monitor_dv ); fork @@ -279,19 +301,20 @@ module tb_axi_xbar #( //----------------------------------- // DUT //----------------------------------- - axi_xbar_intf #( - .AXI_USER_WIDTH ( TbAxiUserWidth ), - .Cfg ( xbar_cfg ), - .rule_t ( rule_t ) + + axi_mcast_xbar_intf #( + .AXI_USER_WIDTH ( TbAxiUserWidth ), + .Cfg ( xbar_cfg ), + .ar_rule_t ( ar_rule_t ), + .aw_rule_t ( aw_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 ) + .ar_addr_map_i ( ArAddrMap ), + .aw_addr_map_i ( AwAddrMap ) ); // logger for master modules @@ -303,7 +326,8 @@ module tb_axi_xbar #( .w_chan_t ( w_chan_t ), // axi W type .b_chan_t ( b_chan_mst_t ), // axi B type .ar_chan_t ( ar_chan_mst_t ), // axi AR type - .r_chan_t ( r_chan_mst_t ) // axi R type + .r_chan_t ( r_chan_mst_t ), // axi R type + .ENABLE_MULTICAST(1) ) i_mst_channel_logger ( .clk_i ( clk ), // Clock .rst_ni ( rst_n ), // Asynchronous reset active low, when `1'b0` no sampling diff --git a/test/tb_axi_mcast_xbar_pkg.sv b/test/tb_axi_mcast_xbar_pkg.sv index fb7098998..d5164631e 100644 --- a/test/tb_axi_mcast_xbar_pkg.sv +++ b/test/tb_axi_mcast_xbar_pkg.sv @@ -9,16 +9,17 @@ // specific language governing permissions and limitations under the License. // // Authors: -// - Florian Zaruba -// - Wolfgang Roenninger +// - Luca Colagrande +// Based on: +// - tb_axi_xbar_pkg.sv -// `axi_xbar_monitor` implements an AXI bus monitor that is tuned for the AXI crossbar. -// It snoops on each of the slaves and master ports of the crossbar and +// `axi_mcast_xbar_monitor` implements an AXI bus monitor that is tuned for the AXI multicast +// crossbar. It snoops on each of the slaves and master ports of the crossbar and // populates FIFOs and ID queues to validate that no AXI beats get // lost or sent to the wrong destination. -package tb_axi_xbar_pkg; - class axi_xbar_monitor #( +package tb_axi_mcast_xbar_pkg; + class axi_mcast_xbar_monitor #( parameter int unsigned AxiAddrWidth, parameter int unsigned AxiDataWidth, parameter int unsigned AxiIdWidthMasters, @@ -27,8 +28,10 @@ package tb_axi_xbar_pkg; parameter int unsigned NoMasters, parameter int unsigned NoSlaves, parameter int unsigned NoAddrRules, - parameter type rule_t, - parameter rule_t [NoAddrRules-1:0] AddrMap, + parameter type ar_rule_t, + parameter type aw_rule_t, + parameter ar_rule_t [NoAddrRules-1:0] ArAddrMap, + parameter aw_rule_t [NoAddrRules-1:0] AwAddrMap, // Stimuli application and test time parameter time TimeTest ); @@ -46,6 +49,7 @@ package tb_axi_xbar_pkg; typedef struct packed { slv_axi_id_t slv_axi_id; axi_addr_t slv_axi_addr; + axi_addr_t slv_axi_mcast; axi_pkg::len_t slv_axi_len; } exp_ax_t; typedef struct packed { @@ -148,50 +152,91 @@ package tb_axi_xbar_pkg; @(posedge masters_axi[0].clk_i); endtask - // This task monitors a slave ports of the crossbar. Every time an AW beat is seen - // it populates an id queue at the right master port (if there is no expected decode error), - // populates the expected b response in its own id_queue and in case when the atomic bit [5] + // This task monitors a slave port of the crossbar. Every time an AW beat is seen + // it populates an id queue at the right master port(s) (if there is no expected decode error), + // 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); - idx_slv_t to_slave_idx; + axi_addr_t aw_addr; + axi_addr_t aw_mcast; + 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; - bit decerr; + string slaves_str; master_exp_t exp_b; if (masters_axi[i].aw_valid && masters_axi[i].aw_ready) begin - // check if it should go to a decerror - decerr = 1'b1; - for (int unsigned j = 0; j < NoAddrRules; j++) begin - if ((masters_axi[i].aw_addr >= AddrMap[j].start_addr) && - (masters_axi[i].aw_addr < AddrMap[j].end_addr)) begin - to_slave_idx = idx_slv_t'(AddrMap[j].idx); - decerr = 1'b0; + + // 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). + 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 < NoSlaves; j++) begin + // request goes to the slave if all bits match, which are neither masked in the + // request nor in the addrmap rule + for (int k = 0; k < AxiAddrWidth; k++) addrmap_masked[k] = AwAddrMap[j].mask[k] ? 1'bx : AwAddrMap[j].addr[k]; + $display("With slave %0d : %b", j, addrmap_masked); + if (&(~(aw_addr ^ AwAddrMap[j].addr) | AwAddrMap[j].mask | aw_mcast)) begin + to_slave_idx.push_back(idx_slv_t'(j)); + mask_to_slave.push_back(aw_mcast & AwAddrMap[j].mask); + addr_to_slave.push_back((~aw_mcast & aw_addr) | (aw_mcast & AwAddrMap[j].addr)); + $display("Pushing mask : %b", aw_mcast & AwAddrMap[j].mask); + $display("Pushing address: %b", (~aw_mcast & aw_addr) | (aw_mcast & AwAddrMap[j].addr)); end end - // send the exp aw beat down into the queue of the slave when no decerror - if (!decerr) begin - exp_aw_id = {idx_mst_t'(i), masters_axi[i].aw_id}; - // $display("Test exp aw_id: %b",exp_aw_id); - exp_aw = '{slv_axi_id: exp_aw_id, - slv_axi_addr: masters_axi[i].aw_addr, - slv_axi_len: masters_axi[i].aw_len }; - this.exp_aw_queue[to_slave_idx].push(exp_aw_id, exp_aw); - incr_expected_tests(3); - $display("%0tns > Master %0d: AW to Slave %0d: Axi ID: %b", - $time, i, to_slave_idx, masters_axi[i].aw_id); - end else begin + num_slaves_matched = to_slave_idx.size(); + decerr = num_slaves_matched == 0; + if (num_slaves_matched > 1 || decerr) begin + $display("MULTICAST occur: %b, %b", aw_addr, aw_mcast); + $display("Matched %0d slaves", num_slaves_matched); + for (int j = 0; j < NoSlaves; j++) begin + $display(" Slave %0d AddrMap: %b, %b", j, AwAddrMap[j].addr, AwAddrMap[j].mask); + end + end + + // send the exp aw beats down into the queues of the selected slaves + // when no decerror + if (decerr) begin $display("%0tns > Master %0d: AW to Decerror: Axi ID: %b", - $time, i, to_slave_idx, masters_axi[i].aw_id); + $time, i, masters_axi[i].aw_id); + end else begin + exp_aw_id = {idx_mst_t'(i), masters_axi[i].aw_id}; + for (int j = 0; j < num_slaves_matched; j++) begin + automatic idx_slv_t slave_idx = to_slave_idx.pop_front(); + // $display("Test exp aw_id: %b",exp_aw_id); + exp_aw = '{slv_axi_id: exp_aw_id, + slv_axi_addr: addr_to_slave.pop_front(), + slv_axi_mcast: mask_to_slave.pop_front(), + slv_axi_len: masters_axi[i].aw_len}; + this.exp_aw_queue[slave_idx].push(exp_aw_id, exp_aw); + incr_expected_tests(4); + if (j == 0) slaves_str = $sformatf("%0d", slave_idx); + else slaves_str = $sformatf("%s, %0d", slaves_str, slave_idx); + end + $display("%0tns > Master %0d: AW to Slaves [%s]: Axi ID: %b", + $time, i, slaves_str, masters_axi[i].aw_id); end + // populate the expected b queue anyway exp_b = '{mst_axi_id: masters_axi[i].aw_id, last: 1'b1}; this.exp_b_queue[i].push(masters_axi[i].aw_id, exp_b); incr_expected_tests(1); $display(" Expect B response."); + // inject expected r beats on this id, if it is an atop + // throw an error if a multicast atop is attempted (not supported) if(masters_axi[i].aw_atop[5]) begin + if (num_slaves_matched > 1) $fatal(0, "Multicast ATOPs are not supported"); // push the required r beats into the right fifo (reuse the exp_b variable) $display(" Expect R response, len: %0d.", masters_axi[i].aw_len); for (int unsigned j = 0; j <= masters_axi[i].aw_len; j++) begin @@ -205,7 +250,7 @@ package tb_axi_xbar_pkg; end endtask : monitor_mst_aw - // This task monitors a slave port of the crossbar. Every time there is an AW vector it + // This task monitors a master port of the crossbar. Every time there is an AW vector it // gets checked for its contents and if it was expected. The task then pushes an expected // amount of W beats in the respective fifo. Emphasis of the last flag. task automatic monitor_slv_aw(input int unsigned i); @@ -227,12 +272,18 @@ package tb_axi_xbar_pkg; $warning("Slave %0d: Unexpected AW with ID: %b and ADDR: %h, exp: %h", i, slaves_axi[i].aw_id, slaves_axi[i].aw_addr, exp_aw.slv_axi_addr); end + if (exp_aw.slv_axi_mcast != slaves_axi[i].aw_user[AxiAddrWidth-1:0]) begin + incr_failed_tests(1); + $warning("Slave %0d: Unexpected AW with ID: %b and MCAST: %h, exp: %h", + i, slaves_axi[i].aw_id, slaves_axi[i].aw_user[AxiAddrWidth-1:0], + exp_aw.slv_axi_mcast); + end if (exp_aw.slv_axi_len != slaves_axi[i].aw_len) begin incr_failed_tests(1); $warning("Slave %0d: Unexpected AW with ID: %b and LEN: %h, exp: %h", i, slaves_axi[i].aw_id, slaves_axi[i].aw_len, exp_aw.slv_axi_len); end - incr_conducted_tests(3); + incr_conducted_tests(4); // push the required w beats into the right fifo incr_expected_tests(slaves_axi[i].aw_len + 1); @@ -320,8 +371,8 @@ package tb_axi_xbar_pkg; exp_slv_axi_id = {idx_mst_t'(i), mst_axi_id}; exp_slv_idx = '0; for (int unsigned j = 0; j < NoAddrRules; j++) begin - if ((mst_axi_addr >= AddrMap[j].start_addr) && (mst_axi_addr < AddrMap[j].end_addr)) begin - exp_slv_idx = AddrMap[j].idx; + if ((mst_axi_addr >= ArAddrMap[j].start_addr) && (mst_axi_addr < ArAddrMap[j].end_addr)) begin + exp_slv_idx = ArAddrMap[j].idx; exp_decerr = 1'b0; end end @@ -334,7 +385,8 @@ package tb_axi_xbar_pkg; // push the expected vectors AW for exp_slv exp_slv_ar = '{slv_axi_id: exp_slv_axi_id, slv_axi_addr: mst_axi_addr, - slv_axi_len: mst_axi_len }; + slv_axi_mcast: '0, + slv_axi_len: mst_axi_len}; //$display("Expected Slv Axi Id is: %b", exp_slv_axi_id); this.exp_ar_queue[exp_slv_idx].push(exp_slv_axi_id, exp_slv_ar); incr_expected_tests(1); @@ -498,6 +550,9 @@ package tb_axi_xbar_pkg; if(tests_conducted == 0) begin $error("Simulation did not conduct any tests!"); end + if (tests_conducted < tests_expected) begin + $error("Some of the expected tests were not conducted!"); + end endtask : print_result - endclass : axi_xbar_monitor + endclass : axi_mcast_xbar_monitor endpackage From 3b5e678a3749937e04ac91a73e43f6948f9227ef Mon Sep 17 00:00:00 2001 From: Luca Colagrande Date: Fri, 25 Nov 2022 11:22:08 +0100 Subject: [PATCH 13/41] axi_mcast_xbar: Correct deadlock condition --- scripts/run_vsim.sh | 2 +- src/axi_mcast_demux.sv | 40 ++++++++++++---------- src/axi_mcast_mux.sv | 75 ++++++++++++++++++++++++++++++++++-------- src/axi_mcast_xbar.sv | 24 ++++++++++++-- 4 files changed, 106 insertions(+), 35 deletions(-) diff --git a/scripts/run_vsim.sh b/scripts/run_vsim.sh index 9d1228dc2..f98d6182f 100755 --- a/scripts/run_vsim.sh +++ b/scripts/run_vsim.sh @@ -248,7 +248,7 @@ exec_test() { for MST_ID_USE in 3 5; do MST_ID=5 for DATA_WIDTH in 64 256; do - for PIPE in 0 1; do + for PIPE in 0; do for UNIQUE_IDS in 0 1; do call_vsim tb_axi_mcast_xbar -t 1ns -voptargs="+acc" \ -gTbNumMasters=$NUM_MST \ diff --git a/src/axi_mcast_demux.sv b/src/axi_mcast_demux.sv index c816a7808..cf945dcf4 100644 --- a/src/axi_mcast_demux.sv +++ b/src/axi_mcast_demux.sv @@ -79,7 +79,9 @@ module axi_mcast_demux #( output axi_resp_t slv_resp_o, // Master Ports output axi_req_t [NoMstPorts-1:0] mst_reqs_o, - input axi_resp_t [NoMstPorts-1:0] mst_resps_i + input axi_resp_t [NoMstPorts-1:0] mst_resps_i, + output logic [NoMstPorts-1:0] mst_is_mcast_o, + output logic [NoMstPorts-1:0] mst_aw_commit_o ); localparam int unsigned IdCounterWidth = cf_math_pkg::idx_width(MaxTrans); @@ -391,6 +393,8 @@ module axi_mcast_demux #( assign outstanding_multicast = |multicast_select_q; assign aw_any_outstanding_trx = aw_any_outstanding_unicast_trx || outstanding_multicast; assign multicast_stall = outstanding_multicast || (aw_is_multicast && aw_any_outstanding_trx); + // We can send this signal to all slaves since we will only have one outstanding aw + assign mst_is_mcast_o = {NoMstPorts{aw_is_multicast}}; // Keep track of which B responses need to be returned to complete the multicast `FFLARN(multicast_select_q, multicast_select_d, multicast_select_load, '0, clk_i, rst_ni) @@ -415,20 +419,18 @@ module axi_mcast_demux #( // When a multicast occurs, the upstream valid signals need to // be forwarded to multiple master ports. - // Proper stream forking is necessary to avoid protocol violations - stream_fork_dynamic #( - .N_OUP(NoMstPorts) - ) i_aw_stream_fork_dynamic ( - .clk_i (clk_i), - .rst_ni (rst_ni), - .valid_i (aw_valid), - .ready_o (aw_ready), - .sel_i (slv_aw_select), - .sel_valid_i(slv_aw_valid_sel), - .sel_ready_o(), - .valid_o (mst_aw_valids), - .ready_i (mst_aw_readies) - ); + // Proper stream forking is necessary to avoid protocol violations. + // We must also require that downstream handshakes occur + // simultaneously on all addressed master ports, otherwise deadlocks + // may occur. To achieve this we modify the ready-valid protocol by adding + // a third signal, called commit, which is asserted only when we have all + // downstream handshakes. This signal notifies the slaves that the + // handshake can now actually take place. + // Using commit, instead of valid, to this end ensures that we don't have + // any combinational loops. + assign mst_aw_valids = {NoMstPorts{aw_valid}} & slv_aw_select; + assign aw_ready = &((mst_aw_valids & mst_aw_readies) | ~slv_aw_select); + assign mst_aw_commit_o = {NoMstPorts{aw_ready && aw_is_multicast}} & slv_aw_select; if (UniqueIds) begin : gen_unique_ids_aw // If the `UniqueIds` parameter is set, each write transaction has an ID that is unique among @@ -1004,7 +1006,9 @@ module axi_mcast_demux_intf #( input idx_select_t slv_ar_select_i, // has to be stable, when ar_valid input aw_multi_addr_t [NO_MST_PORTS-1:0] slv_aw_mcast_i, AXI_BUS.Slave slv, // slave port - AXI_BUS.Master mst [NO_MST_PORTS-1:0] // master ports + AXI_BUS.Master mst [NO_MST_PORTS-1:0], // master ports + output logic [NO_MST_PORTS-1:0] mst_is_mcast_o, + output logic [NO_MST_PORTS-1:0] mst_aw_commit_o ); typedef logic [AXI_ID_WIDTH-1:0] id_t; @@ -1064,6 +1068,8 @@ module axi_mcast_demux_intf #( .slv_resp_o ( slv_resp ), // master port .mst_reqs_o ( mst_req ), - .mst_resps_i ( mst_resp ) + .mst_resps_i ( mst_resp ), + .mst_is_mcast_o ( mst_is_mcast_o ), + .mst_aw_commit_o ( mst_aw_commit_o ) ); endmodule diff --git a/src/axi_mcast_mux.sv b/src/axi_mcast_mux.sv index 358cef8b7..50c608929 100644 --- a/src/axi_mcast_mux.sv +++ b/src/axi_mcast_mux.sv @@ -58,6 +58,8 @@ module axi_mcast_mux #( input logic rst_ni, // Asynchronous reset active low input logic test_i, // Test Mode enable // slave ports (AXI inputs), connect master modules here + input logic [NoSlvPorts-1:0] slv_is_mcast_i, + input logic [NoSlvPorts-1:0] slv_aw_commit_i, input slv_req_t [NoSlvPorts-1:0] slv_reqs_i, output slv_resp_t [NoSlvPorts-1:0] slv_resps_o, // master port (AXI outputs), connect slave modules here @@ -65,6 +67,10 @@ module axi_mcast_mux #( input mst_resp_t mst_resp_i ); + // TODO colluca: can this be merged with MstIdxBits? + localparam int unsigned SlvPortIdxBits = cf_math_pkg::idx_width(NoSlvPorts); + typedef logic [SlvPortIdxBits-1:0] mst_idx_t; + localparam int unsigned MstIdxBits = $clog2(NoSlvPorts); localparam int unsigned MstAxiIDWidth = SlvAxiIDWidth + MstIdxBits; @@ -169,6 +175,15 @@ module axi_mcast_mux #( mst_aw_chan_t mst_aw_chan; logic mst_aw_valid, mst_aw_ready; + // AW arbiter signals + mst_aw_chan_t ucast_aw_chan, mcast_aw_chan; + logic ucast_aw_valid, ucast_aw_ready; + logic mcast_aw_valid, mcast_aw_ready, mcast_aw_commit; + logic mcast_not_aw_valid; + mst_idx_t mcast_sel; + logic [NoSlvPorts-1:0] mcast_sel_mask; + logic [NoSlvPorts-1:0] ucast_aw_readies, mcast_aw_readies; + // AW master handshake internal, so that we are able to stall, if w_fifo is full logic aw_valid, aw_ready; @@ -261,25 +276,53 @@ module axi_mcast_mux #( //-------------------------------------- // AW Channel //-------------------------------------- + // Arbitrate unicast requests in round-robin fashion rr_arb_tree #( .NumIn ( NoSlvPorts ), .DataType ( mst_aw_chan_t ), .AxiVldRdy( 1'b1 ), .LockIn ( 1'b1 ) - ) i_aw_arbiter ( + ) i_aw_ucast_arbiter ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), .flush_i( 1'b0 ), .rr_i ( '0 ), - .req_i ( slv_aw_valids ), - .gnt_o ( slv_aw_readies ), + .req_i ( slv_aw_valids & ~slv_is_mcast_i ), + .gnt_o ( ucast_aw_readies ), .data_i ( slv_aw_chans ), - .gnt_i ( aw_ready ), - .req_o ( aw_valid ), - .data_o ( mst_aw_chan ), + .gnt_i ( ucast_aw_ready ), + .req_o ( ucast_aw_valid ), + .data_o ( ucast_aw_chan ), .idx_o ( ) ); + // Arbitrate multicast requests in priority encoder fashion + // TODO colluca: extend lzc to return mask form instead of cnt? + lzc #( + .WIDTH ( NoSlvPorts ), + .MODE ( 1'b0 ) // Trailing zero mode + ) i_aw_mcast_lzc ( + .in_i ( slv_aw_valids & slv_is_mcast_i ), + .cnt_o ( mcast_sel ), + .empty_o ( mcast_not_aw_valid ) + ); + assign mcast_sel_mask = mcast_not_aw_valid ? '0 : 1 << mcast_sel; + assign mcast_aw_chan = slv_aw_chans[mcast_sel]; + assign mcast_aw_valid = !mcast_not_aw_valid; + assign mcast_aw_commit = |slv_aw_commit_i; + assign mcast_aw_readies = {NoSlvPorts{mcast_aw_ready}} & mcast_sel_mask; + + // Arbitrate "winners" of unicast and multicast arbitrations + // giving priority to multicast + assign mcast_aw_ready = aw_ready && mcast_aw_valid; + assign ucast_aw_ready = aw_ready && !mcast_aw_valid; + assign mst_aw_chan = mcast_aw_commit ? mcast_aw_chan : ucast_aw_chan; + assign slv_aw_readies = mcast_aw_readies | ucast_aw_readies; + // !!! CAUTION !!! + // This valid depends combinationally on aw_ready (through aw_commit), + // hence aw_ready shouldn't depend on aw_valid to avoid combinational loops! + assign aw_valid = mcast_aw_commit || (ucast_aw_valid && ucast_aw_ready); + // control of the AW channel always_comb begin // default assignments @@ -298,15 +341,18 @@ module axi_mcast_mux #( load_aw_lock = 1'b1; end end else begin - if (!w_fifo_full && aw_valid) begin - mst_aw_valid = 1'b1; - w_fifo_push = 1'b1; + if (!w_fifo_full) begin if (mst_aw_ready) begin aw_ready = 1'b1; - end else begin - // go to lock if transaction not in this cycle - lock_aw_valid_d = 1'b1; - load_aw_lock = 1'b1; + end + if (aw_valid) begin + mst_aw_valid = 1'b1; + w_fifo_push = 1'b1; + if (!mst_aw_ready) begin + // go to lock if transaction not in this cycle + lock_aw_valid_d = 1'b1; + load_aw_lock = 1'b1; + end end end end @@ -494,10 +540,11 @@ module axi_mcast_mux #( // pragma translate_on endmodule +// TODO colluca: adapt this // interface wrap `include "axi/assign.svh" `include "axi/typedef.svh" -module axi_mux_intf #( +module axi_mcast_mux_intf #( parameter int unsigned SLV_AXI_ID_WIDTH = 32'd0, // Synopsys DC requires default value for params parameter int unsigned MST_AXI_ID_WIDTH = 32'd0, parameter int unsigned AXI_ADDR_WIDTH = 32'd0, diff --git a/src/axi_mcast_xbar.sv b/src/axi_mcast_xbar.sv index d95a07d54..3339fc04f 100644 --- a/src/axi_mcast_xbar.sv +++ b/src/axi_mcast_xbar.sv @@ -114,11 +114,15 @@ import cf_math_pkg::idx_width; // signals from the axi_demuxes, one index more for decode error slv_req_t [Cfg.NoSlvPorts-1:0][Cfg.NoMstPorts:0] slv_reqs; slv_resp_t [Cfg.NoSlvPorts-1:0][Cfg.NoMstPorts:0] slv_resps; + logic [Cfg.NoSlvPorts-1:0][Cfg.NoMstPorts:0] slv_is_mcast; + logic [Cfg.NoSlvPorts-1:0][Cfg.NoMstPorts:0] slv_aw_commit; // workaround for issue #133 (problem with vsim 10.6c) localparam int unsigned cfg_NoMstPorts = Cfg.NoMstPorts; // signals into the axi_muxes, are of type slave as the multiplexer extends the ID + logic [Cfg.NoMstPorts-1:0][Cfg.NoSlvPorts-1:0] mst_is_mcast; + logic [Cfg.NoMstPorts-1:0][Cfg.NoSlvPorts-1:0] mst_aw_commit; slv_req_t [Cfg.NoMstPorts-1:0][Cfg.NoSlvPorts-1:0] mst_reqs; slv_resp_t [Cfg.NoMstPorts-1:0][Cfg.NoSlvPorts-1:0] mst_resps; @@ -210,7 +214,9 @@ import cf_math_pkg::idx_width; .slv_aw_mcast_i ( slv_aw_mcast ), .slv_resp_o ( slv_ports_resp_o[i] ), .mst_reqs_o ( slv_reqs[i] ), - .mst_resps_i ( slv_resps[i] ) + .mst_resps_i ( slv_resps[i] ), + .mst_is_mcast_o ( slv_is_mcast[i] ), + .mst_aw_commit_o ( slv_aw_commit[i] ) ); axi_err_slv #( @@ -236,8 +242,13 @@ import cf_math_pkg::idx_width; for (genvar i = 0; i < Cfg.NoSlvPorts; i++) begin : gen_xbar_slv_cross for (genvar j = 0; j < Cfg.NoMstPorts; j++) begin : gen_xbar_mst_cross if (Connectivity[i][j]) begin : gen_connection + + assign mst_is_mcast[j][i] = slv_is_mcast[i][j]; + assign mst_aw_commit[j][i] = slv_aw_commit[i][j]; + axi_multicut #( - .NoCuts ( Cfg.PipelineStages ), + // Internal pipelining is currently not supported in multicast XBAR + .NoCuts ( 0 ), .aw_chan_t ( slv_aw_chan_t ), .w_chan_t ( w_chan_t ), .b_chan_t ( slv_b_chan_t ), @@ -255,7 +266,12 @@ import cf_math_pkg::idx_width; ); end else begin : gen_no_connection + + assign mst_is_mcast[j][i] = 1'b0; + assign mst_aw_commit[j][i] = 1'b0; + assign mst_reqs[j][i] = '0; + axi_err_slv #( .AxiIdWidth ( Cfg.AxiIdWidthSlvPorts ), .axi_req_t ( slv_req_t ), @@ -275,7 +291,7 @@ import cf_math_pkg::idx_width; end for (genvar i = 0; i < Cfg.NoMstPorts; i++) begin : gen_mst_port_mux - axi_mux #( + axi_mcast_mux #( .SlvAxiIDWidth ( Cfg.AxiIdWidthSlvPorts ), // ID width of the slave ports .slv_aw_chan_t ( slv_aw_chan_t ), // AW Channel Type, slave ports .mst_aw_chan_t ( mst_aw_chan_t ), // AW Channel Type, master port @@ -302,6 +318,8 @@ import cf_math_pkg::idx_width; .clk_i, // Clock .rst_ni, // Asynchronous reset active low .test_i, // Test Mode enable + .slv_is_mcast_i ( mst_is_mcast[i] ), + .slv_aw_commit_i ( mst_aw_commit[i] ), .slv_reqs_i ( mst_reqs[i] ), .slv_resps_o ( mst_resps[i] ), .mst_req_o ( mst_ports_req_o[i] ), From 02df0cd907f170bf4f5e250cb645ec035b94b1bb Mon Sep 17 00:00:00 2001 From: Luca Colagrande Date: Wed, 7 Dec 2022 13:51:26 +0100 Subject: [PATCH 14/41] axi_mcast_xbar: Cut valid->ready->commit combinational path To be improved: - 50% multicast AW throughput - Potential for combinational loops in mux --- src/axi_mcast_demux.sv | 34 +++++++++++++++++++++++++++++++--- src/axi_mcast_mux.sv | 21 ++++++++++++++------- 2 files changed, 45 insertions(+), 10 deletions(-) diff --git a/src/axi_mcast_demux.sv b/src/axi_mcast_demux.sv index cf945dcf4..85acfac97 100644 --- a/src/axi_mcast_demux.sv +++ b/src/axi_mcast_demux.sv @@ -175,6 +175,7 @@ module axi_mcast_demux #( logic slv_aw_valid, slv_aw_valid_chan, slv_aw_valid_sel, slv_aw_valid_mcast; logic slv_aw_ready, slv_aw_ready_chan, slv_aw_ready_sel, slv_aw_ready_mcast; + logic accept_aw; // AW channel to slave ports logic [NoMstPorts-1:0] mst_aw_valids, mst_aw_readies; @@ -192,7 +193,8 @@ module axi_mcast_demux #( logic multicast_stall; mask_select_t multicast_select_q, multicast_select_d; logic multicast_select_load; - logic [$clog2(NoMstPorts)+1-1:0] aw_select_popcount; + logic [$clog2(NoMstPorts)+1-1:0] aw_select_popcount; + logic mcast_aw_hs_in_progress; // W select counter: stores the decision to which masters W beats should go mask_select_t w_select, w_select_q; @@ -417,6 +419,31 @@ module axi_mcast_demux #( end end + // Multicast AW transaction handshake state + typedef enum logic {MCastAwHandshakeIdle, MCastAwHandshakeInProgress} mcast_aw_hs_state_e; + mcast_aw_hs_state_e mcast_aw_hs_state_q, mcast_aw_hs_state_d; + + // Update of the multicast AW handshake state + always_comb begin + mcast_aw_hs_state_d = mcast_aw_hs_state_q; + unique case (mcast_aw_hs_state_q) + // Waiting for all selected master ports to be ready + MCastAwHandshakeIdle: + if (accept_aw && aw_is_multicast) begin + mcast_aw_hs_state_d = MCastAwHandshakeInProgress; + end + // Commit is asserted and handshake takes place in the current cycle. + // In the next cycle we are again idle + MCastAwHandshakeInProgress: + mcast_aw_hs_state_d = MCastAwHandshakeIdle; + default: ; + endcase + end + + assign mcast_aw_hs_in_progress = mcast_aw_hs_state_q == MCastAwHandshakeInProgress; + + `FFARN(mcast_aw_hs_state_q, mcast_aw_hs_state_d, MCastAwHandshakeIdle, clk_i, rst_ni) + // When a multicast occurs, the upstream valid signals need to // be forwarded to multiple master ports. // Proper stream forking is necessary to avoid protocol violations. @@ -429,8 +456,9 @@ module axi_mcast_demux #( // Using commit, instead of valid, to this end ensures that we don't have // any combinational loops. assign mst_aw_valids = {NoMstPorts{aw_valid}} & slv_aw_select; - assign aw_ready = &((mst_aw_valids & mst_aw_readies) | ~slv_aw_select); - assign mst_aw_commit_o = {NoMstPorts{aw_ready && aw_is_multicast}} & slv_aw_select; + assign accept_aw = &((mst_aw_valids & mst_aw_readies) | ~slv_aw_select); + assign aw_ready = aw_is_multicast ? mcast_aw_hs_in_progress : accept_aw; + assign mst_aw_commit_o = {NoMstPorts{mcast_aw_hs_in_progress}} & slv_aw_select; if (UniqueIds) begin : gen_unique_ids_aw // If the `UniqueIds` parameter is set, each write transaction has an ID that is unique among diff --git a/src/axi_mcast_mux.sv b/src/axi_mcast_mux.sv index 50c608929..313251af8 100644 --- a/src/axi_mcast_mux.sv +++ b/src/axi_mcast_mux.sv @@ -76,13 +76,16 @@ module axi_mcast_mux #( // pass through if only one slave port if (NoSlvPorts == 32'h1) begin : gen_no_mux + spill_register #( .T ( mst_aw_chan_t ), .Bypass ( ~SpillAw ) ) i_aw_spill_reg ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), - .valid_i ( slv_reqs_i[0].aw_valid ), + .valid_i ( slv_is_mcast_i[0] ? + slv_aw_commit_i[0] : + slv_reqs_i[0].aw_valid ), .ready_o ( slv_resps_o[0].aw_ready ), .data_i ( slv_reqs_i[0].aw ), .valid_o ( mst_req_o.aw_valid ), @@ -180,7 +183,7 @@ module axi_mcast_mux #( logic ucast_aw_valid, ucast_aw_ready; logic mcast_aw_valid, mcast_aw_ready, mcast_aw_commit; logic mcast_not_aw_valid; - mst_idx_t mcast_sel; + mst_idx_t mcast_sel_q, mcast_sel_d; logic [NoSlvPorts-1:0] mcast_sel_mask; logic [NoSlvPorts-1:0] ucast_aw_readies, mcast_aw_readies; @@ -303,24 +306,28 @@ module axi_mcast_mux #( .MODE ( 1'b0 ) // Trailing zero mode ) i_aw_mcast_lzc ( .in_i ( slv_aw_valids & slv_is_mcast_i ), - .cnt_o ( mcast_sel ), + .cnt_o ( mcast_sel_d ), .empty_o ( mcast_not_aw_valid ) ); - assign mcast_sel_mask = mcast_not_aw_valid ? '0 : 1 << mcast_sel; - assign mcast_aw_chan = slv_aw_chans[mcast_sel]; + assign mcast_sel_mask = mcast_not_aw_valid ? '0 : 1 << mcast_sel_d; + assign mcast_aw_chan = slv_aw_chans[mcast_sel_q]; assign mcast_aw_valid = !mcast_not_aw_valid; assign mcast_aw_commit = |slv_aw_commit_i; assign mcast_aw_readies = {NoSlvPorts{mcast_aw_ready}} & mcast_sel_mask; + // TODO colluca: change all FFxARN to FFx + `FFLARN(mcast_sel_q, mcast_sel_d, mcast_aw_valid && mcast_aw_ready, '0, clk_i, rst_ni) + // Arbitrate "winners" of unicast and multicast arbitrations // giving priority to multicast - assign mcast_aw_ready = aw_ready && mcast_aw_valid; - assign ucast_aw_ready = aw_ready && !mcast_aw_valid; + assign mcast_aw_ready = aw_ready && mcast_aw_valid && !mcast_aw_commit; + assign ucast_aw_ready = aw_ready && !mcast_aw_valid && !mcast_aw_commit; assign mst_aw_chan = mcast_aw_commit ? mcast_aw_chan : ucast_aw_chan; assign slv_aw_readies = mcast_aw_readies | ucast_aw_readies; // !!! CAUTION !!! // This valid depends combinationally on aw_ready (through aw_commit), // hence aw_ready shouldn't depend on aw_valid to avoid combinational loops! + // TODO colluca: replace ucast_aw_ready with !mcast_aw_valid to remove combinational loop assign aw_valid = mcast_aw_commit || (ucast_aw_valid && ucast_aw_ready); // control of the AW channel From ec76868d728d148124aedb02ff4d92918a03113c Mon Sep 17 00:00:00 2001 From: Luca Colagrande Date: Wed, 23 Nov 2022 16:10:13 +0100 Subject: [PATCH 15/41] axi_mcast_demux: Retrieve AW select index form from the mask --- src/axi_mcast_demux.sv | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/src/axi_mcast_demux.sv b/src/axi_mcast_demux.sv index 85acfac97..582ef45bb 100644 --- a/src/axi_mcast_demux.sv +++ b/src/axi_mcast_demux.sv @@ -170,7 +170,8 @@ module axi_mcast_demux #( //-------------------------------------- // comes from spill register at input aw_chan_t slv_aw_chan; - mask_select_t slv_aw_select; + idx_select_t slv_aw_select; + mask_select_t slv_aw_select_mask; aw_multi_addr_t [NoMstPorts-1:0] slv_aw_mcast; logic slv_aw_valid, slv_aw_valid_chan, slv_aw_valid_sel, slv_aw_valid_mcast; @@ -181,7 +182,7 @@ module axi_mcast_demux #( logic [NoMstPorts-1:0] mst_aw_valids, mst_aw_readies; // AW ID counter - mask_select_t lookup_aw_select; + idx_select_t lookup_aw_select; logic aw_select_occupied, aw_id_cnt_full; logic aw_any_outstanding_unicast_trx; logic aw_any_outstanding_trx; @@ -283,7 +284,7 @@ module axi_mcast_demux #( .data_i ( slv_aw_select_i ), .valid_o ( slv_aw_valid_sel ), .ready_i ( slv_aw_ready ), - .data_o ( slv_aw_select ) + .data_o ( slv_aw_select_mask ) ); spill_register #( .T ( aw_multi_addr_t [NoMstPorts-1:0] ), @@ -340,7 +341,7 @@ module axi_mcast_demux #( // This prevents deadlocking of the W channel. The counters are there for the // Handling of the B responses. if (slv_aw_valid && - ((w_open == '0) || (w_select == slv_aw_select)) && + ((w_open == '0) || (w_select == slv_aw_select_mask)) && (!aw_select_occupied || (slv_aw_select == lookup_aw_select)) && !multicast_stall) begin // connect the handshake @@ -367,9 +368,21 @@ module axi_mcast_demux #( /// Multicast logic + // Convert AW select mask to select index since the indices + // are smaller than the masks and thus cheaper to store in + // the ID counters. We anyways don't use the ID counters on + // multicast transactions... + + onehot_to_bin #( + .ONEHOT_WIDTH(NoMstPorts) + ) i_onehot_to_bin ( + .onehot(slv_aw_select_mask), + .bin (slv_aw_select) + ); + // Popcount to identify multicast requests popcount #(NoMstPorts) i_aw_select_popcount ( - .data_i (slv_aw_select), + .data_i (slv_aw_select_mask), .popcount_o(aw_select_popcount) ); @@ -408,7 +421,7 @@ module axi_mcast_demux #( multicast_select_load = 1'b0; unique if (aw_is_multicast && aw_valid && aw_ready) begin - multicast_select_d = slv_aw_select; + multicast_select_d = slv_aw_select_mask; multicast_select_load = 1'b1; end else if (outstanding_multicast && slv_b_valid && slv_b_ready) begin multicast_select_d = '0; @@ -455,10 +468,10 @@ module axi_mcast_demux #( // handshake can now actually take place. // Using commit, instead of valid, to this end ensures that we don't have // any combinational loops. - assign mst_aw_valids = {NoMstPorts{aw_valid}} & slv_aw_select; - assign accept_aw = &((mst_aw_valids & mst_aw_readies) | ~slv_aw_select); + assign mst_aw_valids = {NoMstPorts{aw_valid}} & slv_aw_select_mask; + assign accept_aw = &((mst_aw_valids & mst_aw_readies) | ~slv_aw_select_mask); assign aw_ready = aw_is_multicast ? mcast_aw_hs_in_progress : accept_aw; - assign mst_aw_commit_o = {NoMstPorts{mcast_aw_hs_in_progress}} & slv_aw_select; + assign mst_aw_commit_o = {NoMstPorts{mcast_aw_hs_in_progress}} & slv_aw_select_mask; if (UniqueIds) begin : gen_unique_ids_aw // If the `UniqueIds` parameter is set, each write transaction has an ID that is unique among @@ -492,10 +505,11 @@ module axi_mcast_demux #( ); end else begin : gen_aw_id_counter + axi_mcast_demux_id_counters #( .AxiIdBits ( AxiLookBits ), .CounterWidth ( IdCounterWidth ), - .mst_port_select_t ( mask_select_t ) + .mst_port_select_t ( idx_select_t ) ) i_aw_id_counter ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), @@ -534,8 +548,8 @@ module axi_mcast_demux #( .overflow_o ( /*not used*/ ) ); - `FFLARN(w_select_q, slv_aw_select, w_cnt_up, mask_select_t'(0), clk_i, rst_ni) - assign w_select = (|w_open) ? w_select_q : slv_aw_select; + `FFLARN(w_select_q, slv_aw_select_mask, w_cnt_up, mask_select_t'(0), clk_i, rst_ni) + assign w_select = (|w_open) ? w_select_q : slv_aw_select_mask; assign w_select_valid = w_cnt_up | (|w_open); assign w_cnt_down = slv_w_valid & slv_w_ready & slv_w_chan.last; From 7d6f06e74614839c6e21670e7d0bbdcea07dc5dd Mon Sep 17 00:00:00 2001 From: Luca Colagrande Date: Mon, 12 Dec 2022 10:14:10 +0100 Subject: [PATCH 16/41] axi_mcast_xbar: Move AW address decoders after spill registers in demux --- src/axi_mcast_demux.sv | 106 +++++++++++++++++------------------------ src/axi_mcast_xbar.sv | 44 ++--------------- 2 files changed, 48 insertions(+), 102 deletions(-) diff --git a/src/axi_mcast_demux.sv b/src/axi_mcast_demux.sv index 582ef45bb..7ffc12e13 100644 --- a/src/axi_mcast_demux.sv +++ b/src/axi_mcast_demux.sv @@ -58,24 +58,19 @@ 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, // Dependent parameters, DO NOT OVERRIDE! parameter int unsigned IdxSelectWidth = (NoMstPorts > 32'd1) ? $clog2(NoMstPorts) : 32'd1, parameter type idx_select_t = logic [IdxSelectWidth-1:0], - parameter type mask_select_t = logic [NoMstPorts-1:0], - // Multi-address type (represents a set of addresses) - parameter type aw_multi_addr_t = struct packed { - aw_addr_t aw_addr; - aw_addr_t aw_mask; - } + parameter type mask_select_t = logic [NoMstPorts-1:0] ) ( input logic clk_i, input logic rst_ni, input logic test_i, // Slave Port + input aw_rule_t [NoMstPorts-2:0] slv_aw_addr_map_i, input axi_req_t slv_req_i, - input mask_select_t slv_aw_select_i, input idx_select_t slv_ar_select_i, - input aw_multi_addr_t [NoMstPorts-1:0] slv_aw_mcast_i, output axi_resp_t slv_resp_o, // Master Ports output axi_req_t [NoMstPorts-1:0] mst_reqs_o, @@ -169,14 +164,17 @@ module axi_mcast_demux #( // Write Transaction //-------------------------------------- // comes from spill register at input - aw_chan_t slv_aw_chan; - idx_select_t slv_aw_select; - mask_select_t slv_aw_select_mask; - aw_multi_addr_t [NoMstPorts-1:0] slv_aw_mcast; - - logic slv_aw_valid, slv_aw_valid_chan, slv_aw_valid_sel, slv_aw_valid_mcast; - logic slv_aw_ready, slv_aw_ready_chan, slv_aw_ready_sel, slv_aw_ready_mcast; - logic accept_aw; + aw_chan_t slv_aw_chan; + logic slv_aw_valid; + 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; + 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; + idx_select_t slv_aw_select; // AW channel to slave ports logic [NoMstPorts-1:0] mst_aw_valids, mst_aw_readies; @@ -195,6 +193,7 @@ module axi_mcast_demux #( mask_select_t multicast_select_q, multicast_select_d; logic multicast_select_load; logic [$clog2(NoMstPorts)+1-1:0] aw_select_popcount; + logic accept_aw; logic mcast_aw_hs_in_progress; // W select counter: stores the decision to which masters W beats should go @@ -267,40 +266,31 @@ module axi_mcast_demux #( .clk_i ( clk_i ), .rst_ni ( rst_ni ), .valid_i ( slv_req_i.aw_valid ), - .ready_o ( slv_aw_ready_chan ), + .ready_o ( slv_resp_o.aw_ready ), .data_i ( slv_req_i.aw ), - .valid_o ( slv_aw_valid_chan ), + .valid_o ( slv_aw_valid ), .ready_i ( slv_aw_ready ), .data_o ( slv_aw_chan ) ); - spill_register #( - .T ( mask_select_t ), - .Bypass ( ~SpillAw ) // because module param indicates if we want a spill reg - ) i_aw_select_spill_reg ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .valid_i ( slv_req_i.aw_valid ), - .ready_o ( slv_aw_ready_sel ), - .data_i ( slv_aw_select_i ), - .valid_o ( slv_aw_valid_sel ), - .ready_i ( slv_aw_ready ), - .data_o ( slv_aw_select_mask ) - ); - spill_register #( - .T ( aw_multi_addr_t [NoMstPorts-1:0] ), - .Bypass ( ~SpillAw ) // because module param indicates if we want a spill reg - ) i_aw_mcast_spill_reg ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .valid_i ( slv_req_i.aw_valid ), - .ready_o ( slv_aw_ready_mcast ), - .data_i ( slv_aw_mcast_i ), - .valid_o ( slv_aw_valid_mcast ), - .ready_i ( slv_aw_ready ), - .data_o ( slv_aw_mcast ) + + multiaddr_decode #( + .NoRules(NoMstPorts-1), + .addr_t (aw_addr_t), + .rule_t (aw_rule_t) + ) i_axi_aw_decode ( + .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), + .addr_o (dec_aw_addr), + .mask_o (dec_aw_mask), + .dec_valid_o(dec_aw_valid), + .dec_error_o(dec_aw_error) ); - assign slv_resp_o.aw_ready = slv_aw_ready_chan & slv_aw_ready_sel & slv_aw_ready_mcast; - assign slv_aw_valid = slv_aw_valid_chan & slv_aw_valid_sel & slv_aw_valid_mcast; + assign slv_aw_select_mask = (dec_aw_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}; // Control of the AW handshake always_comb begin @@ -376,7 +366,7 @@ module axi_mcast_demux #( onehot_to_bin #( .ONEHOT_WIDTH(NoMstPorts) ) i_onehot_to_bin ( - .onehot(slv_aw_select_mask), + .onehot(slv_aw_select_mask & {NoMstPorts{!aw_is_multicast}}), .bin (slv_aw_select) ); @@ -804,8 +794,8 @@ module axi_mcast_demux #( for (int unsigned i = 0; i < NoMstPorts; i++) begin // AW channel mst_reqs_o[i].aw = slv_aw_chan; - mst_reqs_o[i].aw.addr = slv_aw_mcast[i].aw_addr; - mst_reqs_o[i].aw.user.mcast = slv_aw_mcast[i].aw_mask; + mst_reqs_o[i].aw.addr = slv_aw_addr[i]; + mst_reqs_o[i].aw.user.mcast = slv_aw_mask[i]; mst_reqs_o[i].aw_valid = mst_aw_valids[i]; // W channel @@ -846,7 +836,7 @@ module axi_mcast_demux #( $fatal(1, "The Number of slaves (NoMstPorts) has to be at least 1"); AXI_ID_BITS: assume (AxiIdWidth >= AxiLookBits) else $fatal(1, "AxiIdBits has to be equal or smaller than AxiIdWidth."); - aw_addr_bits: assume ($bits(slv_aw_mcast_i[0].aw_addr) == $bits(slv_req_i.aw.addr)) else + aw_addr_bits: assume ($bits(slv_aw_addr[0]) == $bits(slv_req_i.aw.addr)) else $fatal(1, "aw_addr_t must be the type of slv_req_i.aw.addr"); end default disable iff (!rst_ni); @@ -1030,23 +1020,17 @@ 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, // 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], - parameter type mask_select_t = logic [NO_MST_PORTS-1:0], - parameter type addr_t = logic [AXI_ADDR_WIDTH-1:0], - // Multi-address type (represents a set of addresses) - parameter type aw_multi_addr_t = struct packed { - addr_t aw_addr; - addr_t aw_mask; - } + parameter type addr_t = logic [AXI_ADDR_WIDTH-1:0] ) ( input logic clk_i, // Clock input logic rst_ni, // Asynchronous reset active low input logic test_i, // Testmode enable - input mask_select_t slv_aw_select_i, // has to be stable, when aw_valid + input aw_rule_t [NO_MST_PORTS-2:0] slv_aw_addr_map_i, input idx_select_t slv_ar_select_i, // has to be stable, when ar_valid - input aw_multi_addr_t [NO_MST_PORTS-1:0] slv_aw_mcast_i, AXI_BUS.Slave slv, // slave port AXI_BUS.Master mst [NO_MST_PORTS-1:0], // master ports output logic [NO_MST_PORTS-1:0] mst_is_mcast_o, @@ -1097,16 +1081,16 @@ module axi_mcast_demux_intf #( .SpillW ( SPILL_W ), .SpillB ( SPILL_B ), .SpillAr ( SPILL_AR ), - .SpillR ( SPILL_R ) + .SpillR ( SPILL_R ), + .aw_rule_t ( aw_rule_t ) ) i_axi_demux ( .clk_i, // Clock .rst_ni, // Asynchronous reset active low .test_i, // Testmode enable // slave port .slv_req_i ( slv_req ), - .slv_aw_select_i ( slv_aw_select_i ), + .slv_aw_addr_map_i ( slv_aw_addr_map_i ), .slv_ar_select_i ( slv_ar_select_i ), - .slv_aw_mcast_i ( slv_aw_mcast_i ), .slv_resp_o ( slv_resp ), // master port .mst_reqs_o ( mst_req ), diff --git a/src/axi_mcast_xbar.sv b/src/axi_mcast_xbar.sv index 3339fc04f..a7cf597ae 100644 --- a/src/axi_mcast_xbar.sv +++ b/src/axi_mcast_xbar.sv @@ -104,12 +104,6 @@ import cf_math_pkg::idx_width; `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; - - typedef struct packed { - addr_t addr; - addr_t mask; - } multi_addr_t; // signals from the axi_demuxes, one index more for decode error slv_req_t [Cfg.NoSlvPorts-1:0][Cfg.NoMstPorts:0] slv_reqs; @@ -132,29 +126,8 @@ import cf_math_pkg::idx_width; `else logic [idx_width(Cfg.NoMstPorts)-1:0] dec_ar_select; `endif - logic [Cfg.NoMstPorts-1:0] dec_aw_select; - addr_t [Cfg.NoMstPorts-1:0] dec_aw_addr, dec_aw_mask; - logic dec_aw_valid, dec_aw_error; logic dec_ar_valid, dec_ar_error; - mst_port_mask_t slv_aw_select; mst_port_idx_t slv_ar_select; - addr_t [Cfg.NoMstPorts:0] slv_aw_addr, slv_aw_mask; - multi_addr_t [Cfg.NoMstPorts:0] slv_aw_mcast; - - multiaddr_decode #( - .NoRules(Cfg.NoMstPorts), - .addr_t (addr_t), - .rule_t (aw_rule_t) - ) i_axi_aw_decode ( - .addr_i (slv_ports_req_i[i].aw.addr), - .mask_i (slv_ports_req_i[i].aw.user.mcast), - .addr_map_i (aw_addr_map_i), - .select_o (dec_aw_select), - .addr_o (dec_aw_addr), - .mask_o (dec_aw_mask), - .dec_valid_o(dec_aw_valid), - .dec_error_o(dec_aw_error) - ); addr_decode #( .NoIndices ( Cfg.NoMstPorts ), @@ -170,19 +143,8 @@ import cf_math_pkg::idx_width; .en_default_idx_i ( '0 ), .default_idx_i ( '0 ) ); - - assign slv_aw_select = (dec_aw_error) ? - {1'b1, {Cfg.NoMstPorts{1'b0}}} : {1'b0, dec_aw_select}; assign slv_ar_select = (dec_ar_error) ? mst_port_idx_t'(Cfg.NoMstPorts) : mst_port_idx_t'(dec_ar_select); - assign slv_aw_addr = {'0, dec_aw_addr}; - assign slv_aw_mask = {'0, dec_aw_mask}; - - // Zip slv_aw_addr and slv_aw_mask into one array of structs - for (genvar mst_idx = 0; mst_idx <= Cfg.NoMstPorts; mst_idx++) begin : gen_aw_mcast - assign slv_aw_mcast[mst_idx].addr = slv_aw_addr[mst_idx]; - assign slv_aw_mcast[mst_idx].mask = slv_aw_mask[mst_idx]; - end axi_mcast_demux #( .AxiIdWidth ( Cfg.AxiIdWidthSlvPorts ), // ID Width @@ -203,15 +165,15 @@ import cf_math_pkg::idx_width; .SpillW ( Cfg.LatencyMode[8] ), .SpillB ( Cfg.LatencyMode[7] ), .SpillAr ( Cfg.LatencyMode[6] ), - .SpillR ( Cfg.LatencyMode[5] ) + .SpillR ( Cfg.LatencyMode[5] ), + .aw_rule_t ( aw_rule_t ) ) 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 ), .slv_req_i ( slv_ports_req_i[i] ), - .slv_aw_select_i ( slv_aw_select ), .slv_ar_select_i ( slv_ar_select ), - .slv_aw_mcast_i ( slv_aw_mcast ), .slv_resp_o ( slv_ports_resp_o[i] ), .mst_reqs_o ( slv_reqs[i] ), .mst_resps_i ( slv_resps[i] ), From c786723597a021f825cdbc2e2171de0a8da5bb34 Mon Sep 17 00:00:00 2001 From: Luca Colagrande Date: Tue, 13 Dec 2022 11:05:02 +0100 Subject: [PATCH 17/41] axi_mcast_demux: Merge B responses appropriately --- src/axi_mcast_demux.sv | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/axi_mcast_demux.sv b/src/axi_mcast_demux.sv index 7ffc12e13..2e0f5c798 100644 --- a/src/axi_mcast_demux.sv +++ b/src/axi_mcast_demux.sv @@ -216,6 +216,8 @@ module axi_mcast_demux #( // B channels input into the arbitration (unicast transactions) // or join module (multicast transactions) b_chan_t [NoMstPorts-1:0] mst_b_chans; + axi_pkg::resp_t [NoMstPorts-1:0] mst_b_resps; + idx_select_t mst_b_valids_tzc; logic [NoMstPorts-1:0] mst_b_valids, mst_b_readies; logic [NoMstPorts-1:0] mst_b_readies_arb, mst_b_readies_join; @@ -623,8 +625,26 @@ module axi_mcast_demux #( .oup_valid_o(slv_b_valid_join), .oup_ready_i(slv_b_ready) ); - // TODO colluca: merge B channels appropriately - assign slv_b_chan_join = mst_b_chans[0]; + for (genvar i=0; i Date: Wed, 26 Apr 2023 09:45:38 +0200 Subject: [PATCH 18/41] axi_mcast_xbar: Allow both regular and mask-based address rules --- scripts/run_vsim.sh | 2 +- src/axi_mcast_demux.sv | 110 ++++++++++++++++++++++++++------- src/axi_mcast_xbar.sv | 73 ++++++++++++---------- src/axi_pkg.sv | 8 ++- test/axi_synth_bench.sv | 36 ++++------- test/tb_axi_mcast_xbar.sv | 72 +++++++++++----------- test/tb_axi_mcast_xbar_pkg.sv | 111 ++++++++++++++++++++++------------ test/tb_axi_xbar.sv | 4 +- 8 files changed, 261 insertions(+), 155 deletions(-) diff --git a/scripts/run_vsim.sh b/scripts/run_vsim.sh index f98d6182f..a0262bb15 100755 --- a/scripts/run_vsim.sh +++ b/scripts/run_vsim.sh @@ -252,7 +252,7 @@ exec_test() { for UNIQUE_IDS in 0 1; do call_vsim tb_axi_mcast_xbar -t 1ns -voptargs="+acc" \ -gTbNumMasters=$NUM_MST \ - -gTbNumSlaves=$NUM_SLV \ + -gTbNumMcastSlaves=$NUM_SLV \ -gTbAxiIdWidthMasters=$MST_ID \ -gTbAxiIdUsed=$MST_ID_USE \ -gTbAxiDataWidth=$DATA_WIDTH \ diff --git a/src/axi_mcast_demux.sv b/src/axi_mcast_demux.sv index 2e0f5c798..04b064023 100644 --- a/src/axi_mcast_demux.sv +++ b/src/axi_mcast_demux.sv @@ -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 rule_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, @@ -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 @@ -169,12 +181,17 @@ 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; - 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; - idx_select_t slv_aw_select; + mask_rule_t [NoMulticastRules-1:0] multicast_rules; + mask_rule_t default_rule; + decode_idx_t dec_aw_idx; + logic dec_aw_idx_valid, dec_aw_idx_error; + logic [NoMulticastPorts-1:0] dec_aw_select_partial; + aw_addr_t [NoMulticastPorts-1:0] dec_aw_addr, dec_aw_mask; + logic dec_aw_select_error; + 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; + idx_select_t slv_aw_select; // AW channel to slave ports logic [NoMstPorts-1:0] mst_aw_valids, mst_aw_readies; @@ -275,23 +292,68 @@ 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(1'b0), + .default_idx_i ('0) + ); + end else begin : g_no_aw_idx_decode + assign dec_aw_idx_valid = 1'b0; + assign dec_aw_idx_error = 1'b1; + 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 + assign default_rule.idx = default_mst_port_i.idx; + assign default_rule.mask = default_mst_port_i.end_addr - default_mst_port_i.start_addr - 1; + assign default_rule.addr = default_mst_port_i.start_addr; + + // 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), + .en_default_idx_i(en_default_mst_port_i), + .default_idx_i (default_rule) ); - assign slv_aw_select_mask = (dec_aw_error) ? - {1'b1, {(NoMstPorts-1){1'b0}}} : {1'b0, dec_aw_select}; - assign slv_aw_addr = {'0, dec_aw_addr}; + + // 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, {(NoMstPorts-NoMulticastPorts){slv_aw_chan.addr}}, dec_aw_addr}; assign slv_aw_mask = {'0, dec_aw_mask}; // Control of the AW handshake @@ -1040,7 +1102,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], @@ -1049,8 +1111,10 @@ 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 + input logic en_default_mst_port_i, + input rule_t default_mst_port_i, AXI_BUS.Slave slv, // slave port AXI_BUS.Master mst [NO_MST_PORTS-1:0], // master ports output logic [NO_MST_PORTS-1:0] mst_is_mcast_o, @@ -1102,14 +1166,16 @@ 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 ), + .en_default_mst_port_i ( en_default_mst_port_i ), + .default_mst_port_i ( default_mst_port_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 diff --git a/src/axi_mcast_xbar.sv b/src/axi_mcast_xbar.sv index a7cf597ae..1797adff8 100644 --- a/src/axi_mcast_xbar.sv +++ b/src/axi_mcast_xbar.sv @@ -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, @@ -89,9 +79,13 @@ 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, + /// 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 rule_t [Cfg.NoSlvPorts-1:0] default_mst_port_i ); // Address type for individual address signals @@ -100,9 +94,13 @@ import cf_math_pkg::idx_width; `ifdef VCS localparam int unsigned MstPortsIdxWidthOne = (Cfg.NoMstPorts == 32'd1) ? 32'd1 : unsigned'($clog2(Cfg.NoMstPorts + 1)); + localparam int unsigned MstPortsIdxWidth = + (Cfg.NoMstPorts == 32'd1) ? 32'd1 : unsigned'($clog2(Cfg.NoMstPorts)); typedef logic [MstPortsIdxWidthOne-1:0] mst_port_idx_t; + typedef logic [MstPortsIdxWidth-1:0] mst_port_idx_m1_t; `else typedef logic [idx_width(Cfg.NoMstPorts + 1)-1:0] mst_port_idx_t; + typedef logic [idx_width(Cfg.NoMstPorts)-1:0] mst_port_idx_m1_t; `endif // signals from the axi_demuxes, one index more for decode error @@ -121,11 +119,7 @@ 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_ar_select; -`else - logic [idx_width(Cfg.NoMstPorts)-1:0] dec_ar_select; -`endif + mst_port_idx_m1_t dec_ar_select; logic dec_ar_valid, dec_ar_error; mst_port_idx_t slv_ar_select; @@ -133,15 +127,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 ( mst_port_idx_m1_t'(default_mst_port_i[i].idx) ) ); assign slv_ar_select = (dec_ar_error) ? mst_port_idx_t'(Cfg.NoMstPorts) : mst_port_idx_t'(dec_ar_select); @@ -166,12 +160,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] ), @@ -317,16 +316,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); @@ -388,8 +395,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, @@ -398,8 +404,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 diff --git a/src/axi_pkg.sv b/src/axi_pkg.sv index c7a974383..713bc9754 100644 --- a/src/axi_pkg.sv +++ b/src/axi_pkg.sv @@ -515,10 +515,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). diff --git a/test/axi_synth_bench.sv b/test/axi_synth_bench.sv index 34f4a87f4..5442556f3 100644 --- a/test/axi_synth_bench.sv +++ b/test/axi_synth_bench.sv @@ -960,11 +960,12 @@ module synth_axi_xbar #( UniqueIds: UniqueIds, AxiAddrWidth: AxiAddrWidth, AxiDataWidth: AxiDataWidth, - NoAddrRules: NoSlvMst + NoAddrRules: NoSlvMst, + NoMulticastRules: EnableMulticast ? NoSlvMst : 0, + NoMulticastPorts: EnableMulticast ? NoSlvMst : 0 }; - typedef axi_pkg::xbar_mask_rule_32_t aw_rule_t; // Has to be the same width as axi addr - typedef axi_pkg::xbar_rule_32_t ar_rule_t; // Has to be the same width as axi addr + typedef axi_pkg::xbar_rule_32_t rule_t; // Has to be the same width as axi addr `AXI_TYPEDEF_AW_CHAN_T(mst_aw_chan_t, addr_t, id_mst_t, aw_user_t) `AXI_TYPEDEF_AW_CHAN_T(slv_aw_chan_t, addr_t, id_slv_t, aw_user_t) @@ -983,12 +984,11 @@ module synth_axi_xbar #( `AXI_TYPEDEF_RESP_T(slv_resp_t, slv_b_chan_t, slv_r_chan_t) // Each slave has its own address range: - localparam ar_rule_t [xbar_cfg.NoAddrRules-1:0] ar_addr_map = ar_addr_map_gen(); - localparam aw_rule_t [xbar_cfg.NoAddrRules-1:0] aw_addr_map = aw_addr_map_gen(); + localparam rule_t [xbar_cfg.NoAddrRules-1:0] addr_map = addr_map_gen(); - function ar_rule_t [xbar_cfg.NoAddrRules-1:0] ar_addr_map_gen (); + function rule_t [xbar_cfg.NoAddrRules-1:0] addr_map_gen (); for (int unsigned i = 0; i < xbar_cfg.NoAddrRules; i++) begin - ar_addr_map_gen[i] = ar_rule_t'{ + addr_map_gen[i] = rule_t'{ idx: unsigned'(i), start_addr: i * 32'h0000_2000, end_addr: (i+1) * 32'h0000_2000, @@ -997,16 +997,6 @@ module synth_axi_xbar #( end endfunction - function aw_rule_t [xbar_cfg.NoAddrRules-1:0] aw_addr_map_gen (); - for (int unsigned i = 0; i < xbar_cfg.NoAddrRules; i++) begin - aw_addr_map_gen[i] = aw_rule_t'{ - addr: i * 32'h0000_2000, - mask: 32'h0000_1FFF, - default: '0 - }; - end - endfunction - slv_req_t [NoSlvMst-1:0] slv_reqs; mst_req_t [NoSlvMst-1:0] mst_reqs; slv_resp_t [NoSlvMst-1:0] slv_resps; @@ -1131,8 +1121,7 @@ module synth_axi_xbar #( .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_dut ( .clk_i (clk_i), .rst_ni (rst_ni), @@ -1141,8 +1130,9 @@ module synth_axi_xbar #( .slv_ports_resp_o (slv_resps), .mst_ports_req_o (mst_reqs), .mst_ports_resp_i (mst_resps), - .ar_addr_map_i (ar_addr_map), - .aw_addr_map_i (aw_addr_map) + .addr_map_i (addr_map), + .en_default_mst_port_i('0), + .default_mst_port_i ('0) ); end else begin : g_no_multicast axi_xbar #( @@ -1160,7 +1150,7 @@ module synth_axi_xbar #( .slv_resp_t (slv_resp_t), .mst_req_t (mst_req_t), .mst_resp_t (mst_resp_t), - .rule_t (ar_rule_t) + .rule_t (rule_t) ) i_xbar_dut ( .clk_i (clk_i), .rst_ni (rst_ni), @@ -1169,7 +1159,7 @@ module synth_axi_xbar #( .slv_ports_resp_o (slv_resps), .mst_ports_req_o (mst_reqs), .mst_ports_resp_i (mst_resps), - .addr_map_i (ar_addr_map), + .addr_map_i (addr_map), .en_default_mst_port_i('0), .default_mst_port_i ('0) ); diff --git a/test/tb_axi_mcast_xbar.sv b/test/tb_axi_mcast_xbar.sv index f86d71a7a..5cb4e8869 100644 --- a/test/tb_axi_mcast_xbar.sv +++ b/test/tb_axi_mcast_xbar.sv @@ -27,8 +27,9 @@ module tb_axi_mcast_xbar #( /// Number of AXI masters connected to the xbar. (Number of slave ports) parameter int unsigned TbNumMasters = 32'd6, - /// Number of AXI slaves connected to the xbar. (Number of master ports) - parameter int unsigned TbNumSlaves = 32'd8, + /// Number of AXI slaves connected to the xbar which can be targeted by multicast + /// transactions. (Number of multicast-enabled master ports) + parameter int unsigned TbNumMcastSlaves = 32'd8, /// Number of write transactions per master. parameter int unsigned TbNumWrites = 32'd200, /// Number of read transactions per master. @@ -62,6 +63,7 @@ module tb_axi_mcast_xbar #( localparam int unsigned TbAxiStrbWidth = TbAxiDataWidth / 8; localparam int unsigned TbAxiUserWidth = TbAxiAddrWidth; // In the bench can change this variables which are set here freely, + localparam TbNumSlaves = TbNumMcastSlaves + 1; localparam axi_pkg::xbar_cfg_t xbar_cfg = '{ NoSlvPorts: TbNumMasters, NoMstPorts: TbNumSlaves, @@ -75,20 +77,18 @@ module tb_axi_mcast_xbar #( UniqueIds: TbUniqueIds, AxiAddrWidth: TbAxiAddrWidth, AxiDataWidth: TbAxiDataWidth, - NoAddrRules: TbNumSlaves + NoAddrRules: TbNumMcastSlaves * 2 + 1, + NoMulticastRules: TbNumMcastSlaves * 2, + NoMulticastPorts: TbNumMcastSlaves }; typedef logic [TbAxiIdWidthMasters-1:0] id_mst_t; typedef logic [TbAxiIdWidthSlaves-1:0] id_slv_t; typedef logic [TbAxiAddrWidth-1:0] addr_t; - typedef struct packed { - addr_t addr; - addr_t mask; - } aw_rule_t; typedef struct packed { int unsigned idx; addr_t start_addr; addr_t end_addr; - } ar_rule_t; + } rule_t; typedef logic [TbAxiDataWidth-1:0] data_t; typedef logic [TbAxiStrbWidth-1:0] strb_t; typedef logic [TbAxiUserWidth-1:0] user_t; @@ -110,30 +110,25 @@ 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 ar_rule_t [xbar_cfg.NoAddrRules-1:0] ArAddrMap = ar_addr_map_gen(); - localparam aw_rule_t [xbar_cfg.NoAddrRules-1:0] AwAddrMap = aw_addr_map_gen(); + localparam rule_t [xbar_cfg.NoAddrRules-1:0] AddrMap = {rule_t'{ + idx: TbNumMcastSlaves, + start_addr: 32'h7000_0000, + end_addr: 32'h7008_0000 + }, + addr_map_gen(32'h1000_0000, 32'h10_0000), + addr_map_gen(32'h0b00_0000, 32'h1_0000)}; - function ar_rule_t [xbar_cfg.NoAddrRules-1:0] ar_addr_map_gen (); - for (int unsigned i = 0; i < xbar_cfg.NoAddrRules; i++) begin - ar_addr_map_gen[i] = ar_rule_t'{ + function rule_t [xbar_cfg.NoMulticastPorts-1:0] addr_map_gen (addr_t base, addr_t offset); + for (int unsigned i = 0; i < xbar_cfg.NoMulticastPorts; 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 endfunction - function aw_rule_t [xbar_cfg.NoAddrRules-1:0] aw_addr_map_gen (); - for (int unsigned i = 0; i < xbar_cfg.NoAddrRules; i++) begin - aw_addr_map_gen[i] = aw_rule_t'{ - addr: i * 32'h0000_2000, - mask: 32'h0000_1FFF, - default: '0 - }; - end - endfunction - typedef axi_test::axi_rand_master #( // AXI interface parameters .AW ( TbAxiAddrWidth ), @@ -237,10 +232,16 @@ module tb_axi_mcast_xbar #( initial begin axi_rand_master[i] = new( master_dv[i] ); end_of_sim[i] <= 1'b0; - axi_rand_master[i].add_memory_region(ArAddrMap[0].start_addr, - ArAddrMap[xbar_cfg.NoAddrRules-1].end_addr, + axi_rand_master[i].add_memory_region(AddrMap[0].start_addr, + AddrMap[xbar_cfg.NoMulticastPorts-1].end_addr, + axi_pkg::DEVICE_NONBUFFERABLE); + axi_rand_master[i].add_memory_region(AddrMap[xbar_cfg.NoMulticastPorts].start_addr, + AddrMap[xbar_cfg.NoMulticastRules-1].end_addr, + axi_pkg::DEVICE_NONBUFFERABLE); + axi_rand_master[i].add_memory_region(AddrMap[xbar_cfg.NoMulticastRules].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); @@ -268,10 +269,9 @@ module tb_axi_mcast_xbar #( .NoMasters ( TbNumMasters ), .NoSlaves ( TbNumSlaves ), .NoAddrRules ( xbar_cfg.NoAddrRules ), - .ar_rule_t ( ar_rule_t ), - .aw_rule_t ( aw_rule_t ), - .ArAddrMap ( ArAddrMap ), - .AwAddrMap ( AwAddrMap ), + .NoMulticastRules ( xbar_cfg.NoMulticastRules ), + .rule_t ( rule_t ), + .AddrMap ( AddrMap ), .TimeTest ( TestTime ) ) monitor = new( master_monitor_dv, slave_monitor_dv ); fork @@ -305,16 +305,16 @@ module tb_axi_mcast_xbar #( axi_mcast_xbar_intf #( .AXI_USER_WIDTH ( TbAxiUserWidth ), .Cfg ( xbar_cfg ), - .ar_rule_t ( ar_rule_t ), - .aw_rule_t ( aw_rule_t ) + .rule_t ( rule_t ) ) i_xbar_dut ( .clk_i ( clk ), .rst_ni ( rst_n ), .test_i ( 1'b0 ), .slv_ports ( master ), .mst_ports ( slave ), - .ar_addr_map_i ( ArAddrMap ), - .aw_addr_map_i ( AwAddrMap ) + .addr_map_i ( AddrMap ), + .en_default_mst_port_i ( '0 ), + .default_mst_port_i ( '0 ) ); // logger for master modules diff --git a/test/tb_axi_mcast_xbar_pkg.sv b/test/tb_axi_mcast_xbar_pkg.sv index d5164631e..7fe7bd520 100644 --- a/test/tb_axi_mcast_xbar_pkg.sv +++ b/test/tb_axi_mcast_xbar_pkg.sv @@ -28,10 +28,9 @@ package tb_axi_mcast_xbar_pkg; parameter int unsigned NoMasters, parameter int unsigned NoSlaves, parameter int unsigned NoAddrRules, - parameter type ar_rule_t, - parameter type aw_rule_t, - parameter ar_rule_t [NoAddrRules-1:0] ArAddrMap, - parameter aw_rule_t [NoAddrRules-1:0] AwAddrMap, + parameter int unsigned NoMulticastRules, + parameter type rule_t, + parameter rule_t [NoAddrRules-1:0] AddrMap, // Stimuli application and test time parameter time TimeTest ); @@ -157,53 +156,89 @@ 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 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; + // TODO colluca: add check that multicast requests only arrive on multicast ports + // (lower NoMulticastPorts) and that multicast requests only originate + // from multicast rules (lower NoMulticastRules) + if (masters_axi[i].aw_valid && masters_axi[i].aw_ready) begin // 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]; + 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 < NoSlaves; j++) begin - // request goes to the slave if all bits match, which are neither masked in the - // request nor in the addrmap rule - for (int k = 0; k < AxiAddrWidth; k++) addrmap_masked[k] = AwAddrMap[j].mask[k] ? 1'bx : AwAddrMap[j].addr[k]; - $display("With slave %0d : %b", j, addrmap_masked); - if (&(~(aw_addr ^ AwAddrMap[j].addr) | AwAddrMap[j].mask | aw_mcast)) begin - to_slave_idx.push_back(idx_slv_t'(j)); - mask_to_slave.push_back(aw_mcast & AwAddrMap[j].mask); - addr_to_slave.push_back((~aw_mcast & aw_addr) | (aw_mcast & AwAddrMap[j].addr)); - $display("Pushing mask : %b", aw_mcast & AwAddrMap[j].mask); - $display("Pushing address: %b", (~aw_mcast & aw_addr) | (aw_mcast & AwAddrMap[j].addr)); + + // Compare request against each multicast 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 = (NoMulticastRules - 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; + 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 + 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; - if (num_slaves_matched > 1 || decerr) begin - $display("MULTICAST occur: %b, %b", aw_addr, aw_mcast); - $display("Matched %0d slaves", num_slaves_matched); - for (int j = 0; j < NoSlaves; j++) begin - $display(" Slave %0d AddrMap: %b, %b", j, AwAddrMap[j].addr, AwAddrMap[j].mask); + + // Compare request against each interval-form rule. We look at the rules starting from + // the last ones. We ignore the case of multiple rules matching for the same slave + // (as is the case in tb_mcast_xbar_pkg.sv) + $display("Trying to match: %x", aw_addr); + for (int j = (NoAddrRules - 1); j >= NoMulticastRules; j--) begin + $display("With slave %3d : [%x, %x)", AddrMap[j].idx, AddrMap[j].start_addr, AddrMap[j].end_addr); + if ((aw_addr >= AddrMap[j].start_addr) && + (aw_addr < AddrMap[j].end_addr)) begin + to_slave_idx.push_back(AddrMap[j].idx); + addr_to_slave.push_back(aw_addr); + mask_to_slave.push_back('0); + $display(" Push address : %x", aw_addr); end end + num_slaves_matched = to_slave_idx.size(); + decerr = num_slaves_matched == 0; + // send the exp aw beats down into the queues of the selected slaves // when no decerror if (decerr) begin @@ -371,8 +406,8 @@ package tb_axi_mcast_xbar_pkg; exp_slv_axi_id = {idx_mst_t'(i), mst_axi_id}; exp_slv_idx = '0; for (int unsigned j = 0; j < NoAddrRules; j++) begin - if ((mst_axi_addr >= ArAddrMap[j].start_addr) && (mst_axi_addr < ArAddrMap[j].end_addr)) begin - exp_slv_idx = ArAddrMap[j].idx; + if ((mst_axi_addr >= AddrMap[j].start_addr) && (mst_axi_addr < AddrMap[j].end_addr)) begin + exp_slv_idx = AddrMap[j].idx; exp_decerr = 1'b0; end end diff --git a/test/tb_axi_xbar.sv b/test/tb_axi_xbar.sv index 3f8b3ffba..1daf39956 100644 --- a/test/tb_axi_xbar.sv +++ b/test/tb_axi_xbar.sv @@ -76,7 +76,9 @@ module tb_axi_xbar #( UniqueIds: TbUniqueIds, AxiAddrWidth: TbAxiAddrWidth, AxiDataWidth: TbAxiDataWidth, - NoAddrRules: TbNumSlaves + NoAddrRules: TbNumSlaves, + NoMulticastRules: 0, + NoMulticastPorts: 0 }; typedef logic [TbAxiIdWidthMasters-1:0] id_mst_t; typedef logic [TbAxiIdWidthSlaves-1:0] id_slv_t; From 7a1335a9c90710f93b8f501a05b80b32abcee54c Mon Sep 17 00:00:00 2001 From: Luca Colagrande Date: Tue, 20 Jun 2023 11:09:22 +0200 Subject: [PATCH 19/41] axi_mcast_xbar: Allow multiple outstanding multicast transactions Multiple outstanding multicast transactions are allowed only if the slaves selected by these transactions are the same. --- src/axi_mcast_demux.sv | 49 +++++++++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/src/axi_mcast_demux.sv b/src/axi_mcast_demux.sv index 04b064023..58f6529ce 100644 --- a/src/axi_mcast_demux.sv +++ b/src/axi_mcast_demux.sv @@ -62,6 +62,7 @@ module axi_mcast_demux #( parameter int unsigned NoAddrRules = 32'd0, parameter int unsigned NoMulticastRules = 32'd0, parameter int unsigned NoMulticastPorts = 32'd0, + parameter int unsigned MaxMcastTrans = 32'd7, // 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, @@ -89,6 +90,9 @@ module axi_mcast_demux #( localparam int unsigned IdCounterWidth = cf_math_pkg::idx_width(MaxTrans); typedef logic [IdCounterWidth-1:0] id_cnt_t; + localparam int unsigned McastCounterWidth = (MaxMcastTrans > 32'd1) ? $clog2(MaxMcastTrans+1) : 32'd1; + typedef logic [McastCounterWidth-1:0] mcast_cnt_t; + typedef struct packed { int unsigned idx; aw_addr_t addr; @@ -200,7 +204,6 @@ module axi_mcast_demux #( idx_select_t lookup_aw_select; logic aw_select_occupied, aw_id_cnt_full; logic aw_any_outstanding_unicast_trx; - logic aw_any_outstanding_trx; // Upon an ATOP load, inject IDs from the AW into the AR channel logic atop_inject; // Multicast logic @@ -208,7 +211,7 @@ module axi_mcast_demux #( logic outstanding_multicast; logic multicast_stall; mask_select_t multicast_select_q, multicast_select_d; - logic multicast_select_load; + mcast_cnt_t outstanding_mcast_cnt_q, outstanding_mcast_cnt_d; logic [$clog2(NoMstPorts)+1-1:0] aw_select_popcount; logic accept_aw; logic mcast_aw_hs_in_progress; @@ -458,31 +461,37 @@ module axi_mcast_demux #( // of a multicast. This means stall an AW request if: // - there is an outstanding multicast transaction or // - if the request is a multicast, until there are no more outstanding transactions - assign aw_is_multicast = aw_select_popcount > 1; - assign outstanding_multicast = |multicast_select_q; - assign aw_any_outstanding_trx = aw_any_outstanding_unicast_trx || outstanding_multicast; - assign multicast_stall = outstanding_multicast || (aw_is_multicast && aw_any_outstanding_trx); + // We can slightly loosen this constraint, in the case of successive multicast + // requests going to the same slaves. In this case, we don't need to buffer any + // additional select signals. + assign aw_is_multicast = aw_select_popcount > 1; + assign outstanding_multicast = outstanding_mcast_cnt_q != '0; + assign multicast_stall = (outstanding_multicast && (slv_aw_select_mask != multicast_select_q)) || + (aw_is_multicast && aw_any_outstanding_unicast_trx) || + (outstanding_mcast_cnt_q == MaxMcastTrans); // We can send this signal to all slaves since we will only have one outstanding aw assign mst_is_mcast_o = {NoMstPorts{aw_is_multicast}}; // Keep track of which B responses need to be returned to complete the multicast - `FFLARN(multicast_select_q, multicast_select_d, multicast_select_load, '0, clk_i, rst_ni) + `FFARN(multicast_select_q, multicast_select_d, '0, clk_i, rst_ni) + `FFARN(outstanding_mcast_cnt_q, outstanding_mcast_cnt_d, '0, clk_i, rst_ni) - // Logic to update multicast_select_q. Loads the register upon the AW handshake - // of a multicast transaction. Successively clears it upon the "joined" B handshake + // Logic to update number of outstanding multicast transactions and current multicast + // transactions' select mask. Counter is incremented upon the AW handshake of a multicast + // transaction and decremented upon the "joined" B handshake. always_comb begin multicast_select_d = multicast_select_q; - multicast_select_load = 1'b0; - - unique if (aw_is_multicast && aw_valid && aw_ready) begin - multicast_select_d = slv_aw_select_mask; - multicast_select_load = 1'b1; - end else if (outstanding_multicast && slv_b_valid && slv_b_ready) begin - multicast_select_d = '0; - multicast_select_load = 1'b1; - end else begin - multicast_select_d = multicast_select_q; - multicast_select_load = 1'b0; + outstanding_mcast_cnt_d = outstanding_mcast_cnt_q; + + // Written as separate if statements as they may both be valid at the same time + // For the same reason the right hand side uses outstanding_mcast_cnt_d + // instead of outstanding_mcast_cnt_q + if (aw_is_multicast && aw_valid && aw_ready) begin + outstanding_mcast_cnt_d = outstanding_mcast_cnt_d + (|slv_aw_select_mask); + multicast_select_d = slv_aw_select_mask; + end + if (outstanding_multicast && slv_b_valid && slv_b_ready) begin + outstanding_mcast_cnt_d = outstanding_mcast_cnt_d - 1; end end From a64618fc4e441ede139648f5e9af9c1e9bbeef56 Mon Sep 17 00:00:00 2001 From: Luca Colagrande Date: Thu, 19 Sep 2024 14:54:43 +0200 Subject: [PATCH 20/41] axi_mcast_xbar: Filter multicast requests to unconnected slaves --- src/axi_mcast_demux.sv | 7 ++++++- src/axi_mcast_xbar.sv | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/axi_mcast_demux.sv b/src/axi_mcast_demux.sv index 58f6529ce..d994ec325 100644 --- a/src/axi_mcast_demux.sv +++ b/src/axi_mcast_demux.sv @@ -50,6 +50,8 @@ module axi_mcast_demux #( parameter type axi_req_t = logic, parameter type axi_resp_t = logic, parameter int unsigned NoMstPorts = 32'd0, + /// Connectivity vector + parameter bit [NoMstPorts-1:0] Connectivity = '1, parameter int unsigned MaxTrans = 32'd8, parameter int unsigned AxiLookBits = 32'd3, parameter bit UniqueIds = 1'b0, @@ -354,8 +356,11 @@ module axi_mcast_demux #( // 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; + // Filter out messages on ports that are not connected, otherwise the error slave + // would respond with DECERR and, when merged with the other responses, this results + // in an error being returned to the master. assign slv_aw_select_mask = (dec_aw_idx_error && dec_aw_select_error) ? - {1'b1, {(NoMstPorts-1){1'b0}}} : {1'b0, dec_aw_select}; + {1'b1, {(NoMstPorts-1){1'b0}}} : {1'b0, dec_aw_select & Connectivity}; assign slv_aw_addr = {'0, {(NoMstPorts-NoMulticastPorts){slv_aw_chan.addr}}, dec_aw_addr}; assign slv_aw_mask = {'0, dec_aw_mask}; diff --git a/src/axi_mcast_xbar.sv b/src/axi_mcast_xbar.sv index 1797adff8..468768f33 100644 --- a/src/axi_mcast_xbar.sv +++ b/src/axi_mcast_xbar.sv @@ -143,6 +143,7 @@ import cf_math_pkg::idx_width; axi_mcast_demux #( .AxiIdWidth ( Cfg.AxiIdWidthSlvPorts ), // ID Width .AtopSupport ( ATOPs ), + .Connectivity ( Connectivity[i] ), .aw_addr_t ( addr_t ), // AW Address Type .aw_chan_t ( slv_aw_chan_t ), // AW Channel Type .w_chan_t ( w_chan_t ), // W Channel Type From 25a9327214f558a27f14b5a1ef3cd4d898aed4ba Mon Sep 17 00:00:00 2001 From: Luca Colagrande Date: Mon, 9 Sep 2024 09:19:35 +0200 Subject: [PATCH 21/41] axi_mcast_xbar: Add to CI --- .github/workflows/gitlab-ci.yml | 2 +- .gitlab-ci.yml | 17 +++++++++++++++++ scripts/run_vsim.sh | 18 +++++++++--------- 3 files changed, 27 insertions(+), 10 deletions(-) diff --git a/.github/workflows/gitlab-ci.yml b/.github/workflows/gitlab-ci.yml index b0fd13261..43bff9759 100644 --- a/.github/workflows/gitlab-ci.yml +++ b/.github/workflows/gitlab-ci.yml @@ -9,7 +9,7 @@ on: jobs: gitlab-ci: runs-on: ubuntu-latest - timeout-minutes: 310 + timeout-minutes: 360 steps: - name: Check Gitlab CI uses: pulp-platform/pulp-actions/gitlab-ci@v2.5.1 diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 146819335..e5e524a0a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -256,3 +256,20 @@ axi_xbar: - src/axi_mux.sv - src/axi_multicut.sv - src/axi_xbar_unmuxed.sv + timeout: 6h 00m + +axi_mcast_xbar: + extends: .run_vsim + variables: + TEST_MODULE: axi_mcast_xbar + rules: + - *run_vsim_common_change_rule + - *run_vsim_module_change_rule + - changes: + compare_to: 'refs/heads/master' + paths: + - src/axi_mcast_demux.sv + - src/axi_err_slv.sv + - src/axi_mcast_mux.sv + - src/axi_multicut.sv + timeout: 6h 00m diff --git a/scripts/run_vsim.sh b/scripts/run_vsim.sh index a0262bb15..76235be7e 100755 --- a/scripts/run_vsim.sh +++ b/scripts/run_vsim.sh @@ -219,7 +219,7 @@ exec_test() { MST_ID=5 for DATA_WIDTH in 64 256; do for PIPE in 0 1; do - call_vsim tb_axi_xbar -t 1ns -voptargs="+acc" \ + call_vsim tb_axi_xbar -t 1ns \ -gTbNumMasters=$NUM_MST \ -gTbNumSlaves=$NUM_SLV \ -gTbAxiIdWidthMasters=$MST_ID \ @@ -250,14 +250,14 @@ exec_test() { for DATA_WIDTH in 64 256; do for PIPE in 0; do for UNIQUE_IDS in 0 1; do - call_vsim tb_axi_mcast_xbar -t 1ns -voptargs="+acc" \ - -gTbNumMasters=$NUM_MST \ - -gTbNumMcastSlaves=$NUM_SLV \ - -gTbAxiIdWidthMasters=$MST_ID \ - -gTbAxiIdUsed=$MST_ID_USE \ - -gTbAxiDataWidth=$DATA_WIDTH \ - -gTbPipeline=$PIPE \ - -gTbEnAtop=$GEN_ATOP \ + call_vsim tb_axi_mcast_xbar -t 1ns \ + -gTbNumMasters=$NUM_MST \ + -gTbNumMcastSlaves=$NUM_SLV \ + -gTbAxiIdWidthMasters=$MST_ID \ + -gTbAxiIdUsed=$MST_ID_USE \ + -gTbAxiDataWidth=$DATA_WIDTH \ + -gTbPipeline=$PIPE \ + -gTbEnAtop=$GEN_ATOP \ -gTbUniqueIds=$UNIQUE_IDS done done From 1fd11968185f0fae44456e793194ec56465db76a Mon Sep 17 00:00:00 2001 From: Lura518 <47368161+Lura518@users.noreply.github.com> Date: Tue, 16 Sep 2025 16:45:57 +0200 Subject: [PATCH 22/41] Improved route decoding for collective operations (#1) --------- Co-authored-by: Luca Colagrande Co-authored-by: Raphael --- src/axi_mcast_demux.sv | 209 +++++++++++++++++++--------------- src/axi_mcast_xbar.sv | 61 +++++----- test/tb_axi_mcast_xbar_pkg.sv | 105 ++++++++++------- 3 files changed, 210 insertions(+), 165 deletions(-) diff --git a/src/axi_mcast_demux.sv b/src/axi_mcast_demux.sv index d994ec325..6e3561acc 100644 --- a/src/axi_mcast_demux.sv +++ b/src/axi_mcast_demux.sv @@ -39,38 +39,38 @@ /// Beats on the B and R channel are multiplexed from the master ports to the slave port with /// a round-robin arbitration tree. module axi_mcast_demux #( - parameter int unsigned AxiIdWidth = 32'd0, - parameter bit AtopSupport = 1'b1, - parameter type aw_addr_t = logic, - parameter type aw_chan_t = logic, - parameter type w_chan_t = logic, - parameter type b_chan_t = logic, - parameter type ar_chan_t = logic, - parameter type r_chan_t = logic, - parameter type axi_req_t = logic, - parameter type axi_resp_t = logic, - parameter int unsigned NoMstPorts = 32'd0, + parameter int unsigned AxiIdWidth = 32'd0, + parameter bit AtopSupport = 1'b1, + parameter type aw_addr_t = logic, + parameter type aw_chan_t = logic, + parameter type w_chan_t = logic, + parameter type b_chan_t = logic, + parameter type ar_chan_t = logic, + parameter type r_chan_t = logic, + parameter type axi_req_t = logic, + parameter type axi_resp_t = logic, + parameter int unsigned NoMstPorts = 32'd0, /// Connectivity vector - parameter bit [NoMstPorts-1:0] Connectivity = '1, - parameter int unsigned MaxTrans = 32'd8, - parameter int unsigned AxiLookBits = 32'd3, - parameter bit UniqueIds = 1'b0, - parameter bit SpillAw = 1'b1, - parameter bit SpillW = 1'b0, - parameter bit SpillB = 1'b0, - parameter bit SpillAr = 1'b1, - 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 bit [NoMstPorts-1:0] Connectivity = '1, + /// Collective Operation Connectivity (to mask certain outputs for coll operations) + parameter bit [NoMstPorts-1:0] CollectiveOpsConnectivity = '1, + parameter int unsigned MaxTrans = 32'd8, + parameter int unsigned AxiLookBits = 32'd3, + parameter bit UniqueIds = 1'b0, + parameter bit SpillAw = 1'b1, + parameter bit SpillW = 1'b0, + parameter bit SpillB = 1'b0, + parameter bit SpillAr = 1'b1, + 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, // 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] + parameter int unsigned IdxSelectWidth = (NoMstPorts > 32'd1) ? $clog2(NoMstPorts) : 32'd1, + 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, @@ -189,13 +189,20 @@ module axi_mcast_demux #( // AW address decoder mask_rule_t [NoMulticastRules-1:0] multicast_rules; mask_rule_t default_rule; - decode_idx_t dec_aw_idx; - logic dec_aw_idx_valid, dec_aw_idx_error; - logic [NoMulticastPorts-1:0] dec_aw_select_partial; - aw_addr_t [NoMulticastPorts-1:0] dec_aw_addr, dec_aw_mask; - logic dec_aw_select_error; - logic [NoMstPorts-2:0] dec_aw_select; - aw_addr_t [NoMstPorts-1:0] slv_aw_addr, slv_aw_mask; + + idx_select_t dec_aw_unicast_selected_idx; + logic [NoMstPorts-1:0] dec_aw_unicast_selected_out; + logic dec_aw_unicast_valid; + logic dec_aw_unicast_error; + + logic [NoMulticastPorts-1:0] dec_aw_multicast_selected_out; + aw_addr_t [NoMulticastPorts-1:0] dec_aw_multicast_addr; + aw_addr_t [NoMulticastPorts-1:0] dec_aw_multicast_mask; + logic dec_aw_multicast_valid; + logic dec_aw_multicast_error; + + aw_addr_t [NoMstPorts-1:0] slv_aw_addr; + aw_addr_t [NoMstPorts-1:0] slv_aw_mask; mask_select_t slv_aw_select_mask; idx_select_t slv_aw_select; @@ -297,28 +304,6 @@ 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(1'b0), - .default_idx_i ('0) - ); - end else begin : g_no_aw_idx_decode - assign dec_aw_idx_valid = 1'b0; - assign dec_aw_idx_error = 1'b1; - 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) @@ -333,36 +318,80 @@ module axi_mcast_demux #( assign default_rule.mask = default_mst_port_i.end_addr - default_mst_port_i.start_addr - 1; assign default_rule.addr = default_mst_port_i.start_addr; - // Compare request against {addr, mask} rules - multiaddr_decode #( - .NoIndices(NoMulticastPorts), - .NoRules(NoMulticastRules), - .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), - .en_default_idx_i(en_default_mst_port_i), - .default_idx_i (default_rule) + // Address decoding for unicast requests + addr_decode #( + .NoIndices (NoMstPorts), + .NoRules (NoAddrRules), + .addr_t (aw_addr_t), + .rule_t (rule_t) + ) i_axi_aw_idx_unicast_decode ( + .addr_i (slv_aw_chan.addr), + .addr_map_i (addr_map_i), + .idx_o (dec_aw_unicast_selected_idx), + .dec_valid_o (dec_aw_unicast_valid), + .dec_error_o (dec_aw_unicast_error), + .en_default_idx_i (en_default_mst_port_i), + .default_idx_i (idx_select_t'(default_mst_port_i.idx)) ); - // 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; + // Generate the output mask from the index + assign dec_aw_unicast_selected_out = (1'b1 << dec_aw_unicast_selected_idx); + + // Address decoding for multicast requests + if (NoMulticastRules > 0) begin : gen_multicast_decoding + multiaddr_decode #( + .NoIndices (NoMulticastPorts), + .NoRules (NoMulticastRules), + .addr_t (aw_addr_t), + .rule_t (mask_rule_t) + ) i_axi_aw_multicast_decode ( + .addr_map_i (multicast_rules), + .addr_i (slv_aw_chan.addr), + .mask_i (slv_aw_chan.user.collective_mask), + .select_o (dec_aw_multicast_selected_out), + .addr_o (dec_aw_multicast_addr), + .mask_o (dec_aw_multicast_mask), + .dec_valid_o (dec_aw_multicast_valid), + .dec_error_o (dec_aw_multicast_error), + .en_default_idx_i (en_default_mst_port_i), + .default_idx_i (default_rule) + ); + end else begin : gen_no_multicast_decoding + assign dec_aw_multicast_selected_out = '0; + assign dec_aw_multicast_addr = '0; + assign dec_aw_multicast_mask = '0; + assign dec_aw_multicast_valid = '0; + assign dec_aw_multicast_error = '0; + end - // Filter out messages on ports that are not connected, otherwise the error slave - // would respond with DECERR and, when merged with the other responses, this results - // in an error being returned to the master. - assign slv_aw_select_mask = (dec_aw_idx_error && dec_aw_select_error) ? - {1'b1, {(NoMstPorts-1){1'b0}}} : {1'b0, dec_aw_select & Connectivity}; - assign slv_aw_addr = {'0, {(NoMstPorts-NoMulticastPorts){slv_aw_chan.addr}}, dec_aw_addr}; - assign slv_aw_mask = {'0, dec_aw_mask}; + // If the address decoding doesn't produce any match, the request + // is routed to the error slave, which lies at the highest index. + mask_select_t select_error_slave; + assign select_error_slave = 1'b1 << (NoMstPorts - 1); + + // Mux the multicast and unicast decoding outputs + always_comb begin + slv_aw_select_mask = '0; + slv_aw_addr = '0; + slv_aw_mask = '0; + + if (slv_aw_chan.user.collective_mask == '0) begin + slv_aw_addr = {NoMstPorts{slv_aw_chan.addr}}; + if (dec_aw_unicast_error) begin + slv_aw_select_mask = select_error_slave; + end else begin + slv_aw_select_mask = dec_aw_unicast_selected_out & Connectivity; + end + end else begin + slv_aw_addr = {'0, {(NoMstPorts-NoMulticastPorts){slv_aw_chan.addr}}, dec_aw_multicast_addr}; + slv_aw_mask = {'0, dec_aw_multicast_mask}; + if (dec_aw_multicast_error) begin + slv_aw_select_mask = select_error_slave; + end else begin + slv_aw_select_mask = {'0, dec_aw_multicast_selected_out} & CollectiveOpsConnectivity; + end + end + end // Control of the AW handshake always_comb begin @@ -889,10 +918,10 @@ module axi_mcast_demux #( for (int unsigned i = 0; i < NoMstPorts; i++) begin // AW channel - mst_reqs_o[i].aw = slv_aw_chan; - mst_reqs_o[i].aw.addr = slv_aw_addr[i]; - mst_reqs_o[i].aw.user.mcast = slv_aw_mask[i]; - mst_reqs_o[i].aw_valid = mst_aw_valids[i]; + mst_reqs_o[i].aw = slv_aw_chan; + mst_reqs_o[i].aw.addr = slv_aw_addr[i]; + mst_reqs_o[i].aw.user.collective_mask = slv_aw_mask[i]; + mst_reqs_o[i].aw_valid = mst_aw_valids[i]; // W channel mst_reqs_o[i].w = slv_w_chan; diff --git a/src/axi_mcast_xbar.sv b/src/axi_mcast_xbar.sv index 468768f33..242a47907 100644 --- a/src/axi_mcast_xbar.sv +++ b/src/axi_mcast_xbar.sv @@ -25,6 +25,8 @@ import cf_math_pkg::idx_width; parameter bit ATOPs = 1'b1, /// Connectivity matrix parameter bit [Cfg.NoSlvPorts-1:0][Cfg.NoMstPorts-1:0] Connectivity = '1, + /// Connectivity matrix for collective operations + parameter bit [Cfg.NoSlvPorts-1:0][Cfg.NoMstPorts-1:0] CollectiveOpsConnectivity = '1, /// AXI4+ATOP AW channel struct type for the slave ports. parameter type slv_aw_chan_t = logic, /// AXI4+ATOP AW channel struct type for the master ports. @@ -141,30 +143,31 @@ import cf_math_pkg::idx_width; mst_port_idx_t'(Cfg.NoMstPorts) : mst_port_idx_t'(dec_ar_select); axi_mcast_demux #( - .AxiIdWidth ( Cfg.AxiIdWidthSlvPorts ), // ID Width - .AtopSupport ( ATOPs ), - .Connectivity ( Connectivity[i] ), - .aw_addr_t ( addr_t ), // AW Address Type - .aw_chan_t ( slv_aw_chan_t ), // AW Channel Type - .w_chan_t ( w_chan_t ), // W Channel Type - .b_chan_t ( slv_b_chan_t ), // B Channel Type - .ar_chan_t ( slv_ar_chan_t ), // AR Channel Type - .r_chan_t ( slv_r_chan_t ), // R Channel Type - .axi_req_t ( slv_req_t ), - .axi_resp_t ( slv_resp_t ), - .NoMstPorts ( Cfg.NoMstPorts + 1 ), - .MaxTrans ( Cfg.MaxMstTrans ), - .AxiLookBits ( Cfg.AxiIdUsedSlvPorts ), - .UniqueIds ( Cfg.UniqueIds ), - .SpillAw ( Cfg.LatencyMode[9] ), - .SpillW ( Cfg.LatencyMode[8] ), - .SpillB ( Cfg.LatencyMode[7] ), - .SpillAr ( Cfg.LatencyMode[6] ), - .SpillR ( Cfg.LatencyMode[5] ), - .rule_t ( rule_t ), - .NoAddrRules ( Cfg.NoAddrRules ), - .NoMulticastRules( Cfg.NoMulticastRules ), - .NoMulticastPorts( Cfg.NoMulticastPorts ) + .AxiIdWidth ( Cfg.AxiIdWidthSlvPorts ), // ID Width + .AtopSupport ( ATOPs ), + .Connectivity ( Connectivity[i] ), + .CollectiveOpsConnectivity( CollectiveOpsConnectivity[i] ), + .aw_addr_t ( addr_t ), // AW Address Type + .aw_chan_t ( slv_aw_chan_t ), // AW Channel Type + .w_chan_t ( w_chan_t ), // W Channel Type + .b_chan_t ( slv_b_chan_t ), // B Channel Type + .ar_chan_t ( slv_ar_chan_t ), // AR Channel Type + .r_chan_t ( slv_r_chan_t ), // R Channel Type + .axi_req_t ( slv_req_t ), + .axi_resp_t ( slv_resp_t ), + .NoMstPorts ( Cfg.NoMstPorts + 1 ), + .MaxTrans ( Cfg.MaxMstTrans ), + .AxiLookBits ( Cfg.AxiIdUsedSlvPorts ), + .UniqueIds ( Cfg.UniqueIds ), + .SpillAw ( Cfg.LatencyMode[9] ), + .SpillW ( Cfg.LatencyMode[8] ), + .SpillB ( Cfg.LatencyMode[7] ), + .SpillAr ( Cfg.LatencyMode[6] ), + .SpillR ( Cfg.LatencyMode[5] ), + .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 @@ -330,11 +333,7 @@ import cf_math_pkg::idx_width; 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.NoSlvPorts-1:0] default_mst_port_i ); localparam int unsigned AxiIdWidthMstPorts = Cfg.AxiIdWidthSlvPorts + $clog2(Cfg.NoSlvPorts); @@ -345,9 +344,9 @@ import cf_math_pkg::idx_width; typedef logic [Cfg.AxiDataWidth -1:0] data_t; typedef logic [Cfg.AxiDataWidth/8 -1:0] strb_t; typedef logic [AXI_USER_WIDTH -1:0] user_t; - // AW channel adds multicast mask to USER signals + // AW channel adds collective mask to USER signals typedef struct packed { - addr_t mcast; + addr_t collective_mask; } aw_user_t; `AXI_TYPEDEF_AW_CHAN_T(mst_aw_chan_t, addr_t, id_mst_t, aw_user_t) diff --git a/test/tb_axi_mcast_xbar_pkg.sv b/test/tb_axi_mcast_xbar_pkg.sv index 7fe7bd520..99b9695d2 100644 --- a/test/tb_axi_mcast_xbar_pkg.sv +++ b/test/tb_axi_mcast_xbar_pkg.sv @@ -187,57 +187,70 @@ package tb_axi_mcast_xbar_pkg; // 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); - - // Compare request against each multicast 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 = (NoMulticastRules - 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; + + // Set decode error by default, reset if a rule is matched in the following + decerr = 1; + + // When a mask is present, multicast rules are used, otherwise the unicast rules are used. + if (aw_mcast != '0) begin + + // Log masked address 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 - 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)); + aw_addr_masked[k] = aw_mcast[k] ? 1'bx : aw_addr[k]; + $display("Trying to match: %b", aw_addr_masked); + + // Compare request against each multicast 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 = (NoMulticastRules - 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; + 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 + int unsigned slave_idx = AddrMap[j].idx; + decerr = 0; + + // 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 - end + + end else begin - // Compare request against each interval-form rule. We look at the rules starting from - // the last ones. We ignore the case of multiple rules matching for the same slave - // (as is the case in tb_mcast_xbar_pkg.sv) - $display("Trying to match: %x", aw_addr); - for (int j = (NoAddrRules - 1); j >= NoMulticastRules; j--) begin - $display("With slave %3d : [%x, %x)", AddrMap[j].idx, AddrMap[j].start_addr, AddrMap[j].end_addr); - if ((aw_addr >= AddrMap[j].start_addr) && - (aw_addr < AddrMap[j].end_addr)) begin - to_slave_idx.push_back(AddrMap[j].idx); - addr_to_slave.push_back(aw_addr); - mask_to_slave.push_back('0); - $display(" Push address : %x", aw_addr); + // Compare request against each interval-form rule. We look at the rules starting from + // the last ones. We ignore the case of multiple rules matching for the same slave + // (as is the case in tb_mcast_xbar_pkg.sv) + $display("Trying to match: %x", aw_addr); + for (int j = (NoAddrRules - 1); j >= 0; j--) begin + $display("With slave %3d : [%x, %x)", AddrMap[j].idx, AddrMap[j].start_addr, AddrMap[j].end_addr); + if ((aw_addr >= AddrMap[j].start_addr) && + (aw_addr < AddrMap[j].end_addr)) begin + decerr = 0; + to_slave_idx.push_back(AddrMap[j].idx); + addr_to_slave.push_back(aw_addr); + mask_to_slave.push_back('0); + $display(" Push address : %x", aw_addr); + end end + end num_slaves_matched = to_slave_idx.size(); - decerr = num_slaves_matched == 0; // send the exp aw beats down into the queues of the selected slaves // when no decerror @@ -321,6 +334,7 @@ package tb_axi_mcast_xbar_pkg; incr_conducted_tests(4); // push the required w beats into the right fifo + $display(" Expect %0d W beats.", slaves_axi[i].aw_len + 1); incr_expected_tests(slaves_axi[i].aw_len + 1); for (int unsigned j = 0; j <= slaves_axi[i].aw_len; j++) begin exp_slv_w = (j == slaves_axi[i].aw_len) ? @@ -427,7 +441,7 @@ package tb_axi_mcast_xbar_pkg; incr_expected_tests(1); end // push the required r beats into the right fifo - $display(" Expect R response, len: %0d.", masters_axi[i].ar_len); + $display(" Expect R response, len: %0d.", mst_axi_len); for (int unsigned j = 0; j <= mst_axi_len; j++) begin exp_mst_r = (j == mst_axi_len) ? '{mst_axi_id: mst_axi_id, last: 1'b1} : '{mst_axi_id: mst_axi_id, last: 1'b0}; @@ -588,6 +602,9 @@ package tb_axi_mcast_xbar_pkg; if (tests_conducted < tests_expected) begin $error("Some of the expected tests were not conducted!"); end + if (tests_conducted > tests_expected) begin + $error("Conducted more than the expected tests!"); + end endtask : print_result endclass : axi_mcast_xbar_monitor endpackage From d5ef25aa27e21bbb7087b8d76775d51b5cd5a1c3 Mon Sep 17 00:00:00 2001 From: Luca Colagrande Date: Fri, 19 Sep 2025 10:22:47 +0200 Subject: [PATCH 23/41] Rebase onto latest master --- Bender.yml | 13 +- src/axi_mcast_demux.sv | 1219 +++++---------------------------- src/axi_mcast_demux_simple.sv | 981 ++++++++++++++++++++++++++ src/axi_mcast_mux.sv | 7 +- src/axi_mcast_xbar.sv | 257 ++----- src/axi_mcast_xbar_unmuxed.sv | 370 ++++++++++ src/axi_pkg.sv | 2 + src/axi_test.sv | 6 +- test/tb_axi_mcast_xbar.sv | 28 +- test/tb_axi_mcast_xbar_pkg.sv | 11 +- 10 files changed, 1600 insertions(+), 1294 deletions(-) create mode 100644 src/axi_mcast_demux_simple.sv create mode 100644 src/axi_mcast_xbar_unmuxed.sv diff --git a/Bender.yml b/Bender.yml index 9d975f0ab..c769ced92 100644 --- a/Bender.yml +++ b/Bender.yml @@ -69,9 +69,10 @@ sources: - src/axi_lite_regs.sv - src/axi_lite_to_apb.sv - src/axi_lite_to_axi.sv + - src/axi_mcast_demux_simple.sv + - src/axi_mcast_mux.sv - src/axi_modify_address.sv - src/axi_mux.sv - - src/axi_mcast_mux.sv - src/axi_rw_join.sv - src/axi_rw_split.sv - src/axi_serializer.sv @@ -82,11 +83,11 @@ sources: - src/axi_burst_splitter.sv - src/axi_cdc.sv - src/axi_demux.sv - - src/axi_mcast_demux.sv - src/axi_err_slv.sv - src/axi_dw_converter.sv - src/axi_from_mem.sv - src/axi_id_serialize.sv + - src/axi_mcast_demux.sv - src/axi_lfsr.sv - src/axi_multicut.sv - src/axi_to_axi_lite.sv @@ -96,13 +97,13 @@ sources: - src/axi_interleaved_xbar.sv - src/axi_iw_converter.sv - src/axi_lite_xbar.sv + - src/axi_mcast_xbar_unmuxed.sv - src/axi_xbar_unmuxed.sv - - src/axi_xbar.sv - - src/axi_mcast_xbar.sv - src/axi_to_mem_banked.sv - src/axi_to_mem_interleaved.sv - src/axi_to_mem_split.sv # Level 5 + - src/axi_mcast_xbar.sv - src/axi_xbar.sv # Level 6 - src/axi_xp.sv @@ -126,8 +127,8 @@ sources: files: # Level 0 - test/tb_axi_dw_pkg.sv - - test/tb_axi_xbar_pkg.sv - test/tb_axi_mcast_xbar_pkg.sv + - test/tb_axi_xbar_pkg.sv # Level 1 - test/tb_axi_addr_test.sv - test/tb_axi_atop_filter.sv @@ -145,6 +146,7 @@ sources: - test/tb_axi_lite_to_apb.sv - test/tb_axi_lite_to_axi.sv - test/tb_axi_lite_xbar.sv + - test/tb_axi_mcast_xbar.sv - test/tb_axi_modify_address.sv - test/tb_axi_serializer.sv - test/tb_axi_sim_mem.sv @@ -152,4 +154,3 @@ sources: - test/tb_axi_to_axi_lite.sv - test/tb_axi_to_mem_banked.sv - test/tb_axi_xbar.sv - - test/tb_axi_mcast_xbar.sv diff --git a/src/axi_mcast_demux.sv b/src/axi_mcast_demux.sv index 6e3561acc..9b570a55c 100644 --- a/src/axi_mcast_demux.sv +++ b/src/axi_mcast_demux.sv @@ -1,4 +1,4 @@ -// Copyright (c) 2022 ETH Zurich and University of Bologna. +// Copyright (c) 2019 ETH Zurich and University of Bologna. // Copyright and related rights are licensed under the Solderpad Hardware // License, Version 0.51 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at @@ -9,9 +9,11 @@ // specific language governing permissions and limitations under the License. // // Authors: +// - Michael Rogenmoser +// - Wolfgang Roenninger +// - Thomas Benz +// - Andreas Kurth // - Luca Colagrande -// Based on: -// - axi_demux.sv `include "common_cells/assertions.svh" `include "common_cells/registers.svh" @@ -50,10 +52,6 @@ module axi_mcast_demux #( parameter type axi_req_t = logic, parameter type axi_resp_t = logic, parameter int unsigned NoMstPorts = 32'd0, - /// Connectivity vector - parameter bit [NoMstPorts-1:0] Connectivity = '1, - /// Collective Operation Connectivity (to mask certain outputs for coll operations) - parameter bit [NoMstPorts-1:0] CollectiveOpsConnectivity = '1, parameter int unsigned MaxTrans = 32'd8, parameter int unsigned AxiLookBits = 32'd3, parameter bit UniqueIds = 1'b0, @@ -62,6 +60,10 @@ module axi_mcast_demux #( parameter bit SpillB = 1'b0, parameter bit SpillAr = 1'b1, parameter bit SpillR = 1'b0, + /// Connectivity vector + parameter bit [NoMstPorts-1:0] Connectivity = '1, + /// Collective operation connectivity + parameter bit [NoMstPorts-1:0] MulticastConnectivity = '1, parameter type rule_t = logic, parameter int unsigned NoAddrRules = 32'd0, parameter int unsigned NoMulticastRules = 32'd0, @@ -69,12 +71,12 @@ module axi_mcast_demux #( parameter int unsigned MaxMcastTrans = 32'd7, // Dependent parameters, DO NOT OVERRIDE! parameter int unsigned IdxSelectWidth = (NoMstPorts > 32'd1) ? $clog2(NoMstPorts) : 32'd1, - parameter type idx_select_t = logic [IdxSelectWidth-1:0], - parameter type mask_select_t = logic [NoMstPorts-1:0] + parameter type idx_select_t = logic [IdxSelectWidth-1:0] ) ( - input logic clk_i, + input logic clk_i, input logic rst_ni, input logic test_i, + // Addressing rules input rule_t [NoAddrRules-1:0] addr_map_i, input logic en_default_mst_port_i, input rule_t default_mst_port_i, @@ -89,1042 +91,131 @@ module axi_mcast_demux #( output logic [NoMstPorts-1:0] mst_aw_commit_o ); - localparam int unsigned IdCounterWidth = cf_math_pkg::idx_width(MaxTrans); - typedef logic [IdCounterWidth-1:0] id_cnt_t; - - localparam int unsigned McastCounterWidth = (MaxMcastTrans > 32'd1) ? $clog2(MaxMcastTrans+1) : 32'd1; - typedef logic [McastCounterWidth-1:0] mcast_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 - spill_register #( - .T ( aw_chan_t ), - .Bypass ( ~SpillAw ) - ) i_aw_spill_reg ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .valid_i ( slv_req_i.aw_valid ), - .ready_o ( slv_resp_o.aw_ready ), - .data_i ( slv_req_i.aw ), - .valid_o ( mst_reqs_o[0].aw_valid ), - .ready_i ( mst_resps_i[0].aw_ready ), - .data_o ( mst_reqs_o[0].aw ) - ); - spill_register #( - .T ( w_chan_t ), - .Bypass ( ~SpillW ) - ) i_w_spill_reg ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .valid_i ( slv_req_i.w_valid ), - .ready_o ( slv_resp_o.w_ready ), - .data_i ( slv_req_i.w ), - .valid_o ( mst_reqs_o[0].w_valid ), - .ready_i ( mst_resps_i[0].w_ready ), - .data_o ( mst_reqs_o[0].w ) - ); - spill_register #( - .T ( b_chan_t ), - .Bypass ( ~SpillB ) - ) i_b_spill_reg ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .valid_i ( mst_resps_i[0].b_valid ), - .ready_o ( mst_reqs_o[0].b_ready ), - .data_i ( mst_resps_i[0].b ), - .valid_o ( slv_resp_o.b_valid ), - .ready_i ( slv_req_i.b_ready ), - .data_o ( slv_resp_o.b ) - ); - spill_register #( - .T ( ar_chan_t ), - .Bypass ( ~SpillAr ) - ) i_ar_spill_reg ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .valid_i ( slv_req_i.ar_valid ), - .ready_o ( slv_resp_o.ar_ready ), - .data_i ( slv_req_i.ar ), - .valid_o ( mst_reqs_o[0].ar_valid ), - .ready_i ( mst_resps_i[0].ar_ready ), - .data_o ( mst_reqs_o[0].ar ) - ); - spill_register #( - .T ( r_chan_t ), - .Bypass ( ~SpillR ) - ) i_r_spill_reg ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .valid_i ( mst_resps_i[0].r_valid ), - .ready_o ( mst_reqs_o[0].r_ready ), - .data_i ( mst_resps_i[0].r ), - .valid_o ( slv_resp_o.r_valid ), - .ready_i ( slv_req_i.r_ready ), - .data_o ( slv_resp_o.r ) - ); - - // other non degenerate cases - end else begin : gen_demux - - //-------------------------------------- - //-------------------------------------- - // Signal Declarations - //-------------------------------------- - //-------------------------------------- - - //-------------------------------------- - // Write Transaction - //-------------------------------------- - // comes from spill register at input - aw_chan_t slv_aw_chan; - logic slv_aw_valid; - logic slv_aw_ready; - - // AW address decoder - mask_rule_t [NoMulticastRules-1:0] multicast_rules; - mask_rule_t default_rule; - - idx_select_t dec_aw_unicast_selected_idx; - logic [NoMstPorts-1:0] dec_aw_unicast_selected_out; - logic dec_aw_unicast_valid; - logic dec_aw_unicast_error; - - logic [NoMulticastPorts-1:0] dec_aw_multicast_selected_out; - aw_addr_t [NoMulticastPorts-1:0] dec_aw_multicast_addr; - aw_addr_t [NoMulticastPorts-1:0] dec_aw_multicast_mask; - logic dec_aw_multicast_valid; - logic dec_aw_multicast_error; - - aw_addr_t [NoMstPorts-1:0] slv_aw_addr; - aw_addr_t [NoMstPorts-1:0] slv_aw_mask; - mask_select_t slv_aw_select_mask; - idx_select_t slv_aw_select; - - // AW channel to slave ports - logic [NoMstPorts-1:0] mst_aw_valids, mst_aw_readies; - - // AW ID counter - idx_select_t lookup_aw_select; - logic aw_select_occupied, aw_id_cnt_full; - logic aw_any_outstanding_unicast_trx; - // Upon an ATOP load, inject IDs from the AW into the AR channel - logic atop_inject; - // Multicast logic - logic aw_is_multicast; - logic outstanding_multicast; - logic multicast_stall; - mask_select_t multicast_select_q, multicast_select_d; - mcast_cnt_t outstanding_mcast_cnt_q, outstanding_mcast_cnt_d; - logic [$clog2(NoMstPorts)+1-1:0] aw_select_popcount; - logic accept_aw; - logic mcast_aw_hs_in_progress; - - // W select counter: stores the decision to which masters W beats should go - mask_select_t w_select, w_select_q; - logic w_select_valid; - id_cnt_t w_open; - logic w_cnt_up, w_cnt_down; - - // Register which locks the AW valid signal - logic lock_aw_valid_d, lock_aw_valid_q, load_aw_lock; - logic aw_valid, aw_ready; - - // W channel from spill reg - w_chan_t slv_w_chan; - logic slv_w_valid, slv_w_ready; - - // W channel to slave ports - logic [NoMstPorts-1:0] mst_w_valids, mst_w_readies; - - // B channels input into the arbitration (unicast transactions) - // or join module (multicast transactions) - b_chan_t [NoMstPorts-1:0] mst_b_chans; - axi_pkg::resp_t [NoMstPorts-1:0] mst_b_resps; - idx_select_t mst_b_valids_tzc; - logic [NoMstPorts-1:0] mst_b_valids, mst_b_readies; - logic [NoMstPorts-1:0] mst_b_readies_arb, mst_b_readies_join; - - // B channel to spill register - b_chan_t slv_b_chan; - logic slv_b_valid, slv_b_ready; - b_chan_t slv_b_chan_arb, slv_b_chan_join; - logic slv_b_valid_arb, slv_b_valid_join; - - //-------------------------------------- - // Read Transaction - //-------------------------------------- - // comes from spill register at input - logic slv_ar_valid, ar_valid_chan, ar_valid_sel; - logic slv_ar_ready, slv_ar_ready_chan, slv_ar_ready_sel; - - // AR ID counter - idx_select_t lookup_ar_select; - logic ar_select_occupied, ar_id_cnt_full; - logic ar_push; - - // Register which locks the AR valid signel - logic lock_ar_valid_d, lock_ar_valid_q, load_ar_lock; - logic ar_valid, ar_ready; - - // R channles input into the arbitration - r_chan_t [NoMstPorts-1:0] mst_r_chans; - logic [NoMstPorts-1:0] mst_r_valids, mst_r_readies; - - // R channel to spill register - r_chan_t slv_r_chan; - logic slv_r_valid, slv_r_ready; - - //-------------------------------------- - //-------------------------------------- - // Channel Control - //-------------------------------------- - //-------------------------------------- - - //-------------------------------------- - // AW Channel - //-------------------------------------- - // spill register at the channel input - spill_register #( - .T ( aw_chan_t ), - .Bypass ( ~SpillAw ) // because module param indicates if we want a spill reg - ) i_aw_channel_spill_reg ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .valid_i ( slv_req_i.aw_valid ), - .ready_o ( slv_resp_o.aw_ready ), - .data_i ( slv_req_i.aw ), - .valid_o ( slv_aw_valid ), - .ready_i ( slv_aw_ready ), - .data_o ( slv_aw_chan ) - ); - - // 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 - assign default_rule.idx = default_mst_port_i.idx; - assign default_rule.mask = default_mst_port_i.end_addr - default_mst_port_i.start_addr - 1; - assign default_rule.addr = default_mst_port_i.start_addr; - - // Address decoding for unicast requests - addr_decode #( - .NoIndices (NoMstPorts), - .NoRules (NoAddrRules), - .addr_t (aw_addr_t), - .rule_t (rule_t) - ) i_axi_aw_idx_unicast_decode ( - .addr_i (slv_aw_chan.addr), - .addr_map_i (addr_map_i), - .idx_o (dec_aw_unicast_selected_idx), - .dec_valid_o (dec_aw_unicast_valid), - .dec_error_o (dec_aw_unicast_error), - .en_default_idx_i (en_default_mst_port_i), - .default_idx_i (idx_select_t'(default_mst_port_i.idx)) - ); - - // Generate the output mask from the index - assign dec_aw_unicast_selected_out = (1'b1 << dec_aw_unicast_selected_idx); - - // Address decoding for multicast requests - if (NoMulticastRules > 0) begin : gen_multicast_decoding - multiaddr_decode #( - .NoIndices (NoMulticastPorts), - .NoRules (NoMulticastRules), - .addr_t (aw_addr_t), - .rule_t (mask_rule_t) - ) i_axi_aw_multicast_decode ( - .addr_map_i (multicast_rules), - .addr_i (slv_aw_chan.addr), - .mask_i (slv_aw_chan.user.collective_mask), - .select_o (dec_aw_multicast_selected_out), - .addr_o (dec_aw_multicast_addr), - .mask_o (dec_aw_multicast_mask), - .dec_valid_o (dec_aw_multicast_valid), - .dec_error_o (dec_aw_multicast_error), - .en_default_idx_i (en_default_mst_port_i), - .default_idx_i (default_rule) - ); - end else begin : gen_no_multicast_decoding - assign dec_aw_multicast_selected_out = '0; - assign dec_aw_multicast_addr = '0; - assign dec_aw_multicast_mask = '0; - assign dec_aw_multicast_valid = '0; - assign dec_aw_multicast_error = '0; - end - - // If the address decoding doesn't produce any match, the request - // is routed to the error slave, which lies at the highest index. - mask_select_t select_error_slave; - assign select_error_slave = 1'b1 << (NoMstPorts - 1); - - // Mux the multicast and unicast decoding outputs - always_comb begin - slv_aw_select_mask = '0; - slv_aw_addr = '0; - slv_aw_mask = '0; - - if (slv_aw_chan.user.collective_mask == '0) begin - slv_aw_addr = {NoMstPorts{slv_aw_chan.addr}}; - if (dec_aw_unicast_error) begin - slv_aw_select_mask = select_error_slave; - end else begin - slv_aw_select_mask = dec_aw_unicast_selected_out & Connectivity; - end - end else begin - slv_aw_addr = {'0, {(NoMstPorts-NoMulticastPorts){slv_aw_chan.addr}}, dec_aw_multicast_addr}; - slv_aw_mask = {'0, dec_aw_multicast_mask}; - if (dec_aw_multicast_error) begin - slv_aw_select_mask = select_error_slave; - end else begin - slv_aw_select_mask = {'0, dec_aw_multicast_selected_out} & CollectiveOpsConnectivity; - end - end - end - - // Control of the AW handshake - always_comb begin - // AXI Handshakes - slv_aw_ready = 1'b0; - aw_valid = 1'b0; - // `lock_aw_valid`, used to be protocol conform as it is not allowed to deassert - // a valid if there was no corresponding ready. As this process has to be able to inject - // an AXI ID into the counter of the AR channel on an ATOP, there could be a case where - // this process waits on `aw_ready` but in the mean time on the AR channel the counter gets - // full. - lock_aw_valid_d = lock_aw_valid_q; - load_aw_lock = 1'b0; - // AW ID counter and W FIFO - w_cnt_up = 1'b0; - // ATOP injection into ar counter - atop_inject = 1'b0; - // we had an arbitration decision, the valid is locked, wait for the transaction - if (lock_aw_valid_q) begin - aw_valid = 1'b1; - // transaction - if (aw_ready) begin - slv_aw_ready = 1'b1; - lock_aw_valid_d = 1'b0; - load_aw_lock = 1'b1; - // inject the ATOP if necessary - atop_inject = slv_aw_chan.atop[axi_pkg::ATOP_R_RESP] & AtopSupport; - end - end else begin - // An AW can be handled if `i_aw_id_counter` and `i_counter_open_w` are not full. An ATOP that - // requires an R response can be handled if additionally `i_ar_id_counter` is not full (this - // only applies if ATOPs are supported at all). - if (!aw_id_cnt_full && (w_open != {IdCounterWidth{1'b1}}) && - (!(ar_id_cnt_full && slv_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. - // Also stall if previous transmitted AWs still have active W's in flight. - // This prevents deadlocking of the W channel. The counters are there for the - // Handling of the B responses. - if (slv_aw_valid && - ((w_open == '0) || (w_select == slv_aw_select_mask)) && - (!aw_select_occupied || (slv_aw_select == lookup_aw_select)) && - !multicast_stall) begin - // connect the handshake - aw_valid = 1'b1; - // push arbitration to the W FIFO regardless, do not wait for the AW transaction - w_cnt_up = 1'b1; - // on AW transaction - if (aw_ready) begin - slv_aw_ready = 1'b1; - atop_inject = slv_aw_chan.atop[axi_pkg::ATOP_R_RESP] & AtopSupport; - // no AW transaction this cycle, lock the decision - end else begin - lock_aw_valid_d = 1'b1; - load_aw_lock = 1'b1; - end - end - end - end - end - - // lock the valid signal, as the selection gets pushed into the W FIFO on first assertion, - // prevent further pushing - `FFLARN(lock_aw_valid_q, lock_aw_valid_d, load_aw_lock, '0, clk_i, rst_ni) - - /// Multicast logic - - // Convert AW select mask to select index since the indices - // are smaller than the masks and thus cheaper to store in - // the ID counters. We anyways don't use the ID counters on - // multicast transactions... - - onehot_to_bin #( - .ONEHOT_WIDTH(NoMstPorts) - ) i_onehot_to_bin ( - .onehot(slv_aw_select_mask & {NoMstPorts{!aw_is_multicast}}), - .bin (slv_aw_select) - ); - - // Popcount to identify multicast requests - popcount #(NoMstPorts) i_aw_select_popcount ( - .data_i (slv_aw_select_mask), - .popcount_o(aw_select_popcount) - ); - - // While there can be multiple outstanding write transactions, i.e. - // multiple AWs can be accepted before the corresponding Bs are returned, - // in the case of multicast transactions this would require the need - // for additional (possibly expensive) hardware. - // The reason is that multicast transactions require merging multiple B - // responses arriving on different master ports. To know which master ports - // need to be merged we need to register the select signal of the - // write transaction. And if we allow multiple outstanding transactions - // we need to register the select signal of each, and we need a big - // associative (by ID) table for this. And actually this still allows - // deadlocks to occur, e.g. if two multicast transactions A and B are partially - // reordered, i.e. some masters respond to A first and some to B. - // If we restrict the outstanding transactions to a single ID then ordering is - // guaranteed, but we anyways need a FIFO to store the selects. - // So for the moment we disallow multiple outstanding transactions in presence - // of a multicast. This means stall an AW request if: - // - there is an outstanding multicast transaction or - // - if the request is a multicast, until there are no more outstanding transactions - // We can slightly loosen this constraint, in the case of successive multicast - // requests going to the same slaves. In this case, we don't need to buffer any - // additional select signals. - assign aw_is_multicast = aw_select_popcount > 1; - assign outstanding_multicast = outstanding_mcast_cnt_q != '0; - assign multicast_stall = (outstanding_multicast && (slv_aw_select_mask != multicast_select_q)) || - (aw_is_multicast && aw_any_outstanding_unicast_trx) || - (outstanding_mcast_cnt_q == MaxMcastTrans); - // We can send this signal to all slaves since we will only have one outstanding aw - assign mst_is_mcast_o = {NoMstPorts{aw_is_multicast}}; - - // Keep track of which B responses need to be returned to complete the multicast - `FFARN(multicast_select_q, multicast_select_d, '0, clk_i, rst_ni) - `FFARN(outstanding_mcast_cnt_q, outstanding_mcast_cnt_d, '0, clk_i, rst_ni) - - // Logic to update number of outstanding multicast transactions and current multicast - // transactions' select mask. Counter is incremented upon the AW handshake of a multicast - // transaction and decremented upon the "joined" B handshake. - always_comb begin - multicast_select_d = multicast_select_q; - outstanding_mcast_cnt_d = outstanding_mcast_cnt_q; - - // Written as separate if statements as they may both be valid at the same time - // For the same reason the right hand side uses outstanding_mcast_cnt_d - // instead of outstanding_mcast_cnt_q - if (aw_is_multicast && aw_valid && aw_ready) begin - outstanding_mcast_cnt_d = outstanding_mcast_cnt_d + (|slv_aw_select_mask); - multicast_select_d = slv_aw_select_mask; - end - if (outstanding_multicast && slv_b_valid && slv_b_ready) begin - outstanding_mcast_cnt_d = outstanding_mcast_cnt_d - 1; - end - end - - // Multicast AW transaction handshake state - typedef enum logic {MCastAwHandshakeIdle, MCastAwHandshakeInProgress} mcast_aw_hs_state_e; - mcast_aw_hs_state_e mcast_aw_hs_state_q, mcast_aw_hs_state_d; - - // Update of the multicast AW handshake state - always_comb begin - mcast_aw_hs_state_d = mcast_aw_hs_state_q; - unique case (mcast_aw_hs_state_q) - // Waiting for all selected master ports to be ready - MCastAwHandshakeIdle: - if (accept_aw && aw_is_multicast) begin - mcast_aw_hs_state_d = MCastAwHandshakeInProgress; - end - // Commit is asserted and handshake takes place in the current cycle. - // In the next cycle we are again idle - MCastAwHandshakeInProgress: - mcast_aw_hs_state_d = MCastAwHandshakeIdle; - default: ; - endcase - end - - assign mcast_aw_hs_in_progress = mcast_aw_hs_state_q == MCastAwHandshakeInProgress; - - `FFARN(mcast_aw_hs_state_q, mcast_aw_hs_state_d, MCastAwHandshakeIdle, clk_i, rst_ni) - - // When a multicast occurs, the upstream valid signals need to - // be forwarded to multiple master ports. - // Proper stream forking is necessary to avoid protocol violations. - // We must also require that downstream handshakes occur - // simultaneously on all addressed master ports, otherwise deadlocks - // may occur. To achieve this we modify the ready-valid protocol by adding - // a third signal, called commit, which is asserted only when we have all - // downstream handshakes. This signal notifies the slaves that the - // handshake can now actually take place. - // Using commit, instead of valid, to this end ensures that we don't have - // any combinational loops. - assign mst_aw_valids = {NoMstPorts{aw_valid}} & slv_aw_select_mask; - assign accept_aw = &((mst_aw_valids & mst_aw_readies) | ~slv_aw_select_mask); - assign aw_ready = aw_is_multicast ? mcast_aw_hs_in_progress : accept_aw; - assign mst_aw_commit_o = {NoMstPorts{mcast_aw_hs_in_progress}} & slv_aw_select_mask; - - if (UniqueIds) begin : gen_unique_ids_aw - // If the `UniqueIds` parameter is set, each write transaction has an ID that is unique among - // all in-flight write transactions, or all write transactions with a given ID target the same - // master port as all write transactions with the same ID, or both. This means that the - // signals that are driven by the ID counters if this parameter is not set can instead be - // derived from existing signals. The ID counters can therefore be omitted. - assign lookup_aw_select = slv_aw_select; - assign aw_select_occupied = 1'b0; - - // We still need a (single) counter to keep track of any outstanding transactions - axi_mcast_demux_id_counters #( - .AxiIdBits ( 0 ), - .CounterWidth ( IdCounterWidth ), - .mst_port_select_t ( idx_select_t ) - ) i_aw_id_counter ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .lookup_axi_id_i ( '0 ), - .lookup_mst_select_o ( /* Not used */ ), - .lookup_mst_select_occupied_o ( /* Not used */ ), - .full_o ( aw_id_cnt_full ), - .inject_axi_id_i ( '0 ), - .inject_i ( 1'b0 ), - .push_axi_id_i ( '0 ), - .push_mst_select_i ( '0 ), - .push_i ( w_cnt_up && !aw_is_multicast ), - .pop_axi_id_i ( '0 ), - .pop_i ( slv_b_valid & slv_b_ready & ~outstanding_multicast ), - .any_outstanding_trx_o ( aw_any_outstanding_unicast_trx ) - ); - - end else begin : gen_aw_id_counter - - axi_mcast_demux_id_counters #( - .AxiIdBits ( AxiLookBits ), - .CounterWidth ( IdCounterWidth ), - .mst_port_select_t ( idx_select_t ) - ) i_aw_id_counter ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .lookup_axi_id_i ( slv_aw_chan.id[0+:AxiLookBits] ), - .lookup_mst_select_o ( lookup_aw_select ), - .lookup_mst_select_occupied_o ( aw_select_occupied ), - .full_o ( aw_id_cnt_full ), - .inject_axi_id_i ( '0 ), - .inject_i ( 1'b0 ), - .push_axi_id_i ( slv_aw_chan.id[0+:AxiLookBits] ), - .push_mst_select_i ( slv_aw_select ), - .push_i ( w_cnt_up && !aw_is_multicast ), - .pop_axi_id_i ( slv_b_chan.id[0+:AxiLookBits] ), - .pop_i ( slv_b_valid & slv_b_ready & ~outstanding_multicast ), - .any_outstanding_trx_o ( aw_any_outstanding_unicast_trx ) - ); - // pop from ID counter on outward transaction - end - - // This counter steers the demultiplexer of the W channel. - // `w_select` determines, which handshaking is connected. - // AWs are only forwarded, if the counter is empty, or `w_select_q` is the same as - // `slv_aw_select`. - counter #( - .WIDTH ( IdCounterWidth ), - .STICKY_OVERFLOW ( 1'b0 ) - ) i_counter_open_w ( - .clk_i, - .rst_ni, - .clear_i ( 1'b0 ), - .en_i ( w_cnt_up ^ w_cnt_down ), - .load_i ( 1'b0 ), - .down_i ( w_cnt_down ), - .d_i ( '0 ), - .q_o ( w_open ), - .overflow_o ( /*not used*/ ) - ); - - `FFLARN(w_select_q, slv_aw_select_mask, w_cnt_up, mask_select_t'(0), clk_i, rst_ni) - assign w_select = (|w_open) ? w_select_q : slv_aw_select_mask; - assign w_select_valid = w_cnt_up | (|w_open); - assign w_cnt_down = slv_w_valid & slv_w_ready & slv_w_chan.last; - - //-------------------------------------- - // W Channel - //-------------------------------------- - spill_register #( - .T ( w_chan_t ), - .Bypass ( ~SpillW ) - ) i_w_spill_reg( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .valid_i ( slv_req_i.w_valid ), - .ready_o ( slv_resp_o.w_ready ), - .data_i ( slv_req_i.w ), - .valid_o ( slv_w_valid ), - .ready_i ( slv_w_ready ), - .data_o ( slv_w_chan ) - ); - - // When a multicast occurs, the upstream valid signals need to - // be forwarded to multiple master ports. - // Proper stream forking is necessary to avoid protocol violations - stream_fork_dynamic #( - .N_OUP(NoMstPorts) - ) i_w_stream_fork_dynamic ( - .clk_i (clk_i), - .rst_ni (rst_ni), - .valid_i (slv_w_valid), - .ready_o (slv_w_ready), - .sel_i (w_select), - .sel_valid_i(w_select_valid), - .sel_ready_o(), - .valid_o (mst_w_valids), - .ready_i (mst_w_readies) - ); - - //-------------------------------------- - // B Channel - //-------------------------------------- - // optional spill register - spill_register #( - .T ( b_chan_t ), - .Bypass ( ~SpillB ) - ) i_b_spill_reg ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .valid_i ( slv_b_valid ), - .ready_o ( slv_b_ready ), - .data_i ( slv_b_chan ), - .valid_o ( slv_resp_o.b_valid ), - .ready_i ( slv_req_i.b_ready ), - .data_o ( slv_resp_o.b ) - ); - - // Arbitration of the different B responses - rr_arb_tree #( - .NumIn ( NoMstPorts ), - .DataType ( b_chan_t ), - .AxiVldRdy( 1'b1 ), - .LockIn ( 1'b1 ) - ) i_b_mux ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .flush_i( 1'b0 ), - .rr_i ( '0 ), - .req_i ( mst_b_valids & {NoMstPorts{!outstanding_multicast}} ), - .gnt_o ( mst_b_readies_arb ), - .data_i ( mst_b_chans ), - .gnt_i ( slv_b_ready ), - .req_o ( slv_b_valid_arb ), - .data_o ( slv_b_chan_arb ), - .idx_o ( ) - ); - - // Streams must be joined instead of arbitrated when multicast - stream_join_dynamic #(NoMstPorts) i_b_stream_join ( - .inp_valid_i(mst_b_valids & {NoMstPorts{outstanding_multicast}}), - .inp_ready_o(mst_b_readies_join), - .sel_i (multicast_select_q), - .oup_valid_o(slv_b_valid_join), - .oup_ready_i(slv_b_ready) - ); - for (genvar i=0; i 0) else - $fatal(1, "The Number of slaves (NoMstPorts) has to be at least 1"); - AXI_ID_BITS: assume (AxiIdWidth >= AxiLookBits) else - $fatal(1, "AxiIdBits has to be equal or smaller than AxiIdWidth."); - aw_addr_bits: assume ($bits(slv_aw_addr[0]) == $bits(slv_req_i.aw.addr)) else - $fatal(1, "aw_addr_t must be the type of slv_req_i.aw.addr"); - end - default disable iff (!rst_ni); - ar_select: assume property( @(posedge clk_i) (slv_req_i.ar_valid |-> - (slv_ar_select_i < NoMstPorts))) else - $fatal(1, "slv_ar_select_i is %d: AR has selected a slave that is not defined.\ - NoMstPorts: %d", slv_ar_select_i, NoMstPorts); - aw_valid_stable: assert property( @(posedge clk_i) (aw_valid && !aw_ready) |=> aw_valid) else - $fatal(1, "aw_valid was deasserted, when aw_ready = 0 in last cycle."); - ar_valid_stable: assert property( @(posedge clk_i) - (ar_valid && !ar_ready) |=> ar_valid) else - $fatal(1, "ar_valid was deasserted, when ar_ready = 0 in last cycle."); - slv_aw_chan_stable: assert property( @(posedge clk_i) (aw_valid && !aw_ready) - |=> $stable(slv_aw_chan)) else - $fatal(1, "slv_aw_chan unstable with valid set."); - slv_aw_select_stable: assert property( @(posedge clk_i) (aw_valid && !aw_ready) - |=> $stable(slv_aw_select)) else - $fatal(1, "slv_aw_select unstable with valid set."); - slv_ar_chan_stable: assert property( @(posedge clk_i) (ar_valid && !ar_ready) - |=> $stable(slv_ar_chan)) else - $fatal(1, "slv_ar_chan unstable with valid set."); - slv_ar_select_stable: assert property( @(posedge clk_i) (ar_valid && !ar_ready) - |=> $stable(slv_ar_select)) else - $fatal(1, "slv_ar_select unstable with valid set."); - internal_ar_select: assert property( @(posedge clk_i) - (ar_valid |-> slv_ar_select < NoMstPorts)) - else $fatal(1, "slv_ar_select illegal while ar_valid."); - w_underflow: assert property( @(posedge clk_i) - ((w_open == '0) && (w_cnt_up ^ w_cnt_down) |-> !w_cnt_down)) else - $fatal(1, "W counter underflowed!"); - `ASSUME(NoAtopAllowed, !AtopSupport && slv_req_i.aw_valid |-> slv_req_i.aw.atop == '0) -`endif -`endif -// pragma translate_on - end -endmodule - -module axi_mcast_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, - // outstanding transactions - output logic any_outstanding_trx_o -); - 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; - //----------------------------------- - // Status - //----------------------------------- - assign any_outstanding_trx_o = |occupied; - - // 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 + axi_req_t slv_req_cut; + axi_resp_t slv_resp_cut; + + logic slv_ar_ready_chan, slv_ar_ready_sel; + logic slv_ar_valid_chan, slv_ar_valid_sel; + + idx_select_t slv_ar_select; + + spill_register #( + .T ( aw_chan_t ), + .Bypass ( ~SpillAw ) + ) i_aw_spill_reg ( + .clk_i, + .rst_ni, + .valid_i ( slv_req_i.aw_valid ), + .ready_o ( slv_resp_o.aw_ready ), + .data_i ( slv_req_i.aw ), + .valid_o ( slv_req_cut.aw_valid ), + .ready_i ( slv_resp_cut.aw_ready ), + .data_o ( slv_req_cut.aw ) + ); + spill_register #( + .T ( w_chan_t ), + .Bypass ( ~SpillW ) + ) i_w_spill_reg ( + .clk_i, + .rst_ni, + .valid_i ( slv_req_i.w_valid ), + .ready_o ( slv_resp_o.w_ready ), + .data_i ( slv_req_i.w ), + .valid_o ( slv_req_cut.w_valid ), + .ready_i ( slv_resp_cut.w_ready ), + .data_o ( slv_req_cut.w ) + ); + spill_register #( + .T ( ar_chan_t ), + .Bypass ( ~SpillAr ) + ) i_ar_spill_reg ( + .clk_i, + .rst_ni, + .valid_i ( slv_req_i.ar_valid ), + .ready_o ( slv_ar_ready_chan ), + .data_i ( slv_req_i.ar ), + .valid_o ( slv_ar_valid_chan ), + .ready_i ( slv_resp_cut.ar_ready ), + .data_o ( slv_req_cut.ar ) + ); + spill_register #( + .T ( idx_select_t ), + .Bypass ( ~SpillAr ) + ) i_ar_sel_spill_reg ( + .clk_i, + .rst_ni, + .valid_i ( slv_req_i.ar_valid ), + .ready_o ( slv_ar_ready_sel ), + .data_i ( slv_ar_select_i ), + .valid_o ( slv_ar_valid_sel ), + .ready_i ( slv_resp_cut.ar_ready ), + .data_o ( slv_ar_select ) + ); - 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); + assign slv_resp_o.ar_ready = slv_ar_ready_chan & slv_ar_ready_sel; + assign slv_req_cut.ar_valid = slv_ar_valid_chan & slv_ar_valid_sel; + + spill_register #( + .T ( b_chan_t ), + .Bypass ( ~SpillB ) + ) i_b_spill_reg ( + .clk_i, + .rst_ni, + .valid_i ( slv_resp_cut.b_valid ), + .ready_o ( slv_req_cut.b_ready ), + .data_i ( slv_resp_cut.b ), + .valid_o ( slv_resp_o.b_valid ), + .ready_i ( slv_req_i.b_ready ), + .data_o ( slv_resp_o.b ) + ); + spill_register #( + .T ( r_chan_t ), + .Bypass ( ~SpillR ) + ) i_r_spill_reg ( + .clk_i, + .rst_ni, + .valid_i ( slv_resp_cut.r_valid ), + .ready_o ( slv_req_cut.r_ready ), + .data_i ( slv_resp_cut.r ), + .valid_o ( slv_resp_o.r_valid ), + .ready_i ( slv_req_i.r_ready ), + .data_o ( slv_resp_o.r ) + ); - // holds the selection signal for this id - `FFLARN(mst_select_q[i], push_mst_select_i, push_en[i], '0, clk_i, rst_ni) + axi_mcast_demux_simple #( + .AxiIdWidth ( AxiIdWidth ), + .AtopSupport( AtopSupport ), + .axi_req_t ( axi_req_t ), + .axi_resp_t ( axi_resp_t ), + .NoMstPorts ( NoMstPorts ), + .MaxTrans ( MaxTrans ), + .AxiLookBits( AxiLookBits ), + .UniqueIds ( UniqueIds ), + .Connectivity ( Connectivity ), + .MulticastConnectivity ( MulticastConnectivity ), + .aw_addr_t ( aw_addr_t ), + .b_chan_t ( b_chan_t ), + .rule_t ( rule_t ), + .NoAddrRules ( NoAddrRules ), + .NoMulticastRules ( NoMulticastRules ), + .NoMulticastPorts ( NoMulticastPorts ), + .MaxMcastTrans ( MaxMcastTrans ) + ) i_demux_simple ( + .clk_i, + .rst_ni, + .test_i, + .addr_map_i, + .en_default_mst_port_i, + .default_mst_port_i, + .slv_req_i ( slv_req_cut ), + .slv_ar_select_i ( slv_ar_select ), + .slv_resp_o ( slv_resp_cut ), + .mst_reqs_o ( mst_reqs_o ), + .mst_resps_i ( mst_resps_i ), + .mst_is_mcast_o, + .mst_aw_commit_o + ); -// 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 @@ -1148,23 +239,23 @@ module axi_mcast_demux_intf #( 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], - parameter type addr_t = logic [AXI_ADDR_WIDTH-1:0] + parameter type idx_select_t = logic [SELECT_WIDTH-1:0] // MST port select type ) ( - input logic clk_i, // Clock - input logic rst_ni, // Asynchronous reset active low - input logic test_i, // Testmode enable + input logic clk_i, // Clock + input logic rst_ni, // Asynchronous reset active low + input logic test_i, // Testmode enable 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 - input logic en_default_mst_port_i, - input rule_t default_mst_port_i, - AXI_BUS.Slave slv, // slave port - AXI_BUS.Master mst [NO_MST_PORTS-1:0], // master ports - output logic [NO_MST_PORTS-1:0] mst_is_mcast_o, - output logic [NO_MST_PORTS-1:0] mst_aw_commit_o + input idx_select_t slv_ar_select_i, // has to be stable, when ar_valid + input logic en_default_mst_port_i, + input rule_t default_mst_port_i, + AXI_BUS.Slave slv, // slave port + AXI_BUS.Master mst [NO_MST_PORTS-1:0], // master ports + output logic [NO_MST_PORTS-1:0] mst_is_mcast_o, + output logic [NO_MST_PORTS-1:0] mst_aw_commit_o ); typedef logic [AXI_ID_WIDTH-1:0] id_t; + typedef logic [AXI_ADDR_WIDTH-1:0] addr_t; typedef logic [AXI_DATA_WIDTH-1:0] data_t; typedef logic [AXI_DATA_WIDTH/8-1:0] strb_t; typedef logic [AXI_USER_WIDTH-1:0] user_t; @@ -1214,17 +305,17 @@ module axi_mcast_demux_intf #( .clk_i, // Clock .rst_ni, // Asynchronous reset active low .test_i, // Testmode enable - .addr_map_i ( addr_map_i ), + .addr_map_i ( addr_map_i ), .en_default_mst_port_i ( en_default_mst_port_i ), - .default_mst_port_i ( default_mst_port_i ), + .default_mst_port_i ( default_mst_port_i ), // slave port - .slv_req_i ( slv_req ), - .slv_ar_select_i ( slv_ar_select_i ), - .slv_resp_o ( slv_resp ), + .slv_req_i ( slv_req ), + .slv_ar_select_i ( slv_ar_select_i ), + .slv_resp_o ( slv_resp ), // master port - .mst_reqs_o ( mst_req ), - .mst_resps_i ( mst_resp ), - .mst_is_mcast_o ( mst_is_mcast_o ), - .mst_aw_commit_o ( mst_aw_commit_o ) + .mst_reqs_o ( mst_req ), + .mst_resps_i ( mst_resp ), + .mst_is_mcast_o ( mst_is_mcast_o ), + .mst_aw_commit_o ( mst_aw_commit_o ) ); endmodule diff --git a/src/axi_mcast_demux_simple.sv b/src/axi_mcast_demux_simple.sv new file mode 100644 index 000000000..f9d84586a --- /dev/null +++ b/src/axi_mcast_demux_simple.sv @@ -0,0 +1,981 @@ +// Copyright (c) 2019 ETH Zurich and University of Bologna. +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. +// +// Authors: +// - Wolfgang Roenninger +// - Michael Rogenmoser +// - Thomas Benz +// - Andreas Kurth +// - Luca Colagrande + +`include "common_cells/assertions.svh" +`include "common_cells/registers.svh" +`include "axi/assign.svh" + +`ifdef QUESTA +// Derive `TARGET_VSIM`, which is used for tool-specific workarounds in this file, from `QUESTA`, +// which is automatically set in Questa. +`define TARGET_VSIM +`endif + +/// Demultiplex one AXI4+ATOP slave port to multiple AXI4+ATOP master ports. +/// +/// The AW and AR slave channels each have a `select` input to determine to which master port the +/// current request is sent. The `select` can, for example, be driven by an address decoding module +/// to map address ranges to different AXI slaves. +/// +/// ## Design overview +/// +/// ![Block diagram](module.axi_demux.png "Block diagram") +/// +/// Beats on the W channel are routed by demultiplexer according to the selection for the +/// corresponding AW beat. This relies on the AXI property that W bursts must be sent in the same +/// order as AW beats and beats from different W bursts may not be interleaved. +/// +/// Beats on the B and R channel are multiplexed from the master ports to the slave port with +/// a round-robin arbitration tree. +module axi_mcast_demux_simple #( + parameter int unsigned AxiIdWidth = 32'd0, + parameter bit AtopSupport = 1'b1, + parameter type axi_req_t = logic, + parameter type axi_resp_t = logic, + parameter int unsigned NoMstPorts = 32'd0, + parameter int unsigned MaxTrans = 32'd8, + parameter int unsigned AxiLookBits = 32'd3, + parameter bit UniqueIds = 1'b0, + parameter bit [NoMstPorts-1:0] Connectivity = '1, + parameter bit [NoMstPorts-1:0] MulticastConnectivity = '1, + parameter type aw_addr_t = logic, + parameter type b_chan_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, + parameter int unsigned MaxMcastTrans = 32'd7, + // Dependent parameters, DO NOT OVERRIDE! + parameter int unsigned IdxSelectWidth = (NoMstPorts > 32'd1) ? $clog2(NoMstPorts) : 32'd1, + 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, + // Addressing rules + input rule_t [NoAddrRules-1:0] addr_map_i, + input logic en_default_mst_port_i, + input rule_t default_mst_port_i, + // Slave Port + input axi_req_t slv_req_i, + input idx_select_t slv_ar_select_i, + output axi_resp_t slv_resp_o, + // Master Ports + output axi_req_t [NoMstPorts-1:0] mst_reqs_o, + input axi_resp_t [NoMstPorts-1:0] mst_resps_i, + output logic [NoMstPorts-1:0] mst_is_mcast_o, + output logic [NoMstPorts-1:0] mst_aw_commit_o +); + + localparam int unsigned IdCounterWidth = cf_math_pkg::idx_width(MaxTrans); + typedef logic [IdCounterWidth-1:0] id_cnt_t; + + localparam int unsigned McastCounterWidth = (MaxMcastTrans > 32'd1) ? $clog2(MaxMcastTrans+1) : 32'd1; + typedef logic [McastCounterWidth-1:0] mcast_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 + `AXI_ASSIGN_REQ_STRUCT(mst_reqs_o[0], slv_req_i) + `AXI_ASSIGN_RESP_STRUCT(slv_resp_o, mst_resps_i[0]) + end else begin : gen_demux + + //-------------------------------------- + //-------------------------------------- + // Signal Declarations + //-------------------------------------- + //-------------------------------------- + + //-------------------------------------- + // Write Transaction + //-------------------------------------- + + // AW decoder inputs + mask_rule_t [NoMulticastRules-1:0] multicast_rules; + mask_rule_t default_rule; + + // AW unicast decoder outputs + idx_select_t dec_aw_unicast_select_idx; + logic [NoMstPorts-1:0] dec_aw_unicast_select_mask; + logic dec_aw_unicast_valid; + logic dec_aw_unicast_error; + + // AW multicast decoder outputs + logic [NoMulticastPorts-1:0] dec_aw_multicast_select_mask; + aw_addr_t [NoMulticastPorts-1:0] dec_aw_multicast_addr; + aw_addr_t [NoMulticastPorts-1:0] dec_aw_multicast_mask; + logic dec_aw_multicast_valid; + logic dec_aw_multicast_error; + + // Merged AW unicast and multicast decoder outputs + aw_addr_t [NoMstPorts-1:0] slv_aw_addr; + aw_addr_t [NoMstPorts-1:0] slv_aw_mask; + mask_select_t slv_aw_select_mask; + idx_select_t slv_aw_select; + + // AW channel to slave ports + logic [NoMstPorts-1:0] mst_aw_valids, mst_aw_readies; + + // Multicast control signals + logic aw_is_multicast; + logic outstanding_multicast; + logic multicast_stall; + mask_select_t multicast_select_q, multicast_select_d; + mcast_cnt_t outstanding_mcast_cnt_q, outstanding_mcast_cnt_d; + logic [$clog2(NoMstPorts)+1-1:0] aw_select_popcount; + logic accept_aw; + logic mcast_aw_hs_in_progress; + + // Register which locks the AW valid signal + logic lock_aw_valid_d, lock_aw_valid_q, load_aw_lock; + logic aw_valid, aw_ready; + + // AW ID counter + idx_select_t lookup_aw_select; + logic aw_select_occupied, aw_id_cnt_full; + logic aw_any_outstanding_unicast_trx; + // Upon an ATOP load, inject IDs from the AW into the AR channel + logic atop_inject; + + // W select counter: stores the decision to which master(s) W beats should go + logic [NoMstPorts-1:0] mst_w_valids, mst_w_readies; + mask_select_t w_select, w_select_q; + logic w_select_valid; + id_cnt_t w_open; + logic w_cnt_up, w_cnt_down; + + // B channels input into the arbitration (unicast transactions) + // or join module (multicast transactions) + axi_pkg::resp_t [NoMstPorts-1:0] mst_b_resps; + idx_select_t mst_b_valids_tzc; + logic [NoMstPorts-1:0] mst_b_valids, mst_b_readies; + logic [NoMstPorts-1:0] mst_b_readies_arb, mst_b_readies_join; + + // B channel to spill register + logic slv_b_valid_arb, slv_b_valid_join; + b_chan_t slv_b_chan_join; + + //-------------------------------------- + // Read Transaction + //-------------------------------------- + + // AR ID counter + idx_select_t lookup_ar_select; + logic ar_select_occupied, ar_id_cnt_full; + logic ar_push; + + // Register which locks the AR valid signel + logic lock_ar_valid_d, lock_ar_valid_q, load_ar_lock; + logic ar_valid, ar_ready; + + logic [NoMstPorts-1:0] mst_r_valids, mst_r_readies; + + + + + + + + //-------------------------------------- + // Channel Control + //-------------------------------------- + //-------------------------------------- + + //-------------------------------------- + // AW Channel + //-------------------------------------- + + // 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 + assign default_rule.idx = default_mst_port_i.idx; + assign default_rule.mask = default_mst_port_i.end_addr - default_mst_port_i.start_addr - 1; + assign default_rule.addr = default_mst_port_i.start_addr; + + // Address decoding for unicast requests + addr_decode #( + .NoIndices (NoMstPorts), + .NoRules (NoAddrRules), + .addr_t (aw_addr_t), + .rule_t (rule_t) + ) i_axi_aw_idx_unicast_decode ( + .addr_i (slv_req_i.aw.addr), + .addr_map_i (addr_map_i), + .idx_o (dec_aw_unicast_select_idx), + .dec_valid_o (dec_aw_unicast_valid), + .dec_error_o (dec_aw_unicast_error), + .en_default_idx_i (en_default_mst_port_i), + .default_idx_i (idx_select_t'(default_mst_port_i.idx)) + ); + + // Generate the output mask from the index + assign dec_aw_unicast_select_mask = (1'b1 << dec_aw_unicast_select_idx); + + // Address decoding for multicast requests + if (NoMulticastRules > 0) begin : gen_multicast_decoding + multiaddr_decode #( + .NoIndices (NoMulticastPorts), + .NoRules (NoMulticastRules), + .addr_t (aw_addr_t), + .rule_t (mask_rule_t) + ) i_axi_aw_multicast_decode ( + .addr_map_i (multicast_rules), + .addr_i (slv_req_i.aw.addr), + .mask_i (slv_req_i.aw.user.collective_mask), + .select_o (dec_aw_multicast_select_mask), + .addr_o (dec_aw_multicast_addr), + .mask_o (dec_aw_multicast_mask), + .dec_valid_o (dec_aw_multicast_valid), + .dec_error_o (dec_aw_multicast_error), + .en_default_idx_i (en_default_mst_port_i), + .default_idx_i (default_rule) + ); + end else begin : gen_no_multicast_decoding + assign dec_aw_multicast_select_mask = '0; + assign dec_aw_multicast_addr = '0; + assign dec_aw_multicast_mask = '0; + assign dec_aw_multicast_valid = '0; + assign dec_aw_multicast_error = '0; + end + + // If the address decoding doesn't produce any match, the request + // is routed to the error slave, which lies at the highest index. + mask_select_t select_error_slave; + assign select_error_slave = 1'b1 << (NoMstPorts - 1); + + // Mux the multicast and unicast decoding outputs + always_comb begin + slv_aw_select_mask = '0; + slv_aw_addr = '0; + slv_aw_mask = '0; + + if (slv_req_i.aw.user.collective_mask == '0) begin + slv_aw_addr = {NoMstPorts{slv_req_i.aw.addr}}; + if (dec_aw_unicast_error) begin + slv_aw_select_mask = select_error_slave; + end else begin + slv_aw_select_mask = dec_aw_unicast_select_mask & Connectivity; + end + end else begin + slv_aw_addr = {'0, {(NoMstPorts-NoMulticastPorts){slv_req_i.aw.addr}}, dec_aw_multicast_addr}; + slv_aw_mask = {'0, dec_aw_multicast_mask}; + if (dec_aw_multicast_error) begin + slv_aw_select_mask = select_error_slave; + end else begin + slv_aw_select_mask = {'0, dec_aw_multicast_select_mask} & MulticastConnectivity; + end + end + end + + // Control of the AW handshake + always_comb begin + // AXI Handshakes + slv_resp_o.aw_ready = 1'b0; + aw_valid = 1'b0; + // `lock_aw_valid`, used to be protocol conform as it is not allowed to deassert + // a valid if there was no corresponding ready. As this process has to be able to inject + // an AXI ID into the counter of the AR channel on an ATOP, there could be a case where + // this process waits on `aw_ready` but in the mean time on the AR channel the counter gets + // full. + lock_aw_valid_d = lock_aw_valid_q; + load_aw_lock = 1'b0; + // AW ID counter and W FIFO + w_cnt_up = 1'b0; + // ATOP injection into ar counter + atop_inject = 1'b0; + // we had an arbitration decision, the valid is locked, wait for the transaction + if (lock_aw_valid_q) begin + aw_valid = 1'b1; + // transaction + if (aw_ready) begin + slv_resp_o.aw_ready = 1'b1; + lock_aw_valid_d = 1'b0; + load_aw_lock = 1'b1; + // inject the ATOP if necessary + atop_inject = slv_req_i.aw.atop[axi_pkg::ATOP_R_RESP] & AtopSupport; + end + end else begin + // An AW can be handled if `i_aw_id_counter` and `i_counter_open_w` are not full. An ATOP that + // requires an R response can be handled if additionally `i_ar_id_counter` is not full (this + // only applies if ATOPs are supported at all). + if (!aw_id_cnt_full && (w_open != {IdCounterWidth{1'b1}}) && + (!(ar_id_cnt_full && slv_req_i.aw.atop[axi_pkg::ATOP_R_RESP]) || + !AtopSupport)) begin + // There is a valid AW vector make the id lookup and go further, if it passes. + // Also stall if previous transmitted AWs still have active W's in flight. + // This prevents deadlocking of the W channel. The counters are there for the + // Handling of the B responses. + if (slv_req_i.aw_valid && + ((w_open == '0) || (w_select == slv_aw_select_mask)) && + (!aw_select_occupied || (slv_aw_select == lookup_aw_select)) && + !multicast_stall) begin + // connect the handshake + aw_valid = 1'b1; + // push arbitration to the W FIFO regardless, do not wait for the AW transaction + w_cnt_up = 1'b1; + // on AW transaction + if (aw_ready) begin + slv_resp_o.aw_ready = 1'b1; + atop_inject = slv_req_i.aw.atop[axi_pkg::ATOP_R_RESP] & AtopSupport; + // no AW transaction this cycle, lock the decision + end else begin + lock_aw_valid_d = 1'b1; + load_aw_lock = 1'b1; + end + end + end + end + end + + // lock the valid signal, as the selection gets pushed into the W FIFO on first assertion, + // prevent further pushing + `FFLARN(lock_aw_valid_q, lock_aw_valid_d, load_aw_lock, '0, clk_i, rst_ni) + + //-------------------------------------- + // Multicast logic + //-------------------------------------- + + // Convert AW select mask to select index since the indices + // are smaller than the masks and thus cheaper to store in + // the ID counters. We anyways don't use the ID counters on + // multicast transactions... + + onehot_to_bin #( + .ONEHOT_WIDTH(NoMstPorts) + ) i_onehot_to_bin ( + .onehot(slv_aw_select_mask & {NoMstPorts{!aw_is_multicast}}), + .bin (slv_aw_select) + ); + + // Popcount to identify multicast requests + popcount #(NoMstPorts) i_aw_select_popcount ( + .data_i (slv_aw_select_mask), + .popcount_o(aw_select_popcount) + ); + + // While there can be multiple outstanding write transactions, i.e. + // multiple AWs can be accepted before the corresponding Bs are returned, + // in the case of multicast transactions this would require the need + // for additional (possibly expensive) hardware. + // The reason is that multicast transactions require merging multiple B + // responses arriving on different master ports. To know which master ports + // need to be merged we need to register the select signal of the + // write transaction. And if we allow multiple outstanding transactions + // we need to register the select signal of each, and we need a big + // associative (by ID) table for this. And actually this still allows + // deadlocks to occur, e.g. if two multicast transactions A and B are partially + // reordered, i.e. some masters respond to A first and some to B. + // If we restrict the outstanding transactions to a single ID then ordering is + // guaranteed, but we anyways need a FIFO to store the selects. + // So for the moment we disallow multiple outstanding transactions in presence + // of a multicast. This means stall an AW request if: + // - there is an outstanding multicast transaction or + // - if the request is a multicast, until there are no more outstanding transactions + // We can slightly loosen this constraint, in the case of successive multicast + // requests going to the same slaves. In this case, we don't need to buffer any + // additional select signals. + assign aw_is_multicast = aw_select_popcount > 1; + assign outstanding_multicast = outstanding_mcast_cnt_q != '0; + assign multicast_stall = (outstanding_multicast && (slv_aw_select_mask != multicast_select_q)) || + (aw_is_multicast && aw_any_outstanding_unicast_trx) || + (outstanding_mcast_cnt_q == MaxMcastTrans); + // We can send this signal to all slaves since we will only have one outstanding aw + assign mst_is_mcast_o = {NoMstPorts{aw_is_multicast}}; + + // Keep track of which B responses need to be returned to complete the multicast + `FFARN(multicast_select_q, multicast_select_d, '0, clk_i, rst_ni) + `FFARN(outstanding_mcast_cnt_q, outstanding_mcast_cnt_d, '0, clk_i, rst_ni) + + // Logic to update number of outstanding multicast transactions and current multicast + // transactions' select mask. Counter is incremented upon the AW handshake of a multicast + // transaction and decremented upon the "joined" B handshake. + always_comb begin + multicast_select_d = multicast_select_q; + outstanding_mcast_cnt_d = outstanding_mcast_cnt_q; + + // Written as separate if statements as they may both be valid at the same time + // For the same reason the right hand side uses outstanding_mcast_cnt_d + // instead of outstanding_mcast_cnt_q + if (aw_is_multicast && aw_valid && aw_ready) begin + outstanding_mcast_cnt_d = outstanding_mcast_cnt_d + (|slv_aw_select_mask); + multicast_select_d = slv_aw_select_mask; + end + if (outstanding_multicast && slv_resp_o.b_valid && slv_req_i.b_ready) begin + outstanding_mcast_cnt_d = outstanding_mcast_cnt_d - 1; + end + end + + // Multicast AW transaction handshake state + typedef enum logic {MCastAwHandshakeIdle, MCastAwHandshakeInProgress} mcast_aw_hs_state_e; + mcast_aw_hs_state_e mcast_aw_hs_state_q, mcast_aw_hs_state_d; + + // Update of the multicast AW handshake state + always_comb begin + mcast_aw_hs_state_d = mcast_aw_hs_state_q; + unique case (mcast_aw_hs_state_q) + // Waiting for all selected master ports to be ready + MCastAwHandshakeIdle: + if (accept_aw && aw_is_multicast) begin + mcast_aw_hs_state_d = MCastAwHandshakeInProgress; + end + // Commit is asserted and handshake takes place in the current cycle. + // In the next cycle we are again idle + MCastAwHandshakeInProgress: + mcast_aw_hs_state_d = MCastAwHandshakeIdle; + default: ; + endcase + end + + assign mcast_aw_hs_in_progress = mcast_aw_hs_state_q == MCastAwHandshakeInProgress; + + `FFARN(mcast_aw_hs_state_q, mcast_aw_hs_state_d, MCastAwHandshakeIdle, clk_i, rst_ni) + + // When a multicast occurs, the upstream valid signals need to + // be forwarded to multiple master ports. + // Proper stream forking is necessary to avoid protocol violations. + // We must also require that downstream handshakes occur + // simultaneously on all addressed master ports, otherwise deadlocks + // may occur. To achieve this we modify the ready-valid protocol by adding + // a third signal, called commit, which is asserted only when we have all + // downstream handshakes. This signal notifies the slaves that the + // handshake can now actually take place. + // Using commit, instead of valid, to this end ensures that we don't have + // any combinational loops. + assign mst_aw_valids = {NoMstPorts{aw_valid}} & slv_aw_select_mask; + assign accept_aw = &((mst_aw_valids & mst_aw_readies) | ~slv_aw_select_mask); + assign aw_ready = aw_is_multicast ? mcast_aw_hs_in_progress : accept_aw; + assign mst_aw_commit_o = {NoMstPorts{mcast_aw_hs_in_progress}} & slv_aw_select_mask; + + if (UniqueIds) begin : gen_unique_ids_aw + // If the `UniqueIds` parameter is set, each write transaction has an ID that is unique among + // all in-flight write transactions, or all write transactions with a given ID target the same + // master port as all write transactions with the same ID, or both. This means that the + // signals that are driven by the ID counters if this parameter is not set can instead be + // derived from existing signals. The ID counters can therefore be omitted. + assign lookup_aw_select = slv_aw_select; + assign aw_select_occupied = 1'b0; + + // We still need a (single) counter to keep track of any outstanding transactions + axi_mcast_demux_id_counters #( + .AxiIdBits ( 0 ), + .CounterWidth ( IdCounterWidth ), + .mst_port_select_t ( idx_select_t ) + ) i_aw_id_counter ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .lookup_axi_id_i ( '0 ), + .lookup_mst_select_o ( /* Not used */ ), + .lookup_mst_select_occupied_o ( /* Not used */ ), + .full_o ( aw_id_cnt_full ), + .inject_axi_id_i ( '0 ), + .inject_i ( 1'b0 ), + .push_axi_id_i ( '0 ), + .push_mst_select_i ( '0 ), + .push_i ( w_cnt_up && !aw_is_multicast ), + .pop_axi_id_i ( '0 ), + .pop_i ( slv_resp_o.b_valid & slv_req_i.b_ready & ~outstanding_multicast ), + .any_outstanding_trx_o ( aw_any_outstanding_unicast_trx ) + ); + + end else begin : gen_aw_id_counter + + axi_mcast_demux_id_counters #( + .AxiIdBits ( AxiLookBits ), + .CounterWidth ( IdCounterWidth ), + .mst_port_select_t ( idx_select_t ) + ) i_aw_id_counter ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .lookup_axi_id_i ( slv_req_i.aw.id[0+:AxiLookBits] ), + .lookup_mst_select_o ( lookup_aw_select ), + .lookup_mst_select_occupied_o ( aw_select_occupied ), + .full_o ( aw_id_cnt_full ), + .inject_axi_id_i ( '0 ), + .inject_i ( 1'b0 ), + .push_axi_id_i ( slv_req_i.aw.id[0+:AxiLookBits] ), + .push_mst_select_i ( slv_aw_select ), + .push_i ( w_cnt_up && !aw_is_multicast ), + .pop_axi_id_i ( slv_resp_o.b.id[0+:AxiLookBits] ), + .pop_i ( slv_resp_o.b_valid & slv_req_i.b_ready & ~outstanding_multicast ), + .any_outstanding_trx_o ( aw_any_outstanding_unicast_trx ) + ); + // pop from ID counter on outward transaction + end + + // This counter steers the demultiplexer of the W channel. + // `w_select` determines, which handshaking is connected. + // AWs are only forwarded, if the counter is empty, or `w_select_q` is the same as + // `slv_aw_select`. + counter #( + .WIDTH ( IdCounterWidth ), + .STICKY_OVERFLOW ( 1'b0 ) + ) i_counter_open_w ( + .clk_i, + .rst_ni, + .clear_i ( 1'b0 ), + .en_i ( w_cnt_up ^ w_cnt_down ), + .load_i ( 1'b0 ), + .down_i ( w_cnt_down ), + .d_i ( '0 ), + .q_o ( w_open ), + .overflow_o ( /*not used*/ ) + ); + + `FFLARN(w_select_q, slv_aw_select_mask, w_cnt_up, mask_select_t'(0), clk_i, rst_ni) + assign w_select = (|w_open) ? w_select_q : slv_aw_select_mask; + assign w_select_valid = w_cnt_up | (|w_open); + assign w_cnt_down = slv_req_i.w_valid & slv_resp_o.w_ready & slv_req_i.w.last; + + //-------------------------------------- + // W Channel + //-------------------------------------- + + // When a multicast occurs, the upstream valid signals need to + // be forwarded to multiple master ports. + // Proper stream forking is necessary to avoid protocol violations + stream_fork_dynamic #( + .N_OUP(NoMstPorts) + ) i_w_stream_fork_dynamic ( + .clk_i (clk_i), + .rst_ni (rst_ni), + .valid_i (slv_req_i.w_valid), + .ready_o (slv_resp_o.w_ready), + .sel_i (w_select), + .sel_valid_i(w_select_valid), + .sel_ready_o(), + .valid_o (mst_w_valids), + .ready_i (mst_w_readies) + ); + + //-------------------------------------- + // B Channel + //-------------------------------------- + logic [cf_math_pkg::idx_width(NoMstPorts)-1:0] b_idx; + + // Arbitration of the different B responses + rr_arb_tree #( + .NumIn ( NoMstPorts ), + .DataType ( logic ), + .AxiVldRdy( 1'b1 ), + .LockIn ( 1'b1 ) + ) i_b_mux ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .flush_i( 1'b0 ), + .rr_i ( '0 ), + .req_i ( mst_b_valids & {NoMstPorts{!outstanding_multicast}} ), + .gnt_o ( mst_b_readies_arb ), + .data_i ( '0 ), + .gnt_i ( slv_req_i.b_ready ), + .req_o ( slv_b_valid_arb ), + .data_o ( ), + .idx_o ( b_idx ) + ); + + // Streams must be joined instead of arbitrated when multicast + stream_join_dynamic #(NoMstPorts) i_b_stream_join ( + .inp_valid_i(mst_b_valids & {NoMstPorts{outstanding_multicast}}), + .inp_ready_o(mst_b_readies_join), + .sel_i (multicast_select_q), + .oup_valid_o(slv_b_valid_join), + .oup_ready_i(slv_req_i.b_ready) + ); + for (genvar i=0; i 0) else + $fatal(1, "The Number of slaves (NoMstPorts) has to be at least 1"); + AXI_ID_BITS: assume (AxiIdWidth >= AxiLookBits) else + $fatal(1, "AxiIdBits has to be equal or smaller than AxiIdWidth."); + aw_addr_bits: assume ($bits(slv_aw_addr[0]) == $bits(slv_req_i.aw.addr)) else + $fatal(1, "aw_addr_t must be the type of slv_req_i.aw.addr"); + end + default disable iff (!rst_ni); + ar_select: assume property( @(posedge clk_i) (slv_req_i.ar_valid |-> + (slv_ar_select_i < NoMstPorts))) else + $fatal(1, "slv_ar_select_i is %d: AR has selected a slave that is not defined.\ + NoMstPorts: %d", slv_ar_select_i, NoMstPorts); + aw_valid_stable: assert property( @(posedge clk_i) (aw_valid && !aw_ready) |=> aw_valid) else + $fatal(1, "aw_valid was deasserted, when aw_ready = 0 in last cycle."); + ar_valid_stable: assert property( @(posedge clk_i) + (ar_valid && !ar_ready) |=> ar_valid) else + $fatal(1, "ar_valid was deasserted, when ar_ready = 0 in last cycle."); + slv_aw_chan_stable: assert property( @(posedge clk_i) (aw_valid && !aw_ready) + |=> $stable(slv_req_i.aw)) else + $fatal(1, "slv_aw_chan unstable with valid set."); + slv_aw_select_stable: assert property( @(posedge clk_i) (aw_valid && !aw_ready) + |=> $stable(slv_aw_select)) else + $fatal(1, "slv_aw_select unstable with valid set."); + slv_ar_chan_stable: assert property( @(posedge clk_i) (ar_valid && !ar_ready) + |=> $stable(slv_req_i.ar)) else + $fatal(1, "slv_ar_chan unstable with valid set."); + slv_ar_select_stable: assert property( @(posedge clk_i) (ar_valid && !ar_ready) + |=> $stable(slv_ar_select_i)) else + $fatal(1, "slv_ar_select_i unstable with valid set."); + internal_ar_select: assert property( @(posedge clk_i) + (ar_valid |-> slv_ar_select_i < NoMstPorts)) + else $fatal(1, "slv_ar_select_i illegal while ar_valid."); + w_underflow: assert property( @(posedge clk_i) + ((w_open == '0) && (w_cnt_up ^ w_cnt_down) |-> !w_cnt_down)) else + $fatal(1, "W counter underflowed!"); + `ASSUME(NoAtopAllowed, !AtopSupport && slv_req_i.aw_valid |-> slv_req_i.aw.atop == '0) +`endif +`endif +// pragma translate_on + end +endmodule + + +module axi_mcast_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 logic clk_i, // Clock + input logic 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, + // outstanding transactions + output logic any_outstanding_trx_o +); + 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; + //----------------------------------- + // Status + //----------------------------------- + assign any_outstanding_trx_o = |occupied; + + // 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 + diff --git a/src/axi_mcast_mux.sv b/src/axi_mcast_mux.sv index 313251af8..5a1c26c1a 100644 --- a/src/axi_mcast_mux.sv +++ b/src/axi_mcast_mux.sv @@ -76,7 +76,6 @@ module axi_mcast_mux #( // pass through if only one slave port if (NoSlvPorts == 32'h1) begin : gen_no_mux - spill_register #( .T ( mst_aw_chan_t ), .Bypass ( ~SpillAw ) @@ -573,6 +572,8 @@ module axi_mcast_mux_intf #( input logic clk_i, // Clock input logic rst_ni, // Asynchronous reset active low input logic test_i, // Testmode enable + input logic [NO_SLV_PORTS-1:0] slv_is_mcast_i, + input logic [NO_SLV_PORTS-1:0] slv_aw_commit_i, AXI_BUS.Slave slv [NO_SLV_PORTS-1:0], // slave ports AXI_BUS.Master mst // master port ); @@ -617,7 +618,7 @@ module axi_mcast_mux_intf #( `AXI_ASSIGN_FROM_REQ(mst, mst_req) `AXI_ASSIGN_TO_RESP(mst_resp, mst) - axi_mux #( + axi_mcast_mux #( .SlvAxiIDWidth ( SLV_AXI_ID_WIDTH ), .slv_aw_chan_t ( slv_aw_chan_t ), // AW Channel Type, slave ports .mst_aw_chan_t ( mst_aw_chan_t ), // AW Channel Type, master port @@ -644,6 +645,8 @@ module axi_mcast_mux_intf #( .clk_i ( clk_i ), // Clock .rst_ni ( rst_ni ), // Asynchronous reset active low .test_i ( test_i ), // Test Mode enable + .slv_is_mcast_i, + .slv_aw_commit_i, .slv_reqs_i ( slv_reqs ), .slv_resps_o ( slv_resps ), .mst_req_o ( mst_req ), diff --git a/src/axi_mcast_xbar.sv b/src/axi_mcast_xbar.sv index 242a47907..0dd385ecc 100644 --- a/src/axi_mcast_xbar.sv +++ b/src/axi_mcast_xbar.sv @@ -1,4 +1,4 @@ -// Copyright (c) 2022 ETH Zurich and University of Bologna. +// Copyright (c) 2019 ETH Zurich and University of Bologna. // Copyright and related rights are licensed under the Solderpad Hardware // License, Version 0.51 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at @@ -9,13 +9,13 @@ // specific language governing permissions and limitations under the License. // // Authors: +// - Wolfgang Roenninger +// - Andreas Kurth +// - Florian Zaruba // - Luca Colagrande -// Based on: -// - axi_xbar.sv -// 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. +/// axi_xbar: 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_mcast_xbar import cf_math_pkg::idx_width; #( @@ -25,8 +25,8 @@ import cf_math_pkg::idx_width; parameter bit ATOPs = 1'b1, /// Connectivity matrix parameter bit [Cfg.NoSlvPorts-1:0][Cfg.NoMstPorts-1:0] Connectivity = '1, - /// Connectivity matrix for collective operations - parameter bit [Cfg.NoSlvPorts-1:0][Cfg.NoMstPorts-1:0] CollectiveOpsConnectivity = '1, + /// Connectivity matrix for multicast transactions + parameter bit [Cfg.NoSlvPorts-1:0][Cfg.NoMstPorts-1:0] MulticastConnectivity = '1, /// AXI4+ATOP AW channel struct type for the slave ports. parameter type slv_aw_chan_t = logic, /// AXI4+ATOP AW channel struct type for the master ports. @@ -37,11 +37,11 @@ import cf_math_pkg::idx_width; parameter type slv_b_chan_t = logic, /// AXI4+ATOP B channel struct type for the master ports. parameter type mst_b_chan_t = logic, - /// AXI4+ATOP AR channel struct type for the slave ports. + /// AXI4+ATOP AR channel struct type for the slave ports. parameter type slv_ar_chan_t = logic, /// AXI4+ATOP AR channel struct type for the master ports. parameter type mst_ar_chan_t = logic, - /// AXI4+ATOP R channel struct type for the slave ports. + /// AXI4+ATOP R channel struct type for the slave ports. parameter type slv_r_chan_t = logic, /// AXI4+ATOP R channel struct type for the master ports. parameter type mst_r_chan_t = logic, @@ -63,25 +63,26 @@ import cf_math_pkg::idx_width; /// axi_addr_t end_addr; /// } rule_t; /// ``` - parameter type rule_t = axi_pkg::xbar_rule_32_t + parameter type rule_t = axi_pkg::xbar_rule_64_t ) ( /// Clock, positive edge triggered. input logic clk_i, - /// Asynchronous reset, active low. + /// Asynchronous reset, active low. input logic rst_ni, /// Testmode enable, active high. input logic test_i, - /// AXI4+ATOP requests to the slave ports. + /// AXI4+ATOP requests to the slave ports. input slv_req_t [Cfg.NoSlvPorts-1:0] slv_ports_req_i, - /// AXI4+ATOP responses of the slave ports. + /// AXI4+ATOP responses of the slave ports. output slv_resp_t [Cfg.NoSlvPorts-1:0] slv_ports_resp_o, - /// AXI4+ATOP requests of the master ports. + /// AXI4+ATOP requests of the master ports. output mst_req_t [Cfg.NoMstPorts-1:0] mst_ports_req_o, - /// AXI4+ATOP responses to the master ports. + /// AXI4+ATOP responses to the master ports. 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 rule_t [Cfg.NoAddrRules-1:0] addr_map_i, + /// Each master port can have multiple different rules. + 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, /// Enables a default master port for each slave port. When this is enabled unmapped @@ -90,170 +91,40 @@ import cf_math_pkg::idx_width; input rule_t [Cfg.NoSlvPorts-1:0] default_mst_port_i ); - // Address type for individual address signals - 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)); - localparam int unsigned MstPortsIdxWidth = - (Cfg.NoMstPorts == 32'd1) ? 32'd1 : unsigned'($clog2(Cfg.NoMstPorts)); - typedef logic [MstPortsIdxWidthOne-1:0] mst_port_idx_t; - typedef logic [MstPortsIdxWidth-1:0] mst_port_idx_m1_t; -`else - typedef logic [idx_width(Cfg.NoMstPorts + 1)-1:0] mst_port_idx_t; - typedef logic [idx_width(Cfg.NoMstPorts)-1:0] mst_port_idx_m1_t; -`endif - - // signals from the axi_demuxes, one index more for decode error - slv_req_t [Cfg.NoSlvPorts-1:0][Cfg.NoMstPorts:0] slv_reqs; - slv_resp_t [Cfg.NoSlvPorts-1:0][Cfg.NoMstPorts:0] slv_resps; - logic [Cfg.NoSlvPorts-1:0][Cfg.NoMstPorts:0] slv_is_mcast; - logic [Cfg.NoSlvPorts-1:0][Cfg.NoMstPorts:0] slv_aw_commit; - - // workaround for issue #133 (problem with vsim 10.6c) - localparam int unsigned cfg_NoMstPorts = Cfg.NoMstPorts; - // signals into the axi_muxes, are of type slave as the multiplexer extends the ID - logic [Cfg.NoMstPorts-1:0][Cfg.NoSlvPorts-1:0] mst_is_mcast; - logic [Cfg.NoMstPorts-1:0][Cfg.NoSlvPorts-1:0] mst_aw_commit; slv_req_t [Cfg.NoMstPorts-1:0][Cfg.NoSlvPorts-1:0] mst_reqs; 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 - mst_port_idx_m1_t dec_ar_select; - logic dec_ar_valid, dec_ar_error; - mst_port_idx_t slv_ar_select; - - addr_decode #( - .NoIndices ( Cfg.NoMstPorts ), - .addr_t ( addr_t ), - .NoRules ( Cfg.NoAddrRules ), - .rule_t ( rule_t ) - ) i_axi_ar_decode ( - .addr_i ( slv_ports_req_i[i].ar.addr ), - .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 ( en_default_mst_port_i[i] ), - .default_idx_i ( mst_port_idx_m1_t'(default_mst_port_i[i].idx) ) - ); - assign slv_ar_select = (dec_ar_error) ? - mst_port_idx_t'(Cfg.NoMstPorts) : mst_port_idx_t'(dec_ar_select); - - axi_mcast_demux #( - .AxiIdWidth ( Cfg.AxiIdWidthSlvPorts ), // ID Width - .AtopSupport ( ATOPs ), - .Connectivity ( Connectivity[i] ), - .CollectiveOpsConnectivity( CollectiveOpsConnectivity[i] ), - .aw_addr_t ( addr_t ), // AW Address Type - .aw_chan_t ( slv_aw_chan_t ), // AW Channel Type - .w_chan_t ( w_chan_t ), // W Channel Type - .b_chan_t ( slv_b_chan_t ), // B Channel Type - .ar_chan_t ( slv_ar_chan_t ), // AR Channel Type - .r_chan_t ( slv_r_chan_t ), // R Channel Type - .axi_req_t ( slv_req_t ), - .axi_resp_t ( slv_resp_t ), - .NoMstPorts ( Cfg.NoMstPorts + 1 ), - .MaxTrans ( Cfg.MaxMstTrans ), - .AxiLookBits ( Cfg.AxiIdUsedSlvPorts ), - .UniqueIds ( Cfg.UniqueIds ), - .SpillAw ( Cfg.LatencyMode[9] ), - .SpillW ( Cfg.LatencyMode[8] ), - .SpillB ( Cfg.LatencyMode[7] ), - .SpillAr ( Cfg.LatencyMode[6] ), - .SpillR ( Cfg.LatencyMode[5] ), - .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 - .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] ), - .mst_reqs_o ( slv_reqs[i] ), - .mst_resps_i ( slv_resps[i] ), - .mst_is_mcast_o ( slv_is_mcast[i] ), - .mst_aw_commit_o ( slv_aw_commit[i] ) - ); - - axi_err_slv #( - .AxiIdWidth ( Cfg.AxiIdWidthSlvPorts ), - .axi_req_t ( slv_req_t ), - .axi_resp_t ( slv_resp_t ), - .Resp ( axi_pkg::RESP_DECERR ), - .ATOPs ( ATOPs ), - .MaxTrans ( 4 ) // Transactions terminate at this slave, so minimize - // resource consumption by accepting only a few - // transactions at a time. - ) i_axi_err_slv ( - .clk_i, // Clock - .rst_ni, // Asynchronous reset active low - .test_i, // Testmode enable - // slave port - .slv_req_i ( slv_reqs[i][Cfg.NoMstPorts] ), - .slv_resp_o ( slv_resps[i][cfg_NoMstPorts] ) - ); - end - - // cross all channels - for (genvar i = 0; i < Cfg.NoSlvPorts; i++) begin : gen_xbar_slv_cross - for (genvar j = 0; j < Cfg.NoMstPorts; j++) begin : gen_xbar_mst_cross - if (Connectivity[i][j]) begin : gen_connection + logic [Cfg.NoMstPorts-1:0][Cfg.NoSlvPorts-1:0] mst_is_mcast; + logic [Cfg.NoMstPorts-1:0][Cfg.NoSlvPorts-1:0] mst_aw_commit; - assign mst_is_mcast[j][i] = slv_is_mcast[i][j]; - assign mst_aw_commit[j][i] = slv_aw_commit[i][j]; - - axi_multicut #( - // Internal pipelining is currently not supported in multicast XBAR - .NoCuts ( 0 ), - .aw_chan_t ( slv_aw_chan_t ), - .w_chan_t ( w_chan_t ), - .b_chan_t ( slv_b_chan_t ), - .ar_chan_t ( slv_ar_chan_t ), - .r_chan_t ( slv_r_chan_t ), - .axi_req_t ( slv_req_t ), - .axi_resp_t ( slv_resp_t ) - ) i_axi_multicut_xbar_pipeline ( - .clk_i, - .rst_ni, - .slv_req_i ( slv_reqs[i][j] ), - .slv_resp_o ( slv_resps[i][j] ), - .mst_req_o ( mst_reqs[j][i] ), - .mst_resp_i ( mst_resps[j][i] ) - ); - - end else begin : gen_no_connection - - assign mst_is_mcast[j][i] = 1'b0; - assign mst_aw_commit[j][i] = 1'b0; - - assign mst_reqs[j][i] = '0; - - axi_err_slv #( - .AxiIdWidth ( Cfg.AxiIdWidthSlvPorts ), - .axi_req_t ( slv_req_t ), - .axi_resp_t ( slv_resp_t ), - .Resp ( axi_pkg::RESP_DECERR ), - .ATOPs ( ATOPs ), - .MaxTrans ( 1 ) - ) i_axi_err_slv ( - .clk_i, - .rst_ni, - .test_i, - .slv_req_i ( slv_reqs[i][j] ), - .slv_resp_o ( slv_resps[i][j] ) - ); - end - end - end + axi_mcast_xbar_unmuxed #( + .Cfg (Cfg), + .ATOPs (ATOPs), + .Connectivity (Connectivity), + .MulticastConnectivity (MulticastConnectivity), + .aw_chan_t (slv_aw_chan_t), + .w_chan_t (w_chan_t), + .b_chan_t (slv_b_chan_t), + .ar_chan_t (slv_ar_chan_t), + .r_chan_t (slv_r_chan_t), + .req_t (slv_req_t), + .resp_t (slv_resp_t), + .rule_t (rule_t) + ) i_xbar_unmuxed ( + .clk_i, + .rst_ni, + .test_i, + .slv_ports_req_i, + .slv_ports_resp_o, + .mst_ports_req_o (mst_reqs), + .mst_ports_resp_i (mst_resps), + .mst_is_mcast_o (mst_is_mcast), + .mst_aw_commit_o (mst_aw_commit), + .addr_map_i, + .en_default_mst_port_i, + .default_mst_port_i + ); for (genvar i = 0; i < Cfg.NoMstPorts; i++) begin : gen_mst_port_mux axi_mcast_mux #( @@ -283,8 +154,8 @@ import cf_math_pkg::idx_width; .clk_i, // Clock .rst_ni, // Asynchronous reset active low .test_i, // Test Mode enable - .slv_is_mcast_i ( mst_is_mcast[i] ), - .slv_aw_commit_i ( mst_aw_commit[i] ), + .slv_is_mcast_i ( mst_is_mcast[i] ), + .slv_aw_commit_i ( mst_aw_commit[i] ), .slv_reqs_i ( mst_reqs[i] ), .slv_resps_o ( mst_resps[i] ), .mst_req_o ( mst_ports_req_o[i] ), @@ -292,22 +163,6 @@ import cf_math_pkg::idx_width; ); end - // pragma translate_off - `ifndef VERILATOR - `ifndef XSIM - initial begin : check_params - id_slv_req_ports: assert ($bits(slv_ports_req_i[0].aw.id ) == Cfg.AxiIdWidthSlvPorts) else - $fatal(1, $sformatf("Slv_req and aw_chan id width not equal.")); - id_slv_resp_ports: assert ($bits(slv_ports_resp_o[0].r.id) == Cfg.AxiIdWidthSlvPorts) else - $fatal(1, $sformatf("Slv_req and aw_chan id width not equal.")); - addr_slv_req_ports: assert ($bits(slv_ports_req_i[0].aw.addr) == Cfg.AxiAddrWidth) else - $fatal(1, $sformatf("Slv_req and aw_addr width not equal.")); - addr_mst_req_ports: assert ($bits(mst_ports_req_o[0].aw.addr) == Cfg.AxiAddrWidth) else - $fatal(1, $sformatf("Mst_req and aw_addr width not equal.")); - end - `endif - `endif - // pragma translate_on endmodule `include "axi/assign.svh" @@ -320,11 +175,8 @@ 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 bit [Cfg.NoSlvPorts-1:0][Cfg.NoMstPorts-1:0] MULTICAST_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, @@ -382,6 +234,7 @@ import cf_math_pkg::idx_width; .Cfg (Cfg), .ATOPs ( ATOPS ), .Connectivity ( CONNECTIVITY ), + .MulticastConnectivity ( MULTICAST_CONNECTIVITY ), .slv_aw_chan_t ( slv_aw_chan_t ), .mst_aw_chan_t ( mst_aw_chan_t ), .w_chan_t ( w_chan_t ), @@ -400,10 +253,10 @@ import cf_math_pkg::idx_width; .clk_i, .rst_ni, .test_i, - .slv_ports_req_i (slv_reqs), - .slv_ports_resp_o(slv_resps), - .mst_ports_req_o (mst_reqs), - .mst_ports_resp_i(mst_resps), + .slv_ports_req_i (slv_reqs ), + .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 diff --git a/src/axi_mcast_xbar_unmuxed.sv b/src/axi_mcast_xbar_unmuxed.sv new file mode 100644 index 000000000..3a0ba02b7 --- /dev/null +++ b/src/axi_mcast_xbar_unmuxed.sv @@ -0,0 +1,370 @@ +// Copyright (c) 2019 ETH Zurich and University of Bologna. +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. +// +// Authors: +// - Wolfgang Roenninger +// - Andreas Kurth +// - Florian Zaruba + +/// axi_xbar: 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_mcast_xbar_unmuxed +import cf_math_pkg::idx_width; +#( + /// Configuration struct for the crossbar see `axi_pkg` for fields and definitions. + parameter axi_pkg::xbar_cfg_t Cfg = '0, + /// Enable atomic operations support. + parameter bit ATOPs = 1'b1, + /// Connectivity matrix + parameter bit [Cfg.NoSlvPorts-1:0][Cfg.NoMstPorts-1:0] Connectivity = '1, + /// Connectivity matrix for multicast transactions + parameter bit [Cfg.NoSlvPorts-1:0][Cfg.NoMstPorts-1:0] MulticastConnectivity = '1, + /// AXI4+ATOP AW channel struct type for the slave ports. + parameter type aw_chan_t = logic, + /// AXI4+ATOP W channel struct type for all ports. + parameter type w_chan_t = logic, + /// AXI4+ATOP B channel struct type for the slave ports. + parameter type b_chan_t = logic, + /// AXI4+ATOP AR channel struct type for the slave ports. + parameter type ar_chan_t = logic, + /// AXI4+ATOP R channel struct type for the slave ports. + parameter type r_chan_t = logic, + /// AXI4+ATOP request struct type for the slave ports. + parameter type req_t = logic, + /// AXI4+ATOP response struct type for the slave ports. + parameter type resp_t = logic, + /// Address rule type for the address decoders from `common_cells:addr_decode`. + /// Example types are provided in `axi_pkg`. + /// Required struct fields: + /// ``` + /// typedef struct packed { + /// int unsigned idx; + /// axi_addr_t start_addr; + /// axi_addr_t end_addr; + /// } rule_t; + /// ``` + parameter type rule_t = axi_pkg::xbar_rule_64_t +) ( + /// Clock, positive edge triggered. + input logic clk_i, + /// Asynchronous reset, active low. + input logic rst_ni, + /// Testmode enable, active high. + input logic test_i, + /// AXI4+ATOP requests to the slave ports. + input req_t [Cfg.NoSlvPorts-1:0] slv_ports_req_i, + /// AXI4+ATOP responses of the slave ports. + output resp_t [Cfg.NoSlvPorts-1:0] slv_ports_resp_o, + /// AXI4+ATOP requests of the master ports. + output req_t [Cfg.NoMstPorts-1:0][Cfg.NoSlvPorts-1:0] mst_ports_req_o, + /// AXI4+ATOP responses to the master ports. + input resp_t [Cfg.NoMstPorts-1:0][Cfg.NoSlvPorts-1:0] mst_ports_resp_i, + /// Additional multicast signals to the master ports. + output logic [Cfg.NoMstPorts-1:0][Cfg.NoSlvPorts-1:0] mst_is_mcast_o, + output logic [Cfg.NoMstPorts-1:0][Cfg.NoSlvPorts-1:0] mst_aw_commit_o, + /// 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. + /// Each master port can have multiple different rules. + 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, + /// 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 rule_t [Cfg.NoSlvPorts-1:0] default_mst_port_i +); + + // Address type for individual address signals + typedef logic [Cfg.AxiAddrWidth-1:0] addr_t; + // to account for the decoding error slave + localparam int unsigned MstPortsIdxWidthOne = + (Cfg.NoMstPorts == 32'd1) ? 32'd1 : unsigned'($clog2(Cfg.NoMstPorts + 1)); + localparam int unsigned MstPortsIdxWidth = + (Cfg.NoMstPorts == 32'd1) ? 32'd1 : unsigned'($clog2(Cfg.NoMstPorts)); + typedef logic [MstPortsIdxWidthOne-1:0] mst_port_idx_t; + typedef logic [MstPortsIdxWidth-1:0] mst_port_idx_m1_t; + + // signals from the axi_demuxes, one index more for decode error + req_t [Cfg.NoSlvPorts-1:0][Cfg.NoMstPorts:0] slv_reqs; + resp_t [Cfg.NoSlvPorts-1:0][Cfg.NoMstPorts:0] slv_resps; + + logic [Cfg.NoSlvPorts-1:0][Cfg.NoMstPorts:0] slv_is_mcast; + logic [Cfg.NoSlvPorts-1:0][Cfg.NoMstPorts:0] slv_aw_commit; + + // workaround for issue #133 (problem with vsim 10.6c) + localparam int unsigned cfg_NoMstPorts = Cfg.NoMstPorts; + + for (genvar i = 0; i < Cfg.NoSlvPorts; i++) begin : gen_slv_port_demux + mst_port_idx_m1_t dec_ar_select; + logic dec_ar_valid, dec_ar_error; + mst_port_idx_t slv_ar_select; + + addr_decode #( + .NoIndices ( Cfg.NoMstPorts ), + .addr_t ( addr_t ), + .NoRules ( Cfg.NoAddrRules ), + .rule_t ( rule_t ) + ) i_axi_ar_decode ( + .addr_i ( slv_ports_req_i[i].ar.addr ), + .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 ( en_default_mst_port_i[i] ), + .default_idx_i ( mst_port_idx_m1_t'(default_mst_port_i[i].idx) ) + ); + assign slv_ar_select = (dec_ar_error) ? + mst_port_idx_t'(Cfg.NoMstPorts) : mst_port_idx_t'(dec_ar_select); + + // 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_mcast_demux #( + .AxiIdWidth ( Cfg.AxiIdWidthSlvPorts ), // ID Width + .AtopSupport ( ATOPs ), + .aw_addr_t ( addr_t ), // AW Address Type + .aw_chan_t ( aw_chan_t ), // AW Channel Type + .w_chan_t ( w_chan_t ), // W Channel Type + .b_chan_t ( b_chan_t ), // B Channel Type + .ar_chan_t ( ar_chan_t ), // AR Channel Type + .r_chan_t ( r_chan_t ), // R Channel Type + .axi_req_t ( req_t ), + .axi_resp_t ( resp_t ), + .NoMstPorts ( Cfg.NoMstPorts + 1 ), + .MaxTrans ( Cfg.MaxMstTrans ), + .AxiLookBits ( Cfg.AxiIdUsedSlvPorts ), + .UniqueIds ( Cfg.UniqueIds ), + .SpillAw ( Cfg.LatencyMode[9] ), + .SpillW ( Cfg.LatencyMode[8] ), + .SpillB ( Cfg.LatencyMode[7] ), + .SpillAr ( Cfg.LatencyMode[6] ), + .SpillR ( Cfg.LatencyMode[5] ), + .Connectivity ( Connectivity[i] ), + .MulticastConnectivity ( MulticastConnectivity[i] ), + .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 + .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] ), + .mst_reqs_o ( slv_reqs[i] ), + .mst_resps_i ( slv_resps[i] ), + .mst_is_mcast_o ( slv_is_mcast[i] ), + .mst_aw_commit_o ( slv_aw_commit[i] ) + ); + + axi_err_slv #( + .AxiIdWidth ( Cfg.AxiIdWidthSlvPorts ), + .axi_req_t ( req_t ), + .axi_resp_t ( resp_t ), + .Resp ( axi_pkg::RESP_DECERR ), + .ATOPs ( ATOPs ), + .MaxTrans ( 4 ) // Transactions terminate at this slave, so minimize + // resource consumption by accepting only a few + // transactions at a time. + ) i_axi_err_slv ( + .clk_i, // Clock + .rst_ni, // Asynchronous reset active low + .test_i, // Testmode enable + // slave port + .slv_req_i ( slv_reqs[i][Cfg.NoMstPorts] ), + .slv_resp_o ( slv_resps[i][cfg_NoMstPorts] ) + ); + end + + // cross all channels + for (genvar i = 0; i < Cfg.NoSlvPorts; i++) begin : gen_xbar_slv_cross + for (genvar j = 0; j < Cfg.NoMstPorts; j++) begin : gen_xbar_mst_cross + if (Connectivity[i][j]) begin : gen_connection + + assign mst_is_mcast_o[j][i] = slv_is_mcast[i][j]; + assign mst_aw_commit_o[j][i] = slv_aw_commit[i][j]; + + axi_multicut #( + .NoCuts ( Cfg.PipelineStages ), + .aw_chan_t ( aw_chan_t ), + .w_chan_t ( w_chan_t ), + .b_chan_t ( b_chan_t ), + .ar_chan_t ( ar_chan_t ), + .r_chan_t ( r_chan_t ), + .axi_req_t ( req_t ), + .axi_resp_t ( resp_t ) + ) i_axi_multicut_xbar_pipeline ( + .clk_i, + .rst_ni, + .slv_req_i ( slv_reqs[i][j] ), + .slv_resp_o ( slv_resps[i][j] ), + .mst_req_o ( mst_ports_req_o[j][i] ), + .mst_resp_i ( mst_ports_resp_i[j][i] ) + ); + + end else begin : gen_no_connection + + assign mst_is_mcast_o[j][i] = 1'b0; + assign mst_aw_commit_o[j][i] = 1'b0; + + assign mst_ports_req_o[j][i] = '0; + axi_err_slv #( + .AxiIdWidth ( Cfg.AxiIdWidthSlvPorts ), + .axi_req_t ( req_t ), + .axi_resp_t ( resp_t ), + .Resp ( axi_pkg::RESP_DECERR ), + .ATOPs ( ATOPs ), + .MaxTrans ( 1 ) + ) i_axi_err_slv ( + .clk_i, + .rst_ni, + .test_i, + .slv_req_i ( slv_reqs[i][j] ), + .slv_resp_o ( slv_resps[i][j] ) + ); + end + end + end + + // pragma translate_off + `ifndef VERILATOR + `ifndef XSIM + initial begin : check_params + id_slv_req_ports: assert ($bits(slv_ports_req_i[0].aw.id ) == Cfg.AxiIdWidthSlvPorts) else + $fatal(1, $sformatf("Slv_req and aw_chan id width not equal.")); + id_slv_resp_ports: assert ($bits(slv_ports_resp_o[0].r.id) == Cfg.AxiIdWidthSlvPorts) else + $fatal(1, $sformatf("Slv_req and aw_chan id width not equal.")); + addr_slv_req_ports: assert ($bits(slv_ports_req_i[0].aw.addr) == Cfg.AxiAddrWidth) else + $fatal(1, $sformatf("Slv_req and aw_addr width not equal.")); + addr_mst_req_ports: assert ($bits(mst_ports_req_o[0][0].aw.addr) == Cfg.AxiAddrWidth) else + $fatal(1, $sformatf("Mst_req and aw_addr width not equal.")); + no_cuts_if_mcast: assert (!Cfg.EnableMulticast || (Cfg.PipelineStages == 0)) else + $fatal(1, $sformatf("Multicast XBAR currently does not support pipeline stages.")); + end + `endif + `endif + // pragma translate_on +endmodule + +`ifndef VCS +// As of now, VCS does not support multi-dimensional array of interfaces. +`include "axi/assign.svh" +`include "axi/typedef.svh" + +module axi_mcast_xbar_unmuxed_intf +import cf_math_pkg::idx_width; +#( + parameter int unsigned AXI_USER_WIDTH = 0, + 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 bit [Cfg.NoSlvPorts-1:0][Cfg.NoMstPorts-1:0] MULTICAST_CONNECTIVITY = '1, + parameter type rule_t = axi_pkg::xbar_rule_64_t +) ( + 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][Cfg.NoSlvPorts-1:0], + input rule_t [Cfg.NoAddrRules-1:0] addr_map_i, + input logic [Cfg.NoSlvPorts-1:0] en_default_mst_port_i, + input logic [Cfg.NoSlvPorts-1:0][idx_width(Cfg.NoMstPorts)-1:0] default_mst_port_i +); + + typedef logic [Cfg.AxiIdWidthSlvPorts -1:0] id_t; + typedef logic [Cfg.AxiAddrWidth -1:0] addr_t; + typedef logic [Cfg.AxiDataWidth -1:0] data_t; + typedef logic [Cfg.AxiDataWidth/8 -1:0] strb_t; + typedef logic [AXI_USER_WIDTH -1:0] user_t; + + `AXI_TYPEDEF_AW_CHAN_T(aw_chan_t, addr_t, id_t, user_t) + `AXI_TYPEDEF_W_CHAN_T(w_chan_t, data_t, strb_t, user_t) + `AXI_TYPEDEF_B_CHAN_T(b_chan_t, id_t, user_t) + `AXI_TYPEDEF_AR_CHAN_T(ar_chan_t, addr_t, id_t, user_t) + `AXI_TYPEDEF_R_CHAN_T(r_chan_t, data_t, id_t, user_t) + `AXI_TYPEDEF_REQ_T(req_t, aw_chan_t, w_chan_t, ar_chan_t) + `AXI_TYPEDEF_RESP_T(resp_t, b_chan_t, r_chan_t) + + req_t [Cfg.NoMstPorts-1:0][Cfg.NoSlvPorts-1:0] mst_reqs; + resp_t [Cfg.NoMstPorts-1:0][Cfg.NoSlvPorts-1:0] mst_resps; + req_t [Cfg.NoSlvPorts-1:0] slv_reqs; + resp_t [Cfg.NoSlvPorts-1:0] slv_resps; + + for (genvar i = 0; i < Cfg.NoMstPorts; i++) begin : gen_assign_mst + for (genvar j = 0; j < Cfg.NoSlvPorts; j++) begin : gen_assign_mst_inner + `AXI_ASSIGN_FROM_REQ(mst_ports[i][j], mst_reqs[i][j]) + `AXI_ASSIGN_TO_RESP(mst_resps[i][j], mst_ports[i][j]) + end + end + + for (genvar i = 0; i < Cfg.NoSlvPorts; i++) begin : gen_assign_slv + `AXI_ASSIGN_TO_REQ(slv_reqs[i], slv_ports[i]) + `AXI_ASSIGN_FROM_RESP(slv_ports[i], slv_resps[i]) + end + + axi_mcast_xbar_unmuxed #( + .Cfg ( Cfg ), + .ATOPs ( ATOPS ), + .Connectivity ( CONNECTIVITY ), + .MulticastConnectivity ( MULTICAST_CONNECTIVITY ), + .aw_chan_t ( aw_chan_t ), + .w_chan_t ( w_chan_t ), + .b_chan_t ( b_chan_t ), + .ar_chan_t ( ar_chan_t ), + .r_chan_t ( r_chan_t ), + .req_t ( req_t ), + .resp_t ( resp_t ), + .rule_t ( rule_t ) + ) i_xbar ( + .clk_i, + .rst_ni, + .test_i, + .slv_ports_req_i (slv_reqs ), + .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 + ); + +endmodule + +`endif diff --git a/src/axi_pkg.sv b/src/axi_pkg.sv index 713bc9754..51952b1a6 100644 --- a/src/axi_pkg.sv +++ b/src/axi_pkg.sv @@ -519,6 +519,8 @@ package axi_pkg; /// 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; + /// When asserted, the XBAR is configured to support multicast. + bit EnableMulticast; /// The number of address rules to be considered for multicasting, /// assumed to be at the start of `addr_map_i`. int unsigned NoMulticastRules; diff --git a/src/axi_test.sv b/src/axi_test.sv index 1c27cfc5e..230081fb0 100644 --- a/src/axi_test.sv +++ b/src/axi_test.sv @@ -987,12 +987,13 @@ package axi_test; mcast -> mcast_mask != 0; }; assert(rand_success); ax_beat.ax_user = mcast_mask; + end else begin + ax_beat.ax_user = user; end // The random ID *must* be legalized with `legalize_id()` before the beat is sent! This is // currently done in the functions `create_aws()` and `send_ars()`. ax_beat.ax_id = id; ax_beat.ax_qos = qos; - ax_beat.ax_user = user; return ax_beat; endfunction @@ -1329,7 +1330,8 @@ package axi_test; aw_done = 1'b0; fork // Cache-Partition: randomize the patid - automatic user_t ax_user = rand_user(AX_USER_RANGE, AX_USER_RAND); + // Multicast: randomize each burst separately + automatic user_t ax_user = ENABLE_MULTICAST ? '0 : rand_user(AX_USER_RANGE, AX_USER_RAND); begin send_ars(n_reads, ax_user); ar_done = 1'b1; diff --git a/test/tb_axi_mcast_xbar.sv b/test/tb_axi_mcast_xbar.sv index 5cb4e8869..703e71f79 100644 --- a/test/tb_axi_mcast_xbar.sv +++ b/test/tb_axi_mcast_xbar.sv @@ -1,4 +1,4 @@ -// Copyright (c) 2022 ETH Zurich and University of Bologna. +// Copyright (c) 2019 ETH Zurich and University of Bologna. // Copyright and related rights are licensed under the Solderpad Hardware // License, Version 0.51 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at @@ -9,9 +9,10 @@ // specific language governing permissions and limitations under the License. // // Authors: +// - Wolfgang Roenninger +// - Florian Zaruba +// - Andreas Kurth // - Luca Colagrande -// Based on: -// - tb_axi_xbar.sv // Directed Random Verification Testbench for `axi_xbar`: The crossbar is instantiated with // a number of random axi master and slave modules. Each random master executes a fixed number of @@ -49,7 +50,7 @@ module tb_axi_mcast_xbar #( /// Enable exclusive accesses parameter bit TbEnExcl = 1'b0, /// Restrict to only unique IDs - parameter bit TbUniqueIds = 1'b0 + parameter bit TbUniqueIds = 1'b0 ); // TB timing parameters @@ -78,6 +79,7 @@ module tb_axi_mcast_xbar #( AxiAddrWidth: TbAxiAddrWidth, AxiDataWidth: TbAxiDataWidth, NoAddrRules: TbNumMcastSlaves * 2 + 1, + EnableMulticast: 1, NoMulticastRules: TbNumMcastSlaves * 2, NoMulticastPorts: TbNumMcastSlaves }; @@ -110,13 +112,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 = {rule_t'{ - idx: TbNumMcastSlaves, - start_addr: 32'h7000_0000, - end_addr: 32'h7008_0000 - }, - addr_map_gen(32'h1000_0000, 32'h10_0000), - addr_map_gen(32'h0b00_0000, 32'h1_0000)}; + localparam rule_t [xbar_cfg.NoAddrRules-1:0] AddrMap = { + rule_t'{ + idx: TbNumMcastSlaves, + start_addr: 32'h7000_0000, + end_addr: 32'h7008_0000 + }, + addr_map_gen(32'h1000_0000, 32'h10_0000), + addr_map_gen(32'h0b00_0000, 32'h1_0000) + }; function rule_t [xbar_cfg.NoMulticastPorts-1:0] addr_map_gen (addr_t base, addr_t offset); for (int unsigned i = 0; i < xbar_cfg.NoMulticastPorts; i++) begin @@ -144,7 +148,7 @@ module tb_axi_mcast_xbar #( .AXI_EXCLS ( TbEnExcl ), .AXI_ATOPS ( TbEnAtop ), .UNIQUE_IDS ( TbUniqueIds ), - .ENABLE_MULTICAST( 1 ) + .ENABLE_MULTICAST ( 1 ) ) axi_rand_master_t; typedef axi_test::axi_rand_slave #( // AXI interface parameters diff --git a/test/tb_axi_mcast_xbar_pkg.sv b/test/tb_axi_mcast_xbar_pkg.sv index 99b9695d2..9b5317b20 100644 --- a/test/tb_axi_mcast_xbar_pkg.sv +++ b/test/tb_axi_mcast_xbar_pkg.sv @@ -9,9 +9,9 @@ // specific language governing permissions and limitations under the License. // // Authors: +// - Florian Zaruba +// - Wolfgang Roenninger // - Luca Colagrande -// Based on: -// - tb_axi_xbar_pkg.sv // `axi_mcast_xbar_monitor` implements an AXI bus monitor that is tuned for the AXI multicast // crossbar. It snoops on each of the slaves and master ports of the crossbar and @@ -104,7 +104,7 @@ package tb_axi_mcast_xbar_pkg; longint unsigned tests_expected; longint unsigned tests_conducted; longint unsigned tests_failed; - semaphore cnt_sem; + std::semaphore cnt_sem; //----------------------------------------- // Constructor @@ -197,7 +197,8 @@ package tb_axi_mcast_xbar_pkg; // Log masked address 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); + + $display("Trying to match: %x", aw_addr_masked); // Compare request against each multicast rule. We look at the rules starting from the // last ones. In case of multiple rules matching for the same slave, we want only @@ -234,10 +235,8 @@ package tb_axi_mcast_xbar_pkg; // Compare request against each interval-form rule. We look at the rules starting from // the last ones. We ignore the case of multiple rules matching for the same slave - // (as is the case in tb_mcast_xbar_pkg.sv) $display("Trying to match: %x", aw_addr); for (int j = (NoAddrRules - 1); j >= 0; j--) begin - $display("With slave %3d : [%x, %x)", AddrMap[j].idx, AddrMap[j].start_addr, AddrMap[j].end_addr); if ((aw_addr >= AddrMap[j].start_addr) && (aw_addr < AddrMap[j].end_addr)) begin decerr = 0; From ce36d53bb7b1ecb682c45b92505949bd2d05daad Mon Sep 17 00:00:00 2001 From: Luca Colagrande Date: Mon, 22 Sep 2025 14:10:13 +0200 Subject: [PATCH 24/41] Continue rebase, make tests pass again --- src/axi_test.sv | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/axi_test.sv b/src/axi_test.sv index 230081fb0..1d1b12d9a 100644 --- a/src/axi_test.sv +++ b/src/axi_test.sv @@ -1005,11 +1005,13 @@ package axi_test; // We can emit ATOPs only if INCR bursts are allowed. $warning("ATOP suppressed because INCR bursts are disabled!"); beat.ax_atop[5:4] = 2'b00; + break; end - if (beat.ax_atop[5:4] != 2'b00 && beat.ax_user != '0) begin + if (ENABLE_MULTICAST && beat.ax_atop[5:4] != 2'b00 && beat.ax_user != '0) begin // We can emit ATOPs only if current burst is not a multicast. $warning("ATOP suppressed because burst is a multicast!"); beat.ax_atop[5:4] = 2'b00; + break; end if (beat.ax_atop[5:4] != 2'b00) begin // ATOP // Determine `ax_atop`. From 0f1798b5f656d4084f24bf9c9cf5a16c843cadb0 Mon Sep 17 00:00:00 2001 From: Luca Colagrande Date: Thu, 29 Jan 2026 18:54:31 +0100 Subject: [PATCH 25/41] Implement unicast XBAR IPs from multicast IPs --- Bender.yml | 2 +- src/axi_demux_simple.sv | 472 ++------------------------ src/axi_mcast_demux.sv | 338 ++++++++++++++----- src/axi_mcast_demux_simple.sv | 462 ++++++-------------------- src/axi_mcast_xbar_unmuxed.sv | 92 ++--- src/axi_mux.sv | 470 ++------------------------ src/axi_xbar.sv | 97 +++--- src/axi_xbar_unmuxed.sv | 218 ++---------- test/tb_axi_mcast_xbar.sv | 2 +- test/tb_axi_mcast_xbar_pkg.sv | 609 ---------------------------------- test/tb_axi_xbar.sv | 1 + test/tb_axi_xbar_pkg.sv | 172 ++++++++-- 12 files changed, 659 insertions(+), 2276 deletions(-) delete mode 100644 test/tb_axi_mcast_xbar_pkg.sv diff --git a/Bender.yml b/Bender.yml index c769ced92..d807e8325 100644 --- a/Bender.yml +++ b/Bender.yml @@ -6,6 +6,7 @@ package: - "Niccolo Giuliani " # current maintainer - "Thomas Benz " - "Matheus Cavalcante " + - "Luca Colagrande " - "Tim Fischer " - "Noah Huetter " - "Cyril Koenig " @@ -127,7 +128,6 @@ sources: files: # Level 0 - test/tb_axi_dw_pkg.sv - - test/tb_axi_mcast_xbar_pkg.sv - test/tb_axi_xbar_pkg.sv # Level 1 - test/tb_axi_addr_test.sv diff --git a/src/axi_demux_simple.sv b/src/axi_demux_simple.sv index 01aad5917..fc365ddbd 100644 --- a/src/axi_demux_simple.sv +++ b/src/axi_demux_simple.sv @@ -65,447 +65,35 @@ module axi_demux_simple #( input axi_resp_t [NoMstPorts-1:0] mst_resps_i ); - localparam int unsigned IdCounterWidth = cc_pkg::idx_width(MaxTrans); - typedef logic [IdCounterWidth-1:0] id_cnt_t; + logic [NoMstPorts-1:0] aw_select_mask; + + assign aw_select_mask = 1'b1 << slv_aw_select_i; + + axi_mcast_demux_simple #( + .AxiIdWidth (AxiIdWidth), + .AtopSupport (AtopSupport), + .axi_req_t (axi_req_t), + .axi_resp_t (axi_resp_t), + .NoMstPorts (NoMstPorts), + .MaxTrans (MaxTrans), + .AxiLookBits (AxiLookBits), + .UniqueIds (UniqueIds), + .NoMulticastPorts (0), + .MaxMcastTrans (1) + ) i_axi_mcast_demux_simple ( + .clk_i (clk_i), + .rst_ni (rst_ni), + .test_i (test_i), + .slv_req_i (slv_req_i), + .slv_aw_select_i (aw_select_mask), + .slv_aw_addr_i ('0), + .slv_aw_mask_i ('0), + .slv_ar_select_i (slv_ar_select_i), + .slv_resp_o (slv_resp_o), + .mst_reqs_o (mst_reqs_o), + .mst_resps_i (mst_resps_i), + .mst_is_mcast_o (), + .mst_aw_commit_o () + ); - // pass through if only one master port - if (NoMstPorts == 32'h1) begin : gen_no_demux - `AXI_ASSIGN_REQ_STRUCT(mst_reqs_o[0], slv_req_i) - `AXI_ASSIGN_RESP_STRUCT(slv_resp_o, mst_resps_i[0]) - end else begin - - //-------------------------------------- - //-------------------------------------- - // Signal Declarations - //-------------------------------------- - //-------------------------------------- - - //-------------------------------------- - // Write Transaction - //-------------------------------------- - - // Register which locks the AW valid signal - logic lock_aw_valid_d, lock_aw_valid_q, load_aw_lock; - logic aw_valid, aw_ready; - - // AW ID counter - select_t lookup_aw_select; - logic aw_select_occupied, aw_id_cnt_full; - // Upon an ATOP load, inject IDs from the AW into the AR channel - logic atop_inject; - - // W select counter: stores the decision to which master W beats should go - select_t w_select, w_select_q; - logic w_select_valid; - id_cnt_t w_open; - logic w_cnt_up, w_cnt_down; - - // B channles input into the arbitration - logic [NoMstPorts-1:0] mst_b_valids, mst_b_readies; - - //-------------------------------------- - // Read Transaction - //-------------------------------------- - - // AR ID counter - select_t lookup_ar_select; - logic ar_select_occupied, ar_id_cnt_full; - logic ar_push; - - // Register which locks the AR valid signel - logic lock_ar_valid_d, lock_ar_valid_q, load_ar_lock; - logic ar_valid, ar_ready; - - logic [NoMstPorts-1:0] mst_r_valids, mst_r_readies; - - - - - - - - //-------------------------------------- - // Channel Control - //-------------------------------------- - //-------------------------------------- - - //-------------------------------------- - // AW Channel - //-------------------------------------- - - // Control of the AW handshake - always_comb begin - // AXI Handshakes - slv_resp_o.aw_ready = 1'b0; - aw_valid = 1'b0; - // `lock_aw_valid`, used to be protocol conform as it is not allowed to deassert - // a valid if there was no corresponding ready. As this process has to be able to inject - // an AXI ID into the counter of the AR channel on an ATOP, there could be a case where - // this process waits on `aw_ready` but in the mean time on the AR channel the counter gets - // full. - lock_aw_valid_d = lock_aw_valid_q; - load_aw_lock = 1'b0; - // AW ID counter and W FIFO - w_cnt_up = 1'b0; - // ATOP injection into ar counter - atop_inject = 1'b0; - // we had an arbitration decision, the valid is locked, wait for the transaction - if (lock_aw_valid_q) begin - aw_valid = 1'b1; - // transaction - if (aw_ready) begin - slv_resp_o.aw_ready = 1'b1; - lock_aw_valid_d = 1'b0; - load_aw_lock = 1'b1; - // inject the ATOP if necessary - atop_inject = slv_req_i.aw.atop[axi_pkg::ATOP_R_RESP] & AtopSupport; - end - end else begin - // An AW can be handled if `i_aw_id_counter` and `i_counter_open_w` are not full. An ATOP that - // requires an R response can be handled if additionally `i_ar_id_counter` is not full (this - // only applies if ATOPs are supported at all). - if (!aw_id_cnt_full && (w_open != {IdCounterWidth{1'b1}}) && - (!(ar_id_cnt_full && slv_req_i.aw.atop[axi_pkg::ATOP_R_RESP]) || - !AtopSupport)) begin - // There is a valid AW vector make the id lookup and go further, if it passes. - // Also stall if previous transmitted AWs still have active W's in flight. - // This prevents deadlocking of the W channel. The counters are there for the - // Handling of the B responses. - if (slv_req_i.aw_valid && - ((w_open == '0) || (w_select == slv_aw_select_i)) && - (!aw_select_occupied || (slv_aw_select_i == lookup_aw_select))) begin - // connect the handshake - aw_valid = 1'b1; - // push arbitration to the W FIFO regardless, do not wait for the AW transaction - w_cnt_up = 1'b1; - // on AW transaction - if (aw_ready) begin - slv_resp_o.aw_ready = 1'b1; - atop_inject = slv_req_i.aw.atop[axi_pkg::ATOP_R_RESP] & AtopSupport; - // no AW transaction this cycle, lock the decision - end else begin - lock_aw_valid_d = 1'b1; - load_aw_lock = 1'b1; - end - end - end - end - end - - // lock the valid signal, as the selection gets pushed into the W FIFO on first assertion, - // prevent further pushing - `FFL(lock_aw_valid_q, lock_aw_valid_d, load_aw_lock, '0, clk_i, rst_ni) - - if (UniqueIds) begin : gen_unique_ids_aw - // If the `UniqueIds` parameter is set, each write transaction has an ID that is unique among - // all in-flight write transactions, or all write transactions with a given ID target the same - // master port as all write transactions with the same ID, or both. This means that the - // signals that are driven by the ID counters if this parameter is not set can instead be - // derived from existing signals. The ID counters can therefore be omitted. - assign lookup_aw_select = slv_aw_select_i; - assign aw_select_occupied = 1'b0; - assign aw_id_cnt_full = 1'b0; - end else begin : gen_aw_id_counter - axi_demux_id_counters #( - .AxiIdBits ( AxiLookBits ), - .CounterWidth ( IdCounterWidth ), - .mst_port_select_t ( select_t ) - ) i_aw_id_counter ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .lookup_axi_id_i ( slv_req_i.aw.id[0+:AxiLookBits] ), - .lookup_mst_select_o ( lookup_aw_select ), - .lookup_mst_select_occupied_o ( aw_select_occupied ), - .full_o ( aw_id_cnt_full ), - .inject_axi_id_i ( '0 ), - .inject_i ( 1'b0 ), - .push_axi_id_i ( slv_req_i.aw.id[0+:AxiLookBits] ), - .push_mst_select_i ( slv_aw_select_i ), - .push_i ( w_cnt_up ), - .pop_axi_id_i ( slv_resp_o.b.id[0+:AxiLookBits] ), - .pop_i ( slv_resp_o.b_valid & slv_req_i.b_ready ), - .any_outstanding_trx_o ( ) - ); - // pop from ID counter on outward transaction - end - - // This counter steers the demultiplexer of the W channel. - // `w_select` determines, which handshaking is connected. - // AWs are only forwarded, if the counter is empty, or `w_select_q` is the same as - // `slv_aw_select_i`. - cc_counter #( - .Width ( IdCounterWidth ), - .StickyOverflow ( 1'b0 ) - ) i_counter_open_w ( - .clk_i, - .rst_ni, - .clr_i ( 1'b0 ), - .en_i ( w_cnt_up ^ w_cnt_down ), - .load_i ( 1'b0 ), - .down_i ( w_cnt_down ), - .d_i ( '0 ), - .q_o ( w_open ), - .overflow_o ( /*not used*/ ) - ); - - `FFL(w_select_q, slv_aw_select_i, w_cnt_up, select_t'(0), clk_i, rst_ni) - assign w_select = (|w_open) ? w_select_q : slv_aw_select_i; - assign w_select_valid = w_cnt_up | (|w_open); - - //-------------------------------------- - // W Channel - //-------------------------------------- - - //-------------------------------------- - // B Channel - //-------------------------------------- - logic [cc_pkg::idx_width(NoMstPorts)-1:0] b_idx; - - // Arbitration of the different B responses - cc_rr_arb_tree #( - .NumIn ( NoMstPorts ), - .data_t ( logic ), - .AxiVldRdy( 1'b1 ), - .LockIn ( 1'b1 ) - ) i_b_mux ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .clr_i ( 1'b0 ), - .rr_i ( '0 ), - .req_i ( mst_b_valids ), - .gnt_o ( mst_b_readies ), - .data_i ( '0 ), - .gnt_i ( slv_req_i.b_ready ), - .req_o ( slv_resp_o.b_valid ), - .data_o ( ), - .idx_o ( b_idx ) - ); - - always_comb begin - if (slv_resp_o.b_valid) begin - `AXI_SET_B_STRUCT(slv_resp_o.b, mst_resps_i[b_idx].b) - end else begin - slv_resp_o.b = '0; - end - end - - //-------------------------------------- - // AR Channel - //-------------------------------------- - - // control of the AR handshake - always_comb begin - // AXI Handshakes - slv_resp_o.ar_ready = 1'b0; - ar_valid = 1'b0; - // `lock_ar_valid`: Used to be protocol conform as it is not allowed to deassert `ar_valid` - // if there was no corresponding `ar_ready`. There is the possibility that an injection - // of a R response from an `atop` from the AW channel can change the occupied flag of the - // `i_ar_id_counter`, even if it was previously empty. This FF prevents the deassertion. - lock_ar_valid_d = lock_ar_valid_q; - load_ar_lock = 1'b0; - // AR id counter - ar_push = 1'b0; - // The process had an arbitration decision in a previous cycle, the valid is locked, - // wait for the AR transaction. - if (lock_ar_valid_q) begin - ar_valid = 1'b1; - // transaction - if (ar_ready) begin - slv_resp_o.ar_ready = 1'b1; - ar_push = 1'b1; - lock_ar_valid_d = 1'b0; - load_ar_lock = 1'b1; - end - end else begin - // The process can start handling AR transaction if `i_ar_id_counter` has space. - if (!ar_id_cnt_full) begin - // There is a valid AR, so look the ID up. - if (slv_req_i.ar_valid && (!ar_select_occupied || - (slv_ar_select_i == lookup_ar_select))) begin - // connect the AR handshake - ar_valid = 1'b1; - // on transaction - if (ar_ready) begin - slv_resp_o.ar_ready = 1'b1; - ar_push = 1'b1; - // no transaction this cycle, lock the valid decision! - end else begin - lock_ar_valid_d = 1'b1; - load_ar_lock = 1'b1; - end - end - end - end - end - - // this ff is needed so that ar does not get de-asserted if an atop gets injected - `FFL(lock_ar_valid_q, lock_ar_valid_d, load_ar_lock, '0, clk_i, rst_ni) - - if (UniqueIds) begin : gen_unique_ids_ar - // If the `UniqueIds` parameter is set, each read transaction has an ID that is unique among - // all in-flight read transactions, or all read transactions with a given ID target the same - // master port as all read transactions with the same ID, or both. This means that the - // signals that are driven by the ID counters if this parameter is not set can instead be - // derived from existing signals. The ID counters can therefore be omitted. - assign lookup_ar_select = slv_ar_select_i; - assign ar_select_occupied = 1'b0; - assign ar_id_cnt_full = 1'b0; - end else begin : gen_ar_id_counter - axi_demux_id_counters #( - .AxiIdBits ( AxiLookBits ), - .CounterWidth ( IdCounterWidth ), - .mst_port_select_t ( select_t ) - ) i_ar_id_counter ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .lookup_axi_id_i ( slv_req_i.ar.id[0+:AxiLookBits] ), - .lookup_mst_select_o ( lookup_ar_select ), - .lookup_mst_select_occupied_o ( ar_select_occupied ), - .full_o ( ar_id_cnt_full ), - .inject_axi_id_i ( slv_req_i.aw.id[0+:AxiLookBits] ), - .inject_i ( atop_inject ), - .push_axi_id_i ( slv_req_i.ar.id[0+:AxiLookBits] ), - .push_mst_select_i ( slv_ar_select_i ), - .push_i ( ar_push ), - .pop_axi_id_i ( slv_resp_o.r.id[0+:AxiLookBits] ), - .pop_i ( slv_resp_o.r_valid & slv_req_i.r_ready & slv_resp_o.r.last ), - .any_outstanding_trx_o ( ) - ); - end - - //-------------------------------------- - // R Channel - //-------------------------------------- - - logic [cc_pkg::idx_width(NoMstPorts)-1:0] r_idx; - - // Arbitration of the different r responses - cc_rr_arb_tree #( - .NumIn ( NoMstPorts ), - .data_t ( logic ), - .AxiVldRdy( 1'b1 ), - .LockIn ( 1'b1 ) - ) i_r_mux ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .clr_i ( 1'b0 ), - .rr_i ( '0 ), - .req_i ( mst_r_valids ), - .gnt_o ( mst_r_readies ), - .data_i ( '0 ), - .gnt_i ( slv_req_i.r_ready ), - .req_o ( slv_resp_o.r_valid ), - .data_o (), - .idx_o ( r_idx ) - ); - - always_comb begin - if (slv_resp_o.r_valid) begin - `AXI_SET_R_STRUCT(slv_resp_o.r, mst_resps_i[r_idx].r) - end else begin - slv_resp_o.r = '0; - end - end - - assign ar_ready = ar_valid & mst_resps_i[slv_ar_select_i].ar_ready; - assign aw_ready = aw_valid & mst_resps_i[slv_aw_select_i].aw_ready; - - // 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! - always_comb begin - // default assignments - mst_reqs_o = '0; - slv_resp_o.w_ready = 1'b0; - w_cnt_down = 1'b0; - - for (int unsigned i = 0; i < NoMstPorts; i++) begin - // AW channel - mst_reqs_o[i].aw = slv_req_i.aw; - mst_reqs_o[i].aw_valid = 1'b0; - if (aw_valid && (slv_aw_select_i == i)) begin - mst_reqs_o[i].aw_valid = 1'b1; - end - - // W channel - mst_reqs_o[i].w = slv_req_i.w; - mst_reqs_o[i].w_valid = 1'b0; - if (w_select_valid && (w_select == i)) begin - mst_reqs_o[i].w_valid = slv_req_i.w_valid; - slv_resp_o.w_ready = mst_resps_i[i].w_ready; - w_cnt_down = slv_req_i.w_valid & mst_resps_i[i].w_ready & slv_req_i.w.last; - end - - // B channel - mst_reqs_o[i].b_ready = mst_b_readies[i]; - - // AR channel - mst_reqs_o[i].ar = slv_req_i.ar; - mst_reqs_o[i].ar_valid = 1'b0; - if (ar_valid && (slv_ar_select_i == i)) begin - mst_reqs_o[i].ar_valid = 1'b1; - end - - // R channel - mst_reqs_o[i].r_ready = mst_r_readies[i]; - end - end - // unpack the response B and R channels for the arbitration - 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; - end - -// Validate parameters. -// pragma translate_off -`ifndef VERILATOR - initial begin: validate_params - no_mst_ports: assume (NoMstPorts > 0) else - $fatal(1, "The Number of slaves (NoMstPorts) has to be at least 1"); - AXI_ID_BITS: assume (AxiIdWidth >= AxiLookBits) else - $fatal(1, "AxiIdBits has to be equal or smaller than AxiIdWidth."); - end -`ifndef XSIM - default disable iff (!rst_ni); - 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.\ - NoMstPorts: %d", slv_aw_select_i, NoMstPorts); - ar_select: assume property( @(posedge clk_i) (slv_req_i.ar_valid |-> - (slv_ar_select_i < NoMstPorts))) else - $fatal(1, "slv_ar_select_i is %d: AR has selected a slave that is not defined.\ - NoMstPorts: %d", slv_ar_select_i, NoMstPorts); - aw_valid_stable: assert property( @(posedge clk_i) (aw_valid && !aw_ready) |=> aw_valid) else - $fatal(1, "aw_valid was deasserted, when aw_ready = 0 in last cycle."); - ar_valid_stable: assert property( @(posedge clk_i) - (ar_valid && !ar_ready) |=> ar_valid) else - $fatal(1, "ar_valid was deasserted, when ar_ready = 0 in last cycle."); - slv_aw_chan_stable: assert property( @(posedge clk_i) (aw_valid && !aw_ready) - |=> $stable(slv_req_i.aw)) else - $fatal(1, "slv_aw_chan unstable with valid set."); - slv_aw_select_stable: assert property( @(posedge clk_i) (aw_valid && !aw_ready) - |=> $stable(slv_aw_select_i)) else - $fatal(1, "slv_aw_select_i unstable with valid set."); - slv_ar_chan_stable: assert property( @(posedge clk_i) (ar_valid && !ar_ready) - |=> $stable(slv_req_i.ar)) else - $fatal(1, "slv_ar_chan unstable with valid set."); - slv_ar_select_stable: assert property( @(posedge clk_i) (ar_valid && !ar_ready) - |=> $stable(slv_ar_select_i)) else - $fatal(1, "slv_ar_select_i unstable with valid set."); - internal_ar_select: assert property( @(posedge clk_i) - (ar_valid |-> slv_ar_select_i < NoMstPorts)) - else $fatal(1, "slv_ar_select_i illegal while ar_valid."); - internal_aw_select: assert property( @(posedge clk_i) - (aw_valid |-> slv_aw_select_i < NoMstPorts)) - else $fatal(1, "slv_aw_select_i illegal while aw_valid."); - w_underflow: assert property( @(posedge clk_i) - ((w_open == '0) && (w_cnt_up ^ w_cnt_down) |-> !w_cnt_down)) else - $fatal(1, "W counter underflowed!"); - `ASSUME(NoAtopAllowed, !AtopSupport && slv_req_i.aw_valid |-> slv_req_i.aw.atop == '0) -`endif -`endif -// pragma translate_on - end endmodule diff --git a/src/axi_mcast_demux.sv b/src/axi_mcast_demux.sv index 9b570a55c..c4c1c662d 100644 --- a/src/axi_mcast_demux.sv +++ b/src/axi_mcast_demux.sv @@ -26,9 +26,9 @@ /// Demultiplex one AXI4+ATOP slave port to multiple AXI4+ATOP master ports. /// -/// The AW and AR slave channels each have a `select` input to determine to which master port the -/// current request is sent. The `select` can, for example, be driven by an address decoding module -/// to map address ranges to different AXI slaves. +/// The module internally decodes Ax requests, determining the master port route based on the +/// address of the request. To this end an address map, and additional inputs required by the +/// address decoding modules, are provided. /// /// ## Design overview /// @@ -41,39 +41,34 @@ /// Beats on the B and R channel are multiplexed from the master ports to the slave port with /// a round-robin arbitration tree. module axi_mcast_demux #( - parameter int unsigned AxiIdWidth = 32'd0, - parameter bit AtopSupport = 1'b1, - parameter type aw_addr_t = logic, - parameter type aw_chan_t = logic, - parameter type w_chan_t = logic, - parameter type b_chan_t = logic, - parameter type ar_chan_t = logic, - parameter type r_chan_t = logic, - parameter type axi_req_t = logic, - parameter type axi_resp_t = logic, - parameter int unsigned NoMstPorts = 32'd0, - parameter int unsigned MaxTrans = 32'd8, - parameter int unsigned AxiLookBits = 32'd3, - parameter bit UniqueIds = 1'b0, - parameter bit SpillAw = 1'b1, - parameter bit SpillW = 1'b0, - parameter bit SpillB = 1'b0, - parameter bit SpillAr = 1'b1, - parameter bit SpillR = 1'b0, - /// Connectivity vector - parameter bit [NoMstPorts-1:0] Connectivity = '1, - /// Collective operation connectivity - parameter bit [NoMstPorts-1:0] MulticastConnectivity = '1, - 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, - // Dependent parameters, DO NOT OVERRIDE! - parameter int unsigned IdxSelectWidth = (NoMstPorts > 32'd1) ? $clog2(NoMstPorts) : 32'd1, - parameter type idx_select_t = logic [IdxSelectWidth-1:0] + parameter int unsigned AxiIdWidth = 32'd0, + parameter int unsigned AxiAddrWidth = 32'd0, + parameter bit AtopSupport = 1'b1, + parameter type aw_chan_t = logic, + parameter type w_chan_t = logic, + parameter type b_chan_t = logic, + parameter type ar_chan_t = logic, + parameter type r_chan_t = logic, + parameter type axi_req_t = logic, + parameter type axi_resp_t = logic, + parameter int unsigned NoMstPorts = 32'd0, + parameter int unsigned MaxTrans = 32'd8, + parameter int unsigned AxiLookBits = 32'd3, + parameter bit UniqueIds = 1'b0, + parameter bit SpillAw = 1'b1, + parameter bit SpillW = 1'b0, + parameter bit SpillB = 1'b0, + parameter bit SpillAr = 1'b1, + parameter bit SpillR = 1'b0, + parameter bit [NoMstPorts-1:0] Connectivity = '1, + parameter bit [NoMstPorts-1:0] MulticastConnectivity = '1, + 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 ) ( - input logic clk_i, + input logic clk_i, input logic rst_ni, input logic test_i, // Addressing rules @@ -82,7 +77,6 @@ module axi_mcast_demux #( input rule_t default_mst_port_i, // Slave Port input axi_req_t slv_req_i, - input idx_select_t slv_ar_select_i, output axi_resp_t slv_resp_o, // Master Ports output axi_req_t [NoMstPorts-1:0] mst_reqs_o, @@ -91,13 +85,30 @@ module axi_mcast_demux #( output logic [NoMstPorts-1:0] mst_aw_commit_o ); - axi_req_t slv_req_cut; - axi_resp_t slv_resp_cut; + // Account for additional error slave + localparam int unsigned NoMstPortsExt = NoMstPorts + 1; + + localparam int unsigned IdxSelectWidth = cf_math_pkg::idx_width(NoMstPorts); + localparam int unsigned IdxSelectWidthExt = cf_math_pkg::idx_width(NoMstPortsExt); + typedef logic [IdxSelectWidth-1:0] idx_select_t; + typedef logic [IdxSelectWidthExt-1:0] idx_select_ext_t; + + typedef logic [NoMstPortsExt-1:0] mask_select_t; + + typedef logic [AxiAddrWidth-1:0] addr_t; - logic slv_ar_ready_chan, slv_ar_ready_sel; - logic slv_ar_valid_chan, slv_ar_valid_sel; + typedef struct packed { + int unsigned idx; + addr_t addr; + addr_t mask; + } mask_rule_t; - idx_select_t slv_ar_select; + // ---------------- + // Spill registers + // ---------------- + + axi_req_t slv_req_cut; + axi_resp_t slv_resp_cut; spill_register #( .T ( aw_chan_t ), @@ -132,29 +143,12 @@ module axi_mcast_demux #( .clk_i, .rst_ni, .valid_i ( slv_req_i.ar_valid ), - .ready_o ( slv_ar_ready_chan ), + .ready_o ( slv_resp_o.ar_ready ), .data_i ( slv_req_i.ar ), - .valid_o ( slv_ar_valid_chan ), + .valid_o ( slv_req_cut.ar_valid ), .ready_i ( slv_resp_cut.ar_ready ), .data_o ( slv_req_cut.ar ) ); - spill_register #( - .T ( idx_select_t ), - .Bypass ( ~SpillAr ) - ) i_ar_sel_spill_reg ( - .clk_i, - .rst_ni, - .valid_i ( slv_req_i.ar_valid ), - .ready_o ( slv_ar_ready_sel ), - .data_i ( slv_ar_select_i ), - .valid_o ( slv_ar_valid_sel ), - .ready_i ( slv_resp_cut.ar_ready ), - .data_o ( slv_ar_select ) - ); - - assign slv_resp_o.ar_ready = slv_ar_ready_chan & slv_ar_ready_sel; - assign slv_req_cut.ar_valid = slv_ar_valid_chan & slv_ar_valid_sel; - spill_register #( .T ( b_chan_t ), .Bypass ( ~SpillB ) @@ -182,38 +176,206 @@ module axi_mcast_demux #( .data_o ( slv_resp_o.r ) ); + // ----------------- + // AR address decoding + // ----------------- + + idx_select_t dec_ar_select_idx; + logic dec_ar_error; + idx_select_ext_t ar_select_idx; + + // Address decoding for unicast requests + addr_decode #( + .NoIndices (NoMstPorts), + .NoRules (NoAddrRules), + .addr_t (addr_t), + .rule_t (rule_t) + ) i_axi_ar_decode ( + .addr_i (slv_req_cut.ar.addr), + .addr_map_i (addr_map_i), + .idx_o (dec_ar_select_idx), + .dec_valid_o (), + .dec_error_o (dec_ar_error), + .en_default_idx_i (en_default_mst_port_i), + .default_idx_i (idx_select_t'(default_mst_port_i.idx)) + ); + + assign ar_select_idx = dec_ar_error ? NoMstPorts : idx_select_ext_t'(dec_ar_select_idx); + + // ----------------- + // AW address decoding + // ----------------- + + // AW decoder inputs + mask_rule_t [NoMulticastRules-1:0] multicast_rules; + mask_rule_t default_rule; + + // AW unicast decoder outputs + idx_select_t dec_aw_unicast_select_idx; + logic [NoMstPorts-1:0] dec_aw_unicast_select_mask; + logic dec_aw_unicast_valid; + logic dec_aw_unicast_error; + + // AW multicast decoder outputs + logic [NoMulticastPorts-1:0] dec_aw_multicast_select_mask; + addr_t [NoMulticastPorts-1:0] dec_aw_multicast_addr; + addr_t [NoMulticastPorts-1:0] dec_aw_multicast_mask; + logic dec_aw_multicast_valid; + logic dec_aw_multicast_error; + + // Decoding outputs (merged from unicast and multicast paths) + mask_select_t dec_aw_select_mask; + addr_t [NoMstPortsExt-1:0] dec_aw_addr; + addr_t [NoMstPortsExt-1:0] dec_aw_mask; + + // 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 + assign default_rule.idx = default_mst_port_i.idx; + assign default_rule.mask = default_mst_port_i.end_addr - default_mst_port_i.start_addr - 1; + assign default_rule.addr = default_mst_port_i.start_addr; + + // Address decoding for unicast requests + addr_decode #( + .NoIndices (NoMstPorts), + .NoRules (NoAddrRules), + .addr_t (addr_t), + .rule_t (rule_t) + ) i_axi_aw_unicast_decode ( + .addr_i (slv_req_cut.aw.addr), + .addr_map_i (addr_map_i), + .idx_o (dec_aw_unicast_select_idx), + .dec_valid_o (dec_aw_unicast_valid), + .dec_error_o (dec_aw_unicast_error), + .en_default_idx_i (en_default_mst_port_i), + .default_idx_i (idx_select_t'(default_mst_port_i.idx)) + ); + + // Generate the output mask from the index + assign dec_aw_unicast_select_mask = 1'b1 << dec_aw_unicast_select_idx; + + // Address decoding for multicast requests + if (NoMulticastRules > 0) begin : gen_multicast_decoding + multiaddr_decode #( + .NoIndices (NoMulticastPorts), + .NoRules (NoMulticastRules), + .addr_t (addr_t), + .rule_t (mask_rule_t) + ) i_axi_aw_multicast_decode ( + .addr_map_i (multicast_rules), + .addr_i (slv_req_cut.aw.addr), + .mask_i (slv_req_cut.aw.user.collective_mask), + .select_o (dec_aw_multicast_select_mask), + .addr_o (dec_aw_multicast_addr), + .mask_o (dec_aw_multicast_mask), + .dec_valid_o (dec_aw_multicast_valid), + .dec_error_o (dec_aw_multicast_error), + .en_default_idx_i (en_default_mst_port_i), + .default_idx_i (default_rule) + ); + end else begin : gen_no_multicast_decoding + assign dec_aw_multicast_select_mask = '0; + assign dec_aw_multicast_addr = '0; + assign dec_aw_multicast_mask = '0; + assign dec_aw_multicast_valid = '0; + assign dec_aw_multicast_error = '0; + end + + // If the address decoding doesn't produce any match, the request + // is routed to the error slave, which lies at the highest index. + mask_select_t select_error_slave; + assign select_error_slave = 1'b1 << NoMstPorts; + + // Mux the multicast and unicast decoding outputs + if (NoMulticastRules > 0) begin : gen_decoding_mux + always_comb begin + dec_aw_select_mask = '0; + dec_aw_addr = '0; + dec_aw_mask = '0; + + if (slv_req_cut.aw.user.collective_mask == '0) begin + dec_aw_addr = {'0, {NoMstPorts{slv_req_cut.aw.addr}}}; + if (dec_aw_unicast_error) begin + dec_aw_select_mask = select_error_slave; + end else begin + dec_aw_select_mask = dec_aw_unicast_select_mask & Connectivity; + end + end else begin + dec_aw_addr = {'0, {(NoMstPorts-NoMulticastPorts){slv_req_cut.aw.addr}}, dec_aw_multicast_addr}; + dec_aw_mask = {'0, dec_aw_multicast_mask}; + if (dec_aw_multicast_error) begin + dec_aw_select_mask = select_error_slave; + end else begin + dec_aw_select_mask = {'0, dec_aw_multicast_select_mask} & MulticastConnectivity; + end + end + end + end else begin + assign dec_aw_addr = {'0, {NoMstPorts{slv_req_cut.aw.addr}}}; + assign dec_aw_mask = '0; + assign dec_aw_select_mask = (dec_aw_unicast_error) ? select_error_slave : + (dec_aw_unicast_select_mask & Connectivity); + end + + // ----------------- + // Demux + // ----------------- + + axi_req_t errslv_req; + axi_resp_t errslv_resp; + logic errslv_is_mcast; + logic errslv_aw_commit; + axi_mcast_demux_simple #( - .AxiIdWidth ( AxiIdWidth ), - .AtopSupport( AtopSupport ), - .axi_req_t ( axi_req_t ), - .axi_resp_t ( axi_resp_t ), - .NoMstPorts ( NoMstPorts ), - .MaxTrans ( MaxTrans ), - .AxiLookBits( AxiLookBits ), - .UniqueIds ( UniqueIds ), - .Connectivity ( Connectivity ), - .MulticastConnectivity ( MulticastConnectivity ), - .aw_addr_t ( aw_addr_t ), - .b_chan_t ( b_chan_t ), - .rule_t ( rule_t ), - .NoAddrRules ( NoAddrRules ), - .NoMulticastRules ( NoMulticastRules ), - .NoMulticastPorts ( NoMulticastPorts ), - .MaxMcastTrans ( MaxMcastTrans ) - ) i_demux_simple ( + .AxiIdWidth ( AxiIdWidth ), + .AtopSupport ( AtopSupport ), + .axi_req_t ( axi_req_t ), + .axi_resp_t ( axi_resp_t ), + .NoMstPorts ( NoMstPortsExt ), + .MaxTrans ( MaxTrans ), + .AxiLookBits ( AxiLookBits ), + .UniqueIds ( UniqueIds ), + .aw_addr_t ( addr_t ), + .NoMulticastPorts ( NoMulticastPorts ), + .MaxMcastTrans ( MaxMcastTrans ) + ) i_mcast_demux_simple ( + .clk_i, + .rst_ni, + .test_i, + .slv_req_i ( slv_req_cut ), + .slv_aw_select_i ( dec_aw_select_mask ), + .slv_aw_addr_i ( dec_aw_addr ), + .slv_aw_mask_i ( dec_aw_mask ), + .slv_ar_select_i ( ar_select_idx ), + .slv_resp_o ( slv_resp_cut ), + .mst_reqs_o ( {errslv_req, mst_reqs_o} ), + .mst_resps_i ( {errslv_resp, mst_resps_i} ), + .mst_is_mcast_o ( {errslv_is_mcast, mst_is_mcast_o} ), + .mst_aw_commit_o ( {errslv_aw_commit, mst_aw_commit_o} ) + ); + + axi_err_slv #( + .AxiIdWidth ( AxiIdWidth ), + .axi_req_t ( axi_req_t ), + .axi_resp_t ( axi_resp_t ), + .Resp ( axi_pkg::RESP_DECERR ), + .ATOPs ( AtopSupport ), + // Transactions terminate at this slave, so minimize resource consumption by accepting + // only a few transactions at a time. + .MaxTrans ( 4 ) + ) i_axi_err_slv ( .clk_i, .rst_ni, .test_i, - .addr_map_i, - .en_default_mst_port_i, - .default_mst_port_i, - .slv_req_i ( slv_req_cut ), - .slv_ar_select_i ( slv_ar_select ), - .slv_resp_o ( slv_resp_cut ), - .mst_reqs_o ( mst_reqs_o ), - .mst_resps_i ( mst_resps_i ), - .mst_is_mcast_o, - .mst_aw_commit_o + .slv_req_i ( errslv_req ), + .slv_resp_o ( errslv_resp ) ); endmodule diff --git a/src/axi_mcast_demux_simple.sv b/src/axi_mcast_demux_simple.sv index f9d84586a..c88e00e05 100644 --- a/src/axi_mcast_demux_simple.sv +++ b/src/axi_mcast_demux_simple.sv @@ -42,37 +42,30 @@ /// Beats on the B and R channel are multiplexed from the master ports to the slave port with /// a round-robin arbitration tree. module axi_mcast_demux_simple #( - parameter int unsigned AxiIdWidth = 32'd0, - parameter bit AtopSupport = 1'b1, - parameter type axi_req_t = logic, - parameter type axi_resp_t = logic, - parameter int unsigned NoMstPorts = 32'd0, - parameter int unsigned MaxTrans = 32'd8, - parameter int unsigned AxiLookBits = 32'd3, - parameter bit UniqueIds = 1'b0, - parameter bit [NoMstPorts-1:0] Connectivity = '1, - parameter bit [NoMstPorts-1:0] MulticastConnectivity = '1, - parameter type aw_addr_t = logic, - parameter type b_chan_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, - parameter int unsigned MaxMcastTrans = 32'd7, + parameter int unsigned AxiIdWidth = 32'd0, + parameter bit AtopSupport = 1'b1, + parameter type axi_req_t = logic, + parameter type axi_resp_t = logic, + parameter int unsigned NoMstPorts = 32'd0, + parameter int unsigned MaxTrans = 32'd8, + parameter int unsigned AxiLookBits = 32'd3, + parameter bit UniqueIds = 1'b0, + parameter type aw_addr_t = logic, + parameter int unsigned NoMulticastPorts = 32'd0, + parameter int unsigned MaxMcastTrans = 32'd7, // Dependent parameters, DO NOT OVERRIDE! - parameter int unsigned IdxSelectWidth = (NoMstPorts > 32'd1) ? $clog2(NoMstPorts) : 32'd1, - parameter type idx_select_t = logic [IdxSelectWidth-1:0], - parameter type mask_select_t = logic [NoMstPorts-1:0] + parameter int unsigned IdxSelectWidth = (NoMstPorts > 32'd1) ? $clog2(NoMstPorts) : 32'd1, + 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, - // Addressing rules - input rule_t [NoAddrRules-1:0] addr_map_i, - input logic en_default_mst_port_i, - input rule_t default_mst_port_i, // Slave Port input axi_req_t slv_req_i, + input mask_select_t slv_aw_select_i, + input aw_addr_t [NoMstPorts-1:0] slv_aw_addr_i, + input aw_addr_t [NoMstPorts-1:0] slv_aw_mask_i, input idx_select_t slv_ar_select_i, output axi_resp_t slv_resp_o, // Master Ports @@ -88,12 +81,6 @@ module axi_mcast_demux_simple #( localparam int unsigned McastCounterWidth = (MaxMcastTrans > 32'd1) ? $clog2(MaxMcastTrans+1) : 32'd1; typedef logic [McastCounterWidth-1:0] mcast_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 `AXI_ASSIGN_REQ_STRUCT(mst_reqs_o[0], slv_req_i) @@ -110,27 +97,7 @@ module axi_mcast_demux_simple #( // Write Transaction //-------------------------------------- - // AW decoder inputs - mask_rule_t [NoMulticastRules-1:0] multicast_rules; - mask_rule_t default_rule; - - // AW unicast decoder outputs - idx_select_t dec_aw_unicast_select_idx; - logic [NoMstPorts-1:0] dec_aw_unicast_select_mask; - logic dec_aw_unicast_valid; - logic dec_aw_unicast_error; - - // AW multicast decoder outputs - logic [NoMulticastPorts-1:0] dec_aw_multicast_select_mask; - aw_addr_t [NoMulticastPorts-1:0] dec_aw_multicast_addr; - aw_addr_t [NoMulticastPorts-1:0] dec_aw_multicast_mask; - logic dec_aw_multicast_valid; - logic dec_aw_multicast_error; - - // Merged AW unicast and multicast decoder outputs - aw_addr_t [NoMstPorts-1:0] slv_aw_addr; - aw_addr_t [NoMstPorts-1:0] slv_aw_mask; - mask_select_t slv_aw_select_mask; + // Index-form AW select signal for unicast requests idx_select_t slv_aw_select; // AW channel to slave ports @@ -173,7 +140,6 @@ module axi_mcast_demux_simple #( // B channel to spill register logic slv_b_valid_arb, slv_b_valid_join; - b_chan_t slv_b_chan_join; //-------------------------------------- // Read Transaction @@ -205,95 +171,6 @@ module axi_mcast_demux_simple #( // AW Channel //-------------------------------------- - // 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 - assign default_rule.idx = default_mst_port_i.idx; - assign default_rule.mask = default_mst_port_i.end_addr - default_mst_port_i.start_addr - 1; - assign default_rule.addr = default_mst_port_i.start_addr; - - // Address decoding for unicast requests - addr_decode #( - .NoIndices (NoMstPorts), - .NoRules (NoAddrRules), - .addr_t (aw_addr_t), - .rule_t (rule_t) - ) i_axi_aw_idx_unicast_decode ( - .addr_i (slv_req_i.aw.addr), - .addr_map_i (addr_map_i), - .idx_o (dec_aw_unicast_select_idx), - .dec_valid_o (dec_aw_unicast_valid), - .dec_error_o (dec_aw_unicast_error), - .en_default_idx_i (en_default_mst_port_i), - .default_idx_i (idx_select_t'(default_mst_port_i.idx)) - ); - - // Generate the output mask from the index - assign dec_aw_unicast_select_mask = (1'b1 << dec_aw_unicast_select_idx); - - // Address decoding for multicast requests - if (NoMulticastRules > 0) begin : gen_multicast_decoding - multiaddr_decode #( - .NoIndices (NoMulticastPorts), - .NoRules (NoMulticastRules), - .addr_t (aw_addr_t), - .rule_t (mask_rule_t) - ) i_axi_aw_multicast_decode ( - .addr_map_i (multicast_rules), - .addr_i (slv_req_i.aw.addr), - .mask_i (slv_req_i.aw.user.collective_mask), - .select_o (dec_aw_multicast_select_mask), - .addr_o (dec_aw_multicast_addr), - .mask_o (dec_aw_multicast_mask), - .dec_valid_o (dec_aw_multicast_valid), - .dec_error_o (dec_aw_multicast_error), - .en_default_idx_i (en_default_mst_port_i), - .default_idx_i (default_rule) - ); - end else begin : gen_no_multicast_decoding - assign dec_aw_multicast_select_mask = '0; - assign dec_aw_multicast_addr = '0; - assign dec_aw_multicast_mask = '0; - assign dec_aw_multicast_valid = '0; - assign dec_aw_multicast_error = '0; - end - - // If the address decoding doesn't produce any match, the request - // is routed to the error slave, which lies at the highest index. - mask_select_t select_error_slave; - assign select_error_slave = 1'b1 << (NoMstPorts - 1); - - // Mux the multicast and unicast decoding outputs - always_comb begin - slv_aw_select_mask = '0; - slv_aw_addr = '0; - slv_aw_mask = '0; - - if (slv_req_i.aw.user.collective_mask == '0) begin - slv_aw_addr = {NoMstPorts{slv_req_i.aw.addr}}; - if (dec_aw_unicast_error) begin - slv_aw_select_mask = select_error_slave; - end else begin - slv_aw_select_mask = dec_aw_unicast_select_mask & Connectivity; - end - end else begin - slv_aw_addr = {'0, {(NoMstPorts-NoMulticastPorts){slv_req_i.aw.addr}}, dec_aw_multicast_addr}; - slv_aw_mask = {'0, dec_aw_multicast_mask}; - if (dec_aw_multicast_error) begin - slv_aw_select_mask = select_error_slave; - end else begin - slv_aw_select_mask = {'0, dec_aw_multicast_select_mask} & MulticastConnectivity; - end - end - end - // Control of the AW handshake always_comb begin // AXI Handshakes @@ -333,7 +210,7 @@ module axi_mcast_demux_simple #( // This prevents deadlocking of the W channel. The counters are there for the // Handling of the B responses. if (slv_req_i.aw_valid && - ((w_open == '0) || (w_select == slv_aw_select_mask)) && + ((w_open == '0) || (w_select == slv_aw_select_i)) && (!aw_select_occupied || (slv_aw_select == lookup_aw_select)) && !multicast_stall) begin // connect the handshake @@ -370,13 +247,13 @@ module axi_mcast_demux_simple #( onehot_to_bin #( .ONEHOT_WIDTH(NoMstPorts) ) i_onehot_to_bin ( - .onehot(slv_aw_select_mask & {NoMstPorts{!aw_is_multicast}}), + .onehot(slv_aw_select_i & {NoMstPorts{!aw_is_multicast}}), .bin (slv_aw_select) ); // Popcount to identify multicast requests popcount #(NoMstPorts) i_aw_select_popcount ( - .data_i (slv_aw_select_mask), + .data_i (slv_aw_select_i), .popcount_o(aw_select_popcount) ); @@ -403,7 +280,7 @@ module axi_mcast_demux_simple #( // additional select signals. assign aw_is_multicast = aw_select_popcount > 1; assign outstanding_multicast = outstanding_mcast_cnt_q != '0; - assign multicast_stall = (outstanding_multicast && (slv_aw_select_mask != multicast_select_q)) || + assign multicast_stall = (outstanding_multicast && (slv_aw_select_i != multicast_select_q)) || (aw_is_multicast && aw_any_outstanding_unicast_trx) || (outstanding_mcast_cnt_q == MaxMcastTrans); // We can send this signal to all slaves since we will only have one outstanding aw @@ -424,8 +301,8 @@ module axi_mcast_demux_simple #( // For the same reason the right hand side uses outstanding_mcast_cnt_d // instead of outstanding_mcast_cnt_q if (aw_is_multicast && aw_valid && aw_ready) begin - outstanding_mcast_cnt_d = outstanding_mcast_cnt_d + (|slv_aw_select_mask); - multicast_select_d = slv_aw_select_mask; + outstanding_mcast_cnt_d = outstanding_mcast_cnt_d + (|slv_aw_select_i); + multicast_select_d = slv_aw_select_i; end if (outstanding_multicast && slv_resp_o.b_valid && slv_req_i.b_ready) begin outstanding_mcast_cnt_d = outstanding_mcast_cnt_d - 1; @@ -468,11 +345,12 @@ module axi_mcast_demux_simple #( // handshake can now actually take place. // Using commit, instead of valid, to this end ensures that we don't have // any combinational loops. - assign mst_aw_valids = {NoMstPorts{aw_valid}} & slv_aw_select_mask; - assign accept_aw = &((mst_aw_valids & mst_aw_readies) | ~slv_aw_select_mask); + assign mst_aw_valids = {NoMstPorts{aw_valid}} & slv_aw_select_i; + assign accept_aw = &((mst_aw_valids & mst_aw_readies) | ~slv_aw_select_i); assign aw_ready = aw_is_multicast ? mcast_aw_hs_in_progress : accept_aw; - assign mst_aw_commit_o = {NoMstPorts{mcast_aw_hs_in_progress}} & slv_aw_select_mask; + assign mst_aw_commit_o = {NoMstPorts{mcast_aw_hs_in_progress}} & slv_aw_select_i; + // If multicast is enabled, we need to count the number of outstanding transactions if (UniqueIds) begin : gen_unique_ids_aw // If the `UniqueIds` parameter is set, each write transaction has an ID that is unique among // all in-flight write transactions, or all write transactions with a given ID target the same @@ -481,32 +359,12 @@ module axi_mcast_demux_simple #( // derived from existing signals. The ID counters can therefore be omitted. assign lookup_aw_select = slv_aw_select; assign aw_select_occupied = 1'b0; - - // We still need a (single) counter to keep track of any outstanding transactions - axi_mcast_demux_id_counters #( - .AxiIdBits ( 0 ), - .CounterWidth ( IdCounterWidth ), - .mst_port_select_t ( idx_select_t ) - ) i_aw_id_counter ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .lookup_axi_id_i ( '0 ), - .lookup_mst_select_o ( /* Not used */ ), - .lookup_mst_select_occupied_o ( /* Not used */ ), - .full_o ( aw_id_cnt_full ), - .inject_axi_id_i ( '0 ), - .inject_i ( 1'b0 ), - .push_axi_id_i ( '0 ), - .push_mst_select_i ( '0 ), - .push_i ( w_cnt_up && !aw_is_multicast ), - .pop_axi_id_i ( '0 ), - .pop_i ( slv_resp_o.b_valid & slv_req_i.b_ready & ~outstanding_multicast ), - .any_outstanding_trx_o ( aw_any_outstanding_unicast_trx ) - ); + assign aw_id_cnt_full = 1'b0; + assign aw_any_outstanding_unicast_trx = 1'b0; end else begin : gen_aw_id_counter - axi_mcast_demux_id_counters #( + axi_demux_id_counters #( .AxiIdBits ( AxiLookBits ), .CounterWidth ( IdCounterWidth ), .mst_port_select_t ( idx_select_t ) @@ -532,7 +390,7 @@ module axi_mcast_demux_simple #( // This counter steers the demultiplexer of the W channel. // `w_select` determines, which handshaking is connected. // AWs are only forwarded, if the counter is empty, or `w_select_q` is the same as - // `slv_aw_select`. + // `slv_aw_select_i`. counter #( .WIDTH ( IdCounterWidth ), .STICKY_OVERFLOW ( 1'b0 ) @@ -548,8 +406,8 @@ module axi_mcast_demux_simple #( .overflow_o ( /*not used*/ ) ); - `FFLARN(w_select_q, slv_aw_select_mask, w_cnt_up, mask_select_t'(0), clk_i, rst_ni) - assign w_select = (|w_open) ? w_select_q : slv_aw_select_mask; + `FFLARN(w_select_q, slv_aw_select_i, w_cnt_up, mask_select_t'(0), clk_i, rst_ni) + assign w_select = (|w_open) ? w_select_q : slv_aw_select_i; assign w_select_valid = w_cnt_up | (|w_open); assign w_cnt_down = slv_req_i.w_valid & slv_resp_o.w_ready & slv_req_i.w.last; @@ -610,6 +468,11 @@ module axi_mcast_demux_simple #( for (genvar i=0; i= AxiLookBits) else $fatal(1, "AxiIdBits has to be equal or smaller than AxiIdWidth."); - aw_addr_bits: assume ($bits(slv_aw_addr[0]) == $bits(slv_req_i.aw.addr)) else - $fatal(1, "aw_addr_t must be the type of slv_req_i.aw.addr"); + no_multicast_ports: assume (NoMstPorts >= NoMulticastPorts) else + $fatal(1, "NoMstPorts needs to be >= NoMulticastPorts."); + unique_ids_multicast: assume (!UniqueIds || (NoMulticastPorts == 0)) else + $fatal(1, "UniqueIds not supported when multicast is enabled (NoMulticastPorts > 0)."); end default disable iff (!rst_ni); ar_select: assume property( @(posedge clk_i) (slv_req_i.ar_valid |-> @@ -829,8 +717,8 @@ module axi_mcast_demux_simple #( |=> $stable(slv_req_i.aw)) else $fatal(1, "slv_aw_chan unstable with valid set."); slv_aw_select_stable: assert property( @(posedge clk_i) (aw_valid && !aw_ready) - |=> $stable(slv_aw_select)) else - $fatal(1, "slv_aw_select unstable with valid set."); + |=> $stable(slv_aw_select_i)) else + $fatal(1, "slv_aw_select_i unstable with valid set."); slv_ar_chan_stable: assert property( @(posedge clk_i) (ar_valid && !ar_ready) |=> $stable(slv_req_i.ar)) else $fatal(1, "slv_ar_chan unstable with valid set."); @@ -849,133 +737,3 @@ module axi_mcast_demux_simple #( // pragma translate_on end endmodule - - -module axi_mcast_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 logic clk_i, // Clock - input logic 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, - // outstanding transactions - output logic any_outstanding_trx_o -); - 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; - //----------------------------------- - // Status - //----------------------------------- - assign any_outstanding_trx_o = |occupied; - - // 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 - diff --git a/src/axi_mcast_xbar_unmuxed.sv b/src/axi_mcast_xbar_unmuxed.sv index 3a0ba02b7..49e81d726 100644 --- a/src/axi_mcast_xbar_unmuxed.sv +++ b/src/axi_mcast_xbar_unmuxed.sv @@ -53,78 +53,46 @@ import cf_math_pkg::idx_width; parameter type rule_t = axi_pkg::xbar_rule_64_t ) ( /// Clock, positive edge triggered. - input logic clk_i, + input logic clk_i, /// Asynchronous reset, active low. - input logic rst_ni, + input logic rst_ni, /// Testmode enable, active high. - input logic test_i, + input logic test_i, /// AXI4+ATOP requests to the slave ports. - input req_t [Cfg.NoSlvPorts-1:0] slv_ports_req_i, + input req_t [Cfg.NoSlvPorts-1:0] slv_ports_req_i, /// AXI4+ATOP responses of the slave ports. - output resp_t [Cfg.NoSlvPorts-1:0] slv_ports_resp_o, + output resp_t [Cfg.NoSlvPorts-1:0] slv_ports_resp_o, /// AXI4+ATOP requests of the master ports. - output req_t [Cfg.NoMstPorts-1:0][Cfg.NoSlvPorts-1:0] mst_ports_req_o, + output req_t [Cfg.NoMstPorts-1:0][Cfg.NoSlvPorts-1:0] mst_ports_req_o, /// AXI4+ATOP responses to the master ports. - input resp_t [Cfg.NoMstPorts-1:0][Cfg.NoSlvPorts-1:0] mst_ports_resp_i, + input resp_t [Cfg.NoMstPorts-1:0][Cfg.NoSlvPorts-1:0] mst_ports_resp_i, /// Additional multicast signals to the master ports. - output logic [Cfg.NoMstPorts-1:0][Cfg.NoSlvPorts-1:0] mst_is_mcast_o, - output logic [Cfg.NoMstPorts-1:0][Cfg.NoSlvPorts-1:0] mst_aw_commit_o, + output logic [Cfg.NoMstPorts-1:0][Cfg.NoSlvPorts-1:0] mst_is_mcast_o, + output logic [Cfg.NoMstPorts-1:0][Cfg.NoSlvPorts-1:0] mst_aw_commit_o, /// 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. /// Each master port can have multiple different rules. - input rule_t [Cfg.NoAddrRules-1:0] 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, + input logic [Cfg.NoSlvPorts-1:0] en_default_mst_port_i, /// 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 rule_t [Cfg.NoSlvPorts-1:0] default_mst_port_i + input rule_t [Cfg.NoSlvPorts-1:0] default_mst_port_i ); - // Address type for individual address signals - typedef logic [Cfg.AxiAddrWidth-1:0] addr_t; - // to account for the decoding error slave - localparam int unsigned MstPortsIdxWidthOne = - (Cfg.NoMstPorts == 32'd1) ? 32'd1 : unsigned'($clog2(Cfg.NoMstPorts + 1)); - localparam int unsigned MstPortsIdxWidth = - (Cfg.NoMstPorts == 32'd1) ? 32'd1 : unsigned'($clog2(Cfg.NoMstPorts)); - typedef logic [MstPortsIdxWidthOne-1:0] mst_port_idx_t; - typedef logic [MstPortsIdxWidth-1:0] mst_port_idx_m1_t; - - // signals from the axi_demuxes, one index more for decode error - req_t [Cfg.NoSlvPorts-1:0][Cfg.NoMstPorts:0] slv_reqs; - resp_t [Cfg.NoSlvPorts-1:0][Cfg.NoMstPorts:0] slv_resps; - - logic [Cfg.NoSlvPorts-1:0][Cfg.NoMstPorts:0] slv_is_mcast; - logic [Cfg.NoSlvPorts-1:0][Cfg.NoMstPorts:0] slv_aw_commit; - - // workaround for issue #133 (problem with vsim 10.6c) - localparam int unsigned cfg_NoMstPorts = Cfg.NoMstPorts; + // signals from the axi_demuxes + req_t [Cfg.NoSlvPorts-1:0][Cfg.NoMstPorts-1:0] slv_reqs; + resp_t [Cfg.NoSlvPorts-1:0][Cfg.NoMstPorts-1:0] slv_resps; + logic [Cfg.NoSlvPorts-1:0][Cfg.NoMstPorts-1:0] slv_is_mcast; + logic [Cfg.NoSlvPorts-1:0][Cfg.NoMstPorts-1:0] slv_aw_commit; for (genvar i = 0; i < Cfg.NoSlvPorts; i++) begin : gen_slv_port_demux - mst_port_idx_m1_t dec_ar_select; - logic dec_ar_valid, dec_ar_error; - mst_port_idx_t slv_ar_select; - - addr_decode #( - .NoIndices ( Cfg.NoMstPorts ), - .addr_t ( addr_t ), - .NoRules ( Cfg.NoAddrRules ), - .rule_t ( rule_t ) - ) i_axi_ar_decode ( - .addr_i ( slv_ports_req_i[i].ar.addr ), - .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 ( en_default_mst_port_i[i] ), - .default_idx_i ( mst_port_idx_m1_t'(default_mst_port_i[i].idx) ) - ); - assign slv_ar_select = (dec_ar_error) ? - mst_port_idx_t'(Cfg.NoMstPorts) : mst_port_idx_t'(dec_ar_select); // make sure that the default slave does not get changed, if there is an unserved Ax // pragma translate_off + // TODO(colluca): is this still the right place for these? and are they still correct after + // moving the address decoders past the spill registers `ifndef VERILATOR `ifndef XSIM default disable iff (~rst_ni); @@ -154,8 +122,8 @@ import cf_math_pkg::idx_width; axi_mcast_demux #( .AxiIdWidth ( Cfg.AxiIdWidthSlvPorts ), // ID Width + .AxiAddrWidth ( Cfg.AxiAddrWidth ), .AtopSupport ( ATOPs ), - .aw_addr_t ( addr_t ), // AW Address Type .aw_chan_t ( aw_chan_t ), // AW Channel Type .w_chan_t ( w_chan_t ), // W Channel Type .b_chan_t ( b_chan_t ), // B Channel Type @@ -163,7 +131,7 @@ import cf_math_pkg::idx_width; .r_chan_t ( r_chan_t ), // R Channel Type .axi_req_t ( req_t ), .axi_resp_t ( resp_t ), - .NoMstPorts ( Cfg.NoMstPorts + 1 ), + .NoMstPorts ( Cfg.NoMstPorts ), .MaxTrans ( Cfg.MaxMstTrans ), .AxiLookBits ( Cfg.AxiIdUsedSlvPorts ), .UniqueIds ( Cfg.UniqueIds ), @@ -186,7 +154,6 @@ import cf_math_pkg::idx_width; .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] ), .mst_reqs_o ( slv_reqs[i] ), .mst_resps_i ( slv_resps[i] ), @@ -194,23 +161,6 @@ import cf_math_pkg::idx_width; .mst_aw_commit_o ( slv_aw_commit[i] ) ); - axi_err_slv #( - .AxiIdWidth ( Cfg.AxiIdWidthSlvPorts ), - .axi_req_t ( req_t ), - .axi_resp_t ( resp_t ), - .Resp ( axi_pkg::RESP_DECERR ), - .ATOPs ( ATOPs ), - .MaxTrans ( 4 ) // Transactions terminate at this slave, so minimize - // resource consumption by accepting only a few - // transactions at a time. - ) i_axi_err_slv ( - .clk_i, // Clock - .rst_ni, // Asynchronous reset active low - .test_i, // Testmode enable - // slave port - .slv_req_i ( slv_reqs[i][Cfg.NoMstPorts] ), - .slv_resp_o ( slv_resps[i][cfg_NoMstPorts] ) - ); end // cross all channels diff --git a/src/axi_mux.sv b/src/axi_mux.sv index f194b9cb1..85f3561a3 100644 --- a/src/axi_mux.sv +++ b/src/axi_mux.sv @@ -64,443 +64,41 @@ module axi_mux #( input mst_resp_t mst_resp_i ); - localparam int unsigned MstIdxBits = $clog2(NoSlvPorts); - localparam int unsigned MstAxiIDWidth = SlvAxiIDWidth + MstIdxBits; - - // pass through if only one slave port - if (NoSlvPorts == 32'h1) begin : gen_no_mux - cc_spill_register #( - .data_t ( mst_aw_chan_t ), - .Bypass ( ~SpillAw ) - ) i_aw_spill_reg ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .clr_i ( 1'b0 ), - .valid_i ( slv_reqs_i[0].aw_valid ), - .ready_o ( slv_resps_o[0].aw_ready ), - .data_i ( slv_reqs_i[0].aw ), - .valid_o ( mst_req_o.aw_valid ), - .ready_i ( mst_resp_i.aw_ready ), - .data_o ( mst_req_o.aw ) - ); - cc_spill_register #( - .data_t ( w_chan_t ), - .Bypass ( ~SpillW ) - ) i_w_spill_reg ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .clr_i ( 1'b0 ), - .valid_i ( slv_reqs_i[0].w_valid ), - .ready_o ( slv_resps_o[0].w_ready ), - .data_i ( slv_reqs_i[0].w ), - .valid_o ( mst_req_o.w_valid ), - .ready_i ( mst_resp_i.w_ready ), - .data_o ( mst_req_o.w ) - ); - cc_spill_register #( - .data_t ( mst_b_chan_t ), - .Bypass ( ~SpillB ) - ) i_b_spill_reg ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .clr_i ( 1'b0 ), - .valid_i ( mst_resp_i.b_valid ), - .ready_o ( mst_req_o.b_ready ), - .data_i ( mst_resp_i.b ), - .valid_o ( slv_resps_o[0].b_valid ), - .ready_i ( slv_reqs_i[0].b_ready ), - .data_o ( slv_resps_o[0].b ) - ); - cc_spill_register #( - .data_t ( mst_ar_chan_t ), - .Bypass ( ~SpillAr ) - ) i_ar_spill_reg ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .clr_i ( 1'b0 ), - .valid_i ( slv_reqs_i[0].ar_valid ), - .ready_o ( slv_resps_o[0].ar_ready ), - .data_i ( slv_reqs_i[0].ar ), - .valid_o ( mst_req_o.ar_valid ), - .ready_i ( mst_resp_i.ar_ready ), - .data_o ( mst_req_o.ar ) - ); - cc_spill_register #( - .data_t ( mst_r_chan_t ), - .Bypass ( ~SpillR ) - ) i_r_spill_reg ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .clr_i ( 1'b0 ), - .valid_i ( mst_resp_i.r_valid ), - .ready_o ( mst_req_o.r_ready ), - .data_i ( mst_resp_i.r ), - .valid_o ( slv_resps_o[0].r_valid ), - .ready_i ( slv_reqs_i[0].r_ready ), - .data_o ( slv_resps_o[0].r ) - ); -// Validate parameters. -// pragma translate_off - `ASSERT_INIT(CorrectIdWidthSlvAw, $bits(slv_reqs_i[0].aw.id) == SlvAxiIDWidth) - `ASSERT_INIT(CorrectIdWidthSlvB, $bits(slv_resps_o[0].b.id) == SlvAxiIDWidth) - `ASSERT_INIT(CorrectIdWidthSlvAr, $bits(slv_reqs_i[0].ar.id) == SlvAxiIDWidth) - `ASSERT_INIT(CorrectIdWidthSlvR, $bits(slv_resps_o[0].r.id) == SlvAxiIDWidth) - `ASSERT_INIT(CorrectIdWidthMstAw, $bits(mst_req_o.aw.id) == SlvAxiIDWidth) - `ASSERT_INIT(CorrectIdWidthMstB, $bits(mst_resp_i.b.id) == SlvAxiIDWidth) - `ASSERT_INIT(CorrectIdWidthMstAr, $bits(mst_req_o.ar.id) == SlvAxiIDWidth) - `ASSERT_INIT(CorrectIdWidthMstR, $bits(mst_resp_i.r.id) == SlvAxiIDWidth) -// pragma translate_on - - // other non degenerate cases - end else begin : gen_mux - - typedef logic [MstIdxBits-1:0] switch_id_t; - - // AXI channels between the ID prepend unit and the rest of the multiplexer - mst_aw_chan_t [NoSlvPorts-1:0] slv_aw_chans; - logic [NoSlvPorts-1:0] slv_aw_valids, slv_aw_readies; - w_chan_t [NoSlvPorts-1:0] slv_w_chans; - logic [NoSlvPorts-1:0] slv_w_valids, slv_w_readies; - mst_b_chan_t [NoSlvPorts-1:0] slv_b_chans; - logic [NoSlvPorts-1:0] slv_b_valids, slv_b_readies; - mst_ar_chan_t [NoSlvPorts-1:0] slv_ar_chans; - logic [NoSlvPorts-1:0] slv_ar_valids, slv_ar_readies; - mst_r_chan_t [NoSlvPorts-1:0] slv_r_chans; - logic [NoSlvPorts-1:0] slv_r_valids, slv_r_readies; - - // These signals are all ID prepended - // AW channel - mst_aw_chan_t mst_aw_chan; - logic mst_aw_valid, mst_aw_ready; - - // AW master handshake internal, so that we are able to stall, if w_fifo is full - logic aw_valid, aw_ready; - - // FF to lock the AW valid signal, when a new arbitration decision is made the decision - // gets pushed into the W FIFO, when it now stalls prevent subsequent pushing - // This FF removes AW to W dependency - logic lock_aw_valid_d, lock_aw_valid_q; - logic load_aw_lock; - - // signals for the FIFO that holds the last switching decision of the AW channel - logic w_fifo_full, w_fifo_empty; - logic w_fifo_push, w_fifo_pop; - switch_id_t w_fifo_data; - - // W channel spill reg - w_chan_t mst_w_chan; - logic mst_w_valid, mst_w_ready; - - // master ID in the b_id - switch_id_t switch_b_id; - - // B channel spill reg - mst_b_chan_t mst_b_chan; - logic mst_b_valid; - - // AR channel for when spill is enabled - mst_ar_chan_t mst_ar_chan; - logic ar_valid, ar_ready; - - // master ID in the r_id - switch_id_t switch_r_id; - - // R channel spill reg - mst_r_chan_t mst_r_chan; - logic mst_r_valid; - - //-------------------------------------- - // ID prepend for all slave ports - //-------------------------------------- - for (genvar i = 0; i < NoSlvPorts; i++) begin : gen_id_prepend - axi_id_prepend #( - .NoBus ( 32'd1 ), // one AXI bus per slave port - .AxiIdWidthSlvPort( SlvAxiIDWidth ), - .AxiIdWidthMstPort( MstAxiIDWidth ), - .slv_aw_chan_t ( slv_aw_chan_t ), - .slv_w_chan_t ( w_chan_t ), - .slv_b_chan_t ( slv_b_chan_t ), - .slv_ar_chan_t ( slv_ar_chan_t ), - .slv_r_chan_t ( slv_r_chan_t ), - .mst_aw_chan_t ( mst_aw_chan_t ), - .mst_w_chan_t ( w_chan_t ), - .mst_b_chan_t ( mst_b_chan_t ), - .mst_ar_chan_t ( mst_ar_chan_t ), - .mst_r_chan_t ( mst_r_chan_t ) - ) i_id_prepend ( - .pre_id_i ( switch_id_t'(i) ), - .slv_aw_chans_i ( slv_reqs_i[i].aw ), - .slv_aw_valids_i ( slv_reqs_i[i].aw_valid ), - .slv_aw_readies_o ( slv_resps_o[i].aw_ready ), - .slv_w_chans_i ( slv_reqs_i[i].w ), - .slv_w_valids_i ( slv_reqs_i[i].w_valid ), - .slv_w_readies_o ( slv_resps_o[i].w_ready ), - .slv_b_chans_o ( slv_resps_o[i].b ), - .slv_b_valids_o ( slv_resps_o[i].b_valid ), - .slv_b_readies_i ( slv_reqs_i[i].b_ready ), - .slv_ar_chans_i ( slv_reqs_i[i].ar ), - .slv_ar_valids_i ( slv_reqs_i[i].ar_valid ), - .slv_ar_readies_o ( slv_resps_o[i].ar_ready ), - .slv_r_chans_o ( slv_resps_o[i].r ), - .slv_r_valids_o ( slv_resps_o[i].r_valid ), - .slv_r_readies_i ( slv_reqs_i[i].r_ready ), - .mst_aw_chans_o ( slv_aw_chans[i] ), - .mst_aw_valids_o ( slv_aw_valids[i] ), - .mst_aw_readies_i ( slv_aw_readies[i] ), - .mst_w_chans_o ( slv_w_chans[i] ), - .mst_w_valids_o ( slv_w_valids[i] ), - .mst_w_readies_i ( slv_w_readies[i] ), - .mst_b_chans_i ( slv_b_chans[i] ), - .mst_b_valids_i ( slv_b_valids[i] ), - .mst_b_readies_o ( slv_b_readies[i] ), - .mst_ar_chans_o ( slv_ar_chans[i] ), - .mst_ar_valids_o ( slv_ar_valids[i] ), - .mst_ar_readies_i ( slv_ar_readies[i] ), - .mst_r_chans_i ( slv_r_chans[i] ), - .mst_r_valids_i ( slv_r_valids[i] ), - .mst_r_readies_o ( slv_r_readies[i] ) - ); - end - - //-------------------------------------- - // AW Channel - //-------------------------------------- - cc_rr_arb_tree #( - .NumIn ( NoSlvPorts ), - .data_t ( mst_aw_chan_t ), - .AxiVldRdy( 1'b1 ), - .LockIn ( 1'b1 ) - ) i_aw_arbiter ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .clr_i ( 1'b0 ), - .rr_i ( '0 ), - .req_i ( slv_aw_valids ), - .gnt_o ( slv_aw_readies ), - .data_i ( slv_aw_chans ), - .gnt_i ( aw_ready ), - .req_o ( aw_valid ), - .data_o ( mst_aw_chan ), - .idx_o ( ) - ); - - // control of the AW channel - always_comb begin - // default assignments - lock_aw_valid_d = lock_aw_valid_q; - load_aw_lock = 1'b0; - w_fifo_push = 1'b0; - mst_aw_valid = 1'b0; - aw_ready = 1'b0; - // had a downstream stall, be valid and send the AW along - if (lock_aw_valid_q) begin - mst_aw_valid = 1'b1; - // transaction - if (mst_aw_ready) begin - aw_ready = 1'b1; - lock_aw_valid_d = 1'b0; - load_aw_lock = 1'b1; - end - end else begin - if (!w_fifo_full && aw_valid) begin - mst_aw_valid = 1'b1; - w_fifo_push = 1'b1; - if (mst_aw_ready) begin - aw_ready = 1'b1; - end else begin - // go to lock if transaction not in this cycle - lock_aw_valid_d = 1'b1; - load_aw_lock = 1'b1; - end - end - end - end - - `FFL(lock_aw_valid_q, lock_aw_valid_d, load_aw_lock, '0, clk_i, rst_ni) - - cc_fifo #( - .FallThrough ( FallThrough ), - .Depth ( MaxWTrans ), - .data_t ( switch_id_t ) - ) i_w_fifo ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .clr_i ( 1'b0 ), - .flush_i ( 1'b0 ), - .full_o ( w_fifo_full ), - .empty_o ( w_fifo_empty ), - .usage_o ( ), - .data_i ( mst_aw_chan.id[SlvAxiIDWidth+:MstIdxBits] ), - .push_i ( w_fifo_push ), - .data_o ( w_fifo_data ), - .pop_i ( w_fifo_pop ) - ); - - cc_spill_register #( - .data_t ( mst_aw_chan_t ), - .Bypass ( ~SpillAw ) // Param indicated that we want a spill reg - ) i_aw_spill_reg ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .clr_i ( 1'b0 ), - .valid_i ( mst_aw_valid ), - .ready_o ( mst_aw_ready ), - .data_i ( mst_aw_chan ), - .valid_o ( mst_req_o.aw_valid ), - .ready_i ( mst_resp_i.aw_ready ), - .data_o ( mst_req_o.aw ) - ); - - //-------------------------------------- - // W Channel - //-------------------------------------- - // multiplexer - assign mst_w_chan = slv_w_chans[w_fifo_data]; - always_comb begin - // default assignments - mst_w_valid = 1'b0; - slv_w_readies = '0; - w_fifo_pop = 1'b0; - // control - if (!w_fifo_empty) begin - // connect the handshake - mst_w_valid = slv_w_valids[w_fifo_data]; - slv_w_readies[w_fifo_data] = mst_w_ready; - // pop FIFO on a last transaction - w_fifo_pop = slv_w_valids[w_fifo_data] & mst_w_ready & mst_w_chan.last; - end - end - - cc_spill_register #( - .data_t ( w_chan_t ), - .Bypass ( ~SpillW ) - ) i_w_spill_reg ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .clr_i ( 1'b0 ), - .valid_i ( mst_w_valid ), - .ready_o ( mst_w_ready ), - .data_i ( mst_w_chan ), - .valid_o ( mst_req_o.w_valid ), - .ready_i ( mst_resp_i.w_ready ), - .data_o ( mst_req_o.w ) - ); - - //-------------------------------------- - // B Channel - //-------------------------------------- - // replicate B channels - assign slv_b_chans = {NoSlvPorts{mst_b_chan}}; - // control B channel handshake - assign switch_b_id = mst_b_chan.id[SlvAxiIDWidth+:MstIdxBits]; - assign slv_b_valids = (mst_b_valid) ? (1 << switch_b_id) : '0; - - cc_spill_register #( - .data_t ( mst_b_chan_t ), - .Bypass ( ~SpillB ) - ) i_b_spill_reg ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .clr_i ( 1'b0 ), - .valid_i ( mst_resp_i.b_valid ), - .ready_o ( mst_req_o.b_ready ), - .data_i ( mst_resp_i.b ), - .valid_o ( mst_b_valid ), - .ready_i ( slv_b_readies[switch_b_id] ), - .data_o ( mst_b_chan ) - ); - - //-------------------------------------- - // AR Channel - //-------------------------------------- - cc_rr_arb_tree #( - .NumIn ( NoSlvPorts ), - .data_t ( mst_ar_chan_t ), - .AxiVldRdy( 1'b1 ), - .LockIn ( 1'b1 ) - ) i_ar_arbiter ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .clr_i ( 1'b0 ), - .rr_i ( '0 ), - .req_i ( slv_ar_valids ), - .gnt_o ( slv_ar_readies ), - .data_i ( slv_ar_chans ), - .gnt_i ( ar_ready ), - .req_o ( ar_valid ), - .data_o ( mst_ar_chan ), - .idx_o ( ) - ); - - cc_spill_register #( - .data_t ( mst_ar_chan_t ), - .Bypass ( ~SpillAr ) - ) i_ar_spill_reg ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .clr_i ( 1'b0 ), - .valid_i ( ar_valid ), - .ready_o ( ar_ready ), - .data_i ( mst_ar_chan ), - .valid_o ( mst_req_o.ar_valid ), - .ready_i ( mst_resp_i.ar_ready ), - .data_o ( mst_req_o.ar ) - ); - - //-------------------------------------- - // R Channel - //-------------------------------------- - // replicate R channels - assign slv_r_chans = {NoSlvPorts{mst_r_chan}}; - // R channel handshake control - assign switch_r_id = mst_r_chan.id[SlvAxiIDWidth+:MstIdxBits]; - assign slv_r_valids = (mst_r_valid) ? (1 << switch_r_id) : '0; - - cc_spill_register #( - .data_t ( mst_r_chan_t ), - .Bypass ( ~SpillR ) - ) i_r_spill_reg ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .clr_i ( 1'b0 ), - .valid_i ( mst_resp_i.r_valid ), - .ready_o ( mst_req_o.r_ready ), - .data_i ( mst_resp_i.r ), - .valid_o ( mst_r_valid ), - .ready_i ( slv_r_readies[switch_r_id] ), - .data_o ( mst_r_chan ) - ); - end + axi_mcast_mux #( + .SlvAxiIDWidth(SlvAxiIDWidth), + .slv_aw_chan_t(slv_aw_chan_t), + .mst_aw_chan_t(mst_aw_chan_t), + .w_chan_t (w_chan_t), + .slv_b_chan_t (slv_b_chan_t), + .mst_b_chan_t (mst_b_chan_t), + .slv_ar_chan_t(slv_ar_chan_t), + .mst_ar_chan_t(mst_ar_chan_t), + .slv_r_chan_t (slv_r_chan_t), + .mst_r_chan_t (mst_r_chan_t), + .slv_req_t (slv_req_t), + .slv_resp_t (slv_resp_t), + .mst_req_t (mst_req_t), + .mst_resp_t (mst_resp_t), + .NoSlvPorts (NoSlvPorts), + .MaxWTrans (MaxWTrans), + .FallThrough (FallThrough), + .SpillAw (SpillAw), + .SpillW (SpillW), + .SpillB (SpillB), + .SpillAr (SpillAr), + .SpillR (SpillR) + ) i_axi_mcast_mux ( + .clk_i (clk_i), + .rst_ni (rst_ni), + .test_i (test_i), + .slv_is_mcast_i ('0), + .slv_aw_commit_i('0), + .slv_reqs_i (slv_reqs_i), + .slv_resps_o (slv_resps_o), + .mst_req_o (mst_req_o), + .mst_resp_i (mst_resp_i) + ); -// pragma translate_off -`ifndef VERILATOR - initial begin - assert (SlvAxiIDWidth > 0) else $fatal(1, "AXI ID width of slave ports must be non-zero!"); - assert (NoSlvPorts > 0) else $fatal(1, "Number of slave ports must be non-zero!"); - assert (MaxWTrans > 0) - else $fatal(1, "Maximum number of outstanding writes must be non-zero!"); - assert (MstAxiIDWidth >= SlvAxiIDWidth + $clog2(NoSlvPorts)) - else $fatal(1, "AXI ID width of master ports must be wide enough to identify slave ports!"); - // Assert ID widths (one slave is sufficient since they all have the same type). - assert ($unsigned($bits(slv_reqs_i[0].aw.id)) == SlvAxiIDWidth) - else $fatal(1, "ID width of AW channel of slave ports does not match parameter!"); - assert ($unsigned($bits(slv_reqs_i[0].ar.id)) == SlvAxiIDWidth) - else $fatal(1, "ID width of AR channel of slave ports does not match parameter!"); - assert ($unsigned($bits(slv_resps_o[0].b.id)) == SlvAxiIDWidth) - else $fatal(1, "ID width of B channel of slave ports does not match parameter!"); - assert ($unsigned($bits(slv_resps_o[0].r.id)) == SlvAxiIDWidth) - else $fatal(1, "ID width of R channel of slave ports does not match parameter!"); - assert ($unsigned($bits(mst_req_o.aw.id)) == MstAxiIDWidth) - else $fatal(1, "ID width of AW channel of master port is wrong!"); - assert ($unsigned($bits(mst_req_o.ar.id)) == MstAxiIDWidth) - else $fatal(1, "ID width of AR channel of master port is wrong!"); - assert ($unsigned($bits(mst_resp_i.b.id)) == MstAxiIDWidth) - else $fatal(1, "ID width of B channel of master port is wrong!"); - assert ($unsigned($bits(mst_resp_i.r.id)) == MstAxiIDWidth) - else $fatal(1, "ID width of R channel of master port is wrong!"); - end -`endif -// pragma translate_on endmodule // interface wrap diff --git a/src/axi_xbar.sv b/src/axi_xbar.sv index e541392bd..43b815456 100644 --- a/src/axi_xbar.sv +++ b/src/axi_xbar.sv @@ -88,68 +88,47 @@ import cc_pkg::idx_width; input logic [Cfg.NoSlvPorts-1:0][MstPortsIdxWidth-1:0] default_mst_port_i ); - // signals into the axi_muxes, are of type slave as the multiplexer extends the ID - slv_req_t [Cfg.NoMstPorts-1:0][Cfg.NoSlvPorts-1:0] mst_reqs; - slv_resp_t [Cfg.NoMstPorts-1:0][Cfg.NoSlvPorts-1:0] mst_resps; + rule_t [Cfg.NoSlvPorts-1:0] default_rules; + for (genvar i = 0; i < Cfg.NoSlvPorts; i++) begin : gen_default_rules + assign default_rules[i] = '{ + idx: default_mst_port_i[i], + start_addr: '0, + end_addr: '0 + }; + end - axi_xbar_unmuxed #( - .Cfg (Cfg), - .ATOPs (ATOPs), - .Connectivity (Connectivity), - .aw_chan_t (slv_aw_chan_t), - .w_chan_t (w_chan_t), - .b_chan_t (slv_b_chan_t), - .ar_chan_t (slv_ar_chan_t), - .r_chan_t (slv_r_chan_t), - .req_t (slv_req_t), - .resp_t (slv_resp_t), - .rule_t (rule_t) - ) i_xbar_unmuxed ( - .clk_i, - .rst_ni, - .slv_ports_req_i, - .slv_ports_resp_o, - .mst_ports_req_o (mst_reqs), - .mst_ports_resp_i (mst_resps), - .addr_map_i, - .en_default_mst_port_i, - .default_mst_port_i + axi_mcast_xbar #( + .Cfg (Cfg), + .ATOPs (ATOPs), + .Connectivity (Connectivity), + .MulticastConnectivity('1), + .slv_aw_chan_t (slv_aw_chan_t), + .mst_aw_chan_t (mst_aw_chan_t), + .w_chan_t (w_chan_t), + .slv_b_chan_t (slv_b_chan_t), + .mst_b_chan_t (mst_b_chan_t), + .slv_ar_chan_t (slv_ar_chan_t), + .mst_ar_chan_t (mst_ar_chan_t), + .slv_r_chan_t (slv_r_chan_t), + .mst_r_chan_t (mst_r_chan_t), + .slv_req_t (slv_req_t), + .slv_resp_t (slv_resp_t), + .mst_req_t (mst_req_t), + .mst_resp_t (mst_resp_t), + .rule_t (rule_t) + ) i_axi_mcast_xbar ( + .clk_i (clk_i), + .rst_ni (rst_ni), + .test_i (test_i), + .slv_ports_req_i (slv_ports_req_i), + .slv_ports_resp_o (slv_ports_resp_o), + .mst_ports_req_o (mst_ports_req_o), + .mst_ports_resp_i (mst_ports_resp_i), + .addr_map_i (addr_map_i), + .en_default_mst_port_i(en_default_mst_port_i), + .default_mst_port_i (default_rules) ); - for (genvar i = 0; i < Cfg.NoMstPorts; i++) begin : gen_mst_port_mux - axi_mux #( - .SlvAxiIDWidth ( Cfg.AxiIdWidthSlvPorts ), // ID width of the slave ports - .slv_aw_chan_t ( slv_aw_chan_t ), // AW Channel Type, slave ports - .mst_aw_chan_t ( mst_aw_chan_t ), // AW Channel Type, master port - .w_chan_t ( w_chan_t ), // W Channel Type, all ports - .slv_b_chan_t ( slv_b_chan_t ), // B Channel Type, slave ports - .mst_b_chan_t ( mst_b_chan_t ), // B Channel Type, master port - .slv_ar_chan_t ( slv_ar_chan_t ), // AR Channel Type, slave ports - .mst_ar_chan_t ( mst_ar_chan_t ), // AR Channel Type, master port - .slv_r_chan_t ( slv_r_chan_t ), // R Channel Type, slave ports - .mst_r_chan_t ( mst_r_chan_t ), // R Channel Type, master port - .slv_req_t ( slv_req_t ), - .slv_resp_t ( slv_resp_t ), - .mst_req_t ( mst_req_t ), - .mst_resp_t ( mst_resp_t ), - .NoSlvPorts ( Cfg.NoSlvPorts ), // Number of Masters for the module - .MaxWTrans ( Cfg.MaxSlvTrans ), - .FallThrough ( Cfg.FallThrough ), - .SpillAw ( Cfg.LatencyMode[4] ), - .SpillW ( Cfg.LatencyMode[3] ), - .SpillB ( Cfg.LatencyMode[2] ), - .SpillAr ( Cfg.LatencyMode[1] ), - .SpillR ( Cfg.LatencyMode[0] ) - ) i_axi_mux ( - .clk_i, // Clock - .rst_ni, // Asynchronous reset active low - .slv_reqs_i ( mst_reqs[i] ), - .slv_resps_o ( mst_resps[i] ), - .mst_req_o ( mst_ports_req_o[i] ), - .mst_resp_i ( mst_ports_resp_i[i] ) - ); - end - endmodule `include "axi/assign.svh" diff --git a/src/axi_xbar_unmuxed.sv b/src/axi_xbar_unmuxed.sv index 740c02367..2c8d66550 100644 --- a/src/axi_xbar_unmuxed.sv +++ b/src/axi_xbar_unmuxed.sv @@ -67,199 +67,49 @@ import cc_pkg::idx_width; /// 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. /// Each master port can have multiple different rules. - input rule_t [Cfg.NoAddrRules-1:0] 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, + input logic [Cfg.NoSlvPorts-1:0] en_default_mst_port_i, /// 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 + input logic [Cfg.NoSlvPorts-1:0][MstPortsIdxWidth-1:0] default_mst_port_i ); - // Address tpye for inidvidual address signals - typedef logic [Cfg.AxiAddrWidth-1:0] addr_t; - // to account for the decoding error slave - localparam int unsigned MstPortsIdxWidthOne = - (Cfg.NoMstPorts == 32'd1) ? 32'd1 : unsigned'($clog2(Cfg.NoMstPorts + 1)); - typedef logic [MstPortsIdxWidthOne-1:0] mst_port_idx_t; - - // signals from the axi_demuxes, one index more for decode error - req_t [Cfg.NoSlvPorts-1:0][Cfg.NoMstPorts:0] slv_reqs; - resp_t [Cfg.NoSlvPorts-1:0][Cfg.NoMstPorts:0] slv_resps; - - // workaround for issue #133 (problem with vsim 10.6c) - localparam int unsigned cfg_NoMstPorts = Cfg.NoMstPorts; - - for (genvar i = 0; i < Cfg.NoSlvPorts; i++) begin : gen_slv_port_demux - logic [MstPortsIdxWidth-1:0] dec_aw, dec_ar; - mst_port_idx_t slv_aw_select, slv_ar_select; - logic dec_aw_valid, dec_aw_error; - logic dec_ar_valid, dec_ar_error; - - cc_addr_decode #( - .NoIndices ( Cfg.NoMstPorts ), - .NoRules ( Cfg.NoAddrRules ), - .addr_t ( addr_t ), - .rule_t ( rule_t ) - ) i_axi_aw_decode ( - .addr_i ( slv_ports_req_i[i].aw.addr ), - .addr_map_i ( addr_map_i ), - .idx_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] ) - ); - - cc_addr_decode #( - .NoIndices ( Cfg.NoMstPorts ), - .addr_t ( addr_t ), - .NoRules ( Cfg.NoAddrRules ), - .rule_t ( rule_t ) - ) i_axi_ar_decode ( - .addr_i ( slv_ports_req_i[i].ar.addr ), - .addr_map_i ( addr_map_i ), - .idx_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] ) - ); - - assign slv_aw_select = (dec_aw_error) ? - mst_port_idx_t'(Cfg.NoMstPorts) : mst_port_idx_t'(dec_aw); - assign slv_ar_select = (dec_ar_error) ? - mst_port_idx_t'(Cfg.NoMstPorts) : mst_port_idx_t'(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 #( - .AxiIdWidth ( Cfg.AxiIdWidthSlvPorts ), // ID Width - .AtopSupport ( ATOPs ), - .aw_chan_t ( aw_chan_t ), // AW Channel Type - .w_chan_t ( w_chan_t ), // W Channel Type - .b_chan_t ( b_chan_t ), // B Channel Type - .ar_chan_t ( ar_chan_t ), // AR Channel Type - .r_chan_t ( r_chan_t ), // R Channel Type - .axi_req_t ( req_t ), - .axi_resp_t ( resp_t ), - .NoMstPorts ( Cfg.NoMstPorts + 1 ), - .MaxTrans ( Cfg.MaxMstTrans ), - .AxiLookBits ( Cfg.AxiIdUsedSlvPorts ), - .UniqueIds ( Cfg.UniqueIds ), - .SpillAw ( Cfg.LatencyMode[9] ), - .SpillW ( Cfg.LatencyMode[8] ), - .SpillB ( Cfg.LatencyMode[7] ), - .SpillAr ( Cfg.LatencyMode[6] ), - .SpillR ( Cfg.LatencyMode[5] ) - ) i_axi_demux ( - .clk_i, // Clock - .rst_ni, // Asynchronous reset active low - .slv_req_i ( slv_ports_req_i[i] ), - .slv_aw_select_i ( slv_aw_select ), - .slv_ar_select_i ( slv_ar_select ), - .slv_resp_o ( slv_ports_resp_o[i] ), - .mst_reqs_o ( slv_reqs[i] ), - .mst_resps_i ( slv_resps[i] ) - ); - - axi_err_slv #( - .AxiIdWidth ( Cfg.AxiIdWidthSlvPorts ), - .axi_req_t ( req_t ), - .axi_resp_t ( resp_t ), - .Resp ( axi_pkg::RESP_DECERR ), - .ATOPs ( ATOPs ), - .MaxTrans ( 4 ) // Transactions terminate at this slave, so minimize - // resource consumption by accepting only a few - // transactions at a time. - ) i_axi_err_slv ( - .clk_i, // Clock - .rst_ni, // Asynchronous reset active low - // slave port - .slv_req_i ( slv_reqs[i][Cfg.NoMstPorts] ), - .slv_resp_o ( slv_resps[i][cfg_NoMstPorts] ) - ); + rule_t [Cfg.NoSlvPorts-1:0] default_rules; + for (genvar i = 0; i < Cfg.NoSlvPorts; i++) begin : gen_default_rules + assign default_rules[i] = '{ + idx: default_mst_port_i[i], + start_addr: '0, + end_addr: '0 + }; end - // cross all channels - for (genvar i = 0; i < Cfg.NoSlvPorts; i++) begin : gen_xbar_slv_cross - for (genvar j = 0; j < Cfg.NoMstPorts; j++) begin : gen_xbar_mst_cross - if (Connectivity[i][j]) begin : gen_connection - axi_multicut #( - .NoCuts ( Cfg.PipelineStages ), - .aw_chan_t ( aw_chan_t ), - .w_chan_t ( w_chan_t ), - .b_chan_t ( b_chan_t ), - .ar_chan_t ( ar_chan_t ), - .r_chan_t ( r_chan_t ), - .axi_req_t ( req_t ), - .axi_resp_t ( resp_t ) - ) i_axi_multicut_xbar_pipeline ( - .clk_i, - .rst_ni, - .slv_req_i ( slv_reqs[i][j] ), - .slv_resp_o ( slv_resps[i][j] ), - .mst_req_o ( mst_ports_req_o[j][i] ), - .mst_resp_i ( mst_ports_resp_i[j][i] ) - ); - - end else begin : gen_no_connection - assign mst_ports_req_o[j][i] = '0; - axi_err_slv #( - .AxiIdWidth ( Cfg.AxiIdWidthSlvPorts ), - .axi_req_t ( req_t ), - .axi_resp_t ( resp_t ), - .Resp ( axi_pkg::RESP_DECERR ), - .ATOPs ( ATOPs ), - .MaxTrans ( 1 ) - ) i_axi_err_slv ( - .clk_i, - .rst_ni, - .slv_req_i ( slv_reqs[i][j] ), - .slv_resp_o ( slv_resps[i][j] ) - ); - end - end - end + axi_mcast_xbar_unmuxed #( + .Cfg (Cfg), + .ATOPs (ATOPs), + .Connectivity (Connectivity), + .aw_chan_t (aw_chan_t), + .w_chan_t (w_chan_t), + .b_chan_t (b_chan_t), + .ar_chan_t (ar_chan_t), + .r_chan_t (r_chan_t), + .req_t (req_t), + .resp_t (resp_t), + .rule_t (rule_t) + ) i_axi_mcast_xbar_unmuxed ( + .clk_i (clk_i), + .rst_ni (rst_ni), + .test_i (test_i), + .slv_ports_req_i (slv_ports_req_i), + .slv_ports_resp_o (slv_ports_resp_o), + .mst_ports_req_o (mst_ports_req_o), + .mst_ports_resp_i (mst_ports_resp_i), + .addr_map_i (addr_map_i), + .en_default_mst_port_i(en_default_mst_port_i), + .default_mst_port_i (default_rules) + ); - // pragma translate_off - `ifndef VERILATOR - `ifndef XSIM - initial begin : check_params - id_slv_req_ports: assert ($bits(slv_ports_req_i[0].aw.id ) == Cfg.AxiIdWidthSlvPorts) else - $fatal(1, $sformatf("Slv_req and aw_chan id width not equal.")); - id_slv_resp_ports: assert ($bits(slv_ports_resp_o[0].r.id) == Cfg.AxiIdWidthSlvPorts) else - $fatal(1, $sformatf("Slv_req and aw_chan id width not equal.")); - end - `endif - `endif - // pragma translate_on endmodule `ifndef VCS diff --git a/test/tb_axi_mcast_xbar.sv b/test/tb_axi_mcast_xbar.sv index 703e71f79..7d7966b1b 100644 --- a/test/tb_axi_mcast_xbar.sv +++ b/test/tb_axi_mcast_xbar.sv @@ -264,7 +264,7 @@ module tb_axi_mcast_xbar #( end initial begin : proc_monitor - static tb_axi_mcast_xbar_pkg::axi_mcast_xbar_monitor #( + static tb_axi_xbar_pkg::axi_xbar_monitor #( .AxiAddrWidth ( TbAxiAddrWidth ), .AxiDataWidth ( TbAxiDataWidth ), .AxiIdWidthMasters ( TbAxiIdWidthMasters ), diff --git a/test/tb_axi_mcast_xbar_pkg.sv b/test/tb_axi_mcast_xbar_pkg.sv deleted file mode 100644 index 9b5317b20..000000000 --- a/test/tb_axi_mcast_xbar_pkg.sv +++ /dev/null @@ -1,609 +0,0 @@ -// Copyright (c) 2019 ETH Zurich and University of Bologna. -// Copyright and related rights are licensed under the Solderpad Hardware -// License, Version 0.51 (the "License"); you may not use this file except in -// compliance with the License. You may obtain a copy of the License at -// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law -// or agreed to in writing, software, hardware and materials distributed under -// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. -// -// Authors: -// - Florian Zaruba -// - Wolfgang Roenninger -// - Luca Colagrande - -// `axi_mcast_xbar_monitor` implements an AXI bus monitor that is tuned for the AXI multicast -// crossbar. It snoops on each of the slaves and master ports of the crossbar and -// populates FIFOs and ID queues to validate that no AXI beats get -// lost or sent to the wrong destination. - -package tb_axi_mcast_xbar_pkg; - class axi_mcast_xbar_monitor #( - parameter int unsigned AxiAddrWidth, - parameter int unsigned AxiDataWidth, - parameter int unsigned AxiIdWidthMasters, - parameter int unsigned AxiIdWidthSlaves, - parameter int unsigned AxiUserWidth, - parameter int unsigned NoMasters, - parameter int unsigned NoSlaves, - parameter int unsigned NoAddrRules, - parameter int unsigned NoMulticastRules, - parameter type rule_t, - parameter rule_t [NoAddrRules-1:0] AddrMap, - // Stimuli application and test time - parameter time TimeTest - ); - typedef logic [AxiIdWidthMasters-1:0] mst_axi_id_t; - typedef logic [AxiIdWidthSlaves-1:0] slv_axi_id_t; - typedef logic [AxiAddrWidth-1:0] axi_addr_t; - - typedef logic [$clog2(NoMasters)-1:0] idx_mst_t; - typedef int unsigned idx_slv_t; // from rule_t - - typedef struct packed { - mst_axi_id_t mst_axi_id; - logic last; - } master_exp_t; - typedef struct packed { - slv_axi_id_t slv_axi_id; - axi_addr_t slv_axi_addr; - axi_addr_t slv_axi_mcast; - axi_pkg::len_t slv_axi_len; - } exp_ax_t; - typedef struct packed { - slv_axi_id_t slv_axi_id; - logic last; - } slave_exp_t; - - typedef rand_id_queue_pkg::rand_id_queue #( - .data_t ( master_exp_t ), - .ID_WIDTH ( AxiIdWidthMasters ) - ) master_exp_queue_t; - typedef rand_id_queue_pkg::rand_id_queue #( - .data_t ( exp_ax_t ), - .ID_WIDTH ( AxiIdWidthSlaves ) - ) ax_queue_t; - - typedef rand_id_queue_pkg::rand_id_queue #( - .data_t ( slave_exp_t ), - .ID_WIDTH ( AxiIdWidthSlaves ) - ) slave_exp_queue_t; - - //----------------------------------------- - // Monitoring virtual interfaces - //----------------------------------------- - virtual AXI_BUS_DV #( - .AXI_ADDR_WIDTH ( AxiAddrWidth ), - .AXI_DATA_WIDTH ( AxiDataWidth ), - .AXI_ID_WIDTH ( AxiIdWidthMasters ), - .AXI_USER_WIDTH ( AxiUserWidth ) - ) masters_axi [NoMasters-1:0]; - virtual AXI_BUS_DV #( - .AXI_ADDR_WIDTH ( AxiAddrWidth ), - .AXI_DATA_WIDTH ( AxiDataWidth ), - .AXI_ID_WIDTH ( AxiIdWidthSlaves ), - .AXI_USER_WIDTH ( AxiUserWidth ) - ) slaves_axi [NoSlaves-1:0]; - //----------------------------------------- - // Queues and FIFOs to hold the expected ids - //----------------------------------------- - // Write transactions - ax_queue_t exp_aw_queue [NoSlaves-1:0]; - slave_exp_t exp_w_fifo [NoSlaves-1:0][$]; - slave_exp_t act_w_fifo [NoSlaves-1:0][$]; - master_exp_queue_t exp_b_queue [NoMasters-1:0]; - - // Read transactions - ax_queue_t exp_ar_queue [NoSlaves-1:0]; - master_exp_queue_t exp_r_queue [NoMasters-1:0]; - - //----------------------------------------- - // Bookkeeping - //----------------------------------------- - longint unsigned tests_expected; - longint unsigned tests_conducted; - longint unsigned tests_failed; - std::semaphore cnt_sem; - - //----------------------------------------- - // Constructor - //----------------------------------------- - function new( - virtual AXI_BUS_DV #( - .AXI_ADDR_WIDTH ( AxiAddrWidth ), - .AXI_DATA_WIDTH ( AxiDataWidth ), - .AXI_ID_WIDTH ( AxiIdWidthMasters ), - .AXI_USER_WIDTH ( AxiUserWidth ) - ) axi_masters_vif [NoMasters-1:0], - virtual AXI_BUS_DV #( - .AXI_ADDR_WIDTH ( AxiAddrWidth ), - .AXI_DATA_WIDTH ( AxiDataWidth ), - .AXI_ID_WIDTH ( AxiIdWidthSlaves ), - .AXI_USER_WIDTH ( AxiUserWidth ) - ) axi_slaves_vif [NoSlaves-1:0] - ); - begin - this.masters_axi = axi_masters_vif; - this.slaves_axi = axi_slaves_vif; - this.tests_expected = 0; - this.tests_conducted = 0; - this.tests_failed = 0; - for (int unsigned i = 0; i < NoMasters; i++) begin - this.exp_b_queue[i] = new; - this.exp_r_queue[i] = new; - end - for (int unsigned i = 0; i < NoSlaves; i++) begin - this.exp_aw_queue[i] = new; - this.exp_ar_queue[i] = new; - end - this.cnt_sem = new(1); - end - endfunction - - // when start the testing - task cycle_start; - #TimeTest; - endtask - - // when is cycle finished - task cycle_end; - @(posedge masters_axi[0].clk_i); - endtask - - // This task monitors a slave port of the crossbar. Every time an AW beat is seen - // it populates an id queue at the right master port(s) (if there is no expected decode error), - // 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[$]; - 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; - - // TODO colluca: add check that multicast requests only arrive on multicast ports - // (lower NoMulticastPorts) and that multicast requests only originate - // from multicast rules (lower NoMulticastRules) - - if (masters_axi[i].aw_valid && masters_axi[i].aw_ready) begin - - // 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_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]; - - // Set decode error by default, reset if a rule is matched in the following - decerr = 1; - - // When a mask is present, multicast rules are used, otherwise the unicast rules are used. - if (aw_mcast != '0) begin - - // Log masked address - for (int k = 0; k < AxiAddrWidth; k++) - aw_addr_masked[k] = aw_mcast[k] ? 1'bx : aw_addr[k]; - - $display("Trying to match: %x", aw_addr_masked); - - // Compare request against each multicast 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 = (NoMulticastRules - 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; - 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 - int unsigned slave_idx = AddrMap[j].idx; - decerr = 0; - - // 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 - - end else begin - - // Compare request against each interval-form rule. We look at the rules starting from - // the last ones. We ignore the case of multiple rules matching for the same slave - $display("Trying to match: %x", aw_addr); - for (int j = (NoAddrRules - 1); j >= 0; j--) begin - if ((aw_addr >= AddrMap[j].start_addr) && - (aw_addr < AddrMap[j].end_addr)) begin - decerr = 0; - to_slave_idx.push_back(AddrMap[j].idx); - addr_to_slave.push_back(aw_addr); - mask_to_slave.push_back('0); - $display(" Push address : %x", aw_addr); - end - end - - end - - num_slaves_matched = to_slave_idx.size(); - - // send the exp aw beats down into the queues of the selected slaves - // when no decerror - if (decerr) begin - $display("%0tns > Master %0d: AW to Decerror: Axi ID: %b", - $time, i, masters_axi[i].aw_id); - end else begin - exp_aw_id = {idx_mst_t'(i), masters_axi[i].aw_id}; - for (int j = 0; j < num_slaves_matched; j++) begin - automatic idx_slv_t slave_idx = to_slave_idx.pop_front(); - // $display("Test exp aw_id: %b",exp_aw_id); - exp_aw = '{slv_axi_id: exp_aw_id, - slv_axi_addr: addr_to_slave.pop_front(), - slv_axi_mcast: mask_to_slave.pop_front(), - slv_axi_len: masters_axi[i].aw_len}; - this.exp_aw_queue[slave_idx].push(exp_aw_id, exp_aw); - incr_expected_tests(4); - if (j == 0) slaves_str = $sformatf("%0d", slave_idx); - else slaves_str = $sformatf("%s, %0d", slaves_str, slave_idx); - end - $display("%0tns > Master %0d: AW to Slaves [%s]: Axi ID: %b", - $time, i, slaves_str, masters_axi[i].aw_id); - end - - // populate the expected b queue anyway - exp_b = '{mst_axi_id: masters_axi[i].aw_id, last: 1'b1}; - this.exp_b_queue[i].push(masters_axi[i].aw_id, exp_b); - incr_expected_tests(1); - $display(" Expect B response."); - - // inject expected r beats on this id, if it is an atop - // throw an error if a multicast atop is attempted (not supported) - if(masters_axi[i].aw_atop[5]) begin - if (num_slaves_matched > 1) $fatal(0, "Multicast ATOPs are not supported"); - // push the required r beats into the right fifo (reuse the exp_b variable) - $display(" Expect R response, len: %0d.", masters_axi[i].aw_len); - for (int unsigned j = 0; j <= masters_axi[i].aw_len; j++) begin - exp_b = (j == masters_axi[i].aw_len) ? - '{mst_axi_id: masters_axi[i].aw_id, last: 1'b1} : - '{mst_axi_id: masters_axi[i].aw_id, last: 1'b0}; - this.exp_r_queue[i].push(masters_axi[i].aw_id, exp_b); - incr_expected_tests(1); - end - end - end - endtask : monitor_mst_aw - - // This task monitors a master port of the crossbar. Every time there is an AW vector it - // gets checked for its contents and if it was expected. The task then pushes an expected - // amount of W beats in the respective fifo. Emphasis of the last flag. - task automatic monitor_slv_aw(input int unsigned i); - exp_ax_t exp_aw; - slave_exp_t exp_slv_w; - // $display("%0t > Was triggered: aw_valid %b, aw_ready: %b", - // $time(), slaves_axi[i].aw_valid, slaves_axi[i].aw_ready); - if (slaves_axi[i].aw_valid && slaves_axi[i].aw_ready) begin - // test if the aw beat was expected - exp_aw = this.exp_aw_queue[i].pop_id(slaves_axi[i].aw_id); - $display("%0tns > Slave %0d: AW Axi ID: %b", - $time, i, slaves_axi[i].aw_id); - if (exp_aw.slv_axi_id != slaves_axi[i].aw_id) begin - incr_failed_tests(1); - $warning("Slave %0d: Unexpected AW with ID: %b", i, slaves_axi[i].aw_id); - end - if (exp_aw.slv_axi_addr != slaves_axi[i].aw_addr) begin - incr_failed_tests(1); - $warning("Slave %0d: Unexpected AW with ID: %b and ADDR: %h, exp: %h", - i, slaves_axi[i].aw_id, slaves_axi[i].aw_addr, exp_aw.slv_axi_addr); - end - if (exp_aw.slv_axi_mcast != slaves_axi[i].aw_user[AxiAddrWidth-1:0]) begin - incr_failed_tests(1); - $warning("Slave %0d: Unexpected AW with ID: %b and MCAST: %h, exp: %h", - i, slaves_axi[i].aw_id, slaves_axi[i].aw_user[AxiAddrWidth-1:0], - exp_aw.slv_axi_mcast); - end - if (exp_aw.slv_axi_len != slaves_axi[i].aw_len) begin - incr_failed_tests(1); - $warning("Slave %0d: Unexpected AW with ID: %b and LEN: %h, exp: %h", - i, slaves_axi[i].aw_id, slaves_axi[i].aw_len, exp_aw.slv_axi_len); - end - incr_conducted_tests(4); - - // push the required w beats into the right fifo - $display(" Expect %0d W beats.", slaves_axi[i].aw_len + 1); - incr_expected_tests(slaves_axi[i].aw_len + 1); - for (int unsigned j = 0; j <= slaves_axi[i].aw_len; j++) begin - exp_slv_w = (j == slaves_axi[i].aw_len) ? - '{slv_axi_id: slaves_axi[i].aw_id, last: 1'b1} : - '{slv_axi_id: slaves_axi[i].aw_id, last: 1'b0}; - this.exp_w_fifo[i].push_back(exp_slv_w); - end - end - endtask : monitor_slv_aw - - // This task just pushes every W beat that gets sent on a master port in its respective fifo. - task automatic monitor_slv_w(input int unsigned i); - slave_exp_t act_slv_w; - if (slaves_axi[i].w_valid && slaves_axi[i].w_ready) begin - // $display("%0t > W beat on Slave %0d, last flag: %b", $time, i, slaves_axi[i].w_last); - act_slv_w = '{last: slaves_axi[i].w_last , default:'0}; - this.act_w_fifo[i].push_back(act_slv_w); - end - endtask : monitor_slv_w - - // This task compares the expected and actual W beats on a master port. The reason that - // this is not done in `monitor_slv_w` is that there can be per protocol W beats on the - // channel, before AW is sent to the slave. - task automatic check_slv_w(input int unsigned i); - slave_exp_t exp_w, act_w; - while (this.exp_w_fifo[i].size() != 0 && this.act_w_fifo[i].size() != 0) begin - - exp_w = this.exp_w_fifo[i].pop_front(); - act_w = this.act_w_fifo[i].pop_front(); - // do the check - incr_conducted_tests(1); - if(exp_w.last != act_w.last) begin - incr_failed_tests(1); - $warning("Slave %d: unexpected W beat last flag %b, expected: %b.", - i, act_w.last, exp_w.last); - end - end - endtask : check_slv_w - - // This task checks if a B response is allowed on a slave port of the crossbar. - task automatic monitor_mst_b(input int unsigned i); - master_exp_t exp_b; - mst_axi_id_t axi_b_id; - if (masters_axi[i].b_valid && masters_axi[i].b_ready) begin - incr_conducted_tests(1); - axi_b_id = masters_axi[i].b_id; - $display("%0tns > Master %0d: Got last B with id: %b", - $time, i, axi_b_id); - if (this.exp_b_queue[i].is_empty()) begin - incr_failed_tests(1); - $warning("Master %d: unexpected B beat with ID: %b detected!", i, axi_b_id); - end else begin - exp_b = this.exp_b_queue[i].pop_id(axi_b_id); - if (axi_b_id != exp_b.mst_axi_id) begin - incr_failed_tests(1); - $warning("Master: %d got unexpected B with ID: %b", i, axi_b_id); - end - end - end - endtask : monitor_mst_b - - // This task monitors the AR channel of a slave port of the crossbar. For each AR it populates - // the corresponding ID queue with the number of r beats indicated on the `ar_len` field. - // Emphasis on the last flag. We will detect reordering, if the last flags do not match, - // as each `random` burst tend to have a different length. - task automatic monitor_mst_ar(input int unsigned i); - mst_axi_id_t mst_axi_id; - axi_addr_t mst_axi_addr; - axi_pkg::len_t mst_axi_len; - - idx_slv_t exp_slv_idx; - slv_axi_id_t exp_slv_axi_id; - exp_ax_t exp_slv_ar; - master_exp_t exp_mst_r; - - logic exp_decerr; - - if (masters_axi[i].ar_valid && masters_axi[i].ar_ready) begin - exp_decerr = 1'b1; - mst_axi_id = masters_axi[i].ar_id; - mst_axi_addr = masters_axi[i].ar_addr; - mst_axi_len = masters_axi[i].ar_len; - exp_slv_axi_id = {idx_mst_t'(i), mst_axi_id}; - exp_slv_idx = '0; - for (int unsigned j = 0; j < NoAddrRules; j++) begin - if ((mst_axi_addr >= AddrMap[j].start_addr) && (mst_axi_addr < AddrMap[j].end_addr)) begin - exp_slv_idx = AddrMap[j].idx; - exp_decerr = 1'b0; - end - end - if (exp_decerr) begin - $display("%0tns > Master %0d: AR to Decerror: Axi ID: %b", - $time, i, mst_axi_id); - end else begin - $display("%0tns > Master %0d: AR to Slave %0d: Axi ID: %b", - $time, i, exp_slv_idx, mst_axi_id); - // push the expected vectors AW for exp_slv - exp_slv_ar = '{slv_axi_id: exp_slv_axi_id, - slv_axi_addr: mst_axi_addr, - slv_axi_mcast: '0, - slv_axi_len: mst_axi_len}; - //$display("Expected Slv Axi Id is: %b", exp_slv_axi_id); - this.exp_ar_queue[exp_slv_idx].push(exp_slv_axi_id, exp_slv_ar); - incr_expected_tests(1); - end - // push the required r beats into the right fifo - $display(" Expect R response, len: %0d.", mst_axi_len); - for (int unsigned j = 0; j <= mst_axi_len; j++) begin - exp_mst_r = (j == mst_axi_len) ? '{mst_axi_id: mst_axi_id, last: 1'b1} : - '{mst_axi_id: mst_axi_id, last: 1'b0}; - this.exp_r_queue[i].push(mst_axi_id, exp_mst_r); - incr_expected_tests(1); - end - end - endtask : monitor_mst_ar - - // This task monitors a master port of the crossbar and checks if a transmitted AR beat was - // expected. - task automatic monitor_slv_ar(input int unsigned i); - exp_ax_t exp_slv_ar; - slv_axi_id_t slv_axi_id; - if (slaves_axi[i].ar_valid && slaves_axi[i].ar_ready) begin - incr_conducted_tests(1); - slv_axi_id = slaves_axi[i].ar_id; - if (this.exp_ar_queue[i].is_empty()) begin - incr_failed_tests(1); - end else begin - // check that the ids are the same - exp_slv_ar = this.exp_ar_queue[i].pop_id(slv_axi_id); - $display("%0tns > Slave %0d: AR Axi ID: %b", $time, i, slv_axi_id); - if (exp_slv_ar.slv_axi_id != slv_axi_id) begin - incr_failed_tests(1); - $warning("Slave %d: Unexpected AR with ID: %b", i, slv_axi_id); - end - end - end - endtask : monitor_slv_ar - - // This task does the R channel monitoring on a slave port. It compares the last flags, - // which are determined by the sequence of previously sent AR vectors. - task automatic monitor_mst_r(input int unsigned i); - master_exp_t exp_mst_r; - mst_axi_id_t mst_axi_r_id; - logic mst_axi_r_last; - if (masters_axi[i].r_valid && masters_axi[i].r_ready) begin - incr_conducted_tests(1); - mst_axi_r_id = masters_axi[i].r_id; - mst_axi_r_last = masters_axi[i].r_last; - if (mst_axi_r_last) begin - $display("%0tns > Master %0d: Got last R with id: %b", - $time, i, mst_axi_r_id); - end - if (this.exp_r_queue[i].is_empty()) begin - incr_failed_tests(1); - $warning("Master %d: unexpected R beat with ID: %b detected!", i, mst_axi_r_id); - end else begin - exp_mst_r = this.exp_r_queue[i].pop_id(mst_axi_r_id); - if (mst_axi_r_id != exp_mst_r.mst_axi_id) begin - incr_failed_tests(1); - $warning("Master: %d got unexpected R with ID: %b", i, mst_axi_r_id); - end - if (mst_axi_r_last != exp_mst_r.last) begin - incr_failed_tests(1); - $warning("Master: %d got unexpected R with ID: %b and last flag: %b", - i, mst_axi_r_id, mst_axi_r_last); - end - end - end - endtask : monitor_mst_r - - // Some tasks to manage bookkeeping of the tests conducted. - task incr_expected_tests(input int unsigned times); - cnt_sem.get(); - this.tests_expected += times; - cnt_sem.put(); - endtask : incr_expected_tests - - task incr_conducted_tests(input int unsigned times); - cnt_sem.get(); - this.tests_conducted += times; - cnt_sem.put(); - endtask : incr_conducted_tests - - task incr_failed_tests(input int unsigned times); - cnt_sem.get(); - this.tests_failed += times; - cnt_sem.put(); - endtask : incr_failed_tests - - // This task invokes the various monitoring tasks. It first forks in two, spitting - // the tasks that should continuously run and the ones that get invoked every clock cycle. - // For the tasks every clock cycle all processes that only push something in the fifo's and - // Queues get run. When they are finished the processes that pop something get run. - task run(); - Continous: fork - begin - do begin - cycle_start(); - // at every cycle span some monitoring processes - // execute all processes that put something into the queues - PushMon: fork - proc_mst_aw: begin - for (int unsigned i = 0; i < NoMasters; i++) begin - monitor_mst_aw(i); - end - end - proc_mst_ar: begin - for (int unsigned i = 0; i < NoMasters; i++) begin - monitor_mst_ar(i); - end - end - join : PushMon - // this one pops and pushes something - proc_slv_aw: begin - for (int unsigned i = 0; i < NoSlaves; i++) begin - monitor_slv_aw(i); - end - end - proc_slv_w: begin - for (int unsigned i = 0; i < NoSlaves; i++) begin - monitor_slv_w(i); - end - end - // These only pop somethong from the queses - PopMon: fork - proc_mst_b: begin - for (int unsigned i = 0; i < NoMasters; i++) begin - monitor_mst_b(i); - end - end - proc_slv_ar: begin - for (int unsigned i = 0; i < NoSlaves; i++) begin - monitor_slv_ar(i); - end - end - proc_mst_r: begin - for (int unsigned i = 0; i < NoMasters; i++) begin - monitor_mst_r(i); - end - end - join : PopMon - // check the slave W fifos last - proc_check_slv_w: begin - for (int unsigned i = 0; i < NoSlaves; i++) begin - check_slv_w(i); - end - end - cycle_end(); - end while (1'b1); - end - join - endtask : run - - task print_result(); - $info("Simulation has ended!"); - $display("Tests Expected: %d", this.tests_expected); - $display("Tests Conducted: %d", this.tests_conducted); - $display("Tests Failed: %d", this.tests_failed); - if(tests_failed > 0) begin - $error("Simulation encountered unexpected Transactions!!!!!!"); - end - if(tests_conducted == 0) begin - $error("Simulation did not conduct any tests!"); - end - if (tests_conducted < tests_expected) begin - $error("Some of the expected tests were not conducted!"); - end - if (tests_conducted > tests_expected) begin - $error("Conducted more than the expected tests!"); - end - endtask : print_result - endclass : axi_mcast_xbar_monitor -endpackage diff --git a/test/tb_axi_xbar.sv b/test/tb_axi_xbar.sv index 1daf39956..3081af785 100644 --- a/test/tb_axi_xbar.sv +++ b/test/tb_axi_xbar.sv @@ -77,6 +77,7 @@ module tb_axi_xbar #( AxiAddrWidth: TbAxiAddrWidth, AxiDataWidth: TbAxiDataWidth, NoAddrRules: TbNumSlaves, + EnableMulticast: 1'b0, NoMulticastRules: 0, NoMulticastPorts: 0 }; diff --git a/test/tb_axi_xbar_pkg.sv b/test/tb_axi_xbar_pkg.sv index 3c90fcca1..5343960b6 100644 --- a/test/tb_axi_xbar_pkg.sv +++ b/test/tb_axi_xbar_pkg.sv @@ -11,9 +11,10 @@ // Authors: // - Florian Zaruba // - Wolfgang Roenninger +// - Luca Colagrande -// `axi_xbar_monitor` implements an AXI bus monitor that is tuned for the AXI crossbar. -// It snoops on each of the slaves and master ports of the crossbar and +// `axi_xbar_monitor` implements an AXI bus monitor that is tuned for the AXI multicast +// crossbar. It snoops on each of the slaves and master ports of the crossbar and // populates FIFOs and ID queues to validate that no AXI beats get // lost or sent to the wrong destination. @@ -27,6 +28,7 @@ package tb_axi_xbar_pkg; parameter int unsigned NoMasters, parameter int unsigned NoSlaves, parameter int unsigned NoAddrRules, + parameter int unsigned NoMulticastRules = 0, parameter type rule_t, parameter rule_t [NoAddrRules-1:0] AddrMap, // Stimuli application and test time @@ -46,6 +48,7 @@ package tb_axi_xbar_pkg; typedef struct packed { slv_axi_id_t slv_axi_id; axi_addr_t slv_axi_addr; + axi_addr_t slv_axi_mcast; axi_pkg::len_t slv_axi_len; } exp_ax_t; typedef struct packed { @@ -148,50 +151,139 @@ package tb_axi_xbar_pkg; @(posedge masters_axi[0].clk_i); endtask - // This task monitors a slave ports of the crossbar. Every time an AW beat is seen - // it populates an id queue at the right master port (if there is no expected decode error), - // populates the expected b response in its own id_queue and in case when the atomic bit [5] + // This task monitors a slave port of the crossbar. Every time an AW beat is seen + // it populates an id queue at the right master port(s) (if there is no expected decode error), + // 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); - idx_slv_t to_slave_idx; - exp_ax_t exp_aw; - slv_axi_id_t exp_aw_id; - bit decerr; + 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; + // TODO colluca: add check that multicast requests only arrive on multicast ports + // (lower NoMulticastPorts) and that multicast requests only originate + // from multicast rules (lower NoMulticastRules) + if (masters_axi[i].aw_valid && masters_axi[i].aw_ready) begin - // check if it should go to a decerror - decerr = 1'b1; - for (int unsigned j = 0; j < NoAddrRules; j++) begin - if ((masters_axi[i].aw_addr >= AddrMap[j].start_addr) && - (masters_axi[i].aw_addr < AddrMap[j].end_addr)) begin - to_slave_idx = idx_slv_t'(AddrMap[j].idx); - decerr = 1'b0; + + // 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_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]; + + // Set decode error by default, reset if a rule is matched in the following + decerr = 1; + + // When a mask is present, multicast rules are used, otherwise the unicast rules are used. + if (aw_mcast != '0) begin + + // Log masked address + for (int k = 0; k < AxiAddrWidth; k++) + aw_addr_masked[k] = aw_mcast[k] ? 1'bx : aw_addr[k]; + + $display("Trying to match: %x", aw_addr_masked); + + // Compare request against each multicast 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 = (NoMulticastRules - 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; + 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 + int unsigned slave_idx = AddrMap[j].idx; + decerr = 0; + + // 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 - end - // send the exp aw beat down into the queue of the slave when no decerror - if (!decerr) begin - exp_aw_id = {idx_mst_t'(i), masters_axi[i].aw_id}; - // $display("Test exp aw_id: %b",exp_aw_id); - exp_aw = '{slv_axi_id: exp_aw_id, - slv_axi_addr: masters_axi[i].aw_addr, - slv_axi_len: masters_axi[i].aw_len }; - this.exp_aw_queue[to_slave_idx].push(exp_aw_id, exp_aw); - incr_expected_tests(3); - $display("%0tns > Master %0d: AW to Slave %0d: Axi ID: %b", - $time, i, to_slave_idx, masters_axi[i].aw_id); + end else begin + + // Compare request against each interval-form rule. We look at the rules starting from + // the last ones. We ignore the case of multiple rules matching for the same slave + $display("Trying to match: %x", aw_addr); + for (int j = (NoAddrRules - 1); j >= 0; j--) begin + if ((aw_addr >= AddrMap[j].start_addr) && + (aw_addr < AddrMap[j].end_addr)) begin + decerr = 0; + to_slave_idx.push_back(AddrMap[j].idx); + addr_to_slave.push_back(aw_addr); + mask_to_slave.push_back('0); + $display(" Push address : %x", aw_addr); + end + end + + end + + num_slaves_matched = to_slave_idx.size(); + + // send the exp aw beats down into the queues of the selected slaves + // when no decerror + if (decerr) begin $display("%0tns > Master %0d: AW to Decerror: Axi ID: %b", - $time, i, to_slave_idx, masters_axi[i].aw_id); + $time, i, masters_axi[i].aw_id); + end else begin + exp_aw_id = {idx_mst_t'(i), masters_axi[i].aw_id}; + for (int j = 0; j < num_slaves_matched; j++) begin + automatic idx_slv_t slave_idx = to_slave_idx.pop_front(); + // $display("Test exp aw_id: %b",exp_aw_id); + exp_aw = '{slv_axi_id: exp_aw_id, + slv_axi_addr: addr_to_slave.pop_front(), + slv_axi_mcast: mask_to_slave.pop_front(), + slv_axi_len: masters_axi[i].aw_len}; + this.exp_aw_queue[slave_idx].push(exp_aw_id, exp_aw); + incr_expected_tests(4); + if (j == 0) slaves_str = $sformatf("%0d", slave_idx); + else slaves_str = $sformatf("%s, %0d", slaves_str, slave_idx); + end + $display("%0tns > Master %0d: AW to Slaves [%s]: Axi ID: %b", + $time, i, slaves_str, masters_axi[i].aw_id); end + // populate the expected b queue anyway exp_b = '{mst_axi_id: masters_axi[i].aw_id, last: 1'b1}; this.exp_b_queue[i].push(masters_axi[i].aw_id, exp_b); incr_expected_tests(1); $display(" Expect B response."); + // inject expected r beats on this id, if it is an atop + // throw an error if a multicast atop is attempted (not supported) if(masters_axi[i].aw_atop[5]) begin + if (num_slaves_matched > 1) $fatal(0, "Multicast ATOPs are not supported"); // push the required r beats into the right fifo (reuse the exp_b variable) $display(" Expect R response, len: %0d.", masters_axi[i].aw_len); for (int unsigned j = 0; j <= masters_axi[i].aw_len; j++) begin @@ -205,7 +297,7 @@ package tb_axi_xbar_pkg; end endtask : monitor_mst_aw - // This task monitors a slave port of the crossbar. Every time there is an AW vector it + // This task monitors a master port of the crossbar. Every time there is an AW vector it // gets checked for its contents and if it was expected. The task then pushes an expected // amount of W beats in the respective fifo. Emphasis of the last flag. task automatic monitor_slv_aw(input int unsigned i); @@ -227,14 +319,21 @@ package tb_axi_xbar_pkg; $warning("Slave %0d: Unexpected AW with ID: %b and ADDR: %h, exp: %h", i, slaves_axi[i].aw_id, slaves_axi[i].aw_addr, exp_aw.slv_axi_addr); end + if (exp_aw.slv_axi_mcast != slaves_axi[i].aw_user[AxiAddrWidth-1:0]) begin + incr_failed_tests(1); + $warning("Slave %0d: Unexpected AW with ID: %b and MCAST: %h, exp: %h", + i, slaves_axi[i].aw_id, slaves_axi[i].aw_user[AxiAddrWidth-1:0], + exp_aw.slv_axi_mcast); + end if (exp_aw.slv_axi_len != slaves_axi[i].aw_len) begin incr_failed_tests(1); $warning("Slave %0d: Unexpected AW with ID: %b and LEN: %h, exp: %h", i, slaves_axi[i].aw_id, slaves_axi[i].aw_len, exp_aw.slv_axi_len); end - incr_conducted_tests(3); + incr_conducted_tests(4); // push the required w beats into the right fifo + $display(" Expect %0d W beats.", slaves_axi[i].aw_len + 1); incr_expected_tests(slaves_axi[i].aw_len + 1); for (int unsigned j = 0; j <= slaves_axi[i].aw_len; j++) begin exp_slv_w = (j == slaves_axi[i].aw_len) ? @@ -334,13 +433,14 @@ package tb_axi_xbar_pkg; // push the expected vectors AW for exp_slv exp_slv_ar = '{slv_axi_id: exp_slv_axi_id, slv_axi_addr: mst_axi_addr, - slv_axi_len: mst_axi_len }; + slv_axi_mcast: '0, + slv_axi_len: mst_axi_len}; //$display("Expected Slv Axi Id is: %b", exp_slv_axi_id); this.exp_ar_queue[exp_slv_idx].push(exp_slv_axi_id, exp_slv_ar); incr_expected_tests(1); end // push the required r beats into the right fifo - $display(" Expect R response, len: %0d.", masters_axi[i].ar_len); + $display(" Expect R response, len: %0d.", mst_axi_len); for (int unsigned j = 0; j <= mst_axi_len; j++) begin exp_mst_r = (j == mst_axi_len) ? '{mst_axi_id: mst_axi_id, last: 1'b1} : '{mst_axi_id: mst_axi_id, last: 1'b0}; @@ -498,6 +598,12 @@ package tb_axi_xbar_pkg; if(tests_conducted == 0) begin $error("Simulation did not conduct any tests!"); end + if (tests_conducted < tests_expected) begin + $error("Some of the expected tests were not conducted!"); + end + if (tests_conducted > tests_expected) begin + $error("Conducted more than the expected tests!"); + end endtask : print_result endclass : axi_xbar_monitor endpackage From 60a12e073ca8edc9743ad8a9deb11860cacc2544 Mon Sep 17 00:00:00 2001 From: Luca Colagrande Date: Tue, 23 Sep 2025 19:17:07 +0200 Subject: [PATCH 26/41] Restrict UniqueIds to 0 when multicast is enabled --- scripts/run_vsim.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/run_vsim.sh b/scripts/run_vsim.sh index 76235be7e..beeab0b34 100755 --- a/scripts/run_vsim.sh +++ b/scripts/run_vsim.sh @@ -249,7 +249,7 @@ exec_test() { MST_ID=5 for DATA_WIDTH in 64 256; do for PIPE in 0; do - for UNIQUE_IDS in 0 1; do + for UNIQUE_IDS in 0; do call_vsim tb_axi_mcast_xbar -t 1ns \ -gTbNumMasters=$NUM_MST \ -gTbNumMcastSlaves=$NUM_SLV \ From abbab23d8d18398d4ec96e7dc90b03c7f021acfa Mon Sep 17 00:00:00 2001 From: Luca Colagrande Date: Tue, 23 Sep 2025 19:48:53 +0200 Subject: [PATCH 27/41] Rename `axi_mcast_demux` to `axi_mcast_demux_mapped` --- Bender.yml | 2 +- src/{axi_mcast_demux.sv => axi_mcast_demux_mapped.sv} | 2 +- src/axi_mcast_xbar_unmuxed.sv | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename src/{axi_mcast_demux.sv => axi_mcast_demux_mapped.sv} (99%) diff --git a/Bender.yml b/Bender.yml index d807e8325..00e713dda 100644 --- a/Bender.yml +++ b/Bender.yml @@ -88,8 +88,8 @@ sources: - src/axi_dw_converter.sv - src/axi_from_mem.sv - src/axi_id_serialize.sv - - src/axi_mcast_demux.sv - src/axi_lfsr.sv + - src/axi_mcast_demux_mapped.sv - src/axi_multicut.sv - src/axi_to_axi_lite.sv - src/axi_to_mem.sv diff --git a/src/axi_mcast_demux.sv b/src/axi_mcast_demux_mapped.sv similarity index 99% rename from src/axi_mcast_demux.sv rename to src/axi_mcast_demux_mapped.sv index c4c1c662d..808980817 100644 --- a/src/axi_mcast_demux.sv +++ b/src/axi_mcast_demux_mapped.sv @@ -40,7 +40,7 @@ /// /// Beats on the B and R channel are multiplexed from the master ports to the slave port with /// a round-robin arbitration tree. -module axi_mcast_demux #( +module axi_mcast_demux_mapped #( parameter int unsigned AxiIdWidth = 32'd0, parameter int unsigned AxiAddrWidth = 32'd0, parameter bit AtopSupport = 1'b1, diff --git a/src/axi_mcast_xbar_unmuxed.sv b/src/axi_mcast_xbar_unmuxed.sv index 49e81d726..ef89e8310 100644 --- a/src/axi_mcast_xbar_unmuxed.sv +++ b/src/axi_mcast_xbar_unmuxed.sv @@ -120,7 +120,7 @@ import cf_math_pkg::idx_width; `endif // pragma translate_on - axi_mcast_demux #( + axi_mcast_demux_mapped #( .AxiIdWidth ( Cfg.AxiIdWidthSlvPorts ), // ID Width .AxiAddrWidth ( Cfg.AxiAddrWidth ), .AtopSupport ( ATOPs ), From adce1aff101c5c44f9698d52831d92c5edc69f40 Mon Sep 17 00:00:00 2001 From: Luca Colagrande Date: Tue, 23 Sep 2025 20:04:00 +0200 Subject: [PATCH 28/41] Minor cleanup --- Bender.yml | 4 ---- src/axi_mcast_xbar_unmuxed.sv | 4 +++- src/axi_pkg.sv | 16 +--------------- test/tb_axi_mcast_xbar.sv | 1 - test/tb_axi_xbar.sv | 1 - 5 files changed, 4 insertions(+), 22 deletions(-) diff --git a/Bender.yml b/Bender.yml index 00e713dda..e316fb964 100644 --- a/Bender.yml +++ b/Bender.yml @@ -113,10 +113,6 @@ sources: files: - test/axi_synth_bench.sv - - target: gf12 - files: - - test/axi_synth_bench.sv - - target: simulation files: - src/axi_chan_compare.sv diff --git a/src/axi_mcast_xbar_unmuxed.sv b/src/axi_mcast_xbar_unmuxed.sv index ef89e8310..8d2ff145d 100644 --- a/src/axi_mcast_xbar_unmuxed.sv +++ b/src/axi_mcast_xbar_unmuxed.sv @@ -81,6 +81,8 @@ import cf_math_pkg::idx_width; input rule_t [Cfg.NoSlvPorts-1:0] default_mst_port_i ); + localparam bit EnableMulticast = (Cfg.NoMulticastPorts > 0) || (Cfg.NoMulticastRules > 0); + // signals from the axi_demuxes req_t [Cfg.NoSlvPorts-1:0][Cfg.NoMstPorts-1:0] slv_reqs; resp_t [Cfg.NoSlvPorts-1:0][Cfg.NoMstPorts-1:0] slv_resps; @@ -225,7 +227,7 @@ import cf_math_pkg::idx_width; $fatal(1, $sformatf("Slv_req and aw_addr width not equal.")); addr_mst_req_ports: assert ($bits(mst_ports_req_o[0][0].aw.addr) == Cfg.AxiAddrWidth) else $fatal(1, $sformatf("Mst_req and aw_addr width not equal.")); - no_cuts_if_mcast: assert (!Cfg.EnableMulticast || (Cfg.PipelineStages == 0)) else + no_cuts_if_mcast: assert (!EnableMulticast || (Cfg.PipelineStages == 0)) else $fatal(1, $sformatf("Multicast XBAR currently does not support pipeline stages.")); end `endif diff --git a/src/axi_pkg.sv b/src/axi_pkg.sv index 51952b1a6..d3937433c 100644 --- a/src/axi_pkg.sv +++ b/src/axi_pkg.sv @@ -515,12 +515,10 @@ package axi_pkg; int unsigned AxiAddrWidth; /// AXI4+ATOP data field width. int unsigned AxiDataWidth; - /// The number of address rules defined for routing of the AR transactions. + /// The number of address rules defined for routing of the 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; - /// When asserted, the XBAR is configured to support multicast. - bit EnableMulticast; /// The number of address rules to be considered for multicasting, /// assumed to be at the start of `addr_map_i`. int unsigned NoMulticastRules; @@ -536,12 +534,6 @@ package axi_pkg; logic [63:0] end_addr; } xbar_rule_64_t; - /// Commonly used rule types for `axi_xbar` (64-bit addresses). - typedef struct packed { - logic [63:0] addr; - logic [63:0] mask; - } xbar_mask_rule_64_t; - /// Commonly used rule types for `axi_xbar` (32-bit addresses). typedef struct packed { int unsigned idx; @@ -549,12 +541,6 @@ package axi_pkg; logic [31:0] end_addr; } xbar_rule_32_t; - /// Commonly used rule types for `axi_xbar` (32-bit addresses). - typedef struct packed { - logic [31:0] addr; - logic [31:0] mask; - } xbar_mask_rule_32_t; - // Return either the argument minus 1 or 0 if 0; useful for IO vector width declaration function automatic integer unsigned iomsb (input integer unsigned width); return (width != 32'd0) ? unsigned'(width-1) : 32'd0; diff --git a/test/tb_axi_mcast_xbar.sv b/test/tb_axi_mcast_xbar.sv index 7d7966b1b..565c4382c 100644 --- a/test/tb_axi_mcast_xbar.sv +++ b/test/tb_axi_mcast_xbar.sv @@ -79,7 +79,6 @@ module tb_axi_mcast_xbar #( AxiAddrWidth: TbAxiAddrWidth, AxiDataWidth: TbAxiDataWidth, NoAddrRules: TbNumMcastSlaves * 2 + 1, - EnableMulticast: 1, NoMulticastRules: TbNumMcastSlaves * 2, NoMulticastPorts: TbNumMcastSlaves }; diff --git a/test/tb_axi_xbar.sv b/test/tb_axi_xbar.sv index 3081af785..1daf39956 100644 --- a/test/tb_axi_xbar.sv +++ b/test/tb_axi_xbar.sv @@ -77,7 +77,6 @@ module tb_axi_xbar #( AxiAddrWidth: TbAxiAddrWidth, AxiDataWidth: TbAxiDataWidth, NoAddrRules: TbNumSlaves, - EnableMulticast: 1'b0, NoMulticastRules: 0, NoMulticastPorts: 0 }; From 3bf21d22cc97bb77273b8e1fcb486a53d0f6346d Mon Sep 17 00:00:00 2001 From: Luca Colagrande Date: Wed, 24 Sep 2025 10:29:10 +0200 Subject: [PATCH 29/41] Add assertions on multicast rule conversion --- src/axi_mcast_demux_mapped.sv | 36 ++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/src/axi_mcast_demux_mapped.sv b/src/axi_mcast_demux_mapped.sv index 808980817..4fcfd8268 100644 --- a/src/axi_mcast_demux_mapped.sv +++ b/src/axi_mcast_demux_mapped.sv @@ -228,11 +228,7 @@ module axi_mcast_demux_mapped #( addr_t [NoMstPortsExt-1:0] dec_aw_addr; addr_t [NoMstPortsExt-1:0] dec_aw_mask; - // 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 + // Convert multicast rules to mask (NAPOT) form, see https://arxiv.org/pdf/2502.19215 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; @@ -378,6 +374,36 @@ module axi_mcast_demux_mapped #( .slv_resp_o ( errslv_resp ) ); + // ----------------- + // Assertions + // ----------------- + + // Check that multicast address map rules expressed in interval form can be converted to + // mask form, see https://arxiv.org/pdf/2502.19215 + for (genvar i = 0; i < NoMulticastRules; i++) begin : gen_multicast_rule_assertion + addr_t size; + assign size = addr_map_i[i].end_addr - addr_map_i[i].start_addr; + `ASSERT(MulticastRuleSize, + ((size & (size - 1)) == 0), clk_i, !rst_ni, + $sformatf("Size %d of rule %d is not a power of 2", size, i)) + `ASSERT(MulticastRuleAlignment, + (addr_map_i[i].start_addr % size) == 0, clk_i, !rst_ni, + $sformatf("Rule %d, starting at 0x%x, is not aligned to its size (%d)", + addr_map_i[i].start_addr, i, size)) + end + // Default rule is only converted to mask form if there are any other multicast rules + if (NoMulticastRules > 0) begin : gen_multicast_default_rule_assertion + addr_t size; + assign size = default_mst_port_i.end_addr - default_mst_port_i.start_addr; + `ASSERT(DefaultRuleSize, + !en_default_mst_port_i || ((size & (size - 1)) == 0), clk_i, !rst_ni, + $sformatf("Size %d of default rule is not a power of 2", size)) + `ASSERT(DefaultRuleAlignment, + !en_default_mst_port_i || ((default_mst_port_i.start_addr % size) == 0), clk_i, !rst_ni, + $sformatf("Default rule, starting at 0x%x, is not aligned to its size (%d)", + default_mst_port_i.start_addr, size)) + end + endmodule // interface wrapper From 34cf9960d43138daf01c73aecbb586dd1c270ae6 Mon Sep 17 00:00:00 2001 From: Luca Colagrande Date: Wed, 24 Sep 2025 10:57:52 +0200 Subject: [PATCH 30/41] Address final TODOs --- src/axi_mcast_demux_mapped.sv | 34 ++++++++++++++++++++++++++++++++++ src/axi_mcast_mux.sv | 11 ++--------- src/axi_mcast_xbar_unmuxed.sv | 31 ------------------------------- src/axi_test.sv | 1 - 4 files changed, 36 insertions(+), 41 deletions(-) diff --git a/src/axi_mcast_demux_mapped.sv b/src/axi_mcast_demux_mapped.sv index 4fcfd8268..2db7496d1 100644 --- a/src/axi_mcast_demux_mapped.sv +++ b/src/axi_mcast_demux_mapped.sv @@ -378,6 +378,10 @@ module axi_mcast_demux_mapped #( // Assertions // ----------------- +// pragma translate_off +`ifndef VERILATOR +`ifndef XSIM + // Check that multicast address map rules expressed in interval form can be converted to // mask form, see https://arxiv.org/pdf/2502.19215 for (genvar i = 0; i < NoMulticastRules; i++) begin : gen_multicast_rule_assertion @@ -404,6 +408,36 @@ module axi_mcast_demux_mapped #( default_mst_port_i.start_addr, size)) end + // Check that addrmap and default slave do not change while there is an unserved Ax + `ASSERT(default_mst_port_en_aw_stable, + (slv_req_cut.aw_valid && !slv_resp_cut.aw_ready) |=> $stable(en_default_mst_port_i), + clk_i, !rst_ni, + "It is not allowed to change the default mst port enable when there is an unserved Aw beat.") + `ASSERT(default_mst_port_aw_stable, + (slv_req_cut.aw_valid && !slv_resp_cut.aw_ready) |=> $stable(default_mst_port_i), + clk_i, !rst_ni, + "It is not allowed to change the default mst port when there is an unserved Aw beat.") + `ASSERT(addrmap_aw_stable, + (slv_req_cut.aw_valid && !slv_resp_cut.aw_ready) |=> $stable(addr_map_i), + clk_i, !rst_ni, + "It is not allowed to change the address map when there is an unserved Aw beat.") + `ASSERT(default_mst_port_en_ar_stable, + (slv_req_cut.ar_valid && !slv_resp_cut.ar_ready) |=> $stable(en_default_mst_port_i), + clk_i, !rst_ni, + "It is not allowed to change the default mst port enable when there is an unserved Ar beat.") + `ASSERT(default_mst_port_ar_stable, + (slv_req_cut.ar_valid && !slv_resp_cut.ar_ready) |=> $stable(default_mst_port_i), + clk_i, !rst_ni, + "It is not allowed to change the default mst port when there is an unserved Ar beat.") + `ASSERT(addrmap_ar_stable, + (slv_req_cut.ar_valid && !slv_resp_cut.ar_ready) |=> $stable(addr_map_i), + clk_i, !rst_ni, + "It is not allowed to change the address map when there is an unserved Ar beat.") + +`endif +`endif +// pragma translate_on + endmodule // interface wrapper diff --git a/src/axi_mcast_mux.sv b/src/axi_mcast_mux.sv index 5a1c26c1a..b81a7c362 100644 --- a/src/axi_mcast_mux.sv +++ b/src/axi_mcast_mux.sv @@ -67,10 +67,6 @@ module axi_mcast_mux #( input mst_resp_t mst_resp_i ); - // TODO colluca: can this be merged with MstIdxBits? - localparam int unsigned SlvPortIdxBits = cf_math_pkg::idx_width(NoSlvPorts); - typedef logic [SlvPortIdxBits-1:0] mst_idx_t; - localparam int unsigned MstIdxBits = $clog2(NoSlvPorts); localparam int unsigned MstAxiIDWidth = SlvAxiIDWidth + MstIdxBits; @@ -182,7 +178,7 @@ module axi_mcast_mux #( logic ucast_aw_valid, ucast_aw_ready; logic mcast_aw_valid, mcast_aw_ready, mcast_aw_commit; logic mcast_not_aw_valid; - mst_idx_t mcast_sel_q, mcast_sel_d; + logic [MstIdxBits-1:0] mcast_sel_q, mcast_sel_d; logic [NoSlvPorts-1:0] mcast_sel_mask; logic [NoSlvPorts-1:0] ucast_aw_readies, mcast_aw_readies; @@ -299,7 +295,6 @@ module axi_mcast_mux #( ); // Arbitrate multicast requests in priority encoder fashion - // TODO colluca: extend lzc to return mask form instead of cnt? lzc #( .WIDTH ( NoSlvPorts ), .MODE ( 1'b0 ) // Trailing zero mode @@ -314,8 +309,7 @@ module axi_mcast_mux #( assign mcast_aw_commit = |slv_aw_commit_i; assign mcast_aw_readies = {NoSlvPorts{mcast_aw_ready}} & mcast_sel_mask; - // TODO colluca: change all FFxARN to FFx - `FFLARN(mcast_sel_q, mcast_sel_d, mcast_aw_valid && mcast_aw_ready, '0, clk_i, rst_ni) + `FFL(mcast_sel_q, mcast_sel_d, mcast_aw_valid && mcast_aw_ready, '0, clk_i, rst_ni) // Arbitrate "winners" of unicast and multicast arbitrations // giving priority to multicast @@ -546,7 +540,6 @@ module axi_mcast_mux #( // pragma translate_on endmodule -// TODO colluca: adapt this // interface wrap `include "axi/assign.svh" `include "axi/typedef.svh" diff --git a/src/axi_mcast_xbar_unmuxed.sv b/src/axi_mcast_xbar_unmuxed.sv index 8d2ff145d..d720f2dfe 100644 --- a/src/axi_mcast_xbar_unmuxed.sv +++ b/src/axi_mcast_xbar_unmuxed.sv @@ -91,37 +91,6 @@ import cf_math_pkg::idx_width; for (genvar i = 0; i < Cfg.NoSlvPorts; i++) begin : gen_slv_port_demux - // make sure that the default slave does not get changed, if there is an unserved Ax - // pragma translate_off - // TODO(colluca): is this still the right place for these? and are they still correct after - // moving the address decoders past the spill registers - `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_mcast_demux_mapped #( .AxiIdWidth ( Cfg.AxiIdWidthSlvPorts ), // ID Width .AxiAddrWidth ( Cfg.AxiAddrWidth ), diff --git a/src/axi_test.sv b/src/axi_test.sv index 1d1b12d9a..7ca986cd0 100644 --- a/src/axi_test.sv +++ b/src/axi_test.sv @@ -906,7 +906,6 @@ package axi_test; // Determine memory type. ax_beat.ax_cache = is_read ? axi_pkg::get_arcache(mem_region.mem_type) : axi_pkg::get_awcache(mem_region.mem_type); // Randomize beat size. - // TODO colluca: how do we handle traffic shaping w/ multicast? if (TRAFFIC_SHAPING) begin rand_success = std::randomize(cprob) with { cprob >= 0; cprob < max_cprob; From 8cba35d37908acbca2d873f535a907657bcb76aa Mon Sep 17 00:00:00 2001 From: Luca Colagrande Date: Thu, 25 Sep 2025 15:25:29 +0200 Subject: [PATCH 31/41] axi_mcast_mux: Remove dependency of valid on ready --- src/axi_mcast_mux.sv | 43 ++++++++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/src/axi_mcast_mux.sv b/src/axi_mcast_mux.sv index b81a7c362..e17cbf40e 100644 --- a/src/axi_mcast_mux.sv +++ b/src/axi_mcast_mux.sv @@ -177,7 +177,7 @@ module axi_mcast_mux #( mst_aw_chan_t ucast_aw_chan, mcast_aw_chan; logic ucast_aw_valid, ucast_aw_ready; logic mcast_aw_valid, mcast_aw_ready, mcast_aw_commit; - logic mcast_not_aw_valid; + logic mcast_not_aw_valid, mcast_aw_priority; logic [MstIdxBits-1:0] mcast_sel_q, mcast_sel_d; logic [NoSlvPorts-1:0] mcast_sel_mask; logic [NoSlvPorts-1:0] ucast_aw_readies, mcast_aw_readies; @@ -189,6 +189,7 @@ module axi_mcast_mux #( // gets pushed into the W FIFO, when it now stalls prevent subsequent pushing // This FF removes AW to W dependency logic lock_aw_valid_d, lock_aw_valid_q; + logic lock_unicast_d, lock_unicast_q; logic load_aw_lock; // signals for the FIFO that holds the last switching decision of the AW channel @@ -311,22 +312,32 @@ module axi_mcast_mux #( `FFL(mcast_sel_q, mcast_sel_d, mcast_aw_valid && mcast_aw_ready, '0, clk_i, rst_ni) - // Arbitrate "winners" of unicast and multicast arbitrations - // giving priority to multicast - assign mcast_aw_ready = aw_ready && mcast_aw_valid && !mcast_aw_commit; - assign ucast_aw_ready = aw_ready && !mcast_aw_valid && !mcast_aw_commit; + // Arbitrate "winners" of unicast and multicast arbitrations, + // giving priority to multicast. + // On a multicast, the downstream valid is gated until we get the commit signal. + // But the commit signal is only received after we have received the downstream + // ready and propagated it upstream. So the downstream ready will be kept high + // for an additional cycle after there was an upstream handshake. We must thus + // gate it upstream for that additional cycle (with !mcast_aw_commit). + // If we already locked the AW on a unicast transaction, we must wait for it to + // complete before accepting a multicast transaction, so we give priority to the + // unicast. + assign mcast_aw_priority = mcast_aw_valid && !lock_unicast_q; + assign mcast_aw_ready = aw_ready && !mcast_aw_commit && mcast_aw_priority; + assign ucast_aw_ready = aw_ready && !mcast_aw_commit && !mcast_aw_priority; assign mst_aw_chan = mcast_aw_commit ? mcast_aw_chan : ucast_aw_chan; assign slv_aw_readies = mcast_aw_readies | ucast_aw_readies; - // !!! CAUTION !!! - // This valid depends combinationally on aw_ready (through aw_commit), - // hence aw_ready shouldn't depend on aw_valid to avoid combinational loops! - // TODO colluca: replace ucast_aw_ready with !mcast_aw_valid to remove combinational loop - assign aw_valid = mcast_aw_commit || (ucast_aw_valid && ucast_aw_ready); + // In case of a multicast transaction, downstream valid should only be asserted + // on commit. However, a multicast transaction is already accepted on the cycle + // before, when we have mcast_aw_valid. We must prevent a unicast transaction + // from raising the downstream valid in that time (with !mcast_aw_valid). + assign aw_valid = mcast_aw_commit || (ucast_aw_valid && !mcast_aw_valid); // control of the AW channel always_comb begin // default assignments lock_aw_valid_d = lock_aw_valid_q; + lock_unicast_d = lock_unicast_q; load_aw_lock = 1'b0; w_fifo_push = 1'b0; mst_aw_valid = 1'b0; @@ -338,27 +349,33 @@ module axi_mcast_mux #( if (mst_aw_ready) begin aw_ready = 1'b1; lock_aw_valid_d = 1'b0; + lock_unicast_d = 1'b0; load_aw_lock = 1'b1; + w_fifo_push = 1'b1; end end else begin if (!w_fifo_full) begin if (mst_aw_ready) begin aw_ready = 1'b1; - end + end if (aw_valid) begin mst_aw_valid = 1'b1; - w_fifo_push = 1'b1; if (!mst_aw_ready) begin // go to lock if transaction not in this cycle lock_aw_valid_d = 1'b1; load_aw_lock = 1'b1; + // remember if it was a unicast transaction + lock_unicast_d = !mcast_aw_commit; + end else begin + w_fifo_push = 1'b1; end end end end end - `FFLARN(lock_aw_valid_q, lock_aw_valid_d, load_aw_lock, '0, clk_i, rst_ni) + `FFL(lock_aw_valid_q, lock_aw_valid_d, load_aw_lock, '0, clk_i, rst_ni) + `FFL(lock_unicast_q, lock_unicast_d, load_aw_lock, '0, clk_i, rst_ni) fifo_v3 #( .FALL_THROUGH ( FallThrough ), From a5301e7fa06b629df0c34aae1d9a5622dd4b0c88 Mon Sep 17 00:00:00 2001 From: Luca Colagrande Date: Fri, 26 Sep 2025 11:05:28 +0200 Subject: [PATCH 32/41] axi_mcast_demux_mapped: Improve readability of assertions --- src/axi_mcast_demux_mapped.sv | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/axi_mcast_demux_mapped.sv b/src/axi_mcast_demux_mapped.sv index 2db7496d1..9540e399e 100644 --- a/src/axi_mcast_demux_mapped.sv +++ b/src/axi_mcast_demux_mapped.sv @@ -389,11 +389,11 @@ module axi_mcast_demux_mapped #( assign size = addr_map_i[i].end_addr - addr_map_i[i].start_addr; `ASSERT(MulticastRuleSize, ((size & (size - 1)) == 0), clk_i, !rst_ni, - $sformatf("Size %d of rule %d is not a power of 2", size, i)) + $sformatf("Size %0d of rule %0d is not a power of 2", size, i)) `ASSERT(MulticastRuleAlignment, (addr_map_i[i].start_addr % size) == 0, clk_i, !rst_ni, - $sformatf("Rule %d, starting at 0x%x, is not aligned to its size (%d)", - addr_map_i[i].start_addr, i, size)) + $sformatf("Rule %0d, starting at 0x%0x, is not aligned to its size (%0d)", + i, addr_map_i[i].start_addr, size)) end // Default rule is only converted to mask form if there are any other multicast rules if (NoMulticastRules > 0) begin : gen_multicast_default_rule_assertion @@ -401,10 +401,10 @@ module axi_mcast_demux_mapped #( assign size = default_mst_port_i.end_addr - default_mst_port_i.start_addr; `ASSERT(DefaultRuleSize, !en_default_mst_port_i || ((size & (size - 1)) == 0), clk_i, !rst_ni, - $sformatf("Size %d of default rule is not a power of 2", size)) + $sformatf("Size %0d of default rule is not a power of 2", size)) `ASSERT(DefaultRuleAlignment, !en_default_mst_port_i || ((default_mst_port_i.start_addr % size) == 0), clk_i, !rst_ni, - $sformatf("Default rule, starting at 0x%x, is not aligned to its size (%d)", + $sformatf("Default rule, starting at 0x%0x, is not aligned to its size (%0d)", default_mst_port_i.start_addr, size)) end From 69dc10b667054b57e26062b0ef68fed6a803c793 Mon Sep 17 00:00:00 2001 From: Luca Colagrande Date: Fri, 26 Sep 2025 14:57:46 +0200 Subject: [PATCH 33/41] axi_mcast_demux_mapped: Allow multicast XBAR with NoMulticastRules == 0 --- src/axi_mcast_demux_mapped.sv | 90 ++++++++++++++++++----------------- 1 file changed, 47 insertions(+), 43 deletions(-) diff --git a/src/axi_mcast_demux_mapped.sv b/src/axi_mcast_demux_mapped.sv index 9540e399e..c4d1f105d 100644 --- a/src/axi_mcast_demux_mapped.sv +++ b/src/axi_mcast_demux_mapped.sv @@ -207,8 +207,8 @@ module axi_mcast_demux_mapped #( // ----------------- // AW decoder inputs - mask_rule_t [NoMulticastRules-1:0] multicast_rules; - mask_rule_t default_rule; + mask_rule_t [axi_pkg::iomsb(NoMulticastRules):0] multicast_rules; + mask_rule_t default_rule; // AW unicast decoder outputs idx_select_t dec_aw_unicast_select_idx; @@ -228,16 +228,6 @@ module axi_mcast_demux_mapped #( addr_t [NoMstPortsExt-1:0] dec_aw_addr; addr_t [NoMstPortsExt-1:0] dec_aw_mask; - // Convert multicast rules to mask (NAPOT) form, see https://arxiv.org/pdf/2502.19215 - 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 - assign default_rule.idx = default_mst_port_i.idx; - assign default_rule.mask = default_mst_port_i.end_addr - default_mst_port_i.start_addr - 1; - assign default_rule.addr = default_mst_port_i.start_addr; - // Address decoding for unicast requests addr_decode #( .NoIndices (NoMstPorts), @@ -257,40 +247,53 @@ module axi_mcast_demux_mapped #( // Generate the output mask from the index assign dec_aw_unicast_select_mask = 1'b1 << dec_aw_unicast_select_idx; - // Address decoding for multicast requests - if (NoMulticastRules > 0) begin : gen_multicast_decoding - multiaddr_decode #( - .NoIndices (NoMulticastPorts), - .NoRules (NoMulticastRules), - .addr_t (addr_t), - .rule_t (mask_rule_t) - ) i_axi_aw_multicast_decode ( - .addr_map_i (multicast_rules), - .addr_i (slv_req_cut.aw.addr), - .mask_i (slv_req_cut.aw.user.collective_mask), - .select_o (dec_aw_multicast_select_mask), - .addr_o (dec_aw_multicast_addr), - .mask_o (dec_aw_multicast_mask), - .dec_valid_o (dec_aw_multicast_valid), - .dec_error_o (dec_aw_multicast_error), - .en_default_idx_i (en_default_mst_port_i), - .default_idx_i (default_rule) - ); - end else begin : gen_no_multicast_decoding - assign dec_aw_multicast_select_mask = '0; - assign dec_aw_multicast_addr = '0; - assign dec_aw_multicast_mask = '0; - assign dec_aw_multicast_valid = '0; - assign dec_aw_multicast_error = '0; - end - // If the address decoding doesn't produce any match, the request // is routed to the error slave, which lies at the highest index. mask_select_t select_error_slave; assign select_error_slave = 1'b1 << NoMstPorts; - // Mux the multicast and unicast decoding outputs - if (NoMulticastRules > 0) begin : gen_decoding_mux + // Disable multicast only if NoMulticastPorts == 0. In some instances you may want to + // match the multicast decoder's default port, even if NoMulticastRules == 0. + if (NoMulticastPorts > 0) begin : gen_multicast + + // Convert multicast rules to mask (NAPOT) form, see https://arxiv.org/pdf/2502.19215 + for (genvar i = 0; i < NoMulticastRules; i++) begin : gen_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 + assign default_rule.idx = default_mst_port_i.idx; + assign default_rule.mask = default_mst_port_i.end_addr - default_mst_port_i.start_addr - 1; + assign default_rule.addr = default_mst_port_i.start_addr; + + if (NoMulticastRules > 0) begin : gen_multiaddr_decode + // Address decoding for multicast requests. + multiaddr_decode #( + .NoIndices (NoMulticastPorts), + .NoRules (NoMulticastRules), + .addr_t (addr_t), + .rule_t (mask_rule_t) + ) i_axi_aw_multicast_decode ( + .addr_map_i (multicast_rules), + .addr_i (slv_req_cut.aw.addr), + .mask_i (slv_req_cut.aw.user.collective_mask), + .select_o (dec_aw_multicast_select_mask), + .addr_o (dec_aw_multicast_addr), + .mask_o (dec_aw_multicast_mask), + .dec_valid_o (dec_aw_multicast_valid), + .dec_error_o (dec_aw_multicast_error), + .en_default_idx_i (en_default_mst_port_i), + .default_idx_i (default_rule) + ); + end else begin : gen_no_multiaddr_decode + assign dec_aw_multicast_select_mask = 1'b1 << default_rule.idx; + assign dec_aw_multicast_addr = slv_req_cut.aw.addr; + assign dec_aw_multicast_mask = slv_req_cut.aw.user.collective_mask; + assign dec_aw_multicast_valid = 1'b1; + assign dec_aw_multicast_error = 1'b0; + end + + // Mux the multicast and unicast decoding outputs. always_comb begin dec_aw_select_mask = '0; dec_aw_addr = '0; @@ -313,7 +316,8 @@ module axi_mcast_demux_mapped #( end end end - end else begin + + end else begin : gen_no_multicast assign dec_aw_addr = {'0, {NoMstPorts{slv_req_cut.aw.addr}}}; assign dec_aw_mask = '0; assign dec_aw_select_mask = (dec_aw_unicast_error) ? select_error_slave : @@ -396,7 +400,7 @@ module axi_mcast_demux_mapped #( i, addr_map_i[i].start_addr, size)) end // Default rule is only converted to mask form if there are any other multicast rules - if (NoMulticastRules > 0) begin : gen_multicast_default_rule_assertion + if (NoMulticastPorts > 0) begin : gen_multicast_default_rule_assertion addr_t size; assign size = default_mst_port_i.end_addr - default_mst_port_i.start_addr; `ASSERT(DefaultRuleSize, From 98f9fc5967296221baf730c9d5b487db3e6297ba Mon Sep 17 00:00:00 2001 From: Luca Colagrande Date: Mon, 15 Dec 2025 11:59:35 +0100 Subject: [PATCH 34/41] axi_mcast_demux_mapped: Fix VCS compilation when `NoMulticastPorts==0` --- src/axi_mcast_demux_mapped.sv | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/axi_mcast_demux_mapped.sv b/src/axi_mcast_demux_mapped.sv index c4d1f105d..cc34f7a13 100644 --- a/src/axi_mcast_demux_mapped.sv +++ b/src/axi_mcast_demux_mapped.sv @@ -211,17 +211,17 @@ module axi_mcast_demux_mapped #( mask_rule_t default_rule; // AW unicast decoder outputs - idx_select_t dec_aw_unicast_select_idx; - logic [NoMstPorts-1:0] dec_aw_unicast_select_mask; - logic dec_aw_unicast_valid; - logic dec_aw_unicast_error; + idx_select_t dec_aw_unicast_select_idx; + logic [NoMstPorts-1:0] dec_aw_unicast_select_mask; + logic dec_aw_unicast_valid; + logic dec_aw_unicast_error; // AW multicast decoder outputs - logic [NoMulticastPorts-1:0] dec_aw_multicast_select_mask; - addr_t [NoMulticastPorts-1:0] dec_aw_multicast_addr; - addr_t [NoMulticastPorts-1:0] dec_aw_multicast_mask; - logic dec_aw_multicast_valid; - logic dec_aw_multicast_error; + logic [axi_pkg::iomsb(NoMulticastPorts):0] dec_aw_multicast_select_mask; + addr_t [axi_pkg::iomsb(NoMulticastPorts):0] dec_aw_multicast_addr; + addr_t [axi_pkg::iomsb(NoMulticastPorts):0] dec_aw_multicast_mask; + logic dec_aw_multicast_valid; + logic dec_aw_multicast_error; // Decoding outputs (merged from unicast and multicast paths) mask_select_t dec_aw_select_mask; From 57e33cdfa5cb6b95a23ed4e41df91e3710852033 Mon Sep 17 00:00:00 2001 From: Luca Colagrande Date: Fri, 23 Jan 2026 14:49:35 +0100 Subject: [PATCH 35/41] Bender.yml: Fix IP sorting by levels --- Bender.yml | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/Bender.yml b/Bender.yml index e316fb964..2724ff96b 100644 --- a/Bender.yml +++ b/Bender.yml @@ -43,22 +43,16 @@ sources: - src/axi_intf.sv # Level 2 - src/axi_atop_filter.sv - - src/axi_burst_splitter_gran.sv - - src/axi_burst_unwrap.sv - src/axi_bus_compare.sv - src/axi_cdc_dst.sv - src/axi_cdc_src.sv - src/axi_cut.sv - src/axi_delayer.sv - - src/axi_demux_simple.sv - - src/axi_dw_downsizer.sv - - src/axi_dw_upsizer.sv - src/axi_fifo.sv - src/axi_fifo_delay_dyn.sv - src/axi_id_remap.sv - src/axi_id_prepend.sv - src/axi_inval_filter.sv - - src/axi_isolate.sv - src/axi_join.sv - src/axi_lite_demux.sv - src/axi_lite_dw_converter.sv @@ -73,7 +67,6 @@ sources: - src/axi_mcast_demux_simple.sv - src/axi_mcast_mux.sv - src/axi_modify_address.sv - - src/axi_mux.sv - src/axi_rw_join.sv - src/axi_rw_split.sv - src/axi_serializer.sv @@ -81,32 +74,40 @@ sources: - src/axi_throttle.sv - src/axi_to_detailed_mem.sv # Level 3 - - src/axi_burst_splitter.sv - src/axi_cdc.sv - - src/axi_demux.sv + - src/axi_demux_simple.sv - src/axi_err_slv.sv - - src/axi_dw_converter.sv - src/axi_from_mem.sv - - src/axi_id_serialize.sv - - src/axi_lfsr.sv - src/axi_mcast_demux_mapped.sv - src/axi_multicut.sv - - src/axi_to_axi_lite.sv + - src/axi_mux.sv - src/axi_to_mem.sv - src/axi_zero_mem.sv # Level 4 - - src/axi_interleaved_xbar.sv - - src/axi_iw_converter.sv + - src/axi_burst_splitter_gran.sv + - src/axi_demux.sv - src/axi_lite_xbar.sv - src/axi_mcast_xbar_unmuxed.sv - - src/axi_xbar_unmuxed.sv - - src/axi_to_mem_banked.sv - src/axi_to_mem_interleaved.sv - src/axi_to_mem_split.sv # Level 5 + - src/axi_burst_splitter.sv + - src/axi_burst_unwrap.sv + - src/axi_dw_downsizer.sv + - src/axi_dw_upsizer.sv + - src/axi_id_serialize.sv + - src/axi_interleaved_xbar.sv + - src/axi_isolate.sv - src/axi_mcast_xbar.sv - - src/axi_xbar.sv + - src/axi_to_mem_banked.sv + - src/axi_xbar_unmuxed.sv # Level 6 + - src/axi_dw_converter.sv + - src/axi_iw_converter.sv + - src/axi_to_axi_lite.sv + - src/axi_xbar.sv + # Level 7 + - src/axi_lfsr.sv - src/axi_xp.sv - target: synth_test From a4bb24206700d2c7c541da15282fd40d7b9e59a3 Mon Sep 17 00:00:00 2001 From: Luca Colagrande Date: Sun, 25 Jan 2026 11:11:16 +0100 Subject: [PATCH 36/41] tb_axi_xbar_pkg: Remove legacy TODO --- test/tb_axi_xbar_pkg.sv | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test/tb_axi_xbar_pkg.sv b/test/tb_axi_xbar_pkg.sv index 5343960b6..895ced8f1 100644 --- a/test/tb_axi_xbar_pkg.sv +++ b/test/tb_axi_xbar_pkg.sv @@ -174,10 +174,6 @@ package tb_axi_xbar_pkg; master_exp_t exp_b; - // TODO colluca: add check that multicast requests only arrive on multicast ports - // (lower NoMulticastPorts) and that multicast requests only originate - // from multicast rules (lower NoMulticastRules) - if (masters_axi[i].aw_valid && masters_axi[i].aw_ready) begin // Check to which slaves the transaction is directed or if it should go to a decerror. From 5d8c00dffc7028887550d012bfb3bdb002180986 Mon Sep 17 00:00:00 2001 From: Luca Colagrande Date: Thu, 29 Jan 2026 16:35:20 +0100 Subject: [PATCH 37/41] axi_mcast_xbar_intf: Do not hardcode `aw_user_t` --- src/axi_mcast_xbar.sv | 5 +---- test/tb_axi_mcast_xbar.sv | 9 +++++++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/axi_mcast_xbar.sv b/src/axi_mcast_xbar.sv index 0dd385ecc..cb0584554 100644 --- a/src/axi_mcast_xbar.sv +++ b/src/axi_mcast_xbar.sv @@ -176,6 +176,7 @@ import cf_math_pkg::idx_width; parameter bit ATOPS = 1'b1, parameter bit [Cfg.NoSlvPorts-1:0][Cfg.NoMstPorts-1:0] CONNECTIVITY = '1, parameter bit [Cfg.NoSlvPorts-1:0][Cfg.NoMstPorts-1:0] MULTICAST_CONNECTIVITY = '1, + parameter type aw_user_t = logic [AXI_USER_WIDTH-1:0], parameter type rule_t = axi_pkg::xbar_rule_64_t ) ( input logic clk_i, @@ -196,10 +197,6 @@ import cf_math_pkg::idx_width; typedef logic [Cfg.AxiDataWidth -1:0] data_t; typedef logic [Cfg.AxiDataWidth/8 -1:0] strb_t; typedef logic [AXI_USER_WIDTH -1:0] user_t; - // AW channel adds collective mask to USER signals - typedef struct packed { - addr_t collective_mask; - } aw_user_t; `AXI_TYPEDEF_AW_CHAN_T(mst_aw_chan_t, addr_t, id_mst_t, aw_user_t) `AXI_TYPEDEF_AW_CHAN_T(slv_aw_chan_t, addr_t, id_slv_t, aw_user_t) diff --git a/test/tb_axi_mcast_xbar.sv b/test/tb_axi_mcast_xbar.sv index 565c4382c..e1540636c 100644 --- a/test/tb_axi_mcast_xbar.sv +++ b/test/tb_axi_mcast_xbar.sv @@ -93,9 +93,13 @@ module tb_axi_mcast_xbar #( typedef logic [TbAxiDataWidth-1:0] data_t; typedef logic [TbAxiStrbWidth-1:0] strb_t; typedef logic [TbAxiUserWidth-1:0] user_t; + // For collectives, AW channel should contain collective mask in USER field + typedef struct packed { + addr_t collective_mask; + } aw_user_t; - `AXI_TYPEDEF_AW_CHAN_T(aw_chan_mst_t, addr_t, id_mst_t, user_t) - `AXI_TYPEDEF_AW_CHAN_T(aw_chan_slv_t, addr_t, id_slv_t, user_t) + `AXI_TYPEDEF_AW_CHAN_T(aw_chan_mst_t, addr_t, id_mst_t, aw_user_t) + `AXI_TYPEDEF_AW_CHAN_T(aw_chan_slv_t, addr_t, id_slv_t, aw_user_t) `AXI_TYPEDEF_W_CHAN_T(w_chan_t, data_t, strb_t, user_t) `AXI_TYPEDEF_B_CHAN_T(b_chan_mst_t, id_mst_t, user_t) `AXI_TYPEDEF_B_CHAN_T(b_chan_slv_t, id_slv_t, user_t) @@ -308,6 +312,7 @@ module tb_axi_mcast_xbar #( axi_mcast_xbar_intf #( .AXI_USER_WIDTH ( TbAxiUserWidth ), .Cfg ( xbar_cfg ), + .aw_user_t ( aw_user_t ), .rule_t ( rule_t ) ) i_xbar_dut ( .clk_i ( clk ), From 69d2fb846c86e78961813012d7f77c2b7213d108 Mon Sep 17 00:00:00 2001 From: Luca Colagrande Date: Thu, 29 Jan 2026 16:51:52 +0100 Subject: [PATCH 38/41] axi_demux_simple: Restore deleted assertion --- src/axi_demux_simple.sv | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/axi_demux_simple.sv b/src/axi_demux_simple.sv index fc365ddbd..bef631554 100644 --- a/src/axi_demux_simple.sv +++ b/src/axi_demux_simple.sv @@ -96,4 +96,8 @@ module axi_demux_simple #( .mst_aw_commit_o () ); + `ASSUME(aw_select, slv_req_i.aw_valid |-> (slv_aw_select_i < NoMstPorts), clk_i, rst_ni, + $sformatf("slv_aw_select_i is %d: AW has selected a slave that is not defined.\ + NoMstPorts: %d", slv_aw_select_i, NoMstPorts)) + endmodule From df6b82ce0e8c1748fb3bf903ec424f107e50a827 Mon Sep 17 00:00:00 2001 From: Luca Colagrande Date: Thu, 26 Feb 2026 10:03:29 +0100 Subject: [PATCH 39/41] axi_mcast_demux_simple: Update popcount width as per common_cells v2 --- src/axi_mcast_demux_simple.sv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/axi_mcast_demux_simple.sv b/src/axi_mcast_demux_simple.sv index c88e00e05..0084baf50 100644 --- a/src/axi_mcast_demux_simple.sv +++ b/src/axi_mcast_demux_simple.sv @@ -109,7 +109,7 @@ module axi_mcast_demux_simple #( logic multicast_stall; mask_select_t multicast_select_q, multicast_select_d; mcast_cnt_t outstanding_mcast_cnt_q, outstanding_mcast_cnt_d; - logic [$clog2(NoMstPorts)+1-1:0] aw_select_popcount; + logic [$clog2(NoMstPorts+1)-1:0] aw_select_popcount; logic accept_aw; logic mcast_aw_hs_in_progress; From 5fd840813756069184af35f953deb51760411ea3 Mon Sep 17 00:00:00 2001 From: Luca Colagrande Date: Sat, 16 May 2026 14:55:34 +0200 Subject: [PATCH 40/41] Bump mcast modules to common_cells v2 --- src/axi_demux_simple.sv | 1 - src/axi_mcast_demux_mapped.sv | 40 ++++++++--------- src/axi_mcast_demux_simple.sv | 62 +++++++++++++-------------- src/axi_mcast_mux.sv | 81 +++++++++++++++++++---------------- src/axi_mcast_xbar.sv | 9 +--- src/axi_mcast_xbar_unmuxed.sv | 9 +--- src/axi_mux.sv | 1 - src/axi_xbar.sv | 1 - src/axi_xbar_unmuxed.sv | 1 - test/axi_synth_bench.sv | 4 -- test/tb_axi_mcast_xbar.sv | 1 - 11 files changed, 99 insertions(+), 111 deletions(-) diff --git a/src/axi_demux_simple.sv b/src/axi_demux_simple.sv index bef631554..357b643c2 100644 --- a/src/axi_demux_simple.sv +++ b/src/axi_demux_simple.sv @@ -83,7 +83,6 @@ module axi_demux_simple #( ) i_axi_mcast_demux_simple ( .clk_i (clk_i), .rst_ni (rst_ni), - .test_i (test_i), .slv_req_i (slv_req_i), .slv_aw_select_i (aw_select_mask), .slv_aw_addr_i ('0), diff --git a/src/axi_mcast_demux_mapped.sv b/src/axi_mcast_demux_mapped.sv index cc34f7a13..718c9e1a5 100644 --- a/src/axi_mcast_demux_mapped.sv +++ b/src/axi_mcast_demux_mapped.sv @@ -70,7 +70,6 @@ module axi_mcast_demux_mapped #( ) ( input logic clk_i, input logic rst_ni, - input logic test_i, // Addressing rules input rule_t [NoAddrRules-1:0] addr_map_i, input logic en_default_mst_port_i, @@ -88,8 +87,8 @@ module axi_mcast_demux_mapped #( // Account for additional error slave localparam int unsigned NoMstPortsExt = NoMstPorts + 1; - localparam int unsigned IdxSelectWidth = cf_math_pkg::idx_width(NoMstPorts); - localparam int unsigned IdxSelectWidthExt = cf_math_pkg::idx_width(NoMstPortsExt); + localparam int unsigned IdxSelectWidth = cc_pkg::idx_width(NoMstPorts); + localparam int unsigned IdxSelectWidthExt = cc_pkg::idx_width(NoMstPortsExt); typedef logic [IdxSelectWidth-1:0] idx_select_t; typedef logic [IdxSelectWidthExt-1:0] idx_select_ext_t; @@ -110,12 +109,13 @@ module axi_mcast_demux_mapped #( axi_req_t slv_req_cut; axi_resp_t slv_resp_cut; - spill_register #( - .T ( aw_chan_t ), + cc_spill_register #( + .data_t ( aw_chan_t ), .Bypass ( ~SpillAw ) ) i_aw_spill_reg ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .valid_i ( slv_req_i.aw_valid ), .ready_o ( slv_resp_o.aw_ready ), .data_i ( slv_req_i.aw ), @@ -123,12 +123,13 @@ module axi_mcast_demux_mapped #( .ready_i ( slv_resp_cut.aw_ready ), .data_o ( slv_req_cut.aw ) ); - spill_register #( - .T ( w_chan_t ), + cc_spill_register #( + .data_t ( w_chan_t ), .Bypass ( ~SpillW ) ) i_w_spill_reg ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .valid_i ( slv_req_i.w_valid ), .ready_o ( slv_resp_o.w_ready ), .data_i ( slv_req_i.w ), @@ -136,12 +137,13 @@ module axi_mcast_demux_mapped #( .ready_i ( slv_resp_cut.w_ready ), .data_o ( slv_req_cut.w ) ); - spill_register #( - .T ( ar_chan_t ), + cc_spill_register #( + .data_t ( ar_chan_t ), .Bypass ( ~SpillAr ) ) i_ar_spill_reg ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .valid_i ( slv_req_i.ar_valid ), .ready_o ( slv_resp_o.ar_ready ), .data_i ( slv_req_i.ar ), @@ -149,12 +151,13 @@ module axi_mcast_demux_mapped #( .ready_i ( slv_resp_cut.ar_ready ), .data_o ( slv_req_cut.ar ) ); - spill_register #( - .T ( b_chan_t ), + cc_spill_register #( + .data_t ( b_chan_t ), .Bypass ( ~SpillB ) ) i_b_spill_reg ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .valid_i ( slv_resp_cut.b_valid ), .ready_o ( slv_req_cut.b_ready ), .data_i ( slv_resp_cut.b ), @@ -162,12 +165,13 @@ module axi_mcast_demux_mapped #( .ready_i ( slv_req_i.b_ready ), .data_o ( slv_resp_o.b ) ); - spill_register #( - .T ( r_chan_t ), + cc_spill_register #( + .data_t ( r_chan_t ), .Bypass ( ~SpillR ) ) i_r_spill_reg ( .clk_i, .rst_ni, + .clr_i ( 1'b0 ), .valid_i ( slv_resp_cut.r_valid ), .ready_o ( slv_req_cut.r_ready ), .data_i ( slv_resp_cut.r ), @@ -185,7 +189,7 @@ module axi_mcast_demux_mapped #( idx_select_ext_t ar_select_idx; // Address decoding for unicast requests - addr_decode #( + cc_addr_decode #( .NoIndices (NoMstPorts), .NoRules (NoAddrRules), .addr_t (addr_t), @@ -229,7 +233,7 @@ module axi_mcast_demux_mapped #( addr_t [NoMstPortsExt-1:0] dec_aw_mask; // Address decoding for unicast requests - addr_decode #( + cc_addr_decode #( .NoIndices (NoMstPorts), .NoRules (NoAddrRules), .addr_t (addr_t), @@ -268,7 +272,7 @@ module axi_mcast_demux_mapped #( if (NoMulticastRules > 0) begin : gen_multiaddr_decode // Address decoding for multicast requests. - multiaddr_decode #( + cc_multiaddr_decode #( .NoIndices (NoMulticastPorts), .NoRules (NoMulticastRules), .addr_t (addr_t), @@ -348,7 +352,6 @@ module axi_mcast_demux_mapped #( ) i_mcast_demux_simple ( .clk_i, .rst_ni, - .test_i, .slv_req_i ( slv_req_cut ), .slv_aw_select_i ( dec_aw_select_mask ), .slv_aw_addr_i ( dec_aw_addr ), @@ -373,7 +376,6 @@ module axi_mcast_demux_mapped #( ) i_axi_err_slv ( .clk_i, .rst_ni, - .test_i, .slv_req_i ( errslv_req ), .slv_resp_o ( errslv_resp ) ); @@ -469,7 +471,6 @@ 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 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 input logic en_default_mst_port_i, @@ -530,7 +531,6 @@ module axi_mcast_demux_intf #( ) i_axi_demux ( .clk_i, // Clock .rst_ni, // Asynchronous reset active low - .test_i, // Testmode enable .addr_map_i ( addr_map_i ), .en_default_mst_port_i ( en_default_mst_port_i ), .default_mst_port_i ( default_mst_port_i ), diff --git a/src/axi_mcast_demux_simple.sv b/src/axi_mcast_demux_simple.sv index 0084baf50..6e52679d9 100644 --- a/src/axi_mcast_demux_simple.sv +++ b/src/axi_mcast_demux_simple.sv @@ -60,7 +60,6 @@ module axi_mcast_demux_simple #( ) ( input logic clk_i, input logic rst_ni, - input logic test_i, // Slave Port input axi_req_t slv_req_i, input mask_select_t slv_aw_select_i, @@ -75,7 +74,7 @@ module axi_mcast_demux_simple #( output logic [NoMstPorts-1:0] mst_aw_commit_o ); - localparam int unsigned IdCounterWidth = cf_math_pkg::idx_width(MaxTrans); + localparam int unsigned IdCounterWidth = cc_pkg::idx_width(MaxTrans); typedef logic [IdCounterWidth-1:0] id_cnt_t; localparam int unsigned McastCounterWidth = (MaxMcastTrans > 32'd1) ? $clog2(MaxMcastTrans+1) : 32'd1; @@ -233,7 +232,7 @@ module axi_mcast_demux_simple #( // lock the valid signal, as the selection gets pushed into the W FIFO on first assertion, // prevent further pushing - `FFLARN(lock_aw_valid_q, lock_aw_valid_d, load_aw_lock, '0, clk_i, rst_ni) + `FFL(lock_aw_valid_q, lock_aw_valid_d, load_aw_lock, '0, clk_i, rst_ni) //-------------------------------------- // Multicast logic @@ -244,15 +243,15 @@ module axi_mcast_demux_simple #( // the ID counters. We anyways don't use the ID counters on // multicast transactions... - onehot_to_bin #( - .ONEHOT_WIDTH(NoMstPorts) + cc_onehot_to_bin #( + .OnehotWidth(NoMstPorts) ) i_onehot_to_bin ( - .onehot(slv_aw_select_i & {NoMstPorts{!aw_is_multicast}}), - .bin (slv_aw_select) + .onehot_i(slv_aw_select_i & {NoMstPorts{!aw_is_multicast}}), + .bin_o (slv_aw_select) ); // Popcount to identify multicast requests - popcount #(NoMstPorts) i_aw_select_popcount ( + cc_popcount #(NoMstPorts) i_aw_select_popcount ( .data_i (slv_aw_select_i), .popcount_o(aw_select_popcount) ); @@ -287,8 +286,8 @@ module axi_mcast_demux_simple #( assign mst_is_mcast_o = {NoMstPorts{aw_is_multicast}}; // Keep track of which B responses need to be returned to complete the multicast - `FFARN(multicast_select_q, multicast_select_d, '0, clk_i, rst_ni) - `FFARN(outstanding_mcast_cnt_q, outstanding_mcast_cnt_d, '0, clk_i, rst_ni) + `FF(multicast_select_q, multicast_select_d, '0, clk_i, rst_ni) + `FF(outstanding_mcast_cnt_q, outstanding_mcast_cnt_d, '0, clk_i, rst_ni) // Logic to update number of outstanding multicast transactions and current multicast // transactions' select mask. Counter is incremented upon the AW handshake of a multicast @@ -332,7 +331,7 @@ module axi_mcast_demux_simple #( assign mcast_aw_hs_in_progress = mcast_aw_hs_state_q == MCastAwHandshakeInProgress; - `FFARN(mcast_aw_hs_state_q, mcast_aw_hs_state_d, MCastAwHandshakeIdle, clk_i, rst_ni) + `FF(mcast_aw_hs_state_q, mcast_aw_hs_state_d, MCastAwHandshakeIdle, clk_i, rst_ni) // When a multicast occurs, the upstream valid signals need to // be forwarded to multiple master ports. @@ -391,13 +390,13 @@ module axi_mcast_demux_simple #( // `w_select` determines, which handshaking is connected. // AWs are only forwarded, if the counter is empty, or `w_select_q` is the same as // `slv_aw_select_i`. - counter #( - .WIDTH ( IdCounterWidth ), - .STICKY_OVERFLOW ( 1'b0 ) + cc_counter #( + .Width ( IdCounterWidth ), + .StickyOverflow ( 1'b0 ) ) i_counter_open_w ( .clk_i, .rst_ni, - .clear_i ( 1'b0 ), + .clr_i ( 1'b0 ), .en_i ( w_cnt_up ^ w_cnt_down ), .load_i ( 1'b0 ), .down_i ( w_cnt_down ), @@ -406,7 +405,7 @@ module axi_mcast_demux_simple #( .overflow_o ( /*not used*/ ) ); - `FFLARN(w_select_q, slv_aw_select_i, w_cnt_up, mask_select_t'(0), clk_i, rst_ni) + `FFL(w_select_q, slv_aw_select_i, w_cnt_up, mask_select_t'(0), clk_i, rst_ni) assign w_select = (|w_open) ? w_select_q : slv_aw_select_i; assign w_select_valid = w_cnt_up | (|w_open); assign w_cnt_down = slv_req_i.w_valid & slv_resp_o.w_ready & slv_req_i.w.last; @@ -418,11 +417,12 @@ module axi_mcast_demux_simple #( // When a multicast occurs, the upstream valid signals need to // be forwarded to multiple master ports. // Proper stream forking is necessary to avoid protocol violations - stream_fork_dynamic #( - .N_OUP(NoMstPorts) + cc_stream_fork_dynamic #( + .NumOup(NoMstPorts) ) i_w_stream_fork_dynamic ( .clk_i (clk_i), .rst_ni (rst_ni), + .clr_i (1'b0), .valid_i (slv_req_i.w_valid), .ready_o (slv_resp_o.w_ready), .sel_i (w_select), @@ -435,18 +435,18 @@ module axi_mcast_demux_simple #( //-------------------------------------- // B Channel //-------------------------------------- - logic [cf_math_pkg::idx_width(NoMstPorts)-1:0] b_idx; + logic [cc_pkg::idx_width(NoMstPorts)-1:0] b_idx; // Arbitration of the different B responses - rr_arb_tree #( + cc_rr_arb_tree #( .NumIn ( NoMstPorts ), - .DataType ( logic ), + .data_t ( logic ), .AxiVldRdy( 1'b1 ), .LockIn ( 1'b1 ) ) i_b_mux ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), - .flush_i( 1'b0 ), + .clr_i ( 1'b0 ), .rr_i ( '0 ), .req_i ( mst_b_valids & {NoMstPorts{!outstanding_multicast}} ), .gnt_o ( mst_b_readies_arb ), @@ -458,7 +458,7 @@ module axi_mcast_demux_simple #( ); // Streams must be joined instead of arbitrated when multicast - stream_join_dynamic #(NoMstPorts) i_b_stream_join ( + cc_stream_join_dynamic #(NoMstPorts) i_b_stream_join ( .inp_valid_i(mst_b_valids & {NoMstPorts{outstanding_multicast}}), .inp_ready_o(mst_b_readies_join), .sel_i (multicast_select_q), @@ -475,9 +475,9 @@ module axi_mcast_demux_simple #( // All fields of B other than RESP can be taken from any slave (need not be merged). // We use a priority encoder to take them from the first addressed slave. - lzc #( - .WIDTH ( NoMstPorts ), - .MODE ( 1'b0 ) // Trailing zero mode + cc_lzc #( + .Width ( NoMstPorts ), + .Mode ( cc_pkg::LZC_TRAILING_ZERO_CNT ) ) i_mst_b_valids_tzc ( .in_i ( mst_b_valids & {NoMstPorts{outstanding_multicast}} ), .cnt_o ( mst_b_valids_tzc ), @@ -551,7 +551,7 @@ module axi_mcast_demux_simple #( end // this ff is needed so that ar does not get de-asserted if an atop gets injected - `FFLARN(lock_ar_valid_q, lock_ar_valid_d, load_ar_lock, '0, clk_i, rst_ni) + `FFL(lock_ar_valid_q, lock_ar_valid_d, load_ar_lock, '0, clk_i, rst_ni) if (UniqueIds) begin : gen_unique_ids_ar // If the `UniqueIds` parameter is set, each read transaction has an ID that is unique among @@ -589,18 +589,18 @@ module axi_mcast_demux_simple #( // R Channel //-------------------------------------- - logic [cf_math_pkg::idx_width(NoMstPorts)-1:0] r_idx; + logic [cc_pkg::idx_width(NoMstPorts)-1:0] r_idx; // Arbitration of the different r responses - rr_arb_tree #( + cc_rr_arb_tree #( .NumIn ( NoMstPorts ), - .DataType ( logic ), + .data_t ( logic ), .AxiVldRdy( 1'b1 ), .LockIn ( 1'b1 ) ) i_r_mux ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), - .flush_i( 1'b0 ), + .clr_i ( 1'b0 ), .rr_i ( '0 ), .req_i ( mst_r_valids ), .gnt_o ( mst_r_readies ), diff --git a/src/axi_mcast_mux.sv b/src/axi_mcast_mux.sv index e17cbf40e..72b0eb1f1 100644 --- a/src/axi_mcast_mux.sv +++ b/src/axi_mcast_mux.sv @@ -56,7 +56,6 @@ module axi_mcast_mux #( ) ( input logic clk_i, // Clock input logic rst_ni, // Asynchronous reset active low - input logic test_i, // Test Mode enable // slave ports (AXI inputs), connect master modules here input logic [NoSlvPorts-1:0] slv_is_mcast_i, input logic [NoSlvPorts-1:0] slv_aw_commit_i, @@ -72,12 +71,13 @@ module axi_mcast_mux #( // pass through if only one slave port if (NoSlvPorts == 32'h1) begin : gen_no_mux - spill_register #( - .T ( mst_aw_chan_t ), + cc_spill_register #( + .data_t ( mst_aw_chan_t ), .Bypass ( ~SpillAw ) ) i_aw_spill_reg ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .valid_i ( slv_is_mcast_i[0] ? slv_aw_commit_i[0] : slv_reqs_i[0].aw_valid ), @@ -87,12 +87,13 @@ module axi_mcast_mux #( .ready_i ( mst_resp_i.aw_ready ), .data_o ( mst_req_o.aw ) ); - spill_register #( - .T ( w_chan_t ), + cc_spill_register #( + .data_t ( w_chan_t ), .Bypass ( ~SpillW ) ) i_w_spill_reg ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .valid_i ( slv_reqs_i[0].w_valid ), .ready_o ( slv_resps_o[0].w_ready ), .data_i ( slv_reqs_i[0].w ), @@ -100,12 +101,13 @@ module axi_mcast_mux #( .ready_i ( mst_resp_i.w_ready ), .data_o ( mst_req_o.w ) ); - spill_register #( - .T ( mst_b_chan_t ), + cc_spill_register #( + .data_t ( mst_b_chan_t ), .Bypass ( ~SpillB ) ) i_b_spill_reg ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .valid_i ( mst_resp_i.b_valid ), .ready_o ( mst_req_o.b_ready ), .data_i ( mst_resp_i.b ), @@ -113,12 +115,13 @@ module axi_mcast_mux #( .ready_i ( slv_reqs_i[0].b_ready ), .data_o ( slv_resps_o[0].b ) ); - spill_register #( - .T ( mst_ar_chan_t ), + cc_spill_register #( + .data_t ( mst_ar_chan_t ), .Bypass ( ~SpillAr ) ) i_ar_spill_reg ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .valid_i ( slv_reqs_i[0].ar_valid ), .ready_o ( slv_resps_o[0].ar_ready ), .data_i ( slv_reqs_i[0].ar ), @@ -126,12 +129,13 @@ module axi_mcast_mux #( .ready_i ( mst_resp_i.ar_ready ), .data_o ( mst_req_o.ar ) ); - spill_register #( - .T ( mst_r_chan_t ), + cc_spill_register #( + .data_t ( mst_r_chan_t ), .Bypass ( ~SpillR ) ) i_r_spill_reg ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .valid_i ( mst_resp_i.r_valid ), .ready_o ( mst_req_o.r_ready ), .data_i ( mst_resp_i.r ), @@ -276,15 +280,15 @@ module axi_mcast_mux #( // AW Channel //-------------------------------------- // Arbitrate unicast requests in round-robin fashion - rr_arb_tree #( + cc_rr_arb_tree #( .NumIn ( NoSlvPorts ), - .DataType ( mst_aw_chan_t ), + .data_t ( mst_aw_chan_t ), .AxiVldRdy( 1'b1 ), .LockIn ( 1'b1 ) ) i_aw_ucast_arbiter ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), - .flush_i( 1'b0 ), + .clr_i ( 1'b0 ), .rr_i ( '0 ), .req_i ( slv_aw_valids & ~slv_is_mcast_i ), .gnt_o ( ucast_aw_readies ), @@ -296,9 +300,9 @@ module axi_mcast_mux #( ); // Arbitrate multicast requests in priority encoder fashion - lzc #( - .WIDTH ( NoSlvPorts ), - .MODE ( 1'b0 ) // Trailing zero mode + cc_lzc #( + .Width ( NoSlvPorts ), + .Mode ( cc_pkg::LZC_TRAILING_ZERO_CNT ) ) i_aw_mcast_lzc ( .in_i ( slv_aw_valids & slv_is_mcast_i ), .cnt_o ( mcast_sel_d ), @@ -377,15 +381,15 @@ module axi_mcast_mux #( `FFL(lock_aw_valid_q, lock_aw_valid_d, load_aw_lock, '0, clk_i, rst_ni) `FFL(lock_unicast_q, lock_unicast_d, load_aw_lock, '0, clk_i, rst_ni) - fifo_v3 #( - .FALL_THROUGH ( FallThrough ), - .DEPTH ( MaxWTrans ), - .dtype ( switch_id_t ) + cc_fifo #( + .FallThrough ( FallThrough ), + .Depth ( MaxWTrans ), + .data_t ( switch_id_t ) ) i_w_fifo ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .flush_i ( 1'b0 ), - .testmode_i( test_i ), .full_o ( w_fifo_full ), .empty_o ( w_fifo_empty ), .usage_o ( ), @@ -395,12 +399,13 @@ module axi_mcast_mux #( .pop_i ( w_fifo_pop ) ); - spill_register #( - .T ( mst_aw_chan_t ), + cc_spill_register #( + .data_t ( mst_aw_chan_t ), .Bypass ( ~SpillAw ) // Param indicated that we want a spill reg ) i_aw_spill_reg ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .valid_i ( mst_aw_valid ), .ready_o ( mst_aw_ready ), .data_i ( mst_aw_chan ), @@ -429,12 +434,13 @@ module axi_mcast_mux #( end end - spill_register #( - .T ( w_chan_t ), + cc_spill_register #( + .data_t ( w_chan_t ), .Bypass ( ~SpillW ) ) i_w_spill_reg ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .valid_i ( mst_w_valid ), .ready_o ( mst_w_ready ), .data_i ( mst_w_chan ), @@ -452,12 +458,13 @@ module axi_mcast_mux #( assign switch_b_id = mst_b_chan.id[SlvAxiIDWidth+:MstIdxBits]; assign slv_b_valids = (mst_b_valid) ? (1 << switch_b_id) : '0; - spill_register #( - .T ( mst_b_chan_t ), + cc_spill_register #( + .data_t ( mst_b_chan_t ), .Bypass ( ~SpillB ) ) i_b_spill_reg ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .valid_i ( mst_resp_i.b_valid ), .ready_o ( mst_req_o.b_ready ), .data_i ( mst_resp_i.b ), @@ -469,15 +476,15 @@ module axi_mcast_mux #( //-------------------------------------- // AR Channel //-------------------------------------- - rr_arb_tree #( + cc_rr_arb_tree #( .NumIn ( NoSlvPorts ), - .DataType ( mst_ar_chan_t ), + .data_t ( mst_ar_chan_t ), .AxiVldRdy( 1'b1 ), .LockIn ( 1'b1 ) ) i_ar_arbiter ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), - .flush_i( 1'b0 ), + .clr_i ( 1'b0 ), .rr_i ( '0 ), .req_i ( slv_ar_valids ), .gnt_o ( slv_ar_readies ), @@ -488,12 +495,13 @@ module axi_mcast_mux #( .idx_o ( ) ); - spill_register #( - .T ( mst_ar_chan_t ), + cc_spill_register #( + .data_t ( mst_ar_chan_t ), .Bypass ( ~SpillAr ) ) i_ar_spill_reg ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .valid_i ( ar_valid ), .ready_o ( ar_ready ), .data_i ( mst_ar_chan ), @@ -511,12 +519,13 @@ module axi_mcast_mux #( assign switch_r_id = mst_r_chan.id[SlvAxiIDWidth+:MstIdxBits]; assign slv_r_valids = (mst_r_valid) ? (1 << switch_r_id) : '0; - spill_register #( - .T ( mst_r_chan_t ), + cc_spill_register #( + .data_t ( mst_r_chan_t ), .Bypass ( ~SpillR ) ) i_r_spill_reg ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .clr_i ( 1'b0 ), .valid_i ( mst_resp_i.r_valid ), .ready_o ( mst_req_o.r_ready ), .data_i ( mst_resp_i.r ), @@ -581,7 +590,6 @@ module axi_mcast_mux_intf #( ) ( input logic clk_i, // Clock input logic rst_ni, // Asynchronous reset active low - input logic test_i, // Testmode enable input logic [NO_SLV_PORTS-1:0] slv_is_mcast_i, input logic [NO_SLV_PORTS-1:0] slv_aw_commit_i, AXI_BUS.Slave slv [NO_SLV_PORTS-1:0], // slave ports @@ -654,7 +662,6 @@ module axi_mcast_mux_intf #( ) i_axi_mux ( .clk_i ( clk_i ), // Clock .rst_ni ( rst_ni ), // Asynchronous reset active low - .test_i ( test_i ), // Test Mode enable .slv_is_mcast_i, .slv_aw_commit_i, .slv_reqs_i ( slv_reqs ), diff --git a/src/axi_mcast_xbar.sv b/src/axi_mcast_xbar.sv index cb0584554..4e9bd81fd 100644 --- a/src/axi_mcast_xbar.sv +++ b/src/axi_mcast_xbar.sv @@ -17,7 +17,7 @@ /// axi_xbar: 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_mcast_xbar -import cf_math_pkg::idx_width; +import cc_pkg::idx_width; #( /// Configuration struct for the crossbar see `axi_pkg` for fields and definitions. parameter axi_pkg::xbar_cfg_t Cfg = '0, @@ -70,7 +70,6 @@ import cf_math_pkg::idx_width; /// Asynchronous reset, active low. input logic rst_ni, /// Testmode enable, active high. - input logic test_i, /// AXI4+ATOP requests to the slave ports. input slv_req_t [Cfg.NoSlvPorts-1:0] slv_ports_req_i, /// AXI4+ATOP responses of the slave ports. @@ -114,7 +113,6 @@ import cf_math_pkg::idx_width; ) i_xbar_unmuxed ( .clk_i, .rst_ni, - .test_i, .slv_ports_req_i, .slv_ports_resp_o, .mst_ports_req_o (mst_reqs), @@ -153,7 +151,6 @@ import cf_math_pkg::idx_width; ) i_axi_mux ( .clk_i, // Clock .rst_ni, // Asynchronous reset active low - .test_i, // Test Mode enable .slv_is_mcast_i ( mst_is_mcast[i] ), .slv_aw_commit_i ( mst_aw_commit[i] ), .slv_reqs_i ( mst_reqs[i] ), @@ -169,7 +166,7 @@ endmodule `include "axi/typedef.svh" module axi_mcast_xbar_intf -import cf_math_pkg::idx_width; +import cc_pkg::idx_width; #( parameter int unsigned AXI_USER_WIDTH = 0, parameter axi_pkg::xbar_cfg_t Cfg = '0, @@ -181,7 +178,6 @@ import cf_math_pkg::idx_width; ) ( 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, @@ -249,7 +245,6 @@ import cf_math_pkg::idx_width; ) i_xbar ( .clk_i, .rst_ni, - .test_i, .slv_ports_req_i (slv_reqs ), .slv_ports_resp_o (slv_resps), .mst_ports_req_o (mst_reqs ), diff --git a/src/axi_mcast_xbar_unmuxed.sv b/src/axi_mcast_xbar_unmuxed.sv index d720f2dfe..db9a375dc 100644 --- a/src/axi_mcast_xbar_unmuxed.sv +++ b/src/axi_mcast_xbar_unmuxed.sv @@ -16,7 +16,7 @@ /// axi_xbar: 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_mcast_xbar_unmuxed -import cf_math_pkg::idx_width; +import cc_pkg::idx_width; #( /// Configuration struct for the crossbar see `axi_pkg` for fields and definitions. parameter axi_pkg::xbar_cfg_t Cfg = '0, @@ -57,7 +57,6 @@ import cf_math_pkg::idx_width; /// Asynchronous reset, active low. input logic rst_ni, /// Testmode enable, active high. - input logic test_i, /// AXI4+ATOP requests to the slave ports. input req_t [Cfg.NoSlvPorts-1:0] slv_ports_req_i, /// AXI4+ATOP responses of the slave ports. @@ -120,7 +119,6 @@ import cf_math_pkg::idx_width; ) i_axi_demux ( .clk_i, // Clock .rst_ni, // Asynchronous reset active low - .test_i, // Testmode enable .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] ), @@ -176,7 +174,6 @@ import cf_math_pkg::idx_width; ) i_axi_err_slv ( .clk_i, .rst_ni, - .test_i, .slv_req_i ( slv_reqs[i][j] ), .slv_resp_o ( slv_resps[i][j] ) ); @@ -210,7 +207,7 @@ endmodule `include "axi/typedef.svh" module axi_mcast_xbar_unmuxed_intf -import cf_math_pkg::idx_width; +import cc_pkg::idx_width; #( parameter int unsigned AXI_USER_WIDTH = 0, parameter axi_pkg::xbar_cfg_t Cfg = '0, @@ -221,7 +218,6 @@ import cf_math_pkg::idx_width; ) ( 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][Cfg.NoSlvPorts-1:0], input rule_t [Cfg.NoAddrRules-1:0] addr_map_i, @@ -276,7 +272,6 @@ import cf_math_pkg::idx_width; ) i_xbar ( .clk_i, .rst_ni, - .test_i, .slv_ports_req_i (slv_reqs ), .slv_ports_resp_o (slv_resps), .mst_ports_req_o (mst_reqs ), diff --git a/src/axi_mux.sv b/src/axi_mux.sv index 85f3561a3..3dc3fd2cf 100644 --- a/src/axi_mux.sv +++ b/src/axi_mux.sv @@ -90,7 +90,6 @@ module axi_mux #( ) i_axi_mcast_mux ( .clk_i (clk_i), .rst_ni (rst_ni), - .test_i (test_i), .slv_is_mcast_i ('0), .slv_aw_commit_i('0), .slv_reqs_i (slv_reqs_i), diff --git a/src/axi_xbar.sv b/src/axi_xbar.sv index 43b815456..a89987fcb 100644 --- a/src/axi_xbar.sv +++ b/src/axi_xbar.sv @@ -119,7 +119,6 @@ import cc_pkg::idx_width; ) i_axi_mcast_xbar ( .clk_i (clk_i), .rst_ni (rst_ni), - .test_i (test_i), .slv_ports_req_i (slv_ports_req_i), .slv_ports_resp_o (slv_ports_resp_o), .mst_ports_req_o (mst_ports_req_o), diff --git a/src/axi_xbar_unmuxed.sv b/src/axi_xbar_unmuxed.sv index 2c8d66550..26b5aaab3 100644 --- a/src/axi_xbar_unmuxed.sv +++ b/src/axi_xbar_unmuxed.sv @@ -100,7 +100,6 @@ import cc_pkg::idx_width; ) i_axi_mcast_xbar_unmuxed ( .clk_i (clk_i), .rst_ni (rst_ni), - .test_i (test_i), .slv_ports_req_i (slv_ports_req_i), .slv_ports_resp_o (slv_ports_resp_o), .mst_ports_req_o (mst_ports_req_o), diff --git a/test/axi_synth_bench.sv b/test/axi_synth_bench.sv index 5442556f3..5f7bc1028 100644 --- a/test/axi_synth_bench.sv +++ b/test/axi_synth_bench.sv @@ -1125,7 +1125,6 @@ module synth_axi_xbar #( ) i_xbar_dut ( .clk_i (clk_i), .rst_ni (rst_ni), - .test_i ('0), .slv_ports_req_i (slv_reqs), .slv_ports_resp_o (slv_resps), .mst_ports_req_o (mst_reqs), @@ -1154,7 +1153,6 @@ module synth_axi_xbar #( ) i_xbar_dut ( .clk_i (clk_i), .rst_ni (rst_ni), - .test_i ('0), .slv_ports_req_i (slv_reqs), .slv_ports_resp_o (slv_resps), .mst_ports_req_o (mst_reqs), @@ -1464,7 +1462,6 @@ module synth_axi_demux import axi_pkg::*; #( ) i_axi_demux ( .clk_i (clk_i), .rst_ni (rst_ni), - .test_i ('0), .slv_req_i (slv_req), .slv_aw_select_i(slv_aw_select_i), .slv_ar_select_i(slv_ar_select_i), @@ -1788,7 +1785,6 @@ module synth_axi_mcast_demux import axi_pkg::*; #( ) i_axi_mcast_demux ( .clk_i (clk_i), .rst_ni (rst_ni), - .test_i ('0), .slv_req_i (slv_req), .slv_aw_select_i(slv_aw_select_i), .slv_ar_select_i(slv_ar_select_i), diff --git a/test/tb_axi_mcast_xbar.sv b/test/tb_axi_mcast_xbar.sv index e1540636c..e76445963 100644 --- a/test/tb_axi_mcast_xbar.sv +++ b/test/tb_axi_mcast_xbar.sv @@ -317,7 +317,6 @@ module tb_axi_mcast_xbar #( ) i_xbar_dut ( .clk_i ( clk ), .rst_ni ( rst_n ), - .test_i ( 1'b0 ), .slv_ports ( master ), .mst_ports ( slave ), .addr_map_i ( AddrMap ), From 0d337aa3cb51d34f149e3666ab574f6ccda193ea Mon Sep 17 00:00:00 2001 From: Luca Colagrande Date: Tue, 2 Jun 2026 19:07:26 +0200 Subject: [PATCH 41/41] Fix non-critical Spyglass warning --- src/axi_mcast_demux_simple.sv | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/axi_mcast_demux_simple.sv b/src/axi_mcast_demux_simple.sv index 6e52679d9..96b49ddba 100644 --- a/src/axi_mcast_demux_simple.sv +++ b/src/axi_mcast_demux_simple.sv @@ -243,12 +243,19 @@ module axi_mcast_demux_simple #( // the ID counters. We anyways don't use the ID counters on // multicast transactions... - cc_onehot_to_bin #( - .OnehotWidth(NoMstPorts) - ) i_onehot_to_bin ( - .onehot_i(slv_aw_select_i & {NoMstPorts{!aw_is_multicast}}), - .bin_o (slv_aw_select) - ); + // Only needed when UniqueIds=0: slv_aw_select feeds the ID counter to track which + // master port a write transaction targets. When UniqueIds=1 the ID counter is absent + // and aw_select_occupied is hardwired to 0, so slv_aw_select is never used. + if (!UniqueIds) begin : gen_onehot_to_bin + cc_onehot_to_bin #( + .OnehotWidth(NoMstPorts) + ) i_onehot_to_bin ( + .onehot_i(slv_aw_select_i & {NoMstPorts{!aw_is_multicast}}), + .bin_o (slv_aw_select) + ); + end else begin : gen_no_onehot_to_bin + assign slv_aw_select = '0; + end // Popcount to identify multicast requests cc_popcount #(NoMstPorts) i_aw_select_popcount (