From 2933f771b5b36cf75d4350d6fdcce3c7d1ea9d53 Mon Sep 17 00:00:00 2001 From: Tim Fischer Date: Tue, 10 Dec 2024 15:54:25 +0100 Subject: [PATCH 1/8] hw(test): Add new `axi_aw_w_sync` module --- Bender.yml | 1 + hw/test/axi_aw_w_sync.sv | 70 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 hw/test/axi_aw_w_sync.sv diff --git a/Bender.yml b/Bender.yml index 35281513..63798892 100644 --- a/Bender.yml +++ b/Bender.yml @@ -73,6 +73,7 @@ sources: - hw/test/axi_reorder_remap_compare.sv - hw/test/axi_bw_monitor.sv - hw/test/floo_hbm_model.sv + - hw/test/axi_aw_w_sync.sv # Level 2 - hw/tb/tb_floo_axi_chimney.sv - hw/tb/tb_floo_nw_chimney.sv diff --git a/hw/test/axi_aw_w_sync.sv b/hw/test/axi_aw_w_sync.sv new file mode 100644 index 00000000..094a3648 --- /dev/null +++ b/hw/test/axi_aw_w_sync.sv @@ -0,0 +1,70 @@ +// Copyright 2024 ETH Zurich and University of Bologna. +// Solderpad Hardware License, Version 0.51, see LICENSE for details. +// SPDX-License-Identifier: SHL-0.51 + +// Authors: +// - Michael Rogenmoser + + +/// Only allows passing of AW if corresponding W is valid. +/// Only allows passing of W if corresponding AW is valid or sent. + + `include "axi/assign.svh" + `include "common_cells/registers.svh" + + module axi_aw_w_sync #( + parameter type axi_req_t = logic, + parameter type axi_resp_t = logic + ) ( + input logic clk_i, + input logic rst_ni, + + input axi_req_t slv_req_i, + output axi_resp_t slv_resp_o, + + output axi_req_t mst_req_o, + input axi_resp_t mst_resp_i + ); + + `AXI_ASSIGN_AR_STRUCT(mst_req_o.ar, slv_req_i.ar) + assign mst_req_o.ar_valid = slv_req_i.ar_valid; + assign slv_resp_o.ar_ready = mst_resp_i.ar_ready; + `AXI_ASSIGN_R_STRUCT(slv_resp_o.r, mst_resp_i.r) + assign slv_resp_o.r_valid = mst_resp_i.r_valid; + assign mst_req_o.r_ready = slv_req_i.r_ready; + `AXI_ASSIGN_B_STRUCT(slv_resp_o.b, mst_resp_i.b) + assign slv_resp_o.b_valid = mst_resp_i.b_valid; + assign mst_req_o.b_ready = slv_req_i.b_ready; + + `AXI_ASSIGN_AW_STRUCT(mst_req_o.aw, slv_req_i.aw) + `AXI_ASSIGN_W_STRUCT(mst_req_o.w, slv_req_i.w) + + logic aw_valid, w_valid; + logic w_completed_d, w_completed_q; + `FF(w_completed_q, w_completed_d, 1'b1) + + + // AW is valid when previous write completed and current AW and W are valid + assign aw_valid = w_completed_q && slv_req_i.aw_valid && slv_req_i.w_valid; + + // W is valid when corresponding AW is valid or sent + assign w_valid = slv_req_i.w_valid && (!w_completed_q || (aw_valid && mst_resp_i.aw_ready)); // This is probably pretty bad for timing + + always_comb begin + w_completed_d = w_completed_q; + // reset w_completed to 0 when a new AW request happens + if (aw_valid && mst_resp_i.aw_ready) begin + w_completed_d = 1'b0; + end + // assign w_completed to w_last when W handshake is done and W is ongoing + if (slv_req_i.w_valid && slv_resp_o.w_ready) begin + w_completed_d = slv_req_i.w.last; + end + end + + assign mst_req_o.w_valid = w_valid; + assign slv_resp_o.w_ready = w_valid && mst_resp_i.w_ready; + assign mst_req_o.aw_valid = aw_valid; + assign slv_resp_o.aw_ready = aw_valid && mst_resp_i.aw_ready; + + endmodule From 3e0b5be18c73e05a4e211c95886832a5bf264df2 Mon Sep 17 00:00:00 2001 From: Tim Fischer Date: Tue, 10 Dec 2024 15:58:57 +0100 Subject: [PATCH 2/8] hw(chimney): Cut AW out paths --- hw/floo_axi_chimney.sv | 37 ++++++++++++++++++++-- hw/floo_nw_chimney.sv | 70 +++++++++++++++++++++++++++++++++++++++--- 2 files changed, 100 insertions(+), 7 deletions(-) diff --git a/hw/floo_axi_chimney.sv b/hw/floo_axi_chimney.sv index 61d3f705..c26e4f54 100644 --- a/hw/floo_axi_chimney.sv +++ b/hw/floo_axi_chimney.sv @@ -86,6 +86,7 @@ module floo_axi_chimney #( typedef logic [AxiCfg.AddrWidth-1:0] axi_addr_t; typedef logic [AxiCfg.InIdWidth-1:0] axi_in_id_t; + typedef logic [AxiCfg.OutIdWidth-1:0] axi_out_id_t; typedef logic [AxiCfg.UserWidth-1:0] axi_user_t; typedef logic [AxiCfg.DataWidth-1:0] axi_data_t; typedef logic [AxiCfg.DataWidth/8-1:0] axi_strb_t; @@ -93,6 +94,7 @@ module floo_axi_chimney #( // (Re-) definitons of `axi_in` and `floo` types, for transport `AXI_TYPEDEF_ALL_CT(axi, axi_req_t, axi_rsp_t, axi_addr_t, axi_in_id_t, axi_data_t, axi_strb_t, axi_user_t) + `AXI_TYPEDEF_AW_CHAN_T(axi_out_aw_chan_t, axi_addr_t, axi_out_id_t, axi_user_t) `FLOO_TYPEDEF_AXI_CHAN_ALL(axi, req, rsp, axi, AxiCfg, hdr_t) // Duplicate AXI port signals to degenerate ports @@ -138,6 +140,8 @@ module floo_axi_chimney #( // Meta Buffer axi_req_t meta_buf_req_in; axi_rsp_t meta_buf_rsp_out; + axi_out_req_t meta_buf_req_out; + axi_out_rsp_t meta_buf_rsp_in; // Flit arbitration typedef enum logic {SelAw, SelW} aw_w_sel_e; @@ -202,6 +206,34 @@ module floo_axi_chimney #( assign axi_ar_queue_valid_out = axi_in_req_i.ar_valid; assign axi_rsp_out.ar_ready = axi_ar_queue_ready_in; end + + logic aw_out_queue_valid, aw_out_queue_ready; + axi_out_aw_chan_t axi_aw_queue_out; + + // Since AW and W are transferred over the same link, it can happen that + // a downstream module does not accept the AW until the W is valid. + // Therefore, we need to add a spill register for the AW channel. + spill_register #( + .T (axi_out_aw_chan_t) + ) i_aw_out_queue ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .valid_i ( meta_buf_req_out.aw_valid ), + .ready_o ( aw_out_queue_ready ), + .data_i ( meta_buf_req_out.aw ), + .valid_o ( aw_out_queue_valid ), + .ready_i ( axi_out_rsp_i.aw_ready ), + .data_o ( axi_aw_queue_out ) + ); + + always_comb begin + axi_out_req_o = meta_buf_req_out; + axi_out_req_o.aw_valid = aw_out_queue_valid; + axi_out_req_o.aw = axi_aw_queue_out; + meta_buf_rsp_in = axi_out_rsp_i; + meta_buf_rsp_in.aw_ready = aw_out_queue_ready; + end + end else begin : gen_err_slv_port axi_err_slv #( .AxiIdWidth ( AxiCfg.InIdWidth ), @@ -663,8 +695,8 @@ module floo_axi_chimney #( .test_enable_i, .axi_req_i ( meta_buf_req_in ), .axi_rsp_o ( meta_buf_rsp_out ), - .axi_req_o ( axi_out_req_o ), - .axi_rsp_i ( axi_out_rsp_i ), + .axi_req_o ( meta_buf_req_out ), + .axi_rsp_i ( meta_buf_rsp_in ), .aw_buf_i ( aw_out_hdr_in ), .ar_buf_i ( ar_out_hdr_in ), .r_buf_o ( ar_out_hdr_out ), @@ -684,7 +716,6 @@ module floo_axi_chimney #( .slv_resp_o ( meta_buf_rsp_out ) ); - assign axi_out_req_o = '0; assign ar_out_hdr_out = '0; assign aw_out_hdr_out = '0; end diff --git a/hw/floo_nw_chimney.sv b/hw/floo_nw_chimney.sv index 13977239..88ce8e8f 100644 --- a/hw/floo_nw_chimney.sv +++ b/hw/floo_nw_chimney.sv @@ -109,10 +109,12 @@ module floo_nw_chimney #( typedef logic [AxiCfgN.AddrWidth-1:0] axi_addr_t; typedef logic [AxiCfgN.InIdWidth-1:0] axi_narrow_in_id_t; + typedef logic [AxiCfgN.OutIdWidth-1:0] axi_narrow_out_id_t; typedef logic [AxiCfgN.UserWidth-1:0] axi_narrow_user_t; typedef logic [AxiCfgN.DataWidth-1:0] axi_narrow_data_t; typedef logic [AxiCfgN.DataWidth/8-1:0] axi_narrow_strb_t; typedef logic [AxiCfgW.InIdWidth-1:0] axi_wide_in_id_t; + typedef logic [AxiCfgW.OutIdWidth-1:0] axi_wide_out_id_t; typedef logic [AxiCfgW.UserWidth-1:0] axi_wide_user_t; typedef logic [AxiCfgW.DataWidth-1:0] axi_wide_data_t; typedef logic [AxiCfgW.DataWidth/8-1:0] axi_wide_strb_t; @@ -122,6 +124,8 @@ module floo_nw_chimney #( axi_narrow_in_id_t, axi_narrow_data_t, axi_narrow_strb_t, axi_narrow_user_t) `AXI_TYPEDEF_ALL_CT(axi_wide, axi_wide_req_t, axi_wide_rsp_t, axi_addr_t, axi_wide_in_id_t, axi_wide_data_t, axi_wide_strb_t, axi_wide_user_t) + `AXI_TYPEDEF_AW_CHAN_T(axi_wide_out_aw_chan_t, axi_addr_t, axi_wide_out_id_t, axi_wide_user_t) + `AXI_TYPEDEF_AW_CHAN_T(axi_narrow_out_aw_chan_t, axi_addr_t, axi_narrow_out_id_t, axi_narrow_user_t) `FLOO_TYPEDEF_NW_CHAN_ALL(axi, req, rsp, wide, axi_narrow, axi_wide, AxiCfgN, AxiCfgW, hdr_t) // Duplicate AXI port signals to degenerate ports @@ -191,8 +195,12 @@ module floo_nw_chimney #( // Meta Buffers axi_narrow_in_req_t axi_narrow_meta_buf_req_in; axi_narrow_in_rsp_t axi_narrow_meta_buf_rsp_out; + axi_narrow_out_req_t axi_narrow_meta_buf_req_out; + axi_narrow_out_rsp_t axi_narrow_meta_buf_rsp_in; axi_wide_in_req_t axi_wide_meta_buf_req_in; axi_wide_in_rsp_t axi_wide_meta_buf_rsp_out; + axi_wide_out_req_t axi_wide_meta_buf_req_out; + axi_wide_out_rsp_t axi_wide_meta_buf_rsp_in; // ID tracking typedef struct packed { @@ -262,6 +270,33 @@ module floo_nw_chimney #( assign axi_narrow_rsp_out.ar_ready = axi_narrow_ar_queue_ready_in; end + logic narrow_aw_out_queue_valid, narrow_aw_out_queue_ready; + axi_narrow_out_aw_chan_t axi_narrow_aw_queue_out; + + // Since AW and W are transferred over the same link, it can happen that + // a downstream module does not accept the AW until the W is valid. + // Therefore, we need to add a spill register for the AW channel. + spill_register #( + .T (axi_narrow_out_aw_chan_t) + ) i_aw_narrow_out_queue ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .valid_i ( axi_narrow_meta_buf_req_out.aw_valid ), + .ready_o ( narrow_aw_out_queue_ready ), + .data_i ( axi_narrow_meta_buf_req_out.aw ), + .valid_o ( narrow_aw_out_queue_valid ), + .ready_i ( axi_narrow_out_rsp_i.aw_ready ), + .data_o ( axi_narrow_aw_queue_out ) + ); + + always_comb begin + axi_narrow_out_req_o = axi_narrow_meta_buf_req_out; + axi_narrow_out_req_o.aw_valid = narrow_aw_out_queue_valid; + axi_narrow_out_req_o.aw = axi_narrow_aw_queue_out; + axi_narrow_meta_buf_rsp_in = axi_narrow_out_rsp_i; + axi_narrow_meta_buf_rsp_in.aw_ready = narrow_aw_out_queue_ready; + end + end else begin : gen_narrow_err_slv_port axi_err_slv #( .AxiIdWidth ( AxiCfgN.InIdWidth ), @@ -321,6 +356,33 @@ module floo_nw_chimney #( assign axi_wide_ar_queue_valid_out = axi_wide_in_req_i.ar_valid; assign axi_wide_rsp_out.ar_ready = axi_wide_ar_queue_ready_in; end + + logic wide_aw_out_queue_valid, wide_aw_out_queue_ready; + axi_wide_out_aw_chan_t axi_wide_aw_queue_out; + + // Since AW and W are transferred over the same link, it can happen that + // a downstream module does not accept the AW until the W is valid. + // Therefore, we need to add a spill register for the AW channel. + spill_register #( + .T (axi_wide_out_aw_chan_t) + ) i_aw_out_queue ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .valid_i ( axi_wide_meta_buf_req_out.aw_valid ), + .ready_o ( wide_aw_out_queue_ready ), + .data_i ( axi_wide_meta_buf_req_out.aw ), + .valid_o ( wide_aw_out_queue_valid ), + .ready_i ( axi_wide_out_rsp_i.aw_ready ), + .data_o ( axi_wide_aw_queue_out ) + ); + + always_comb begin + axi_wide_out_req_o = axi_wide_meta_buf_req_out; + axi_wide_out_req_o.aw_valid = wide_aw_out_queue_valid; + axi_wide_out_req_o.aw = axi_wide_aw_queue_out; + axi_wide_meta_buf_rsp_in = axi_wide_out_rsp_i; + axi_wide_meta_buf_rsp_in.aw_ready = wide_aw_out_queue_ready; + end end else begin : gen_wide_err_slv_port axi_err_slv #( .AxiIdWidth ( AxiCfgW.InIdWidth ), @@ -1106,8 +1168,8 @@ module floo_nw_chimney #( .test_enable_i, .axi_req_i ( axi_narrow_meta_buf_req_in ), .axi_rsp_o ( axi_narrow_meta_buf_rsp_out ), - .axi_req_o ( axi_narrow_out_req_o ), - .axi_rsp_i ( axi_narrow_out_rsp_i ), + .axi_req_o ( axi_narrow_meta_buf_req_out ), + .axi_rsp_i ( axi_narrow_meta_buf_rsp_in ), .aw_buf_i ( narrow_aw_buf_hdr_in ), .ar_buf_i ( narrow_ar_buf_hdr_in ), .r_buf_o ( narrow_ar_buf_hdr_out ), @@ -1150,8 +1212,8 @@ module floo_nw_chimney #( .test_enable_i, .axi_req_i ( axi_wide_meta_buf_req_in ), .axi_rsp_o ( axi_wide_meta_buf_rsp_out ), - .axi_req_o ( axi_wide_out_req_o ), - .axi_rsp_i ( axi_wide_out_rsp_i ), + .axi_req_o ( axi_wide_meta_buf_req_out ), + .axi_rsp_i ( axi_wide_meta_buf_rsp_in ), .aw_buf_i ( wide_aw_buf_hdr_in ), .ar_buf_i ( wide_ar_buf_hdr_in ), .r_buf_o ( wide_ar_buf_hdr_out ), From 1875126fcccba995c9c1d03403e92a6dee6c4262 Mon Sep 17 00:00:00 2001 From: Tim Fischer Date: Tue, 10 Dec 2024 15:59:08 +0100 Subject: [PATCH 3/8] tb(chimney): Add axi_aw_w_sync to make compare module happy --- hw/tb/tb_floo_axi_chimney.sv | 60 +++++++++++++++++++++++---------- hw/tb/tb_floo_nw_chimney.sv | 65 ++++++++++++++++++++++++------------ 2 files changed, 86 insertions(+), 39 deletions(-) diff --git a/hw/tb/tb_floo_axi_chimney.sv b/hw/tb/tb_floo_axi_chimney.sv index 8047304a..f80aa9fa 100644 --- a/hw/tb/tb_floo_axi_chimney.sv +++ b/hw/tb/tb_floo_axi_chimney.sv @@ -34,15 +34,15 @@ module tb_floo_axi_chimney; axi_in_req_t [NumTargets-1:0] node_man_req; axi_in_rsp_t [NumTargets-1:0] node_man_rsp; - axi_out_req_t [NumTargets-1:0] node_sub_req; - axi_out_rsp_t [NumTargets-1:0] node_sub_rsp; + axi_out_req_t [NumTargets-1:0] node_sub_req, node_sub_req_sync; + axi_out_rsp_t [NumTargets-1:0] node_sub_rsp, node_sub_rsp_sync; axi_in_req_t [NumTargets-1:0] sub_req_id_assign; axi_in_rsp_t [NumTargets-1:0] sub_rsp_id_assign; for (genvar i = 0; i < NumTargets; i++) begin : gen_axi_assign - `AXI_ASSIGN_REQ_STRUCT(sub_req_id_assign[i], node_sub_req[i]) - `AXI_ASSIGN_RESP_STRUCT(sub_rsp_id_assign[i], node_sub_rsp[i]) + `AXI_ASSIGN_REQ_STRUCT(sub_req_id_assign[i], node_sub_req_sync[i]) + `AXI_ASSIGN_RESP_STRUCT(sub_rsp_id_assign[i], node_sub_rsp_sync[i]) end floo_req_t [NumTargets-1:0] chimney_req; @@ -83,13 +83,13 @@ module tb_floo_axi_chimney; .NumReads ( NumReads0 ), .NumWrites ( NumWrites0 ) ) i_test_node_0 ( - .clk_i ( clk ), - .rst_ni ( rst_n ), - .mst_port_req_o ( node_man_req[0] ), - .mst_port_rsp_i ( node_man_rsp[0] ), - .slv_port_req_i ( node_sub_req[0] ), - .slv_port_rsp_o ( node_sub_rsp[0] ), - .end_of_sim ( end_of_sim[0] ) + .clk_i ( clk ), + .rst_ni ( rst_n ), + .mst_port_req_o ( node_man_req[0] ), + .mst_port_rsp_i ( node_man_rsp[0] ), + .slv_port_req_i ( node_sub_req_sync[0] ), + .slv_port_rsp_o ( node_sub_rsp_sync[0] ), + .end_of_sim ( end_of_sim[0] ) ); axi_reorder_remap_compare #( @@ -111,6 +111,18 @@ module tb_floo_axi_chimney; .end_of_sim_o ( end_of_sim[1] ) ); + axi_aw_w_sync #( + .axi_req_t ( axi_out_req_t ), + .axi_resp_t ( axi_out_rsp_t ) + ) i_axi_aw_w_sync_0 ( + .clk_i ( clk ), + .rst_ni ( rst_n ), + .slv_req_i ( node_sub_req[0] ), + .slv_resp_o ( node_sub_rsp[0] ), + .mst_req_o ( node_sub_req_sync[0] ), + .mst_resp_i ( node_sub_rsp_sync[0] ) + ); + floo_axi_chimney #( .AxiCfg ( floo_test_pkg::AxiCfg ), .ChimneyCfg ( floo_test_pkg::ChimneyCfg ), @@ -173,6 +185,18 @@ module tb_floo_axi_chimney; .floo_rsp_i ( chimney_rsp[0] ) ); + axi_aw_w_sync #( + .axi_req_t ( axi_out_req_t ), + .axi_resp_t ( axi_out_rsp_t ) + ) i_axi_aw_w_sync_1 ( + .clk_i ( clk ), + .rst_ni ( rst_n ), + .slv_req_i ( node_sub_req[1] ), + .slv_resp_o ( node_sub_rsp[1] ), + .mst_req_o ( node_sub_req_sync[1] ), + .mst_resp_i ( node_sub_rsp_sync[1] ) + ); + axi_reorder_remap_compare #( .AxiInIdWidth ( floo_test_pkg::AxiCfg.InIdWidth ), .AxiOutIdWidth ( floo_test_pkg::AxiCfg.OutIdWidth ), @@ -207,13 +231,13 @@ module tb_floo_axi_chimney; .NumReads ( NumReads1 ), .NumWrites ( NumWrites1 ) ) i_test_node_1 ( - .clk_i ( clk ), - .rst_ni ( rst_n ), - .mst_port_req_o ( node_man_req[1] ), - .mst_port_rsp_i ( node_man_rsp[1] ), - .slv_port_req_i ( node_sub_req[1] ), - .slv_port_rsp_o ( node_sub_rsp[1] ), - .end_of_sim ( end_of_sim[3] ) + .clk_i ( clk ), + .rst_ni ( rst_n ), + .mst_port_req_o ( node_man_req[1] ), + .mst_port_rsp_i ( node_man_rsp[1] ), + .slv_port_req_i ( node_sub_req_sync[1] ), + .slv_port_rsp_o ( node_sub_rsp_sync[1] ), + .end_of_sim ( end_of_sim[3] ) ); axi_bw_monitor #( diff --git a/hw/tb/tb_floo_nw_chimney.sv b/hw/tb/tb_floo_nw_chimney.sv index ef8736bb..ffeed1dc 100644 --- a/hw/tb/tb_floo_nw_chimney.sv +++ b/hw/tb/tb_floo_nw_chimney.sv @@ -61,8 +61,8 @@ module tb_floo_nw_chimney; axi_wide_in_req_t [NumTargets-1:0] wide_man_req; axi_wide_in_rsp_t [NumTargets-1:0] wide_man_rsp; - axi_narrow_out_req_t [NumTargets-1:0] narrow_sub_req; - axi_narrow_out_rsp_t [NumTargets-1:0] narrow_sub_rsp; + axi_narrow_out_req_t [NumTargets-1:0] narrow_sub_req, narrow_sub_req_sync; + axi_narrow_out_rsp_t [NumTargets-1:0] narrow_sub_rsp, narrow_sub_rsp_sync; axi_wide_out_req_t [NumTargets-1:0] wide_sub_req; axi_wide_out_rsp_t [NumTargets-1:0] wide_sub_rsp; @@ -72,8 +72,8 @@ module tb_floo_nw_chimney; axi_wide_in_rsp_t [NumTargets-1:0] wide_sub_rsp_id_mapped; for (genvar i = 0; i < NumTargets; i++) begin : gen_dir - `AXI_ASSIGN_REQ_STRUCT(narrow_sub_req_id_mapped[i], narrow_sub_req[i]) - `AXI_ASSIGN_RESP_STRUCT(narrow_sub_rsp_id_mapped[i], narrow_sub_rsp[i]) + `AXI_ASSIGN_REQ_STRUCT(narrow_sub_req_id_mapped[i], narrow_sub_req_sync[i]) + `AXI_ASSIGN_RESP_STRUCT(narrow_sub_rsp_id_mapped[i], narrow_sub_rsp_sync[i]) `AXI_ASSIGN_REQ_STRUCT(wide_sub_req_id_mapped[i], wide_sub_req[i]) `AXI_ASSIGN_RESP_STRUCT(wide_sub_rsp_id_mapped[i], wide_sub_rsp[i]) end @@ -118,13 +118,13 @@ module tb_floo_nw_chimney; .NumReads ( NarrowNumReads ), .NumWrites ( NarrowNumWrites ) ) i_narrow_test_node_0 ( - .clk_i ( clk ), - .rst_ni ( rst_n ), - .mst_port_req_o ( narrow_man_req[0] ), - .mst_port_rsp_i ( narrow_man_rsp[0] ), - .slv_port_req_i ( narrow_sub_req[0] ), - .slv_port_rsp_o ( narrow_sub_rsp[0] ), - .end_of_sim ( end_of_sim[0] ) + .clk_i ( clk ), + .rst_ni ( rst_n ), + .mst_port_req_o ( narrow_man_req[0] ), + .mst_port_rsp_i ( narrow_man_rsp[0] ), + .slv_port_req_i ( narrow_sub_req_sync[0] ), + .slv_port_rsp_o ( narrow_sub_rsp_sync[0] ), + .end_of_sim ( end_of_sim[0] ) ); floo_axi_test_node #( @@ -188,6 +188,18 @@ module tb_floo_nw_chimney; .axi_b_res ( wide_sub_rsp_id_mapped[1] ) ); + axi_aw_w_sync #( + .axi_req_t ( axi_narrow_out_req_t ), + .axi_resp_t ( axi_narrow_out_rsp_t ) + ) i_axi_aw_w_sync_0 ( + .clk_i ( clk ), + .rst_ni ( rst_n ), + .slv_req_i ( narrow_sub_req[0] ), + .slv_resp_o ( narrow_sub_rsp[0] ), + .mst_req_o ( narrow_sub_req_sync[0] ), + .mst_resp_i ( narrow_sub_rsp_sync[0] ) + ); + floo_nw_chimney #( .AxiCfgN ( floo_test_pkg::AxiCfgN ), .AxiCfgW ( floo_test_pkg::AxiCfgW ), @@ -209,7 +221,7 @@ module tb_floo_nw_chimney; .floo_req_t ( floo_req_t ), .floo_rsp_t ( floo_rsp_t ), .floo_wide_t ( floo_wide_t ) - ) i_floo_narrow_wide_chimney_0 ( + ) i_floo_nw_chimney_0 ( .clk_i ( clk ), .rst_ni ( rst_n ), .sram_cfg_i ( '0 ), @@ -253,7 +265,7 @@ module tb_floo_nw_chimney; .floo_req_t ( floo_req_t ), .floo_rsp_t ( floo_rsp_t ), .floo_wide_t ( floo_wide_t ) - ) i_floo_narrow_wide_chimney_1 ( + ) i_floo_nw_chimney_1 ( .clk_i ( clk ), .rst_ni ( rst_n ), .sram_cfg_i ( '0 ), @@ -276,6 +288,18 @@ module tb_floo_nw_chimney; .floo_wide_i ( chimney_wide[0] ) ); + axi_aw_w_sync #( + .axi_req_t ( axi_narrow_out_req_t ), + .axi_resp_t ( axi_narrow_out_rsp_t ) + ) i_axi_aw_w_sync_1 ( + .clk_i ( clk ), + .rst_ni ( rst_n ), + .slv_req_i ( narrow_sub_req[1] ), + .slv_resp_o ( narrow_sub_rsp[1] ), + .mst_req_o ( narrow_sub_req_sync[1] ), + .mst_resp_i ( narrow_sub_rsp_sync[1] ) + ); + axi_reorder_remap_compare #( .AxiInIdWidth ( floo_test_pkg::AxiCfgN.InIdWidth ), .AxiOutIdWidth ( floo_test_pkg::AxiCfgN.OutIdWidth ), @@ -325,18 +349,17 @@ module tb_floo_nw_chimney; .NumAddrRegions ( NumAddrRegions ), .rule_t ( node_addr_region_t ), .AddrRegions ( AddrRegions ), - .AxiMaxBurstLen ( 1 ), .NumReads ( NarrowNumReads ), .NumWrites ( NarrowNumWrites ) ) i_narrow_test_node_1 ( - .clk_i ( clk ), - .rst_ni ( rst_n ), - .mst_port_req_o ( narrow_man_req[1] ), - .mst_port_rsp_i ( narrow_man_rsp[1] ), - .slv_port_req_i ( narrow_sub_req[1] ), - .slv_port_rsp_o ( narrow_sub_rsp[1] ), - .end_of_sim ( end_of_sim[4] ) + .clk_i ( clk ), + .rst_ni ( rst_n ), + .mst_port_req_o ( narrow_man_req[1] ), + .mst_port_rsp_i ( narrow_man_rsp[1] ), + .slv_port_req_i ( narrow_sub_req_sync[1] ), + .slv_port_rsp_o ( narrow_sub_rsp_sync[1] ), + .end_of_sim ( end_of_sim[4] ) ); floo_axi_test_node #( From 6cef8b82796f286614b23ec9937dc26837ade702 Mon Sep 17 00:00:00 2001 From: Tim Fischer Date: Tue, 10 Dec 2024 16:06:52 +0100 Subject: [PATCH 4/8] lint: Verilog sources --- hw/floo_nw_chimney.sv | 3 ++- hw/test/axi_aw_w_sync.sv | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/hw/floo_nw_chimney.sv b/hw/floo_nw_chimney.sv index 88ce8e8f..750dc6ef 100644 --- a/hw/floo_nw_chimney.sv +++ b/hw/floo_nw_chimney.sv @@ -125,7 +125,8 @@ module floo_nw_chimney #( `AXI_TYPEDEF_ALL_CT(axi_wide, axi_wide_req_t, axi_wide_rsp_t, axi_addr_t, axi_wide_in_id_t, axi_wide_data_t, axi_wide_strb_t, axi_wide_user_t) `AXI_TYPEDEF_AW_CHAN_T(axi_wide_out_aw_chan_t, axi_addr_t, axi_wide_out_id_t, axi_wide_user_t) - `AXI_TYPEDEF_AW_CHAN_T(axi_narrow_out_aw_chan_t, axi_addr_t, axi_narrow_out_id_t, axi_narrow_user_t) + `AXI_TYPEDEF_AW_CHAN_T(axi_narrow_out_aw_chan_t, axi_addr_t, + axi_narrow_out_id_t, axi_narrow_user_t) `FLOO_TYPEDEF_NW_CHAN_ALL(axi, req, rsp, wide, axi_narrow, axi_wide, AxiCfgN, AxiCfgW, hdr_t) // Duplicate AXI port signals to degenerate ports diff --git a/hw/test/axi_aw_w_sync.sv b/hw/test/axi_aw_w_sync.sv index 094a3648..ef201a1e 100644 --- a/hw/test/axi_aw_w_sync.sv +++ b/hw/test/axi_aw_w_sync.sv @@ -48,7 +48,8 @@ assign aw_valid = w_completed_q && slv_req_i.aw_valid && slv_req_i.w_valid; // W is valid when corresponding AW is valid or sent - assign w_valid = slv_req_i.w_valid && (!w_completed_q || (aw_valid && mst_resp_i.aw_ready)); // This is probably pretty bad for timing + // This is probably pretty bad for timing! + assign w_valid = slv_req_i.w_valid && (!w_completed_q || (aw_valid && mst_resp_i.aw_ready)); always_comb begin w_completed_d = w_completed_q; From a33ee96feee5dcaa0cbdf82bd8c7ab5478b8635e Mon Sep 17 00:00:00 2001 From: Tim Fischer Date: Tue, 10 Dec 2024 16:06:59 +0100 Subject: [PATCH 5/8] make: Fix `clean` command --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 035e1d03..cfe0ff15 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ MKFILE_DIR := $(dir $(MKFILE_PATH)) .PHONY: all clean compile-sim run-sim run-sim-batch all: compile-sim -clean: clean-sim clean-spyglass clean-jobs clean-sources clean-vcs +clean: clean-vsim clean-spyglass clean-jobs clean-sources clean-vcs compile-sim: compile-vsim run-sim: run-vsim run-sim-batch: run-vsim-batch From a074e8686fd5b9dd70fddeebe7f159013d4630da Mon Sep 17 00:00:00 2001 From: Tim Fischer Date: Tue, 10 Dec 2024 17:57:03 +0100 Subject: [PATCH 6/8] hw(chimney): Fix location of AW cuts --- hw/floo_axi_chimney.sv | 55 ++++++++++++----------- hw/floo_nw_chimney.sv | 100 +++++++++++++++++++---------------------- 2 files changed, 75 insertions(+), 80 deletions(-) diff --git a/hw/floo_axi_chimney.sv b/hw/floo_axi_chimney.sv index c26e4f54..b04e4591 100644 --- a/hw/floo_axi_chimney.sv +++ b/hw/floo_axi_chimney.sv @@ -207,33 +207,6 @@ module floo_axi_chimney #( assign axi_rsp_out.ar_ready = axi_ar_queue_ready_in; end - logic aw_out_queue_valid, aw_out_queue_ready; - axi_out_aw_chan_t axi_aw_queue_out; - - // Since AW and W are transferred over the same link, it can happen that - // a downstream module does not accept the AW until the W is valid. - // Therefore, we need to add a spill register for the AW channel. - spill_register #( - .T (axi_out_aw_chan_t) - ) i_aw_out_queue ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .valid_i ( meta_buf_req_out.aw_valid ), - .ready_o ( aw_out_queue_ready ), - .data_i ( meta_buf_req_out.aw ), - .valid_o ( aw_out_queue_valid ), - .ready_i ( axi_out_rsp_i.aw_ready ), - .data_o ( axi_aw_queue_out ) - ); - - always_comb begin - axi_out_req_o = meta_buf_req_out; - axi_out_req_o.aw_valid = aw_out_queue_valid; - axi_out_req_o.aw = axi_aw_queue_out; - meta_buf_rsp_in = axi_out_rsp_i; - meta_buf_rsp_in.aw_ready = aw_out_queue_ready; - end - end else begin : gen_err_slv_port axi_err_slv #( .AxiIdWidth ( AxiCfg.InIdWidth ), @@ -289,6 +262,34 @@ module floo_axi_chimney #( assign floo_rsp_o.ready = floo_rsp_out_ready; end + + logic aw_out_queue_valid, aw_out_queue_ready; + axi_out_aw_chan_t axi_aw_queue_out; + + // Since AW and W are transferred over the same link, it can happen that + // a downstream module does not accept the AW until the W is valid. + // Therefore, we need to add a spill register for the AW channel. + spill_register #( + .T (axi_out_aw_chan_t) + ) i_aw_out_queue ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .valid_i ( meta_buf_req_out.aw_valid ), + .ready_o ( aw_out_queue_ready ), + .data_i ( meta_buf_req_out.aw ), + .valid_o ( aw_out_queue_valid ), + .ready_i ( axi_out_rsp_i.aw_ready ), + .data_o ( axi_aw_queue_out ) + ); + + always_comb begin + axi_out_req_o = meta_buf_req_out; + axi_out_req_o.aw_valid = aw_out_queue_valid; + axi_out_req_o.aw = axi_aw_queue_out; + meta_buf_rsp_in = axi_out_rsp_i; + meta_buf_rsp_in.aw_ready = aw_out_queue_ready; + end + /////////////////////// // Reorder Buffers // /////////////////////// diff --git a/hw/floo_nw_chimney.sv b/hw/floo_nw_chimney.sv index 750dc6ef..e1084c3e 100644 --- a/hw/floo_nw_chimney.sv +++ b/hw/floo_nw_chimney.sv @@ -271,33 +271,6 @@ module floo_nw_chimney #( assign axi_narrow_rsp_out.ar_ready = axi_narrow_ar_queue_ready_in; end - logic narrow_aw_out_queue_valid, narrow_aw_out_queue_ready; - axi_narrow_out_aw_chan_t axi_narrow_aw_queue_out; - - // Since AW and W are transferred over the same link, it can happen that - // a downstream module does not accept the AW until the W is valid. - // Therefore, we need to add a spill register for the AW channel. - spill_register #( - .T (axi_narrow_out_aw_chan_t) - ) i_aw_narrow_out_queue ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .valid_i ( axi_narrow_meta_buf_req_out.aw_valid ), - .ready_o ( narrow_aw_out_queue_ready ), - .data_i ( axi_narrow_meta_buf_req_out.aw ), - .valid_o ( narrow_aw_out_queue_valid ), - .ready_i ( axi_narrow_out_rsp_i.aw_ready ), - .data_o ( axi_narrow_aw_queue_out ) - ); - - always_comb begin - axi_narrow_out_req_o = axi_narrow_meta_buf_req_out; - axi_narrow_out_req_o.aw_valid = narrow_aw_out_queue_valid; - axi_narrow_out_req_o.aw = axi_narrow_aw_queue_out; - axi_narrow_meta_buf_rsp_in = axi_narrow_out_rsp_i; - axi_narrow_meta_buf_rsp_in.aw_ready = narrow_aw_out_queue_ready; - end - end else begin : gen_narrow_err_slv_port axi_err_slv #( .AxiIdWidth ( AxiCfgN.InIdWidth ), @@ -358,32 +331,6 @@ module floo_nw_chimney #( assign axi_wide_rsp_out.ar_ready = axi_wide_ar_queue_ready_in; end - logic wide_aw_out_queue_valid, wide_aw_out_queue_ready; - axi_wide_out_aw_chan_t axi_wide_aw_queue_out; - - // Since AW and W are transferred over the same link, it can happen that - // a downstream module does not accept the AW until the W is valid. - // Therefore, we need to add a spill register for the AW channel. - spill_register #( - .T (axi_wide_out_aw_chan_t) - ) i_aw_out_queue ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .valid_i ( axi_wide_meta_buf_req_out.aw_valid ), - .ready_o ( wide_aw_out_queue_ready ), - .data_i ( axi_wide_meta_buf_req_out.aw ), - .valid_o ( wide_aw_out_queue_valid ), - .ready_i ( axi_wide_out_rsp_i.aw_ready ), - .data_o ( axi_wide_aw_queue_out ) - ); - - always_comb begin - axi_wide_out_req_o = axi_wide_meta_buf_req_out; - axi_wide_out_req_o.aw_valid = wide_aw_out_queue_valid; - axi_wide_out_req_o.aw = axi_wide_aw_queue_out; - axi_wide_meta_buf_rsp_in = axi_wide_out_rsp_i; - axi_wide_meta_buf_rsp_in.aw_ready = wide_aw_out_queue_ready; - end end else begin : gen_wide_err_slv_port axi_err_slv #( .AxiIdWidth ( AxiCfgW.InIdWidth ), @@ -456,6 +403,53 @@ module floo_nw_chimney #( assign floo_wide_o.ready = floo_wide_out_ready; end + logic narrow_aw_out_queue_valid, narrow_aw_out_queue_ready; + logic wide_aw_out_queue_valid, wide_aw_out_queue_ready; + axi_narrow_out_aw_chan_t axi_narrow_aw_queue_out; + axi_wide_out_aw_chan_t axi_wide_aw_queue_out; + + // Since AW and W are transferred over the same link, it can happen that + // a downstream module does not accept the AW until the W is valid. + // Therefore, we need to add a spill register for the AW channel. + spill_register #( + .T (axi_narrow_out_aw_chan_t) + ) i_aw_narrow_out_queue ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .valid_i ( axi_narrow_meta_buf_req_out.aw_valid ), + .ready_o ( narrow_aw_out_queue_ready ), + .data_i ( axi_narrow_meta_buf_req_out.aw ), + .valid_o ( narrow_aw_out_queue_valid ), + .ready_i ( axi_narrow_out_rsp_i.aw_ready ), + .data_o ( axi_narrow_aw_queue_out ) + ); + + spill_register #( + .T (axi_wide_out_aw_chan_t) + ) i_aw_out_queue ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .valid_i ( axi_wide_meta_buf_req_out.aw_valid ), + .ready_o ( wide_aw_out_queue_ready ), + .data_i ( axi_wide_meta_buf_req_out.aw ), + .valid_o ( wide_aw_out_queue_valid ), + .ready_i ( axi_wide_out_rsp_i.aw_ready ), + .data_o ( axi_wide_aw_queue_out ) + ); + + always_comb begin + axi_narrow_out_req_o = axi_narrow_meta_buf_req_out; + axi_narrow_out_req_o.aw_valid = narrow_aw_out_queue_valid; + axi_narrow_out_req_o.aw = axi_narrow_aw_queue_out; + axi_narrow_meta_buf_rsp_in = axi_narrow_out_rsp_i; + axi_narrow_meta_buf_rsp_in.aw_ready = narrow_aw_out_queue_ready; + axi_wide_out_req_o = axi_wide_meta_buf_req_out; + axi_wide_out_req_o.aw_valid = wide_aw_out_queue_valid; + axi_wide_out_req_o.aw = axi_wide_aw_queue_out; + axi_wide_meta_buf_rsp_in = axi_wide_out_rsp_i; + axi_wide_meta_buf_rsp_in.aw_ready = wide_aw_out_queue_ready; + end + /////////////////////// // Reorder Buffers // /////////////////////// From aa87bc3a8ec039f52f31e8d663a06ace00791001 Mon Sep 17 00:00:00 2001 From: Tim Fischer Date: Tue, 10 Dec 2024 18:14:38 +0100 Subject: [PATCH 7/8] docs: Update CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d950cae2..fca94d98 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - The `ReorderBufferSize` parameters was shortened to `RoBSize`. - All testbenches were adapted to all changes. - All verification IPs were adapted to the new configuration structs. +- Added spill registers for outgoing AW requests in the chimneys. This is necessary since AXI allows to wait for AW *and* W to be valid before asserting the ready. Since, the AW and W beats are sent over the same channel, this might cause a deadlock if there there are no buffers downstream. #### FlooGen - The link typedefs are now renderd with the macros in `typedef.svh` instead of rendering them in pure SystemVerilog. From 5ccc6b78289d6279a8c0fb4cbdaf7b71a2925358 Mon Sep 17 00:00:00 2001 From: Tim Fischer Date: Thu, 12 Dec 2024 09:47:17 +0100 Subject: [PATCH 8/8] hw(nw_chimney): Fix duplicate drivers --- hw/floo_axi_chimney.sv | 2 +- hw/floo_nw_chimney.sv | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/floo_axi_chimney.sv b/hw/floo_axi_chimney.sv index b04e4591..275dd758 100644 --- a/hw/floo_axi_chimney.sv +++ b/hw/floo_axi_chimney.sv @@ -716,7 +716,7 @@ module floo_axi_chimney #( .slv_req_i ( meta_buf_req_in ), .slv_resp_o ( meta_buf_rsp_out ) ); - + assign meta_buf_req_out = '0; assign ar_out_hdr_out = '0; assign aw_out_hdr_out = '0; end diff --git a/hw/floo_nw_chimney.sv b/hw/floo_nw_chimney.sv index e1084c3e..6da15334 100644 --- a/hw/floo_nw_chimney.sv +++ b/hw/floo_nw_chimney.sv @@ -1183,7 +1183,7 @@ module floo_nw_chimney #( .slv_req_i ( axi_narrow_meta_buf_req_in ), .slv_resp_o ( axi_narrow_meta_buf_rsp_out ) ); - assign axi_narrow_out_req_o = '0; + assign axi_narrow_meta_buf_req_out = '0; assign narrow_ar_buf_hdr_out = '0; assign narrow_aw_buf_hdr_out = '0; end @@ -1227,7 +1227,7 @@ module floo_nw_chimney #( .slv_req_i ( axi_wide_meta_buf_req_in ), .slv_resp_o ( axi_wide_meta_buf_rsp_out ) ); - assign axi_wide_out_req_o = '0; + assign axi_wide_meta_buf_req_out = '0; assign wide_ar_buf_hdr_out = '0; assign wide_aw_buf_hdr_out = '0; end