From 9dc5a41483e3507a2018444aecf26f6e1ea061e4 Mon Sep 17 00:00:00 2001 From: Luca Colagrande Date: Mon, 11 Dec 2023 14:43:47 +0100 Subject: [PATCH 01/62] src: Remove missing pin warnings --- src/axi_to_mem_interleaved.sv | 3 +++ src/axi_to_mem_split.sv | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/axi_to_mem_interleaved.sv b/src/axi_to_mem_interleaved.sv index 9a5f87805..06dc1c2a4 100644 --- a/src/axi_to_mem_interleaved.sv +++ b/src/axi_to_mem_interleaved.sv @@ -282,6 +282,8 @@ module axi_to_mem_interleaved_intf #( input logic clk_i, /// 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 @@ -337,6 +339,7 @@ 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 28ce40831..3e98bda2e 100644 --- a/src/axi_to_mem_split.sv +++ b/src/axi_to_mem_split.sv @@ -196,6 +196,8 @@ module axi_to_mem_split_intf #( input logic clk_i, /// 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. @@ -244,6 +246,7 @@ 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), From abcec9d115000133b26bfcbbd57775607e91f124 Mon Sep 17 00:00:00 2001 From: Thomas Benz Date: Wed, 21 Feb 2024 09:38:29 +0100 Subject: [PATCH 02/62] Move AXI-related IPs from Snitch and Occamy repository to AXI --- Bender.yml | 2 + src/axi_interleaved_xbar.sv | 411 ++++++++++++++++++++++++++++++++++++ src/axi_zero_mem.sv | 97 +++++++++ 3 files changed, 510 insertions(+) create mode 100644 src/axi_interleaved_xbar.sv create mode 100644 src/axi_zero_mem.sv diff --git a/Bender.yml b/Bender.yml index d5cc6d008..25022ca77 100644 --- a/Bender.yml +++ b/Bender.yml @@ -79,7 +79,9 @@ sources: - src/axi_multicut.sv - src/axi_to_axi_lite.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_lite_xbar.sv - src/axi_xbar.sv diff --git a/src/axi_interleaved_xbar.sv b/src/axi_interleaved_xbar.sv new file mode 100644 index 000000000..77c112f45 --- /dev/null +++ b/src/axi_interleaved_xbar.sv @@ -0,0 +1,411 @@ +// Copyright 2020 ETH Zurich and University of Bologna. +// Solderpad Hardware License, Version 0.51, see LICENSE for details. +// SPDX-License-Identifier: SHL-0.51 +// +// Authors: +// - Wolfgang Roenninger +// - Andreas Kurth +// - Florian Zaruba +// - Thomas Benz + +// axi_interleaved_xbar +module axi_interleaved_xbar +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 slv_aw_chan_t = logic, + parameter type mst_aw_chan_t = logic, + parameter type w_chan_t = logic, + parameter type slv_b_chan_t = logic, + parameter type mst_b_chan_t = logic, + parameter type slv_ar_chan_t = logic, + parameter type mst_ar_chan_t = logic, + parameter type slv_r_chan_t = logic, + parameter type mst_r_chan_t = logic, + parameter type slv_req_t = logic, + parameter type slv_resp_t = logic, + parameter type mst_req_t = logic, + parameter type mst_resp_t = logic, + parameter type rule_t = axi_pkg::xbar_rule_64_t, + // don't overwrite + parameter int unsigned MstPortsIdxWidth = + (Cfg.NoMstPorts == 32'd1) ? 32'd1 : unsigned'($clog2(Cfg.NoMstPorts)) +) ( + 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, + input mst_resp_t [Cfg.NoMstPorts-1:0] mst_ports_resp_i, + input rule_t [Cfg.NoAddrRules-1:0] addr_map_i, + input logic interleaved_mode_ena_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 +); + + 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; + + // interleaved address modify + slv_req_t [Cfg.NoSlvPorts-1:0] slv_reqs_mod; + + 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_inter_aw, dec_inter_ar; +`else + logic [idx_width(Cfg.NoMstPorts)-1:0] dec_aw, dec_ar; + logic [idx_width(Cfg.NoMstPorts)-1:0] dec_inter_aw, dec_inter_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; + + localparam int unsigned BankSelLow = 'd16; + localparam int unsigned BankSelHigh = BankSelLow + MstPortsIdxWidth; + + // interleaved select (4kiB blocks) + assign dec_inter_aw = slv_ports_req_i[i].aw.addr[BankSelLow +: MstPortsIdxWidth]; + assign dec_inter_ar = slv_ports_req_i[i].ar.addr[BankSelLow +: MstPortsIdxWidth]; + + // interleaved address modify + always_comb begin : proc_modify_addr_interleaved + slv_reqs_mod[i] = slv_ports_req_i[i]; + + // only modify if interleaved mode is active + if (interleaved_mode_ena_i == 1'b1) begin + // modify AW address by removing bank bits + slv_reqs_mod[i].aw.addr = { {(MstPortsIdxWidth){1'b0}}, + slv_ports_req_i[i].aw.addr[Cfg.AxiAddrWidth-1:BankSelHigh], + slv_ports_req_i[i].aw.addr[BankSelLow-1:0] }; + + // modify AR address by removing bank bits + slv_reqs_mod[i].ar.addr = { {(MstPortsIdxWidth){1'b0}}, + slv_ports_req_i[i].ar.addr[Cfg.AxiAddrWidth-1:BankSelHigh], + slv_ports_req_i[i].ar.addr[BankSelLow-1:0] }; + end + end + + 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] ) + ); + + always_comb begin : ax_select + if (interleaved_mode_ena_i == 1'b1) begin + slv_aw_select = dec_inter_aw; + slv_ar_select = dec_inter_ar; + end else begin + slv_aw_select = (dec_aw_error) ? + mst_port_idx_t'(Cfg.NoMstPorts) : mst_port_idx_t'(dec_aw); + slv_ar_select = (dec_ar_error) ? + mst_port_idx_t'(Cfg.NoMstPorts) : mst_port_idx_t'(dec_ar); + end + 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 #( + .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_reqs_mod[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 + assign mst_reqs[j][i] = slv_reqs[i][j]; + assign slv_resps[i][j] = 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 : axi_interleaved_xbar + +`include "axi/assign.svh" +`include "axi/typedef.svh" + +module axi_interleaved_xbar_intf +import cf_math_pkg::idx_width; +#( + parameter int unsigned AXI_USER_WIDTH = 0, + parameter bit ATOPS = 1'b1, + parameter bit [Cfg.NoSlvPorts-1:0][Cfg.NoMstPorts-1:0] CONNECTIVITY = '1, + parameter axi_pkg::xbar_cfg_t Cfg = '0, + 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, + input logic interleaved_mode_ena_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_interleaved_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_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 ), + .mst_ports_resp_i (mst_resps), + .addr_map_i, + .interleaved_mode_ena_i, + .en_default_mst_port_i, + .default_mst_port_i + ); + +endmodule : axi_interleaved_xbar_intf diff --git a/src/axi_zero_mem.sv b/src/axi_zero_mem.sv new file mode 100644 index 000000000..66fb34c46 --- /dev/null +++ b/src/axi_zero_mem.sv @@ -0,0 +1,97 @@ +// 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: +// - Gianna Paulin +// - Thomas Benz + +`include "common_cells/registers.svh" +/// AXI4+ATOP slave module which translates AXI bursts into a memory stream +/// which behaves as a memory containing only `0` data which cannot be +/// overwritten by `write` operations. +/// - `read`: grants the request and returns data `0`. +/// - `write`: grants the request, write data goes into nothingness (can be used as data sink) +/// If both read and write channels of the AXI4+ATOP are active, both will have an +/// utilization of 50%. +module axi_zero_mem #( + /// AXI4+ATOP request type. See `include/axi/typedef.svh`. + parameter type axi_req_t = logic, + /// AXI4+ATOP response type. See `include/axi/typedef.svh`. + parameter type axi_resp_t = logic, + /// Address width, has to be less or equal than the width off the AXI address field. + /// Determines the width of `mem_addr_o`. Has to be wide enough to emit the memory region + /// which should be accessible. + parameter int unsigned AddrWidth = 0, + /// AXI4+ATOP data width. + parameter int unsigned DataWidth = 0, + /// AXI4+ATOP ID width. + parameter int unsigned IdWidth = 0, + /// Number of banks at output, must evenly divide `DataWidth`. + parameter int unsigned NumBanks = 0, + /// Depth of memory response buffer. This should be equal to the memory response latency. + parameter int unsigned BufDepth = 1, + /// Dependent parameter, do not override. Memory address type. + localparam type addr_t = logic [AddrWidth-1:0], + /// Dependent parameter, do not override. Memory data type. + localparam type mem_data_t = logic [DataWidth/NumBanks-1:0], + /// Dependent parameter, do not override. Memory write strobe type. + localparam type mem_strb_t = logic [DataWidth/NumBanks/8-1:0] +) ( + /// Clock input. + input logic clk_i, + /// Asynchronous reset, active low. + input logic rst_ni, + /// The unit is busy handling an AXI4+ATOP request. + output logic busy_o, + /// AXI4+ATOP slave port, request input. + input axi_req_t axi_req_i, + /// AXI4+ATOP slave port, response output. + output axi_resp_t axi_resp_o +); + + logic zero_mem_gnt, zero_mem_req, zero_mem_we; + logic zero_mem_valid_req_d, zero_mem_valid_req_q; + + axi_to_detailed_mem #( + .axi_req_t ( axi_req_t ), + .axi_resp_t ( axi_resp_t ), + .AddrWidth ( AddrWidth ), + .DataWidth ( DataWidth ), + .IdWidth ( IdWidth ), + .NumBanks ( 32'd1 ), + .BufDepth ( BufDepth ), + .HideStrb ( 1'b0 ), + .OutFifoDepth( 32'd1 ) + ) i_axi_to_detailed_mem ( + .clk_i, + .rst_ni, + .busy_o, + .axi_req_i, + .axi_resp_o, + .mem_req_o ( zero_mem_req ), + .mem_gnt_i ( zero_mem_gnt ), + .mem_addr_o ( /* NC */ ), + .mem_wdata_o ( /* NC */ ), + .mem_strb_o ( /* NC */ ), + .mem_atop_o ( /* NC */ ), + .mem_lock_o ( /* NC */ ), + .mem_we_o ( /* NC */ ), + .mem_id_o ( /* NC */ ), + .mem_user_o ( /* NC */ ), + .mem_cache_o ( /* NC */ ), + .mem_prot_o ( /* NC */ ), + .mem_qos_o ( /* NC */ ), + .mem_region_o ( /* NC */ ), + .mem_rvalid_i ( zero_mem_valid_req_q ), + .mem_rdata_i ( '0 ), + .mem_err_i ( 1'b0 ), + .mem_exokay_i ( 1'b0 ) + ); + + assign zero_mem_gnt = zero_mem_req; + assign zero_mem_valid_req_d = zero_mem_gnt & zero_mem_req; + + `FF(zero_mem_valid_req_q, zero_mem_valid_req_d, '0, clk_i, rst_ni) + +endmodule From fd1277e833507835e97ac97af6b21acf79fe4bdc Mon Sep 17 00:00:00 2001 From: Thomas Benz Date: Wed, 28 Feb 2024 11:37:21 +0100 Subject: [PATCH 03/62] axi_to_detailed_mem: VCS crashes with parameters equal to zero --- src/axi_to_detailed_mem.sv | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/axi_to_detailed_mem.sv b/src/axi_to_detailed_mem.sv index 8f5c11d21..d66c4d143 100644 --- a/src/axi_to_detailed_mem.sv +++ b/src/axi_to_detailed_mem.sv @@ -24,15 +24,15 @@ module axi_to_detailed_mem #( /// Address width, has to be less or equal than the width off the AXI address field. /// Determines the width of `mem_addr_o`. Has to be wide enough to emit the memory region /// which should be accessible. - parameter int unsigned AddrWidth = 0, + parameter int unsigned AddrWidth = 1, /// AXI4+ATOP data width. - parameter int unsigned DataWidth = 0, + parameter int unsigned DataWidth = 1, /// AXI4+ATOP ID width. - parameter int unsigned IdWidth = 0, + parameter int unsigned IdWidth = 1, /// AXI4+ATOP user width. - parameter int unsigned UserWidth = 0, + parameter int unsigned UserWidth = 1, /// Number of banks at output, must evenly divide `DataWidth`. - parameter int unsigned NumBanks = 0, + parameter int unsigned NumBanks = 1, /// Depth of memory response buffer. This should be equal to the memory response latency. parameter int unsigned BufDepth = 1, /// Hide write requests if the strb == '0 From eb1fe639eefbd4179e1f8e06e7f2d20e4350f94c Mon Sep 17 00:00:00 2001 From: Luca Zulberti Date: Wed, 13 Mar 2024 09:53:07 +0100 Subject: [PATCH 04/62] Fix byte calculation in R and W forks (#331) --- src/axi_sim_mem.sv | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/axi_sim_mem.sv b/src/axi_sim_mem.sv index b8b6b12c0..79b277843 100644 --- a/src/axi_sim_mem.sv +++ b/src/axi_sim_mem.sv @@ -162,8 +162,8 @@ module axi_sim_mem #( mon_w.user = aw_queue[0].user; mon_w.beat_count = w_cnt; for (shortint unsigned - i_byte = axi_pkg::beat_lower_byte(addr, size, len, burst, StrbWidth, w_cnt); - i_byte <= axi_pkg::beat_upper_byte(addr, size, len, burst, StrbWidth, w_cnt); + i_byte = axi_pkg::beat_lower_byte(aw_queue[0].addr, size, len, burst, StrbWidth, w_cnt); + i_byte <= axi_pkg::beat_upper_byte(aw_queue[0].addr, size, len, burst, StrbWidth, w_cnt); i_byte++) begin if (axi_req_i.w.strb[i_byte]) begin automatic addr_t byte_addr = (addr / StrbWidth) * StrbWidth + i_byte; @@ -232,8 +232,8 @@ module axi_sim_mem #( r_beat.id = ar_queue[0].id; r_beat.resp = axi_pkg::RESP_OKAY; for (shortint unsigned - i_byte = axi_pkg::beat_lower_byte(addr, size, len, burst, StrbWidth, r_cnt); - i_byte <= axi_pkg::beat_upper_byte(addr, size, len, burst, StrbWidth, r_cnt); + i_byte = axi_pkg::beat_lower_byte(ar_queue[0].addr, size, len, burst, StrbWidth, r_cnt); + i_byte <= axi_pkg::beat_upper_byte(ar_queue[0].addr, size, len, burst, StrbWidth, r_cnt); i_byte++) begin automatic addr_t byte_addr = (addr / StrbWidth) * StrbWidth + i_byte; if (!mem.exists(byte_addr)) begin From ac5deb3ff086aa34b168f392c051e92603d6c0e2 Mon Sep 17 00:00:00 2001 From: Thomas Benz Date: Wed, 13 Mar 2024 10:11:06 +0100 Subject: [PATCH 05/62] Release v0.39.2 --- CHANGELOG.md | 14 ++++++++++++++ README.md | 2 ++ VERSION | 2 +- axi.core | 4 +++- src/axi_interleaved_xbar.sv | 15 +++++++++++---- src/axi_zero_mem.sv | 15 +++++++++++---- src_files.yml | 2 ++ 7 files changed, 44 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 33d9a0783..6290aac80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,20 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## Unreleased +## 0.39.2 - 2024-03-13 + +### Added +- `axi_interleaved_xbar`: An experimental crossbar extension interleaving memory transfers over #334 + subordinate devices. ***Use at your own risk***. +- `axi_zero_mem`: Implementing *\dev\zero* function for AXI. #334 + +### Fixed +- `axi_to_detailed_mem`: VCS crashed on default parameters 0, changed them to 1 #334 +- `axi_to_mem`: Add missing testmode pins #327 +- `axi_sim_mem`: Fix byte calculation in R and W forks #331 + +`v0.39.2` is fully **backward-compatible** to `v0.39.1`. + ## 0.39.1 - 2023-09-05 ### Added diff --git a/README.md b/README.md index 962185172..83c37e32e 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,7 @@ In addition to the documents linked in the following table, we are setting up [d | [`axi_id_prepend`](src/axi_id_prepend.sv) | This module prepends/strips the MSB from the AXI IDs. | | | [`axi_id_remap`](src/axi_id_remap.sv) | Remap AXI IDs from wide IDs at the slave port to narrower IDs at the master port. | [Doc][doc.axi_id_remap] | | [`axi_id_serialize`](src/axi_id_serialize.sv) | Reduce AXI IDs by serializing transactions when necessary. | [Doc][doc.axi_id_serialize] | +| [`axi_interleaved_xbar`](src/axi_interleaved_xbar.sv) | Interleaved version of the crossbar. This module is experimental; use at your own risk. | | | [`axi_intf`](src/axi_intf.sv) | This file defines the interfaces we support. | | | [`axi_isolate`](src/axi_isolate.sv) | A module that can isolate downstream slaves from receiving new AXI4 transactions. | | | [`axi_iw_converter`](src/axi_iw_converter.sv) | Convert between any two AXI ID widths. | [Doc][doc.axi_iw_converter] | @@ -67,6 +68,7 @@ In addition to the documents linked in the following table, we are setting up [d | [`axi_to_mem`](src/axi_to_mem.sv) | AXI4 to memory protocol (req, gnt, rvalid) converter. Additional banked, interleaved, split variant. | | | [`axi_xbar`](src/axi_xbar.sv) | Fully-connected AXI4+ATOP crossbar with an arbitrary number of slave and master ports. | [Doc](doc/axi_xbar.md) | | [`axi_xp`](src/axi_xp.sv) | AXI Crosspoint (XP) with homomorphous slave and master ports. | | +| [`axi_zero_mem`](src/axi_zero_mem.sv) | AXI-attached /dev/zero. All reads will be zero, writes are absorbed. | | ## Synthesizable Verification Modules diff --git a/VERSION b/VERSION index d2e2400ee..e06193879 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.39.1 +0.39.2 diff --git a/axi.core b/axi.core index a44922d2c..893c7b863 100644 --- a/axi.core +++ b/axi.core @@ -1,6 +1,6 @@ CAPI=2: -name : pulp-platform.org::axi:0.39.1 +name : pulp-platform.org::axi:0.39.2 filesets: rtl: @@ -59,7 +59,9 @@ filesets: - src/axi_multicut.sv - src/axi_to_axi_lite.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_lite_xbar.sv - src/axi_xbar.sv diff --git a/src/axi_interleaved_xbar.sv b/src/axi_interleaved_xbar.sv index 77c112f45..f5f25f5b3 100644 --- a/src/axi_interleaved_xbar.sv +++ b/src/axi_interleaved_xbar.sv @@ -1,6 +1,13 @@ -// Copyright 2020 ETH Zurich and University of Bologna. -// Solderpad Hardware License, Version 0.51, see LICENSE for details. -// SPDX-License-Identifier: SHL-0.51 +// Copyright (c) 2020 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 @@ -8,7 +15,7 @@ // - Florian Zaruba // - Thomas Benz -// axi_interleaved_xbar +/// Interleaved version of the crossbar. This module is experimental; use at your own risk. module axi_interleaved_xbar import cf_math_pkg::idx_width; #( diff --git a/src/axi_zero_mem.sv b/src/axi_zero_mem.sv index 66fb34c46..1cb48b27b 100644 --- a/src/axi_zero_mem.sv +++ b/src/axi_zero_mem.sv @@ -1,7 +1,14 @@ -// Copyright 2024 ETH Zurich and University of Bologna. -// Solderpad Hardware License, Version 0.51, see LICENSE for details. -// SPDX-License-Identifier: SHL-0.51 - +// Copyright (c) 2024 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: // - Gianna Paulin // - Thomas Benz diff --git a/src_files.yml b/src_files.yml index 16cc1ce00..ae79a8d43 100644 --- a/src_files.yml +++ b/src_files.yml @@ -58,7 +58,9 @@ axi: - src/axi_multicut.sv - src/axi_to_axi_lite.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_lite_xbar.sv - src/axi_xbar.sv From be01569f984e04ebce26748553d3e52c68bc15fd Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Tue, 30 Apr 2024 17:05:57 +0200 Subject: [PATCH 06/62] `axi_sim_mem`: Configure response data Allow response data for uninitialized region to have configurable defined value, based on a parameter. --- CHANGELOG.md | 2 ++ src/axi_sim_mem.sv | 15 ++++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6290aac80..6df8c1eb3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## Unreleased +### Added +- `axi_sim_mem`: Allow response data for uninitialized region to have configurable defined value. ## 0.39.2 - 2024-03-13 diff --git a/src/axi_sim_mem.sv b/src/axi_sim_mem.sv index 79b277843..564cfc9da 100644 --- a/src/axi_sim_mem.sv +++ b/src/axi_sim_mem.sv @@ -39,6 +39,8 @@ module axi_sim_mem #( parameter type axi_rsp_t = logic, /// Warn on accesses to uninitialized bytes parameter bit WarnUninitialized = 1'b0, + /// Default value for uninitialized memory (undefined, zeros, ones, random) + parameter UninitializedData = "undefined", /// Clear error on access parameter bit ClearErrOnAccess = 1'b0, /// Application delay (measured after rising clock edge) @@ -241,7 +243,16 @@ module axi_sim_mem #( $warning("Access to non-initialized byte at address 0x%016x by ID 0x%x.", byte_addr, r_beat.id); end - r_data[i_byte*8+:8] = 'x; + case (UninitializedData) + "random": + r_data[i_byte*8+:8] = $urandom; + "ones": + r_data[i_byte*8+:8] = '1; + "zeros": + r_data[i_byte*8+:8] = '0; + default: + r_data[i_byte*8+:8] = 'x; + endcase end else begin r_data[i_byte*8+:8] = mem[byte_addr]; end @@ -342,6 +353,7 @@ module axi_sim_mem_intf #( parameter int unsigned AXI_ID_WIDTH = 32'd0, parameter int unsigned AXI_USER_WIDTH = 32'd0, parameter bit WARN_UNINITIALIZED = 1'b0, + parameter UNINITIALIZED_DATA = "undefined", parameter bit ClearErrOnAccess = 1'b0, parameter time APPL_DELAY = 0ps, parameter time ACQ_DELAY = 0ps @@ -386,6 +398,7 @@ module axi_sim_mem_intf #( .axi_req_t (axi_req_t), .axi_rsp_t (axi_resp_t), .WarnUninitialized (WARN_UNINITIALIZED), + .UninitializedData (UNINITIALIZED_DATA), .ClearErrOnAccess (ClearErrOnAccess), .ApplDelay (APPL_DELAY), .AcqDelay (ACQ_DELAY) From 3f790832bb4a65744ccfaa866483e9482440fd0f Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Tue, 7 May 2024 14:46:05 +0200 Subject: [PATCH 07/62] Allow custom XBAR latency configurations (e.g., vivado) --- src/axi_pkg.sv | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/axi_pkg.sv b/src/axi_pkg.sv index dd60c451e..4102be0e8 100644 --- a/src/axi_pkg.sv +++ b/src/axi_pkg.sv @@ -445,27 +445,27 @@ package axi_pkg; // `xbar_latency_e` and `xbar_cfg_t` are documented in `doc/axi_xbar.md`. /// Slice on Demux AW channel. - localparam logic [9:0] DemuxAw = (1 << 9); + localparam bit [9:0] DemuxAw = (1 << 9); /// Slice on Demux W channel. - localparam logic [9:0] DemuxW = (1 << 8); + localparam bit [9:0] DemuxW = (1 << 8); /// Slice on Demux B channel. - localparam logic [9:0] DemuxB = (1 << 7); + localparam bit [9:0] DemuxB = (1 << 7); /// Slice on Demux AR channel. - localparam logic [9:0] DemuxAr = (1 << 6); + localparam bit [9:0] DemuxAr = (1 << 6); /// Slice on Demux R channel. - localparam logic [9:0] DemuxR = (1 << 5); + localparam bit [9:0] DemuxR = (1 << 5); /// Slice on Mux AW channel. - localparam logic [9:0] MuxAw = (1 << 4); + localparam bit [9:0] MuxAw = (1 << 4); /// Slice on Mux W channel. - localparam logic [9:0] MuxW = (1 << 3); + localparam bit [9:0] MuxW = (1 << 3); /// Slice on Mux B channel. - localparam logic [9:0] MuxB = (1 << 2); + localparam bit [9:0] MuxB = (1 << 2); /// Slice on Mux AR channel. - localparam logic [9:0] MuxAr = (1 << 1); + localparam bit [9:0] MuxAr = (1 << 1); /// Slice on Mux R channel. - localparam logic [9:0] MuxR = (1 << 0); + localparam bit [9:0] MuxR = (1 << 0); /// Latency configuration for `axi_xbar`. - typedef enum logic [9:0] { + typedef enum bit [9:0] { NO_LATENCY = 10'b000_00_000_00, CUT_SLV_AX = DemuxAw | DemuxAr, CUT_MST_AX = MuxAw | MuxAr, @@ -496,7 +496,7 @@ package axi_pkg; /// The Latency mode of the xbar. This determines if the channels on the ports have /// a spill register instantiated. /// Example configurations are provided with the enum `xbar_latency_e`. - xbar_latency_e LatencyMode; + bit [9:0] LatencyMode; /// This is the number of `axi_multicut` stages instantiated in the line cross of the channels. /// Having multiple stages can potentially add a large number of FFs! int unsigned PipelineStages; From 4de9078004ac1329cc7a62a55857d5ca8027d9fb Mon Sep 17 00:00:00 2001 From: Luca Valente Date: Mon, 15 Jan 2024 11:41:47 +0100 Subject: [PATCH 08/62] `axi_test`: add `clear_memory_regions` to `axi_rand_master`. --- src/axi_test.sv | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/axi_test.sv b/src/axi_test.sv index c9fca2697..6a06d1340 100644 --- a/src/axi_test.sv +++ b/src/axi_test.sv @@ -808,6 +808,10 @@ package axi_test; mem_map.push_back({addr_begin, addr_end, mem_type}); endfunction + function void clear_memory_regions(); + mem_map.delete(); + endfunction + function void add_traffic_shaping(input int unsigned len, input int unsigned freq); if (traffic_shape.size() == 0) traffic_shape.push_back({len, freq}); From 210ab3947480616a6b03012fb038b3d70a96e752 Mon Sep 17 00:00:00 2001 From: Luca Valente Date: Mon, 15 Jan 2024 11:46:36 +0100 Subject: [PATCH 09/62] `axi_rand_master`: prevent stall if `RESP_MIN/MAX_WAIT_CYCLES=0` --- src/axi_test.sv | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/axi_test.sv b/src/axi_test.sv index 6a06d1340..8d2ef2d06 100644 --- a/src/axi_test.sv +++ b/src/axi_test.sv @@ -1153,6 +1153,8 @@ package axi_test; end cnt_sem.put(); end + end else begin + rand_wait(1,1); end end endtask From 6089791b8603c6852c417b3156332a3adcd95315 Mon Sep 17 00:00:00 2001 From: Luca Valente Date: Mon, 15 Jan 2024 12:05:36 +0100 Subject: [PATCH 10/62] `axi_rand_master`: add `size` input to `add_traffic_shaping` --- src/axi_test.sv | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/axi_test.sv b/src/axi_test.sv index 8d2ef2d06..080a91975 100644 --- a/src/axi_test.sv +++ b/src/axi_test.sv @@ -762,6 +762,7 @@ package axi_test; struct packed { int unsigned len ; + int unsigned size ; int unsigned cprob; } traffic_shape[$]; int unsigned max_cprob; @@ -812,11 +813,11 @@ package axi_test; mem_map.delete(); endfunction - function void add_traffic_shaping(input int unsigned len, input int unsigned freq); + function void add_traffic_shaping(input int unsigned len, input int unsigned size, input int unsigned freq); if (traffic_shape.size() == 0) - traffic_shape.push_back({len, freq}); + traffic_shape.push_back({len, size, freq}); else - traffic_shape.push_back({len, traffic_shape[$].cprob + freq}); + traffic_shape.push_back({len, size, traffic_shape[$].cprob + freq}); max_cprob = traffic_shape[$].cprob; endfunction : add_traffic_shaping @@ -867,6 +868,7 @@ package axi_test; for (int i = 0; i < traffic_shape.size(); i++) if (traffic_shape[i].cprob > cprob) begin len = traffic_shape[i].len; + size = traffic_shape[i].size; if (ax_beat.ax_burst == BURST_WRAP) begin assert (len inside {len_t'(1), len_t'(3), len_t'(7), len_t'(15)}); end @@ -875,12 +877,17 @@ package axi_test; // Randomize address. Make sure that the burst does not cross a 4KiB boundary. forever begin - rand_success = std::randomize(size) with { - 2**size <= AXI_STRB_WIDTH; - 2**size <= len; - }; assert(rand_success); - ax_beat.ax_size = size; - ax_beat.ax_len = ((len + (1 << size) - 1) >> size) - 1; + if(size==-1) begin + rand_success = std::randomize(size) with { + 2**size <= AXI_STRB_WIDTH; + 2**size <= len; + }; assert(rand_success); + ax_beat.ax_size = size; + ax_beat.ax_len = ((len + (1 << size) - 1) >> size) - 1; + end else begin + ax_beat.ax_size = size; + ax_beat.ax_len = len; + end rand_success = std::randomize(addr) with { addr >= mem_region.addr_begin; From 6d30a5a0fd1839470bac41dcd124aaa5cb89194d Mon Sep 17 00:00:00 2001 From: Luca Valente Date: Wed, 20 Mar 2024 12:32:00 +0100 Subject: [PATCH 11/62] Add function `add_traffic_shaping_with_size` to avoid changing `add_traffic_shaping`'s interface. --- src/axi_test.sv | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/axi_test.sv b/src/axi_test.sv index 080a91975..eadadcaff 100644 --- a/src/axi_test.sv +++ b/src/axi_test.sv @@ -813,7 +813,8 @@ package axi_test; mem_map.delete(); endfunction - function void add_traffic_shaping(input int unsigned len, input int unsigned size, input int unsigned freq); + function void add_traffic_shaping(input int unsigned len, input int unsigned freq); + int unsigned size = -1; if (traffic_shape.size() == 0) traffic_shape.push_back({len, size, freq}); else @@ -822,6 +823,15 @@ package axi_test; max_cprob = traffic_shape[$].cprob; endfunction : add_traffic_shaping + function void add_traffic_shaping_with_size(input int unsigned len, input int unsigned size, input int unsigned freq); + if (traffic_shape.size() == 0) + traffic_shape.push_back({len, size, freq}); + else + traffic_shape.push_back({len, size, traffic_shape[$].cprob + freq}); + + max_cprob = traffic_shape[$].cprob; + endfunction : add_traffic_shaping_with_size + function ax_beat_t new_rand_burst(input logic is_read); automatic logic rand_success; automatic ax_beat_t ax_beat = new; From 9402c8a9ce0a7b5253c3c29e788612d771e8b5d6 Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Wed, 8 May 2024 16:27:47 +0200 Subject: [PATCH 12/62] Release v0.39.3 --- CHANGELOG.md | 11 +++++++++++ VERSION | 2 +- axi.core | 2 +- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6df8c1eb3..a829a952d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,8 +6,19 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## Unreleased + +## 0.39.3 - 2024-05-08 ### Added - `axi_sim_mem`: Allow response data for uninitialized region to have configurable defined value. +- `axi_test`: add `clear_memory_regions` to `axi_rand_master`. +- `axi_test`: Add `add_traffic_shaping_with_size` to `axi_rand_master` to allow for traffic shaping + with a custom size. + +### Changed +- `axi_pkg`: Adjust `LatencyMode` parameter of `xbar_cfg_t` to bit vector from `xbar_pipeline_e` + enum to allow custom configurations. + +`v0.39.3` is fully **backward-compatible** to `v0.39.2`. ## 0.39.2 - 2024-03-13 diff --git a/VERSION b/VERSION index e06193879..e0c2d6587 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.39.2 +0.39.3 diff --git a/axi.core b/axi.core index 893c7b863..a68f7648c 100644 --- a/axi.core +++ b/axi.core @@ -1,6 +1,6 @@ CAPI=2: -name : pulp-platform.org::axi:0.39.2 +name : pulp-platform.org::axi:0.39.3 filesets: rtl: From f03fe4246f55adf0acf148989c5e3d1fc97ed9da Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Tue, 16 Jul 2024 17:56:51 +0200 Subject: [PATCH 13/62] axi_sim_mem: Increase number of ports --- src/axi_sim_mem.sv | 468 +++++++++++++++++++++++---------------------- 1 file changed, 238 insertions(+), 230 deletions(-) diff --git a/src/axi_sim_mem.sv b/src/axi_sim_mem.sv index 564cfc9da..bdc74715c 100644 --- a/src/axi_sim_mem.sv +++ b/src/axi_sim_mem.sv @@ -33,6 +33,8 @@ module axi_sim_mem #( parameter int unsigned IdWidth = 32'd0, /// AXI User Width. parameter int unsigned UserWidth = 32'd0, + /// Number of request ports + parameter int unsigned NumPorts = 32'd1, /// AXI4 request struct definition parameter type axi_req_t = logic, /// AXI4 response struct definition @@ -53,41 +55,41 @@ module axi_sim_mem #( /// Active-low reset input logic rst_ni, /// AXI4 request struct - input axi_req_t axi_req_i, + input axi_req_t [NumPorts-1:0] axi_req_i, /// AXI4 response struct - output axi_rsp_t axi_rsp_o, + output axi_rsp_t [NumPorts-1:0] axi_rsp_o, /// Memory monitor write valid. All `mon_w_*` outputs are only valid if this signal is high. /// A write to the memory is visible on the `mon_w_*` outputs in the clock cycle after it has /// happened. - output logic mon_w_valid_o, + output logic [NumPorts-1:0] mon_w_valid_o, /// Memory monitor write address - output logic [AddrWidth-1:0] mon_w_addr_o, + output logic [NumPorts-1:0][AddrWidth-1:0] mon_w_addr_o, /// Memory monitor write data - output logic [DataWidth-1:0] mon_w_data_o, + output logic [NumPorts-1:0][DataWidth-1:0] mon_w_data_o, /// Memory monitor write ID - output logic [IdWidth-1:0] mon_w_id_o, + output logic [NumPorts-1:0][IdWidth-1:0] mon_w_id_o, /// Memory monitor write user - output logic [UserWidth-1:0] mon_w_user_o, + output logic [NumPorts-1:0][UserWidth-1:0] mon_w_user_o, /// Memory monitor write beat count - output axi_pkg::len_t mon_w_beat_count_o, + output axi_pkg::len_t [NumPorts-1:0] mon_w_beat_count_o, /// Memory monitor write last - output logic mon_w_last_o, + output logic [NumPorts-1:0] mon_w_last_o, /// Memory monitor read valid. All `mon_r_*` outputs are only valid if this signal is high. /// A read from the memory is visible on the `mon_w_*` outputs in the clock cycle after it has /// happened. - output logic mon_r_valid_o, + output logic [NumPorts-1:0] mon_r_valid_o, /// Memory monitor read address - output logic [AddrWidth-1:0] mon_r_addr_o, + output logic [NumPorts-1:0][AddrWidth-1:0] mon_r_addr_o, /// Memory monitor read data - output logic [DataWidth-1:0] mon_r_data_o, + output logic [NumPorts-1:0][DataWidth-1:0] mon_r_data_o, /// Memory monitor read ID - output logic [IdWidth-1:0] mon_r_id_o, + output logic [NumPorts-1:0][IdWidth-1:0] mon_r_id_o, /// Memory monitor read user - output logic [UserWidth-1:0] mon_r_user_o, + output logic [NumPorts-1:0][UserWidth-1:0] mon_r_user_o, /// Memory monitor read beat count - output axi_pkg::len_t mon_r_beat_count_o, + output axi_pkg::len_t [NumPorts-1:0] mon_r_beat_count_o, /// Memory monitor read last - output logic mon_r_last_o + output logic [NumPorts-1:0] mon_r_last_o ); localparam int unsigned StrbWidth = DataWidth / 8; @@ -112,222 +114,224 @@ module axi_sim_mem #( logic last; } monitor_t; - monitor_t mon_w, mon_r; + monitor_t [NumPorts-1:0] mon_w, mon_r; logic [7:0] mem[addr_t]; axi_pkg::resp_t rerr[addr_t] = '{default: axi_pkg::RESP_OKAY}; axi_pkg::resp_t werr[addr_t] = '{default: axi_pkg::RESP_OKAY}; // error happened in write burst - axi_pkg::resp_t error_happened = axi_pkg::RESP_OKAY; + axi_pkg::resp_t [NumPorts-1:0] error_happened = axi_pkg::RESP_OKAY; - initial begin - automatic ar_t ar_queue[$]; - automatic aw_t aw_queue[$]; - automatic b_t b_queue[$]; - automatic shortint unsigned r_cnt = 0, w_cnt = 0; - axi_rsp_o = '0; - // Monitor interface - mon_w = '0; - mon_r = '0; - wait (rst_ni); - fork - // AW - forever begin - @(posedge clk_i); - #(ApplDelay); - axi_rsp_o.aw_ready = 1'b1; - #(AcqDelay - ApplDelay); - if (axi_req_i.aw_valid) begin - automatic aw_t aw = axi_req_i.aw; - aw_queue.push_back(aw); - end - end - // W - forever begin - @(posedge clk_i); - #(ApplDelay); - axi_rsp_o.w_ready = 1'b0; - mon_w = '0; - if (aw_queue.size() != 0) begin - axi_rsp_o.w_ready = 1'b1; + for (genvar i = 0; i < NumPorts; i++) begin + initial begin + automatic ar_t ar_queue[$]; + automatic aw_t aw_queue[$]; + automatic b_t b_queue[$]; + automatic shortint unsigned r_cnt = 0, w_cnt = 0; + axi_rsp_o[i] = '0; + // Monitor interface + mon_w[i] = '0; + mon_r[i] = '0; + wait (rst_ni); + fork + // AW + forever begin + @(posedge clk_i); + #(ApplDelay); + axi_rsp_o[i].aw_ready = 1'b1; #(AcqDelay - ApplDelay); - if (axi_req_i.w_valid) begin - automatic axi_pkg::burst_t burst = aw_queue[0].burst; - automatic axi_pkg::len_t len = aw_queue[0].len; - automatic axi_pkg::size_t size = aw_queue[0].size; - automatic addr_t addr = axi_pkg::beat_addr(aw_queue[0].addr, size, len, burst, - w_cnt); - mon_w.valid = 1'b1; - mon_w.addr = addr; - mon_w.data = axi_req_i.w.data; - mon_w.id = aw_queue[0].id; - mon_w.user = aw_queue[0].user; - mon_w.beat_count = w_cnt; - for (shortint unsigned - i_byte = axi_pkg::beat_lower_byte(aw_queue[0].addr, size, len, burst, StrbWidth, w_cnt); - i_byte <= axi_pkg::beat_upper_byte(aw_queue[0].addr, size, len, burst, StrbWidth, w_cnt); - i_byte++) begin - if (axi_req_i.w.strb[i_byte]) begin - automatic addr_t byte_addr = (addr / StrbWidth) * StrbWidth + i_byte; - mem[byte_addr] = axi_req_i.w.data[i_byte*8+:8]; - error_happened = axi_pkg::resp_precedence(werr[byte_addr], error_happened); - if (ClearErrOnAccess) - werr[byte_addr] = axi_pkg::RESP_OKAY; + if (axi_req_i[i].aw_valid) begin + automatic aw_t aw = axi_req_i[i].aw; + aw_queue.push_back(aw); + end + end + // W + forever begin + @(posedge clk_i); + #(ApplDelay); + axi_rsp_o[i].w_ready = 1'b0; + mon_w[i] = '0; + if (aw_queue.size() != 0) begin + axi_rsp_o[i].w_ready = 1'b1; + #(AcqDelay - ApplDelay); + if (axi_req_i[i].w_valid) begin + automatic axi_pkg::burst_t burst = aw_queue[0].burst; + automatic axi_pkg::len_t len = aw_queue[0].len; + automatic axi_pkg::size_t size = aw_queue[0].size; + automatic addr_t addr = axi_pkg::beat_addr(aw_queue[0].addr, size, len, burst, + w_cnt); + mon_w[i].valid = 1'b1; + mon_w[i].addr = addr; + mon_w[i].data = axi_req_i[i].w.data; + mon_w[i].id = aw_queue[0].id; + mon_w[i].user = aw_queue[0].user; + mon_w[i].beat_count = w_cnt; + for (shortint unsigned + i_byte = axi_pkg::beat_lower_byte(aw_queue[0].addr, size, len, burst, StrbWidth, w_cnt); + i_byte <= axi_pkg::beat_upper_byte(aw_queue[0].addr, size, len, burst, StrbWidth, w_cnt); + i_byte++) begin + if (axi_req_i[i].w.strb[i_byte]) begin + automatic addr_t byte_addr = (addr / StrbWidth) * StrbWidth + i_byte; + mem[byte_addr] = axi_req_i[i].w.data[i_byte*8+:8]; + error_happened[i] = axi_pkg::resp_precedence(werr[byte_addr], error_happened[i]); + if (ClearErrOnAccess) + werr[byte_addr] = axi_pkg::RESP_OKAY; + end + end + if (w_cnt == aw_queue[0].len) begin + automatic b_t b_beat = '0; + assert (axi_req_i[i].w.last) else $error("Expected last beat of W burst!"); + b_beat.id = aw_queue[0].id; + b_beat.resp = error_happened[i]; + b_queue.push_back(b_beat); + w_cnt = 0; + mon_w[i].last = 1'b1; + error_happened[i] = axi_pkg::RESP_OKAY; + void'(aw_queue.pop_front()); + end else begin + assert (!axi_req_i[i].w.last) else $error("Did not expect last beat of W burst!"); + w_cnt++; end end - if (w_cnt == aw_queue[0].len) begin - automatic b_t b_beat = '0; - assert (axi_req_i.w.last) else $error("Expected last beat of W burst!"); - b_beat.id = aw_queue[0].id; - b_beat.resp = error_happened; - b_queue.push_back(b_beat); - w_cnt = 0; - mon_w.last = 1'b1; - error_happened = axi_pkg::RESP_OKAY; - void'(aw_queue.pop_front()); - end else begin - assert (!axi_req_i.w.last) else $error("Did not expect last beat of W burst!"); - w_cnt++; + end + end + // B + forever begin + @(posedge clk_i); + #(ApplDelay); + axi_rsp_o[i].b_valid = 1'b0; + if (b_queue.size() != 0) begin + axi_rsp_o[i].b = b_queue[0]; + axi_rsp_o[i].b_valid = 1'b1; + #(AcqDelay - ApplDelay); + if (axi_req_i[i].b_ready) begin + void'(b_queue.pop_front()); end end end - end - // B - forever begin - @(posedge clk_i); - #(ApplDelay); - axi_rsp_o.b_valid = 1'b0; - if (b_queue.size() != 0) begin - axi_rsp_o.b = b_queue[0]; - axi_rsp_o.b_valid = 1'b1; + // AR + forever begin + @(posedge clk_i); + #(ApplDelay); + axi_rsp_o[i].ar_ready = 1'b1; #(AcqDelay - ApplDelay); - if (axi_req_i.b_ready) begin - void'(b_queue.pop_front()); + if (axi_req_i[i].ar_valid) begin + automatic ar_t ar = axi_req_i[i].ar; + ar_queue.push_back(ar); end end - end - // AR - forever begin - @(posedge clk_i); - #(ApplDelay); - axi_rsp_o.ar_ready = 1'b1; - #(AcqDelay - ApplDelay); - if (axi_req_i.ar_valid) begin - automatic ar_t ar = axi_req_i.ar; - ar_queue.push_back(ar); - end - end - // R - forever begin - @(posedge clk_i); - #(ApplDelay); - axi_rsp_o.r_valid = 1'b0; - mon_r = '0; - if (ar_queue.size() != 0) begin - automatic axi_pkg::burst_t burst = ar_queue[0].burst; - automatic axi_pkg::len_t len = ar_queue[0].len; - automatic axi_pkg::size_t size = ar_queue[0].size; - automatic addr_t addr = axi_pkg::beat_addr(ar_queue[0].addr, size, len, burst, r_cnt); - automatic r_t r_beat = '0; - automatic data_t r_data = 'x; // compatibility reasons - r_beat.data = 'x; - r_beat.id = ar_queue[0].id; - r_beat.resp = axi_pkg::RESP_OKAY; - for (shortint unsigned - i_byte = axi_pkg::beat_lower_byte(ar_queue[0].addr, size, len, burst, StrbWidth, r_cnt); - i_byte <= axi_pkg::beat_upper_byte(ar_queue[0].addr, size, len, burst, StrbWidth, r_cnt); - i_byte++) begin - automatic addr_t byte_addr = (addr / StrbWidth) * StrbWidth + i_byte; - if (!mem.exists(byte_addr)) begin - if (WarnUninitialized) begin - $warning("Access to non-initialized byte at address 0x%016x by ID 0x%x.", byte_addr, - r_beat.id); + // R + forever begin + @(posedge clk_i); + #(ApplDelay); + axi_rsp_o[i].r_valid = 1'b0; + mon_r[i] = '0; + if (ar_queue.size() != 0) begin + automatic axi_pkg::burst_t burst = ar_queue[0].burst; + automatic axi_pkg::len_t len = ar_queue[0].len; + automatic axi_pkg::size_t size = ar_queue[0].size; + automatic addr_t addr = axi_pkg::beat_addr(ar_queue[0].addr, size, len, burst, r_cnt); + automatic r_t r_beat = '0; + automatic data_t r_data = 'x; // compatibility reasons + r_beat.data = 'x; + r_beat.id = ar_queue[0].id; + r_beat.resp = axi_pkg::RESP_OKAY; + for (shortint unsigned + i_byte = axi_pkg::beat_lower_byte(ar_queue[0].addr, size, len, burst, StrbWidth, r_cnt); + i_byte <= axi_pkg::beat_upper_byte(ar_queue[0].addr, size, len, burst, StrbWidth, r_cnt); + i_byte++) begin + automatic addr_t byte_addr = (addr / StrbWidth) * StrbWidth + i_byte; + if (!mem.exists(byte_addr)) begin + if (WarnUninitialized) begin + $warning("Access to non-initialized byte at address 0x%016x by ID 0x%x.", byte_addr, + r_beat.id); + end + case (UninitializedData) + "random": + r_data[i_byte*8+:8] = $urandom; + "ones": + r_data[i_byte*8+:8] = '1; + "zeros": + r_data[i_byte*8+:8] = '0; + default: + r_data[i_byte*8+:8] = 'x; + endcase + end else begin + r_data[i_byte*8+:8] = mem[byte_addr]; + end + r_beat.resp = axi_pkg::resp_precedence(rerr[byte_addr], r_beat.resp); + if (ClearErrOnAccess & axi_req_i[i].r_ready) begin + rerr[byte_addr] = axi_pkg::RESP_OKAY; end - case (UninitializedData) - "random": - r_data[i_byte*8+:8] = $urandom; - "ones": - r_data[i_byte*8+:8] = '1; - "zeros": - r_data[i_byte*8+:8] = '0; - default: - r_data[i_byte*8+:8] = 'x; - endcase - end else begin - r_data[i_byte*8+:8] = mem[byte_addr]; end - r_beat.resp = axi_pkg::resp_precedence(rerr[byte_addr], r_beat.resp); - if (ClearErrOnAccess & axi_req_i.r_ready) begin - rerr[byte_addr] = axi_pkg::RESP_OKAY; + r_beat.data = r_data; + if (r_cnt == ar_queue[0].len) begin + r_beat.last = 1'b1; + mon_r[i].last = 1'b1; + end + axi_rsp_o[i].r = r_beat; + axi_rsp_o[i].r_valid = 1'b1; + mon_r[i].valid = 1'b1; + mon_r[i].addr = addr; + mon_r[i].data = r_beat.data; + mon_r[i].id = r_beat.id; + mon_r[i].user = ar_queue[0].user; + mon_r[i].beat_count = r_cnt; + #(AcqDelay - ApplDelay); + while (!axi_req_i[i].r_ready) begin + @(posedge clk_i); + #(AcqDelay); + mon_r[i] = '0; + end + if (r_beat.last) begin + r_cnt = 0; + void'(ar_queue.pop_front()); + end else begin + r_cnt++; end - end - r_beat.data = r_data; - if (r_cnt == ar_queue[0].len) begin - r_beat.last = 1'b1; - mon_r.last = 1'b1; - end - axi_rsp_o.r = r_beat; - axi_rsp_o.r_valid = 1'b1; - mon_r.valid = 1'b1; - mon_r.addr = addr; - mon_r.data = r_beat.data; - mon_r.id = r_beat.id; - mon_r.user = ar_queue[0].user; - mon_r.beat_count = r_cnt; - #(AcqDelay - ApplDelay); - while (!axi_req_i.r_ready) begin - @(posedge clk_i); - #(AcqDelay); - mon_r = '0; - end - if (r_beat.last) begin - r_cnt = 0; - void'(ar_queue.pop_front()); - end else begin - r_cnt++; end end - end - join - end + join + end - // Assign the monitor output in the next clock cycle. Rationale: We only know whether we are - // writing until after `AcqDelay`. This means we could only provide the monitoring output for - // writes after `AcqDelay` in the same cycle, which is incompatible with ATI timing. Thus, we - // provide the monitoring output for writes (and for uniformity also for reads) in the next clock - // cycle. - initial begin - mon_w_valid_o = '0; - mon_w_addr_o = '0; - mon_w_data_o = '0; - mon_w_id_o = '0; - mon_w_user_o = '0; - mon_w_beat_count_o = '0; - mon_w_last_o = '0; - mon_r_valid_o = '0; - mon_r_addr_o = '0; - mon_r_data_o = '0; - mon_r_id_o = '0; - mon_r_user_o = '0; - mon_r_beat_count_o = '0; - mon_r_last_o = '0; - wait (rst_ni); - forever begin - @(posedge clk_i); - mon_w_valid_o <= #(ApplDelay) mon_w.valid; - mon_w_addr_o <= #(ApplDelay) mon_w.addr; - mon_w_data_o <= #(ApplDelay) mon_w.data; - mon_w_id_o <= #(ApplDelay) mon_w.id; - mon_w_user_o <= #(ApplDelay) mon_w.user; - mon_w_beat_count_o <= #(ApplDelay) mon_w.beat_count; - mon_w_last_o <= #(ApplDelay) mon_w.last; - mon_r_valid_o <= #(ApplDelay) mon_r.valid; - mon_r_addr_o <= #(ApplDelay) mon_r.addr; - mon_r_data_o <= #(ApplDelay) mon_r.data; - mon_r_id_o <= #(ApplDelay) mon_r.id; - mon_r_user_o <= #(ApplDelay) mon_r.user; - mon_r_beat_count_o <= #(ApplDelay) mon_r.beat_count; - mon_r_last_o <= #(ApplDelay) mon_r.last; + // Assign the monitor output in the next clock cycle. Rationale: We only know whether we are + // writing until after `AcqDelay`. This means we could only provide the monitoring output for + // writes after `AcqDelay` in the same cycle, which is incompatible with ATI timing. Thus, we + // provide the monitoring output for writes (and for uniformity also for reads) in the next clock + // cycle. + initial begin + mon_w_valid_o[i] = '0; + mon_w_addr_o[i] = '0; + mon_w_data_o[i] = '0; + mon_w_id_o[i] = '0; + mon_w_user_o[i] = '0; + mon_w_beat_count_o[i] = '0; + mon_w_last_o[i] = '0; + mon_r_valid_o[i] = '0; + mon_r_addr_o[i] = '0; + mon_r_data_o[i] = '0; + mon_r_id_o[i] = '0; + mon_r_user_o[i] = '0; + mon_r_beat_count_o[i] = '0; + mon_r_last_o[i] = '0; + wait (rst_ni); + forever begin + @(posedge clk_i); + mon_w_valid_o[i] <= #(ApplDelay) mon_w[i].valid; + mon_w_addr_o[i] <= #(ApplDelay) mon_w[i].addr; + mon_w_data_o[i] <= #(ApplDelay) mon_w[i].data; + mon_w_id_o[i] <= #(ApplDelay) mon_w[i].id; + mon_w_user_o[i] <= #(ApplDelay) mon_w[i].user; + mon_w_beat_count_o[i] <= #(ApplDelay) mon_w[i].beat_count; + mon_w_last_o[i] <= #(ApplDelay) mon_w[i].last; + mon_r_valid_o[i] <= #(ApplDelay) mon_r[i].valid; + mon_r_addr_o[i] <= #(ApplDelay) mon_r[i].addr; + mon_r_data_o[i] <= #(ApplDelay) mon_r[i].data; + mon_r_id_o[i] <= #(ApplDelay) mon_r[i].id; + mon_r_user_o[i] <= #(ApplDelay) mon_r[i].user; + mon_r_beat_count_o[i] <= #(ApplDelay) mon_r[i].beat_count; + mon_r_last_o[i] <= #(ApplDelay) mon_r[i].last; + end end end @@ -352,6 +356,7 @@ module axi_sim_mem_intf #( parameter int unsigned AXI_DATA_WIDTH = 32'd0, parameter int unsigned AXI_ID_WIDTH = 32'd0, parameter int unsigned AXI_USER_WIDTH = 32'd0, + parameter int unsigned NUM_PORTS = 32'd1, parameter bit WARN_UNINITIALIZED = 1'b0, parameter UNINITIALIZED_DATA = "undefined", parameter bit ClearErrOnAccess = 1'b0, @@ -360,21 +365,21 @@ module axi_sim_mem_intf #( ) ( input logic clk_i, input logic rst_ni, - AXI_BUS.Slave axi_slv, - output logic mon_w_valid_o, - output logic [AXI_ADDR_WIDTH-1:0] mon_w_addr_o, - output logic [AXI_DATA_WIDTH-1:0] mon_w_data_o, - output logic [AXI_ID_WIDTH-1:0] mon_w_id_o, - output logic [AXI_USER_WIDTH-1:0] mon_w_user_o, - output axi_pkg::len_t mon_w_beat_count_o, - output logic mon_w_last_o, - output logic mon_r_valid_o, - output logic [AXI_ADDR_WIDTH-1:0] mon_r_addr_o, - output logic [AXI_DATA_WIDTH-1:0] mon_r_data_o, - output logic [AXI_ID_WIDTH-1:0] mon_r_id_o, - output logic [AXI_USER_WIDTH-1:0] mon_r_user_o, - output axi_pkg::len_t mon_r_beat_count_o, - output logic mon_r_last_o + AXI_BUS.Slave axi_slv[NUM_PORTS], + output logic [NUM_PORTS-1:0] mon_w_valid_o, + output logic [NUM_PORTS-1:0][AXI_ADDR_WIDTH-1:0] mon_w_addr_o, + output logic [NUM_PORTS-1:0][AXI_DATA_WIDTH-1:0] mon_w_data_o, + output logic [NUM_PORTS-1:0][AXI_ID_WIDTH-1:0] mon_w_id_o, + output logic [NUM_PORTS-1:0][AXI_USER_WIDTH-1:0] mon_w_user_o, + output axi_pkg::len_t [NUM_PORTS-1:0] mon_w_beat_count_o, + output logic [NUM_PORTS-1:0] mon_w_last_o, + output logic [NUM_PORTS-1:0] mon_r_valid_o, + output logic [NUM_PORTS-1:0][AXI_ADDR_WIDTH-1:0] mon_r_addr_o, + output logic [NUM_PORTS-1:0][AXI_DATA_WIDTH-1:0] mon_r_data_o, + output logic [NUM_PORTS-1:0][AXI_ID_WIDTH-1:0] mon_r_id_o, + output logic [NUM_PORTS-1:0][AXI_USER_WIDTH-1:0] mon_r_user_o, + output axi_pkg::len_t [NUM_PORTS-1:0] mon_r_beat_count_o, + output logic [NUM_PORTS-1:0] mon_r_last_o ); typedef logic [AXI_ADDR_WIDTH-1:0] axi_addr_t; @@ -384,17 +389,20 @@ module axi_sim_mem_intf #( typedef logic [AXI_USER_WIDTH-1:0] axi_user_t; `AXI_TYPEDEF_ALL(axi, axi_addr_t, axi_id_t, axi_data_t, axi_strb_t, axi_user_t) - axi_req_t axi_req; - axi_resp_t axi_rsp; + axi_req_t [NUM_PORTS-1:0] axi_req; + axi_resp_t [NUM_PORTS-1:0] axi_rsp; - `AXI_ASSIGN_TO_REQ(axi_req, axi_slv) - `AXI_ASSIGN_FROM_RESP(axi_slv, axi_rsp) + for (genvar i = 0; i < NUM_PORTS; i++) begin + `AXI_ASSIGN_TO_REQ(axi_req[i], axi_slv[i]) + `AXI_ASSIGN_FROM_RESP(axi_slv[i], axi_rsp[i]) + end axi_sim_mem #( .AddrWidth (AXI_ADDR_WIDTH), .DataWidth (AXI_DATA_WIDTH), .IdWidth (AXI_ID_WIDTH), .UserWidth (AXI_USER_WIDTH), + .NumPorts (NUM_PORTS), .axi_req_t (axi_req_t), .axi_rsp_t (axi_resp_t), .WarnUninitialized (WARN_UNINITIALIZED), From bf900080be69151d54db9d9c6990c23a872397eb Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Tue, 16 Jul 2024 18:32:33 +0200 Subject: [PATCH 14/62] axi_sim_mem: add basic and multiport interface variant Ensures backward-compatability --- src/axi_sim_mem.sv | 81 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/src/axi_sim_mem.sv b/src/axi_sim_mem.sv index bdc74715c..9bf164229 100644 --- a/src/axi_sim_mem.sv +++ b/src/axi_sim_mem.sv @@ -352,6 +352,87 @@ endmodule /// /// See the documentation of the main module for the definition of ports and parameters. module axi_sim_mem_intf #( + parameter int unsigned AXI_ADDR_WIDTH = 32'd0, + parameter int unsigned AXI_DATA_WIDTH = 32'd0, + parameter int unsigned AXI_ID_WIDTH = 32'd0, + parameter int unsigned AXI_USER_WIDTH = 32'd0, + parameter bit WARN_UNINITIALIZED = 1'b0, + parameter UNINITIALIZED_DATA = "undefined", + parameter bit ClearErrOnAccess = 1'b0, + parameter time APPL_DELAY = 0ps, + parameter time ACQ_DELAY = 0ps +) ( + input logic clk_i, + input logic rst_ni, + AXI_BUS.Slave axi_slv, + output logic mon_w_valid_o, + output logic [AXI_ADDR_WIDTH-1:0] mon_w_addr_o, + output logic [AXI_DATA_WIDTH-1:0] mon_w_data_o, + output logic [AXI_ID_WIDTH-1:0] mon_w_id_o, + output logic [AXI_USER_WIDTH-1:0] mon_w_user_o, + output axi_pkg::len_t mon_w_beat_count_o, + output logic mon_w_last_o, + output logic mon_r_valid_o, + output logic [AXI_ADDR_WIDTH-1:0] mon_r_addr_o, + output logic [AXI_DATA_WIDTH-1:0] mon_r_data_o, + output logic [AXI_ID_WIDTH-1:0] mon_r_id_o, + output logic [AXI_USER_WIDTH-1:0] mon_r_user_o, + output axi_pkg::len_t mon_r_beat_count_o, + output logic mon_r_last_o +); + + typedef logic [AXI_ADDR_WIDTH-1:0] axi_addr_t; + typedef logic [AXI_DATA_WIDTH-1:0] axi_data_t; + typedef logic [AXI_ID_WIDTH-1:0] axi_id_t; + typedef logic [AXI_DATA_WIDTH/8-1:0] axi_strb_t; + typedef logic [AXI_USER_WIDTH-1:0] axi_user_t; + `AXI_TYPEDEF_ALL(axi, axi_addr_t, axi_id_t, axi_data_t, axi_strb_t, axi_user_t) + + axi_req_t axi_req; + axi_resp_t axi_rsp; + + `AXI_ASSIGN_TO_REQ(axi_req, axi_slv) + `AXI_ASSIGN_FROM_RESP(axi_slv, axi_rsp) + + axi_sim_mem #( + .AddrWidth (AXI_ADDR_WIDTH), + .DataWidth (AXI_DATA_WIDTH), + .IdWidth (AXI_ID_WIDTH), + .UserWidth (AXI_USER_WIDTH), + .axi_req_t (axi_req_t), + .axi_rsp_t (axi_resp_t), + .WarnUninitialized (WARN_UNINITIALIZED), + .UninitializedData (UNINITIALIZED_DATA), + .ClearErrOnAccess (ClearErrOnAccess), + .ApplDelay (APPL_DELAY), + .AcqDelay (ACQ_DELAY) + ) i_sim_mem ( + .clk_i, + .rst_ni, + .axi_req_i (axi_req), + .axi_rsp_o (axi_rsp), + .mon_w_valid_o, + .mon_w_addr_o, + .mon_w_data_o, + .mon_w_id_o, + .mon_w_user_o, + .mon_w_beat_count_o, + .mon_w_last_o, + .mon_r_valid_o, + .mon_r_addr_o, + .mon_r_data_o, + .mon_r_id_o, + .mon_r_user_o, + .mon_r_beat_count_o, + .mon_r_last_o + ); + +endmodule + +/// Mutliport interface variant of [`axi_sim_mem`](module.axi_sim_mem). +/// +/// See the documentation of the main module for the definition of ports and parameters. +module axi_sim_mem_multiport_intf #( parameter int unsigned AXI_ADDR_WIDTH = 32'd0, parameter int unsigned AXI_DATA_WIDTH = 32'd0, parameter int unsigned AXI_ID_WIDTH = 32'd0, From 71649629bcdac690de3b1f5567a01fe5a84f9ce6 Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Tue, 16 Jul 2024 18:32:49 +0200 Subject: [PATCH 15/62] tb_axi_sim_mem: instantiate unused missing signals --- test/tb_axi_sim_mem.sv | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/test/tb_axi_sim_mem.sv b/test/tb_axi_sim_mem.sv index d6a899fc1..dda3de6a9 100644 --- a/test/tb_axi_sim_mem.sv +++ b/test/tb_axi_sim_mem.sv @@ -71,7 +71,21 @@ module tb_axi_sim_mem #( ) i_sim_mem ( .clk_i (clk), .rst_ni (rst_n), - .axi_slv (axi) + .axi_slv (axi), + .mon_w_valid_o (), + .mon_w_addr_o (), + .mon_w_data_o (), + .mon_w_id_o (), + .mon_w_user_o (), + .mon_w_beat_count_o(), + .mon_w_last_o (), + .mon_r_valid_o (), + .mon_r_addr_o (), + .mon_r_data_o (), + .mon_r_id_o (), + .mon_r_user_o (), + .mon_r_beat_count_o(), + .mon_r_last_o () ); // Simply read and write a random memory region. From 62fab3837dc5e6bd8ec2fb4ff2e84921e320c16c Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Wed, 17 Jul 2024 10:08:40 +0200 Subject: [PATCH 16/62] Update Changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a829a952d..fc2bd93be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## Unreleased +### Added +- `axi_sim_mem`: Increase number of request ports, add multiport interface variant. ## 0.39.3 - 2024-05-08 ### Added From 50b033d30b5ea3fd19964571b4267c464633fdd9 Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Wed, 10 Jul 2024 16:33:15 +0200 Subject: [PATCH 17/62] Fix mismatch detection --- src/axi_bus_compare.sv | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/axi_bus_compare.sv b/src/axi_bus_compare.sv index b92e6159f..a8de54379 100644 --- a/src/axi_bus_compare.sv +++ b/src/axi_bus_compare.sv @@ -556,13 +556,13 @@ module axi_bus_compare #( //----------------------------------- for (genvar id = 0; id < 2**AxiIdWidth; id++) begin : gen_cmp assign aw_mismatch_o [id] = (fifo_cmp_valid_aw_a [id] & fifo_cmp_valid_aw_b [id]) ? - fifo_cmp_data_aw_a [id] == fifo_cmp_data_aw_b [id] : '0; + fifo_cmp_data_aw_a [id] != fifo_cmp_data_aw_b [id] : '0; assign b_mismatch_o [id] = (fifo_cmp_valid_b_a [id] & fifo_cmp_valid_b_b [id]) ? - fifo_cmp_data_b_a [id] == fifo_cmp_data_b_b [id] : '0; + fifo_cmp_data_b_a [id] != fifo_cmp_data_b_b [id] : '0; assign ar_mismatch_o [id] = (fifo_cmp_valid_ar_a [id] & fifo_cmp_valid_ar_b [id]) ? - fifo_cmp_data_ar_a [id] == fifo_cmp_data_ar_b [id] : '0; + fifo_cmp_data_ar_a [id] != fifo_cmp_data_ar_b [id] : '0; assign r_mismatch_o [id] = (fifo_cmp_valid_r_a [id] & fifo_cmp_valid_r_b [id]) ? - fifo_cmp_data_r_a [id] == fifo_cmp_data_r_b [id] : '0; + fifo_cmp_data_r_a [id] != fifo_cmp_data_r_b [id] : '0; end assign w_mismatch_o = (fifo_cmp_valid_w_a & fifo_cmp_valid_w_b ) ? From 9011c2453fa686dc6ad85ac8d004673c0075ada8 Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Thu, 11 Jul 2024 12:47:02 +0200 Subject: [PATCH 18/62] bus_compare: consider size field for comparison --- src/axi_bus_compare.sv | 143 ++++++++++++++++++++++++++++++++++++++- src/axi_slave_compare.sv | 6 ++ 2 files changed, 147 insertions(+), 2 deletions(-) diff --git a/src/axi_bus_compare.sv b/src/axi_bus_compare.sv index a8de54379..e1a3426ee 100644 --- a/src/axi_bus_compare.sv +++ b/src/axi_bus_compare.sv @@ -20,6 +20,10 @@ module axi_bus_compare #( parameter int unsigned AxiIdWidth = 32'd0, /// FIFO depth parameter int unsigned FifoDepth = 32'd0, + /// Consider size field in comparison + parameter bit UseSize = 1'b0, + /// Data width of the AXI4+ATOP interface + parameter int unsigned DataWidth = 32'd8, /// AW channel type of the AXI4+ATOP interface parameter type axi_aw_chan_t = logic, /// W channel type of the AXI4+ATOP interface @@ -151,6 +155,12 @@ module axi_bus_compare #( axi_r_chan_t [2**AxiIdWidth-1:0] fifo_cmp_data_r_b; + // Size alignment signals + logic [2:0] w_size; + logic [$clog2(DataWidth/8)-1:0] w_lower, w_offset, w_increment; + logic [2**AxiIdWidth-1:0][2:0] r_size; + logic [2**AxiIdWidth-1:0][$clog2(DataWidth/8)-1:0] r_lower, r_offset, r_increment; + //----------------------------------- // Channel A stream forks //----------------------------------- @@ -272,6 +282,46 @@ module axi_bus_compare #( .ready_i ( fifo_cmp_valid_ar_a [id] & fifo_cmp_valid_ar_b [id] ) ); + 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 ) + ) 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} ), + .valid_i ( fifo_valid_ar_a [id] & fifo_ready_ar_a [id] ), + .ready_o (), + .data_o ( {r_offset[id], r_size[id]} ), + .valid_o (), + .ready_i ( fifo_cmp_valid_r_a[id] & fifo_cmp_valid_r_b[id] & fifo_cmp_data_r_a[id].last ) + ); + always_ff @(posedge clk_i or negedge rst_ni) begin : proc_r_increment + if(!rst_ni) begin + r_increment[id] <= '0; + end else begin + if (fifo_cmp_valid_r_a[id] && fifo_cmp_valid_r_b[id]) begin + if (fifo_cmp_data_r_a[id].last) begin + r_increment[id] <= '0; + end else begin + r_increment[id] <= r_increment[id] + 2**r_size[id] - ((r_offset[id]+r_increment[id])%(2**r_size[id])); + end + end + end + end + assign r_lower[id] = r_offset[id] + r_increment[id]; + end else begin : gen_no_size + assign r_offset[id] = '0; + assign r_size[id] = '1; + assign r_lower[id] = '0; + end + + stream_fifo #( .FALL_THROUGH ( 1'b0 ), .DATA_WIDTH ( 1'b0 ), @@ -292,6 +342,45 @@ 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 ) + ) 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} ), + .valid_i ( axi_a_req_i.aw_valid & axi_a_rsp_o.aw_ready ), + .ready_o (), + .data_o ( {w_offset, w_size} ), + .valid_o (), + .ready_i ( fifo_cmp_valid_w_a & fifo_cmp_valid_w_b & fifo_cmp_data_w_a.last ) + ); + always_ff @(posedge clk_i or negedge rst_ni) begin : proc_w_increment + if(!rst_ni) begin + w_increment <= '0; + end else begin + if (fifo_cmp_valid_w_a && fifo_cmp_valid_w_b) begin + if (fifo_cmp_data_w_a.last) begin + w_increment <= '0; + end else begin + w_increment <= (w_increment + 2**w_size) - ((w_offset+w_increment)%(2**w_size)); + end + end + end + end + assign w_lower = w_offset + w_increment; + end else begin : gen_no_size + assign w_offset = '0; + assign w_size = '1; + assign w_lower = '0; + end + stream_fifo #( .FALL_THROUGH ( 1'b0 ), .DATA_WIDTH ( 1'b0 ), @@ -555,6 +644,26 @@ module axi_bus_compare #( // Comparison //----------------------------------- for (genvar id = 0; id < 2**AxiIdWidth; id++) begin : gen_cmp + logic [DataWidth/8-1:0] r_data_partial_mismatch; + logic r_data_mismatch; + + if (UseSize) begin : gen_r_mismatch_sized + for (genvar j = 0; j < DataWidth/8; j++) begin : gen_r_partial_mismatch + assign r_data_partial_mismatch[j] = fifo_cmp_data_r_a[id].data[8*j+:8] != fifo_cmp_data_r_b[id].data[8*j+:8]; + end + + always_comb begin : proc_r_data_mismatch + r_data_mismatch = '0; + for (int unsigned j = 0; j < DataWidth/8; j++) begin + if (j >= r_lower[id] && j < (r_lower[id] + 2**r_size[id])-((r_lower[id] + 2**r_size[id])%(2**r_size[id])) ) begin + r_data_mismatch |= r_data_partial_mismatch[j]; + end + end + end + end else begin : gen_r_mismatch_unsized + assign r_data_mismatch = fifo_cmp_data_r_a[id].data != fifo_cmp_data_r_b[id].data; + end + assign aw_mismatch_o [id] = (fifo_cmp_valid_aw_a [id] & fifo_cmp_valid_aw_b [id]) ? fifo_cmp_data_aw_a [id] != fifo_cmp_data_aw_b [id] : '0; assign b_mismatch_o [id] = (fifo_cmp_valid_b_a [id] & fifo_cmp_valid_b_b [id]) ? @@ -562,11 +671,41 @@ module axi_bus_compare #( assign ar_mismatch_o [id] = (fifo_cmp_valid_ar_a [id] & fifo_cmp_valid_ar_b [id]) ? fifo_cmp_data_ar_a [id] != fifo_cmp_data_ar_b [id] : '0; assign r_mismatch_o [id] = (fifo_cmp_valid_r_a [id] & fifo_cmp_valid_r_b [id]) ? - fifo_cmp_data_r_a [id] != fifo_cmp_data_r_b [id] : '0; + ( fifo_cmp_data_r_a[id].id != fifo_cmp_data_r_b[id].id | + r_data_mismatch | + fifo_cmp_data_r_a[id].resp != fifo_cmp_data_r_b[id].resp | + fifo_cmp_data_r_a[id].last != fifo_cmp_data_r_b[id].last | + fifo_cmp_data_r_a[id].user != fifo_cmp_data_r_b[id].user ) + : '0; + end + + logic [DataWidth/8-1:0] w_data_partial_mismatch; + logic w_data_mismatch; + + if (UseSize) begin : gen_w_mismatch_sized + for (genvar j = 0; j < DataWidth/8; j++) begin : gen_w_partial_mismatch + assign w_data_partial_mismatch[j] = fifo_cmp_data_w_a.data[8*j+:8] != fifo_cmp_data_w_b.data[8*j+:8] | + fifo_cmp_data_w_a.strb[ j ] != fifo_cmp_data_w_b.strb[ j ]; + end + + always_comb begin : proc_w_data_mismatch + w_data_mismatch = '0; + for (int unsigned j = 0; j < DataWidth/8; j++) begin + if (j >= w_lower && j < (w_lower + 2**w_size)-((w_lower + 2**w_size)%(2**w_size)) ) begin + w_data_mismatch |= w_data_partial_mismatch[j]; + end + end + end + end else begin : gen_w_mismatch_unsized + assign w_data_mismatch = fifo_cmp_data_w_a.data != fifo_cmp_data_w_b.data | + fifo_cmp_data_w_a.strb != fifo_cmp_data_w_b.strb; end assign w_mismatch_o = (fifo_cmp_valid_w_a & fifo_cmp_valid_w_b ) ? - fifo_cmp_data_w_a != fifo_cmp_data_w_b : '0; + ( w_data_mismatch | + fifo_cmp_data_w_a.last != fifo_cmp_data_w_b.last | + fifo_cmp_data_w_a.user != fifo_cmp_data_w_b.user ) + : '0; //----------------------------------- diff --git a/src/axi_slave_compare.sv b/src/axi_slave_compare.sv index a4442985c..6cda82e05 100644 --- a/src/axi_slave_compare.sv +++ b/src/axi_slave_compare.sv @@ -22,6 +22,10 @@ module axi_slave_compare #( parameter int unsigned AxiIdWidth = 32'd0, /// FIFO depth parameter int unsigned FifoDepth = 32'd0, + /// Consider size field in comparison + parameter bit UseSize = 1'b0, + /// Data width of the AXI4+ATOP interface + parameter int unsigned DataWidth = 32'd8, /// AW channel type of the AXI4+ATOP interface parameter type axi_aw_chan_t = logic, /// W channel type of the AXI4+ATOP interface @@ -154,6 +158,8 @@ module axi_slave_compare #( axi_bus_compare #( .AxiIdWidth ( AxiIdWidth ), .FifoDepth ( FifoDepth ), + .UseSize ( UseSize ), + .DataWidth ( DataWidth ), .axi_aw_chan_t ( axi_aw_chan_t ), .axi_w_chan_t ( axi_w_chan_t ), .axi_b_chan_t ( axi_b_chan_t ), From f638f47437100cae8b84e6da50b26e59f6ed7a1c Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Wed, 17 Jul 2024 10:11:56 +0200 Subject: [PATCH 19/62] Update Changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fc2bd93be..a3afe9f30 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## Unreleased ### Added - `axi_sim_mem`: Increase number of request ports, add multiport interface variant. +- `axi_bus_compare`: Optionally consider AXI `size` field to only compare used data. + +### Fixed +- `axi_bus_compare`: Fix mismatch detection. ## 0.39.3 - 2024-05-08 ### Added From bc35bd3cc9aa303627c87b1fb1336ce3e8d4852d Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Tue, 16 Jul 2024 17:59:59 +0200 Subject: [PATCH 20/62] axi_to_detailed_mem: Only exokay if request had lock --- src/axi_to_detailed_mem.sv | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/axi_to_detailed_mem.sv b/src/axi_to_detailed_mem.sv index d66c4d143..2ea01f3bf 100644 --- a/src/axi_to_detailed_mem.sv +++ b/src/axi_to_detailed_mem.sv @@ -533,9 +533,9 @@ module axi_to_detailed_mem #( ((i*NumBytesPerBank) < ((meta_buf.addr % DataWidth/8) + 1< Date: Wed, 17 Jul 2024 10:19:06 +0200 Subject: [PATCH 21/62] Update Changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a3afe9f30..dedac2a37 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Fixed - `axi_bus_compare`: Fix mismatch detection. +- `axi_to_detailed_mem`: Only respond with `exokay` if `lock` was set on the request. ## 0.39.3 - 2024-05-08 ### Added From c8a37b51955e0e8f8c2f1187e77adcfcf8c5fe36 Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Thu, 18 Jul 2024 14:24:43 +0200 Subject: [PATCH 22/62] Bump `common_cells` for `mem_to_banks` fix. --- Bender.yml | 2 +- CHANGELOG.md | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Bender.yml b/Bender.yml index 25022ca77..5995dc034 100644 --- a/Bender.yml +++ b/Bender.yml @@ -19,7 +19,7 @@ package: - "Florian Zaruba " dependencies: - common_cells: { git: "https://github.com/pulp-platform/common_cells.git", version: 1.31.1 } + common_cells: { git: "https://github.com/pulp-platform/common_cells.git", version: 1.37.0 } common_verification: { git: "https://github.com/pulp-platform/common_verification.git", version: 0.2.3 } tech_cells_generic: { git: "https://github.com/pulp-platform/tech_cells_generic.git", version: 0.2.2 } diff --git a/CHANGELOG.md b/CHANGELOG.md index dedac2a37..ca9cbfb12 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Fixed - `axi_bus_compare`: Fix mismatch detection. - `axi_to_detailed_mem`: Only respond with `exokay` if `lock` was set on the request. + Bump `common_cells` for `mem_to_banks` fix. ## 0.39.3 - 2024-05-08 ### Added From 165264bfc854179d070ac53bb1a89727db50fc26 Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Thu, 18 Jul 2024 15:08:58 +0200 Subject: [PATCH 23/62] tb_axi_dw_downsizer: Add initial stall to B and R Forces error fixed in #323 --- test/tb_axi_dw_downsizer.sv | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/test/tb_axi_dw_downsizer.sv b/test/tb_axi_dw_downsizer.sv index 1edd3b16f..e687de066 100644 --- a/test/tb_axi_dw_downsizer.sv +++ b/test/tb_axi_dw_downsizer.sv @@ -21,6 +21,8 @@ module tb_axi_dw_downsizer #( parameter int unsigned TbAxiSlvPortDataWidth = 64 , parameter int unsigned TbAxiMstPortDataWidth = 32 , parameter int unsigned TbAxiUserWidth = 8 , + parameter int unsigned TbInitialBStallCycles = 1000, + parameter int unsigned TbInitialRStallCycles = 1000, // TB Parameters parameter time TbCyclTime = 10ns, parameter time TbApplTime = 2ns , @@ -35,6 +37,9 @@ module tb_axi_dw_downsizer #( logic rst_n; logic eos; + int unsigned b_stall; + int unsigned r_stall; + clk_rst_gen #( .ClkPeriod (TbCyclTime), .RstClkCycles (5 ) @@ -65,7 +70,31 @@ module tb_axi_dw_downsizer #( .AXI_USER_WIDTH(TbAxiUserWidth ) ) master (); - `AXI_ASSIGN(master, master_dv) + `AXI_ASSIGN_AW(master, master_dv) + `AXI_ASSIGN_W(master, master_dv) + `AXI_ASSIGN_AR(master, master_dv) + assign master_dv.b_id = master.b_id; + assign master_dv.b_resp = master.b_resp; + assign master_dv.b_user = master.b_user; + assign master_dv.b_valid = b_stall != 0 ? 1'b0 : master.b_valid; + assign master.b_ready = b_stall != 0 ? 1'b0 : master_dv.b_ready; + assign master_dv.r_id = master.r_id; + assign master_dv.r_data = master.r_data; + assign master_dv.r_resp = master.r_resp; + assign master_dv.r_last = master.r_last; + assign master_dv.r_user = master.r_user; + assign master_dv.r_valid = r_stall != 0 ? 1'b0 : master.r_valid; + assign master.r_ready = r_stall != 0 ? 1'b0 : master_dv.r_ready; + + always_ff @(posedge clk or negedge rst_n) begin : proc_ + if(~rst_n) begin + b_stall <= TbInitialBStallCycles; + r_stall <= TbInitialRStallCycles; + end else begin + b_stall <= b_stall == 0 ? 0 : b_stall-1; + r_stall <= r_stall == 0 ? 0 : r_stall-1; + end + end axi_test::axi_rand_master #( .AW (TbAxiAddrWidth ), From d3786169a8103e3f4123dc74f5fd0a03f2f036e7 Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Thu, 18 Jul 2024 17:01:49 +0200 Subject: [PATCH 24/62] Modify test to force the error --- scripts/run_vsim.sh | 8 ++++++++ test/tb_axi_dw_downsizer.sv | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/scripts/run_vsim.sh b/scripts/run_vsim.sh index 9812c5ed5..aaf8c3f22 100755 --- a/scripts/run_vsim.sh +++ b/scripts/run_vsim.sh @@ -49,6 +49,14 @@ exec_test() { call_vsim tb_$1 ;; axi_dw_downsizer) + call_vsim tb_axi_dw_downsizer \ + -gTbAxiSlvPortDataWidth=32 \ + -gTbAxiMstPortDataWidth=16 \ + -gTbInitialBStallCycles=100000 -t 1ps + call_vsim tb_axi_dw_downsizer \ + -gTbAxiSlvPortDataWidth=32 \ + -gTbAxiMstPortDataWidth=16 \ + -gTbInitialRStallCycles=100000 -t 1ps for AxiSlvPortDataWidth in 8 16 32 64 128 256 512 1024; do for (( AxiMstPortDataWidth = 8; \ AxiMstPortDataWidth < $AxiSlvPortDataWidth; \ diff --git a/test/tb_axi_dw_downsizer.sv b/test/tb_axi_dw_downsizer.sv index e687de066..a11baf9d3 100644 --- a/test/tb_axi_dw_downsizer.sv +++ b/test/tb_axi_dw_downsizer.sv @@ -21,8 +21,8 @@ module tb_axi_dw_downsizer #( parameter int unsigned TbAxiSlvPortDataWidth = 64 , parameter int unsigned TbAxiMstPortDataWidth = 32 , parameter int unsigned TbAxiUserWidth = 8 , - parameter int unsigned TbInitialBStallCycles = 1000, - parameter int unsigned TbInitialRStallCycles = 1000, + parameter int unsigned TbInitialBStallCycles = 0, + parameter int unsigned TbInitialRStallCycles = 0, // TB Parameters parameter time TbCyclTime = 10ns, parameter time TbApplTime = 2ns , From 33cc1638ec4ac6cdd584d53dce603c52e87b97f8 Mon Sep 17 00:00:00 2001 From: Luca Colagrande Date: Tue, 3 Oct 2023 12:42:52 +0200 Subject: [PATCH 25/62] axi_dw_downsizer: Fix `i_forward_b_beats_queue` underflow --- src/axi_dw_downsizer.sv | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/axi_dw_downsizer.sv b/src/axi_dw_downsizer.sv index 88d774ad0..b1513775d 100644 --- a/src/axi_dw_downsizer.sv +++ b/src/axi_dw_downsizer.sv @@ -733,7 +733,7 @@ module axi_dw_downsizer #( automatic addr_t slv_port_offset = AxiSlvPortStrbWidth == 1 ? '0 : w_req_q.aw.addr[idx_width(AxiSlvPortStrbWidth)-1:0]; // Valid output - mst_req.w_valid = 1'b1 ; + mst_req.w_valid = !forward_b_beat_full; mst_req.w.last = w_req_q.aw.len == 0; mst_req.w.user = slv_req_i.w.user ; @@ -774,7 +774,7 @@ module axi_dw_downsizer #( // Trigger another burst request, if needed if (w_state_q == W_SPLIT_INCR_DOWNSIZE) // Finished current burst, but whole transaction hasn't finished - if (w_req_q.aw.len == '0 && w_req_q.burst_len != '0 && !forward_b_beat_full) begin + if (w_req_q.aw.len == '0 && w_req_q.burst_len != '0) begin w_req_d.aw_valid = 1'b1; w_req_d.aw.len = (w_req_d.burst_len <= 255) ? w_req_d.burst_len : 255; @@ -783,7 +783,7 @@ module axi_dw_downsizer #( forward_b_beat_push = 1'b1; end - if (w_req_q.burst_len == 0 && !forward_b_beat_full) begin + if (w_req_q.burst_len == 0) begin w_state_d = W_IDLE; forward_b_beat_push = 1'b1; From 7c37f95e0298553a559fe333bd3aa90e4b4fb0cb Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Wed, 17 Jul 2024 11:22:13 +0200 Subject: [PATCH 26/62] axi_dw_downsizer: Ensure begin/end for all blocks --- src/axi_dw_downsizer.sv | 55 ++++++++++++++++++++++++++++------------- 1 file changed, 38 insertions(+), 17 deletions(-) diff --git a/src/axi_dw_downsizer.sv b/src/axi_dw_downsizer.sv index b1513775d..55484cfd5 100644 --- a/src/axi_dw_downsizer.sv +++ b/src/axi_dw_downsizer.sv @@ -545,9 +545,9 @@ module axi_dw_downsizer #( end // Request was accepted - if (!r_req_q.ar_valid) + if (!r_req_q.ar_valid) begin // Our turn - if ((idqueue_id == t) && idqueue_valid) + if ((idqueue_id == t) && idqueue_valid) begin // Ready to accept more data if (!slv_r_valid_tran[t] || (slv_r_valid_tran[t] && slv_r_ready_tran[t])) begin mst_r_ready_tran[t] = 1'b1; @@ -557,12 +557,13 @@ module axi_dw_downsizer #( automatic addr_t slv_port_offset = AxiSlvPortStrbWidth == 1 ? '0 : r_req_q.ar.addr[idx_width(AxiSlvPortStrbWidth)-1:0]; // Serialization - for (int b = 0; b < AxiSlvPortStrbWidth; b++) + for (int b = 0; b < AxiSlvPortStrbWidth; b++) begin if ((b >= slv_port_offset) && (b - slv_port_offset < (1 << r_req_q.orig_ar_size)) && (b + mst_port_offset - slv_port_offset < AxiMstPortStrbWidth)) begin r_data[b] = mst_resp.r.data[8*(b + mst_port_offset - slv_port_offset) +: 8]; end + end r_req_d.burst_len = r_req_q.burst_len - 1 ; r_req_d.ar.len = r_req_q.ar.len - 1 ; @@ -583,33 +584,44 @@ module axi_dw_downsizer #( end endcase - if (r_req_q.burst_len == 0) + if (r_req_q.burst_len == 0) begin idqueue_pop[t] = 1'b1; + end case (r_state_q) - R_PASSTHROUGH : + R_PASSTHROUGH : begin // Forward data as soon as we can r_req_d.r_valid = 1'b1; + end - R_INCR_DOWNSIZE, R_SPLIT_INCR_DOWNSIZE: + R_INCR_DOWNSIZE, R_SPLIT_INCR_DOWNSIZE: begin // Forward when the burst is finished, or after filling up a word - if (r_req_q.burst_len == 0 || (aligned_addr(r_req_d.ar.addr, r_req_q.orig_ar_size) != aligned_addr(r_req_q.ar.addr, r_req_q.orig_ar_size))) + if (r_req_q.burst_len == 0 || + (aligned_addr(r_req_d.ar.addr, r_req_q.orig_ar_size) != + aligned_addr(r_req_q.ar.addr, r_req_q.orig_ar_size) )) begin r_req_d.r_valid = 1'b1; + end + end endcase // Trigger another burst request, if needed - if (r_state_q == R_SPLIT_INCR_DOWNSIZE) + if (r_state_q == R_SPLIT_INCR_DOWNSIZE) begin // Finished current burst, but whole transaction hasn't finished if (r_req_q.ar.len == '0 && r_req_q.burst_len != '0) begin r_req_d.ar_valid = !r_req_q.injected_aw; r_req_d.ar.len = (r_req_d.burst_len <= 255) ? r_req_d.burst_len : 255; end + end end end + end + end - if (slv_r_valid_tran[t] && slv_r_ready_tran[t]) - if (r_req_q.burst_len == '1) + if (slv_r_valid_tran[t] && slv_r_ready_tran[t]) begin + if (r_req_q.burst_len == '1) begin r_state_d = R_IDLE; + end + end end endcase end @@ -709,8 +721,9 @@ module axi_dw_downsizer #( mst_req.b_ready = slv_req_i.b_ready; // Got an ack on the B channel. Pop transaction. - if (mst_req.b_ready && mst_resp.b_valid) + if (mst_req.b_ready && mst_resp.b_valid) begin forward_b_beat_pop = 1'b1; + end end else begin // Otherwise, just acknowlegde the B beats slv_resp_o.b_valid = 1'b0 ; @@ -727,7 +740,7 @@ module axi_dw_downsizer #( case (w_state_q) W_PASSTHROUGH, W_INCR_DOWNSIZE, W_SPLIT_INCR_DOWNSIZE: begin // Request was accepted - if (!w_req_q.aw_valid) + if (!w_req_q.aw_valid) begin if (slv_req_i.w_valid) begin automatic addr_t mst_port_offset = AxiMstPortStrbWidth == 1 ? '0 : w_req_q.aw.addr[idx_width(AxiMstPortStrbWidth)-1:0]; automatic addr_t slv_port_offset = AxiSlvPortStrbWidth == 1 ? '0 : w_req_q.aw.addr[idx_width(AxiSlvPortStrbWidth)-1:0]; @@ -738,15 +751,17 @@ module axi_dw_downsizer #( mst_req.w.user = slv_req_i.w.user ; // Lane steering - for (int b = 0; b < AxiSlvPortStrbWidth; b++) + for (int b = 0; b < AxiSlvPortStrbWidth; b++) begin if ((b >= slv_port_offset) && (b - slv_port_offset < (1 << w_req_q.orig_aw_size)) && (b + mst_port_offset - slv_port_offset < AxiMstPortStrbWidth)) begin w_data[b + mst_port_offset - slv_port_offset] = slv_req_i.w.data[8*b +: 8]; mst_req.w.strb[b + mst_port_offset - slv_port_offset] = slv_req_i.w.strb[b] ; end + end mst_req.w.data = w_data; end + end // Acknowledgment if (mst_resp.w_ready && mst_req.w_valid) begin @@ -763,16 +778,21 @@ module axi_dw_downsizer #( endcase case (w_state_q) - W_PASSTHROUGH: + W_PASSTHROUGH: begin slv_resp_o.w_ready = 1'b1; + end - W_INCR_DOWNSIZE, W_SPLIT_INCR_DOWNSIZE: - if (w_req_q.burst_len == 0 || (aligned_addr(w_req_d.aw.addr, w_req_q.orig_aw_size) != aligned_addr(w_req_q.aw.addr, w_req_q.orig_aw_size))) + W_INCR_DOWNSIZE, W_SPLIT_INCR_DOWNSIZE: begin + if (w_req_q.burst_len == 0 || + (aligned_addr(w_req_d.aw.addr, w_req_q.orig_aw_size) != + aligned_addr(w_req_q.aw.addr, w_req_q.orig_aw_size) )) begin slv_resp_o.w_ready = 1'b1; + end + end endcase // Trigger another burst request, if needed - if (w_state_q == W_SPLIT_INCR_DOWNSIZE) + if (w_state_q == W_SPLIT_INCR_DOWNSIZE) begin // Finished current burst, but whole transaction hasn't finished if (w_req_q.aw.len == '0 && w_req_q.burst_len != '0) begin w_req_d.aw_valid = 1'b1; @@ -782,6 +802,7 @@ module axi_dw_downsizer #( forward_b_beat_i = 1'b0; forward_b_beat_push = 1'b1; end + end if (w_req_q.burst_len == 0) begin w_state_d = W_IDLE; From 9a765c9085d2ce80a468de76cc7f0ea8e2f677fd Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Wed, 17 Jul 2024 11:38:54 +0200 Subject: [PATCH 27/62] axi_dw_downsizer: Only delay last W beat Ensures last W beat is not sent if B fifo is full, allowing all W beats except last to pass. --- src/axi_dw_downsizer.sv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/axi_dw_downsizer.sv b/src/axi_dw_downsizer.sv index 55484cfd5..949b3caf3 100644 --- a/src/axi_dw_downsizer.sv +++ b/src/axi_dw_downsizer.sv @@ -746,7 +746,7 @@ module axi_dw_downsizer #( automatic addr_t slv_port_offset = AxiSlvPortStrbWidth == 1 ? '0 : w_req_q.aw.addr[idx_width(AxiSlvPortStrbWidth)-1:0]; // Valid output - mst_req.w_valid = !forward_b_beat_full; + mst_req.w_valid = !(forward_b_beat_full && w_req_q.aw.len == 0); mst_req.w.last = w_req_q.aw.len == 0; mst_req.w.user = slv_req_i.w.user ; From 1d04d8873bbfbd77356d6fdc8f0facd41bdede1f Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Wed, 17 Jul 2024 11:39:01 +0200 Subject: [PATCH 28/62] Update Changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ca9cbfb12..4419e29d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - `axi_bus_compare`: Fix mismatch detection. - `axi_to_detailed_mem`: Only respond with `exokay` if `lock` was set on the request. Bump `common_cells` for `mem_to_banks` fix. +- `axi_dw_downsizer`: Fix `i_forward_b_beats_queue` underflow. ## 0.39.3 - 2024-05-08 ### Added From 4b386feee92b551942f65b4adde8aad63ec1e1b4 Mon Sep 17 00:00:00 2001 From: Eugene Feinberg Date: Sun, 17 Sep 2023 09:34:57 -0700 Subject: [PATCH 29/62] Add reset states to axi_atop_filter to fix zero time sim hang --- src/axi_atop_filter.sv | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/axi_atop_filter.sv b/src/axi_atop_filter.sv index de60516a3..55ad491b2 100644 --- a/src/axi_atop_filter.sv +++ b/src/axi_atop_filter.sv @@ -67,11 +67,11 @@ module axi_atop_filter #( cnt_t w_cnt_d, w_cnt_q; typedef enum logic [2:0] { - W_FEEDTHROUGH, BLOCK_AW, ABSORB_W, HOLD_B, INJECT_B, WAIT_R + W_RESET, W_FEEDTHROUGH, BLOCK_AW, ABSORB_W, HOLD_B, INJECT_B, WAIT_R } w_state_e; w_state_e w_state_d, w_state_q; - typedef enum logic [1:0] { R_FEEDTHROUGH, INJECT_R, R_HOLD } r_state_e; + typedef enum logic [1:0] { R_RESET, R_FEEDTHROUGH, INJECT_R, R_HOLD } r_state_e; r_state_e r_state_d, r_state_q; typedef logic [AxiIdWidth-1:0] id_t; @@ -116,6 +116,8 @@ module axi_atop_filter #( w_state_d = w_state_q; unique case (w_state_q) + W_RESET: w_state_d = W_FEEDTHROUGH; + W_FEEDTHROUGH: begin // Feed AW channel through if the maximum number of outstanding bursts is not reached. if (complete_w_without_aw_downstream || (w_cnt_q.cnt < AxiMaxWriteTxns)) begin @@ -238,7 +240,7 @@ module axi_atop_filter #( end end - default: w_state_d = W_FEEDTHROUGH; + default: w_state_d = W_RESET; endcase end // Connect signals on AW and W channel that are not managed by the control FSM from slave port to @@ -266,6 +268,8 @@ module axi_atop_filter #( r_state_d = r_state_q; unique case (r_state_q) + R_RESET: r_state_d = R_FEEDTHROUGH; + R_FEEDTHROUGH: begin if (mst_resp_i.r_valid && !slv_req_i.r_ready) begin r_state_d = R_HOLD; @@ -301,7 +305,7 @@ module axi_atop_filter #( end end - default: r_state_d = R_FEEDTHROUGH; + default: r_state_d = R_RESET; endcase end // Feed all signals on AR through. @@ -329,9 +333,9 @@ module axi_atop_filter #( if (!rst_ni) begin id_q <= '0; r_beats_q <= '0; - r_state_q <= R_FEEDTHROUGH; + r_state_q <= R_RESET; w_cnt_q <= '{default: '0}; - w_state_q <= W_FEEDTHROUGH; + w_state_q <= W_RESET; end else begin id_q <= id_d; r_beats_q <= r_beats_d; From 9f06dbd5e1f7f3bf92426a3ba9aae251db739441 Mon Sep 17 00:00:00 2001 From: Andreas Kurth Date: Tue, 28 Apr 2020 10:13:22 +0200 Subject: [PATCH 30/62] AXI_BUS_DV: Assert burst on one page --- src/axi_intf.sv | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/axi_intf.sv b/src/axi_intf.sv index c0257f21c..273e9baae 100644 --- a/src/axi_intf.sv +++ b/src/axi_intf.sv @@ -249,6 +249,16 @@ interface AXI_BUS_DV #( assert property (@(posedge clk_i) ( r_valid && ! r_ready |=> $stable(r_last))); assert property (@(posedge clk_i) ( r_valid && ! r_ready |=> $stable(r_user))); assert property (@(posedge clk_i) ( r_valid && ! r_ready |=> r_valid)); + // Address-Channel Assertions: The address of the last beat of a burst must be on the same 4 KiB + // page as the address of the first beat of a burst. Bus is always word-aligned, word < page. + assert property (@(posedge clk_i) aw_valid |-> (aw_burst != axi_pkg::BURST_INCR) || ( + axi_pkg::beat_addr(aw_addr, aw_size, aw_len, aw_burst, 0) >> 12 == // lowest beat address + axi_pkg::beat_addr(aw_addr, aw_size, aw_len, aw_burst, aw_len) >> 12 // highest beat address + )) else $error("AW burst crossing 4 KiB page boundary detected, which is illegal!"); + assert property (@(posedge clk_i) ar_valid |-> (aw_burst != axi_pkg::BURST_INCR) || ( + axi_pkg::beat_addr(ar_addr, ar_size, ar_len, ar_burst, 0) >> 12 == // lowest beat address + axi_pkg::beat_addr(ar_addr, ar_size, ar_len, ar_burst, ar_len) >> 12 // highest beat address + )) else $error("AR burst crossing 4 KiB page boundary detected, which is illegal!"); `endif // pragma translate_on From 0548f74f19c792b3a8309bf16335eb1e3f531477 Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Fri, 2 Sep 2022 16:44:56 +0200 Subject: [PATCH 31/62] axi_test: update rand_master 4KiB boundary check --- src/axi_test.sv | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/src/axi_test.sv b/src/axi_test.sv index eadadcaff..ad42d2174 100644 --- a/src/axi_test.sv +++ b/src/axi_test.sv @@ -905,14 +905,9 @@ package axi_test; addr + len <= mem_region.addr_end; }; assert(rand_success); - if (ax_beat.ax_burst == axi_pkg::BURST_FIXED) begin - if (((addr + 2**ax_beat.ax_size) & PFN_MASK) == (addr & PFN_MASK)) begin - break; - end - end else begin // BURST_INCR - if (((addr + 2**ax_beat.ax_size * (ax_beat.ax_len + 1)) & PFN_MASK) == (addr & PFN_MASK)) begin - break; - end + if (axi_pkg::beat_addr(addr, ax_beat.ax_size, ax_beat.ax_len, ax_beat.ax_burst, 0) >> 12 == + axi_pkg::beat_addr(addr, ax_beat.ax_size, ax_beat.ax_len, ax_beat.ax_burst, ax_beat.ax_len) >> 12) begin + break; end end end else begin @@ -937,14 +932,9 @@ package axi_test; addr + ((len + 1) << size) <= mem_region.addr_end; }; assert(rand_success); - if (ax_beat.ax_burst == axi_pkg::BURST_FIXED) begin - if (((addr + 2**ax_beat.ax_size) & PFN_MASK) == (addr & PFN_MASK)) begin - break; - end - end else begin // BURST_INCR, BURST_WRAP - if (((addr + 2**ax_beat.ax_size * (ax_beat.ax_len + 1)) & PFN_MASK) == (addr & PFN_MASK)) begin - break; - end + if (axi_pkg::beat_addr(addr, ax_beat.ax_size, ax_beat.ax_len, ax_beat.ax_burst, 0) >> 12 == + axi_pkg::beat_addr(addr, ax_beat.ax_size, ax_beat.ax_len, ax_beat.ax_burst, ax_beat.ax_len) >> 12) begin + break; end end end From 67de5356c5348016c90712228b6d249583f9126b Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Fri, 2 Sep 2022 17:27:59 +0200 Subject: [PATCH 32/62] axi_test: update rand_master 4KiB boundary check for atops --- src/axi_test.sv | 105 ++++++++++++++++++++++++++---------------------- 1 file changed, 56 insertions(+), 49 deletions(-) diff --git a/src/axi_test.sv b/src/axi_test.sv index ad42d2174..eecbc91d1 100644 --- a/src/axi_test.sv +++ b/src/axi_test.sv @@ -958,62 +958,69 @@ package axi_test; 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 || - beat.ax_atop[5:4] == axi_pkg::ATOP_ATOMICLOAD) begin - // Endianness - beat.ax_atop[3] = $random(); - // Atomic operation - beat.ax_atop[2:0] = $random(); - end else begin // Atomic{Swap,Compare} - beat.ax_atop[3:1] = '0; - beat.ax_atop[0] = $random(); - end - // Determine `ax_size` and `ax_len`. - if (2**beat.ax_size < AXI_STRB_WIDTH) begin - // Transaction does *not* occupy full data bus, so we must send just one beat. [E1.1.3] - beat.ax_len = '0; - end else begin - automatic int unsigned bytes; - if (beat.ax_atop == axi_pkg::ATOP_ATOMICCMP) begin - // Total data transferred in burst can be 2, 4, 8, 16, or 32 B. - automatic int unsigned log_bytes; - rand_success = std::randomize(log_bytes) with { - log_bytes > 0; 2**log_bytes <= 32; - }; assert(rand_success); - bytes = 2**log_bytes; + forever begin + // Determine `ax_atop`. + if (beat.ax_atop[5:4] == axi_pkg::ATOP_ATOMICSTORE || + beat.ax_atop[5:4] == axi_pkg::ATOP_ATOMICLOAD) begin + // Endianness + beat.ax_atop[3] = $random(); + // Atomic operation + beat.ax_atop[2:0] = $random(); + end else begin // Atomic{Swap,Compare} + beat.ax_atop[3:1] = '0; + beat.ax_atop[0] = $random(); + end + // Determine `ax_size` and `ax_len`. + if (2**beat.ax_size < AXI_STRB_WIDTH) begin + // Transaction does *not* occupy full data bus, so we must send just one beat. [E1.1.3] + beat.ax_len = '0; end else begin - // Total data transferred in burst can be 1, 2, 4, or 8 B. - if (AXI_STRB_WIDTH >= 8) begin - bytes = AXI_STRB_WIDTH; - end else begin + automatic int unsigned bytes; + if (beat.ax_atop == axi_pkg::ATOP_ATOMICCMP) begin + // Total data transferred in burst can be 2, 4, 8, 16, or 32 B. automatic int unsigned log_bytes; - rand_success = std::randomize(log_bytes); assert(rand_success); - log_bytes = log_bytes % (4 - $clog2(AXI_STRB_WIDTH)) - $clog2(AXI_STRB_WIDTH); + rand_success = std::randomize(log_bytes) with { + log_bytes > 0; 2**log_bytes <= 32; + }; assert(rand_success); bytes = 2**log_bytes; + end else begin + // Total data transferred in burst can be 1, 2, 4, or 8 B. + if (AXI_STRB_WIDTH >= 8) begin + bytes = AXI_STRB_WIDTH; + end else begin + automatic int unsigned log_bytes; + rand_success = std::randomize(log_bytes); assert(rand_success); + log_bytes = log_bytes % (4 - $clog2(AXI_STRB_WIDTH)) - $clog2(AXI_STRB_WIDTH); + bytes = 2**log_bytes; + end end + beat.ax_len = bytes / AXI_STRB_WIDTH - 1; end - beat.ax_len = bytes / AXI_STRB_WIDTH - 1; - end - // Determine `ax_addr` and `ax_burst`. - if (beat.ax_atop == axi_pkg::ATOP_ATOMICCMP) begin - // The address must be aligned to half the outbound data size. [E1.1.3] - beat.ax_addr = beat.ax_addr & ~((1'b1 << beat.ax_size) - 1); - // If the address is aligned to the total size of outgoing data, the burst type must be - // INCR. Otherwise, it must be WRAP. [E1.1.3] - beat.ax_burst = (beat.ax_addr % ((beat.ax_len+1) * 2**beat.ax_size) == 0) ? - axi_pkg::BURST_INCR : axi_pkg::BURST_WRAP; - // If we are not allowed to emit WRAP bursts, align the address to the total size of - // outgoing data and fall back to INCR. - if (beat.ax_burst == axi_pkg::BURST_WRAP && !AXI_BURST_WRAP) begin - beat.ax_addr -= (beat.ax_addr % ((beat.ax_len+1) * 2**beat.ax_size)); + // Determine `ax_addr` and `ax_burst`. + if (beat.ax_atop == axi_pkg::ATOP_ATOMICCMP) begin + // The address must be aligned to half the outbound data size. [E1.1.3] + beat.ax_addr = beat.ax_addr & ~((1'b1 << beat.ax_size) - 1); + // If the address is aligned to the total size of outgoing data, the burst type must be + // INCR. Otherwise, it must be WRAP. [E1.1.3] + beat.ax_burst = (beat.ax_addr % ((beat.ax_len+1) * 2**beat.ax_size) == 0) ? + axi_pkg::BURST_INCR : axi_pkg::BURST_WRAP; + // If we are not allowed to emit WRAP bursts, align the address to the total size of + // outgoing data and fall back to INCR. + if (beat.ax_burst == axi_pkg::BURST_WRAP && !AXI_BURST_WRAP) begin + beat.ax_addr -= (beat.ax_addr % ((beat.ax_len+1) * 2**beat.ax_size)); + beat.ax_burst = axi_pkg::BURST_INCR; + end + end else begin + // The address must be aligned to the data size. [E1.1.3] + beat.ax_addr = beat.ax_addr & ~((1'b1 << (beat.ax_size+1)) - 1); + // Only INCR allowed. beat.ax_burst = axi_pkg::BURST_INCR; end - end else begin - // The address must be aligned to the data size. [E1.1.3] - beat.ax_addr = beat.ax_addr & ~((1'b1 << (beat.ax_size+1)) - 1); - // Only INCR allowed. - beat.ax_burst = axi_pkg::BURST_INCR; + // Make sure that the burst does not cross a 4KiB boundary. + if (axi_pkg::beat_addr(beat.ax_addr, beat.ax_size, beat.ax_len, beat.ax_burst, 0) >> 12 == + axi_pkg::beat_addr(beat.ax_addr, beat.ax_size, beat.ax_len, beat.ax_burst, beat.ax_len) >> 12) begin + break; + end end end endtask From 352285363dd47a4086557c5ed5e72264cd53b66b Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Fri, 2 Sep 2022 18:25:56 +0200 Subject: [PATCH 33/62] tb_axi_sim_mem: Fix for 4KiB boundary checking --- test/tb_axi_sim_mem.sv | 40 +++++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/test/tb_axi_sim_mem.sv b/test/tb_axi_sim_mem.sv index dda3de6a9..76ddb03f8 100644 --- a/test/tb_axi_sim_mem.sv +++ b/test/tb_axi_sim_mem.sv @@ -99,18 +99,25 @@ module tb_axi_sim_mem #( drv.reset_master(); wait (rst_n); // AW + forever begin `ifdef XSIM - // std::randomize(aw_beat) may behave differently to aw_beat.randomize() wrt. limited ranges - // Keeping alternate implementation for XSIM only - rand_success = std::randomize(aw_beat); assert (rand_success); + // std::randomize(aw_beat) may behave differently to aw_beat.randomize() wrt. limited ranges + // Keeping alternate implementation for XSIM only + rand_success = std::randomize(aw_beat); assert (rand_success); `else - rand_success = aw_beat.randomize(); assert (rand_success); + rand_success = aw_beat.randomize(); assert (rand_success); `endif - aw_beat.ax_addr >>= $clog2(StrbWidth); // align address with data width - aw_beat.ax_addr <<= $clog2(StrbWidth); - aw_beat.ax_len = $urandom(); - aw_beat.ax_size = $clog2(StrbWidth); - aw_beat.ax_burst = axi_pkg::BURST_INCR; + aw_beat.ax_addr >>= $clog2(StrbWidth); // align address with data width + aw_beat.ax_addr <<= $clog2(StrbWidth); + aw_beat.ax_len = $urandom(); + aw_beat.ax_size = $clog2(StrbWidth); + aw_beat.ax_burst = axi_pkg::BURST_INCR; + // Make sure that the burst does not cross a 4KiB boundary. + if (axi_pkg::beat_addr(aw_beat.ax_addr, aw_beat.ax_size, aw_beat.ax_len, aw_beat.ax_burst, 0) >> 12 == + axi_pkg::beat_addr(aw_beat.ax_addr, aw_beat.ax_size, aw_beat.ax_len, aw_beat.ax_burst, aw_beat.ax_len) >> 12) begin + break; + end + end drv.send_aw(aw_beat); // W beats for (int unsigned i = 0; i <= aw_beat.ax_len; i++) begin @@ -132,10 +139,17 @@ module tb_axi_sim_mem #( drv.recv_b(b_beat); assert(b_beat.b_resp == axi_pkg::RESP_OKAY); // AR - ar_beat.ax_addr = aw_beat.ax_addr; - ar_beat.ax_len = aw_beat.ax_len; - ar_beat.ax_size = aw_beat.ax_size; - ar_beat.ax_burst = aw_beat.ax_burst; + forever begin + ar_beat.ax_addr = aw_beat.ax_addr; + ar_beat.ax_len = aw_beat.ax_len; + ar_beat.ax_size = aw_beat.ax_size; + ar_beat.ax_burst = aw_beat.ax_burst; + // Make sure that the burst does not cross a 4KiB boundary. + if (axi_pkg::beat_addr(ar_beat.ax_addr, ar_beat.ax_size, ar_beat.ax_len, ar_beat.ax_burst, 0) >> 12 == + axi_pkg::beat_addr(ar_beat.ax_addr, ar_beat.ax_size, ar_beat.ax_len, ar_beat.ax_burst, ar_beat.ax_len) >> 12) begin + break; + end + end drv.send_ar(ar_beat); // R beats for (int unsigned i = 0; i <= ar_beat.ax_len; i++) begin From e1f5b280786a9b362600391a67ad5ae4b24a2805 Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Fri, 2 Sep 2022 18:25:42 +0200 Subject: [PATCH 34/62] axi_test: fix random_master AR 4KiB boundary checking --- src/axi_test.sv | 55 ++++++++++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 24 deletions(-) diff --git a/src/axi_test.sv b/src/axi_test.sv index eecbc91d1..10caf777b 100644 --- a/src/axi_test.sv +++ b/src/axi_test.sv @@ -1026,30 +1026,37 @@ package axi_test; endtask function void rand_excl_ar(inout ax_beat_t ar_beat); - ar_beat.ax_lock = $random(); - if (ar_beat.ax_lock) begin - automatic logic rand_success; - automatic int unsigned n_bytes; - automatic size_t size; - automatic addr_t addr_mask; - // In an exclusive burst, the number of bytes to be transferred must be a power of 2, i.e., - // 1, 2, 4, 8, 16, 32, 64, or 128 bytes, and the burst length must not exceed 16 transfers. - static int unsigned ul = (AXI_STRB_WIDTH < 8) ? 4 + $clog2(AXI_STRB_WIDTH) : 7; - rand_success = std::randomize(n_bytes) with { - n_bytes >= 1; - n_bytes <= ul; - }; assert(rand_success); - n_bytes = 2**n_bytes; - rand_success = std::randomize(size) with { - size >= 0; - 2**size <= n_bytes; - 2**size <= AXI_STRB_WIDTH; - n_bytes / 2**size <= 16; - }; assert(rand_success); - ar_beat.ax_size = size; - ar_beat.ax_len = n_bytes / 2**size; - // The address must be aligned to the total number of bytes in the burst. - ar_beat.ax_addr = ar_beat.ax_addr & ~(n_bytes-1); + forever begin + ar_beat.ax_lock = $random(); + if (ar_beat.ax_lock) begin + automatic logic rand_success; + automatic int unsigned n_bytes; + automatic size_t size; + automatic addr_t addr_mask; + // In an exclusive burst, the number of bytes to be transferred must be a power of 2, i.e., + // 1, 2, 4, 8, 16, 32, 64, or 128 bytes, and the burst length must not exceed 16 transfers. + static int unsigned ul = (AXI_STRB_WIDTH < 8) ? 4 + $clog2(AXI_STRB_WIDTH) : 7; + rand_success = std::randomize(n_bytes) with { + n_bytes >= 1; + n_bytes <= ul; + }; assert(rand_success); + n_bytes = 2**n_bytes; + rand_success = std::randomize(size) with { + size >= 0; + 2**size <= n_bytes; + 2**size <= AXI_STRB_WIDTH; + n_bytes / 2**size <= 16; + }; assert(rand_success); + ar_beat.ax_size = size; + ar_beat.ax_len = n_bytes / 2**size; + // The address must be aligned to the total number of bytes in the burst. + ar_beat.ax_addr = ar_beat.ax_addr & ~(n_bytes-1); + end + // Make sure that the burst does not cross a 4KiB boundary. + if (axi_pkg::beat_addr(ar_beat.ax_addr, ar_beat.ax_size, ar_beat.ax_len, ar_beat.ax_burst, 0) >> 12 == + axi_pkg::beat_addr(ar_beat.ax_addr, ar_beat.ax_size, ar_beat.ax_len, ar_beat.ax_burst, ar_beat.ax_len) >> 12) begin + break; + end end endfunction From 840b6ce354e74afe34561edf71786a1e5ed57fbf Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Fri, 19 Jul 2024 12:00:30 +0200 Subject: [PATCH 35/62] Re-randomize beat to ensure 4KiB-safe Ax is found --- src/axi_test.sv | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/axi_test.sv b/src/axi_test.sv index 10caf777b..ce8638343 100644 --- a/src/axi_test.sv +++ b/src/axi_test.sv @@ -951,14 +951,14 @@ package axi_test; task rand_atop_burst(inout ax_beat_t beat); automatic logic rand_success; - beat.ax_atop[5:4] = $random(); - if (beat.ax_atop[5:4] != 2'b00 && !AXI_BURST_INCR) begin - // 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; - end - if (beat.ax_atop[5:4] != 2'b00) begin // ATOP - forever begin + forever begin + beat.ax_atop[5:4] = $random(); + if (beat.ax_atop[5:4] != 2'b00 && !AXI_BURST_INCR) begin + // 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; + end + if (beat.ax_atop[5:4] != 2'b00) begin // ATOP // Determine `ax_atop`. if (beat.ax_atop[5:4] == axi_pkg::ATOP_ATOMICSTORE || beat.ax_atop[5:4] == axi_pkg::ATOP_ATOMICLOAD) begin @@ -1020,6 +1020,8 @@ package axi_test; if (axi_pkg::beat_addr(beat.ax_addr, beat.ax_size, beat.ax_len, beat.ax_burst, 0) >> 12 == axi_pkg::beat_addr(beat.ax_addr, beat.ax_size, beat.ax_len, beat.ax_burst, beat.ax_len) >> 12) begin break; + end else begin + beat = new_rand_burst(1'b0); end end end @@ -1056,6 +1058,8 @@ package axi_test; if (axi_pkg::beat_addr(ar_beat.ax_addr, ar_beat.ax_size, ar_beat.ax_len, ar_beat.ax_burst, 0) >> 12 == axi_pkg::beat_addr(ar_beat.ax_addr, ar_beat.ax_size, ar_beat.ax_len, ar_beat.ax_burst, ar_beat.ax_len) >> 12) begin break; + end else begin + ar_beat = new_rand_burst(1'b1); end end endfunction From ca4695052484b235a0f0b2106fadaee26cfdd5ef Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Thu, 25 Jul 2024 11:21:54 +0200 Subject: [PATCH 36/62] update CHANGELOG --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4419e29d1..0db60adee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,12 +9,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Added - `axi_sim_mem`: Increase number of request ports, add multiport interface variant. - `axi_bus_compare`: Optionally consider AXI `size` field to only compare used data. +- `AXI_BUS_DV`: Add property checking that bursts do not cross 4KiB page boundaries. ### Fixed - `axi_bus_compare`: Fix mismatch detection. - `axi_to_detailed_mem`: Only respond with `exokay` if `lock` was set on the request. Bump `common_cells` for `mem_to_banks` fix. - `axi_dw_downsizer`: Fix `i_forward_b_beats_queue` underflow. +- `axi_test`: Ensure random requests do not cross 4KiB page boundaries. ## 0.39.3 - 2024-05-08 ### Added From b1fe195cc8c2af5815d319a77daa51e815a165bd Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Tue, 2 Jul 2024 16:08:37 +0200 Subject: [PATCH 37/62] Add `axi_xbar_unmuxed`: Partial crossbar with unmultiplexed mst_ports --- Bender.yml | 4 +- CHANGELOG.md | 1 + src/axi_xbar.sv | 206 +++------------------- src/axi_xbar_unmuxed.sv | 373 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 401 insertions(+), 183 deletions(-) create mode 100644 src/axi_xbar_unmuxed.sv diff --git a/Bender.yml b/Bender.yml index 5995dc034..f30fcff2d 100644 --- a/Bender.yml +++ b/Bender.yml @@ -84,11 +84,13 @@ sources: - src/axi_interleaved_xbar.sv - src/axi_iw_converter.sv - src/axi_lite_xbar.sv - - src/axi_xbar.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_xbar.sv + # Level 6 - src/axi_xp.sv - target: synth_test diff --git a/CHANGELOG.md b/CHANGELOG.md index 0db60adee..2c00e5b7b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - `axi_sim_mem`: Increase number of request ports, add multiport interface variant. - `axi_bus_compare`: Optionally consider AXI `size` field to only compare used data. - `AXI_BUS_DV`: Add property checking that bursts do not cross 4KiB page boundaries. +- Add `axi_xbar_unmuxed`: Partial crossbar with unmultiplexed mst_ports. ### Fixed - `axi_bus_compare`: Fix mismatch detection. diff --git a/src/axi_xbar.sv b/src/axi_xbar.sv index 52769a66c..5d977660c 100644 --- a/src/axi_xbar.sv +++ b/src/axi_xbar.sv @@ -99,192 +99,34 @@ import cf_math_pkg::idx_width; `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 + 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, + .test_i, + .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 + ); for (genvar i = 0; i < Cfg.NoMstPorts; i++) begin : gen_mst_port_mux axi_mux #( diff --git a/src/axi_xbar_unmuxed.sv b/src/axi_xbar_unmuxed.sv new file mode 100644 index 000000000..a25187702 --- /dev/null +++ b/src/axi_xbar_unmuxed.sv @@ -0,0 +1,373 @@ +// 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_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, + /// 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 +`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 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, + /// 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 + 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 +`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 ( 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 + .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 ( 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 + 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, + .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.")); + end + `endif + `endif + // pragma translate_on +endmodule + +`include "axi/assign.svh" +`include "axi/typedef.svh" + +module axi_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 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][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, +`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 +); + + 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_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_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 From 937191cfb1f03067febc7a35bd0a16494152dad9 Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Wed, 3 Jul 2024 15:25:25 +0200 Subject: [PATCH 38/62] axi_interleaved_xbar: fix parameter order --- src/axi_interleaved_xbar.sv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/axi_interleaved_xbar.sv b/src/axi_interleaved_xbar.sv index f5f25f5b3..83d215df7 100644 --- a/src/axi_interleaved_xbar.sv +++ b/src/axi_interleaved_xbar.sv @@ -320,10 +320,10 @@ endmodule : axi_interleaved_xbar module axi_interleaved_xbar_intf import cf_math_pkg::idx_width; #( + parameter axi_pkg::xbar_cfg_t Cfg = '0, parameter int unsigned AXI_USER_WIDTH = 0, parameter bit ATOPS = 1'b1, parameter bit [Cfg.NoSlvPorts-1:0][Cfg.NoMstPorts-1:0] CONNECTIVITY = '1, - parameter axi_pkg::xbar_cfg_t Cfg = '0, parameter type rule_t = axi_pkg::xbar_rule_64_t `ifdef VCS , localparam int unsigned MstPortsIdxWidth = From 4267979e362c385d9d0dae86ece2da5aa3bd17e6 Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Wed, 3 Jul 2024 15:32:06 +0200 Subject: [PATCH 39/62] axi_xbar_unmuxed: add to Readme, fusesoc, src_files --- README.md | 1 + axi.core | 4 +++- src_files.yml | 4 +++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 83c37e32e..6f798139e 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,7 @@ In addition to the documents linked in the following table, we are setting up [d | [`axi_to_axi_lite`](src/axi_to_axi_lite.sv) | AXI4 to AXI4-Lite protocol converter. | | | [`axi_to_mem`](src/axi_to_mem.sv) | AXI4 to memory protocol (req, gnt, rvalid) converter. Additional banked, interleaved, split variant. | | | [`axi_xbar`](src/axi_xbar.sv) | Fully-connected AXI4+ATOP crossbar with an arbitrary number of slave and master ports. | [Doc](doc/axi_xbar.md) | +| [`axi_xbar_unmuxed`](src/axi_xbar_unmuxed.sv) | Demux side of fully-connected AXI4+ATOP crossbar with an arbitrary number of slave and master ports. | [Doc](doc/axi_xbar.md) | | [`axi_xp`](src/axi_xp.sv) | AXI Crosspoint (XP) with homomorphous slave and master ports. | | | [`axi_zero_mem`](src/axi_zero_mem.sv) | AXI-attached /dev/zero. All reads will be zero, writes are absorbed. | | diff --git a/axi.core b/axi.core index a68f7648c..5c60a6969 100644 --- a/axi.core +++ b/axi.core @@ -64,7 +64,7 @@ filesets: - src/axi_interleaved_xbar.sv - src/axi_iw_converter.sv - src/axi_lite_xbar.sv - - src/axi_xbar.sv + - src/axi_xbar_unmuxed.sv - src/axi_to_mem_banked.sv - src/axi_to_mem_interleaved.sv - src/axi_to_mem_split.sv @@ -73,6 +73,8 @@ filesets: - src/axi_sim_mem.sv - src/axi_test.sv # Level 5 + - src/axi_xbar.sv + # Level 6 - src/axi_xp.sv file_type : systemVerilogSource depend : diff --git a/src_files.yml b/src_files.yml index ae79a8d43..451c85658 100644 --- a/src_files.yml +++ b/src_files.yml @@ -63,11 +63,13 @@ axi: - src/axi_interleaved_xbar.sv - src/axi_iw_converter.sv - src/axi_lite_xbar.sv - - src/axi_xbar.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_xbar.sv + # Level 6 - src/axi_xp.sv axi_sim: From 4e98cb8bfeff6ea58855949e07a949490a006112 Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Wed, 22 May 2024 17:52:57 +0200 Subject: [PATCH 40/62] Rewrite simpler axi_id_serializer Removes demux and mux inside --- src/axi_id_serialize.sv | 316 ++++++++++++++-------------------------- 1 file changed, 112 insertions(+), 204 deletions(-) diff --git a/src/axi_id_serialize.sv b/src/axi_id_serialize.sv index 9a787dd25..0d1553b99 100644 --- a/src/axi_id_serialize.sv +++ b/src/axi_id_serialize.sv @@ -12,6 +12,7 @@ // Authors: // - Andreas Kurth // - Paul Scheffler +// - Michael Rogenmoser `include "axi/assign.svh" `include "axi/typedef.svh" @@ -29,9 +30,6 @@ module axi_id_serialize #( /// ID width of the AXI4+ATOP slave port parameter int unsigned AxiSlvPortIdWidth = 32'd0, - /// Maximum number of transactions that can be in flight at the slave port. Reads and writes are - /// counted separately (except for ATOPs, which count as both read and write). - parameter int unsigned AxiSlvPortMaxTxns = 32'd0, /// ID width of the AXI4+ATOP master port parameter int unsigned AxiMstPortIdWidth = 32'd0, /// Maximum number of different IDs that can be in flight at the master port. Reads and writes @@ -41,14 +39,6 @@ module axi_id_serialize #( parameter int unsigned AxiMstPortMaxUniqIds = 32'd0, /// Maximum number of in-flight transactions with the same ID at the master port. parameter int unsigned AxiMstPortMaxTxnsPerId = 32'd0, - /// Address width of both AXI4+ATOP ports - parameter int unsigned AxiAddrWidth = 32'd0, - /// Data width of both AXI4+ATOP ports - parameter int unsigned AxiDataWidth = 32'd0, - /// User width of both AXI4+ATOP ports - parameter int unsigned AxiUserWidth = 32'd0, - /// Enable support for AXI4+ATOP atomics - parameter bit AtopSupport = 1'b1, /// Request struct type of the AXI4+ATOP slave port parameter type slv_req_t = logic, /// Response struct type of the AXI4+ATOP slave port @@ -66,7 +56,13 @@ module axi_id_serialize #( /// Number of Entries in the explicit ID map (default: None) parameter int unsigned IdMapNumEntries = 32'd0, /// Explicit ID map; index [0] in each entry is the input ID to match, index [1] the output ID. - parameter int unsigned IdMap [IdMapNumEntries-1:0][0:1] = '{default: {32'b0, 32'b0}} + parameter int unsigned IdMap [IdMapNumEntries-1:0][0:1] = '{default: {32'b0, 32'b0}}, + // unused parameters, no longer needed, left for backwards-compatibility + parameter int unsigned AxiSlvPortMaxTxns = 32'd0, // unused + parameter int unsigned AxiAddrWidth = 32'd0, + parameter int unsigned AxiDataWidth = 32'd0, + parameter int unsigned AxiUserWidth = 32'd0, + parameter bit AtopSupport = 1'b1 ) ( /// Rising-edge clock of both ports input logic clk_i, @@ -87,73 +83,9 @@ module axi_id_serialize #( /// Slice of slave port IDs that determines the master port ID typedef logic [SelectWidth-1:0] select_t; - /// ID width after the multiplexer - localparam int unsigned MuxIdWidth = (AxiMstPortMaxUniqIds > 32'd1) ? SelectWidth + 32'd1 : 32'd1; - - /// ID after serializer (i.e., with a constant value of zero) - typedef logic [0:0] ser_id_t; - /// ID after the multiplexer - typedef logic [MuxIdWidth-1:0] mux_id_t; - /// ID at the slave port - typedef logic [AxiSlvPortIdWidth-1:0] slv_id_t; /// ID at the master port typedef logic [AxiMstPortIdWidth-1:0] mst_id_t; - /// Address in any AXI channel - typedef logic [AxiAddrWidth-1:0] addr_t; - /// Data in any AXI channel - typedef logic [AxiDataWidth-1:0] data_t; - /// Strobe in any AXI channel - typedef logic [AxiDataWidth/8-1:0] strb_t; - /// User signal in any AXI channel - typedef logic [AxiUserWidth-1:0] user_t; - - /// W channel at any interface - `AXI_TYPEDEF_W_CHAN_T(w_t, data_t, strb_t, user_t) - - /// AW channel at slave port - `AXI_TYPEDEF_AW_CHAN_T(slv_aw_t, addr_t, slv_id_t, user_t) - /// B channel at slave port - `AXI_TYPEDEF_B_CHAN_T(slv_b_t, slv_id_t, user_t) - /// AR channel at slave port - `AXI_TYPEDEF_AR_CHAN_T(slv_ar_t, addr_t, slv_id_t, user_t) - /// R channel at slave port - `AXI_TYPEDEF_R_CHAN_T(slv_r_t, data_t, slv_id_t, user_t) - - /// AW channel after serializer - `AXI_TYPEDEF_AW_CHAN_T(ser_aw_t, addr_t, ser_id_t, user_t) - /// B channel after serializer - `AXI_TYPEDEF_B_CHAN_T(ser_b_t, ser_id_t, user_t) - /// AR channel after serializer - `AXI_TYPEDEF_AR_CHAN_T(ser_ar_t, addr_t, ser_id_t, user_t) - /// R channel after serializer - `AXI_TYPEDEF_R_CHAN_T(ser_r_t, data_t, ser_id_t, user_t) - /// AXI Requests from serializer - `AXI_TYPEDEF_REQ_T(ser_req_t, ser_aw_t, w_t, ser_ar_t) - /// AXI responses to serializer - `AXI_TYPEDEF_RESP_T(ser_resp_t, ser_b_t, ser_r_t) - - /// AW channel after the multiplexer - `AXI_TYPEDEF_AW_CHAN_T(mux_aw_t, addr_t, mux_id_t, user_t) - /// B channel after the multiplexer - `AXI_TYPEDEF_B_CHAN_T(mux_b_t, mux_id_t, user_t) - /// AR channel after the multiplexer - `AXI_TYPEDEF_AR_CHAN_T(mux_ar_t, addr_t, mux_id_t, user_t) - /// R channel after the multiplexer - `AXI_TYPEDEF_R_CHAN_T(mux_r_t, data_t, mux_id_t, user_t) - /// AXI requests from the multiplexer - `AXI_TYPEDEF_REQ_T(mux_req_t, mux_aw_t, w_t, mux_ar_t) - /// AXI responses to the multiplexer - `AXI_TYPEDEF_RESP_T(mux_resp_t, mux_b_t, mux_r_t) - - /// AW channel at master port - `AXI_TYPEDEF_AW_CHAN_T(mst_aw_t, addr_t, mst_id_t, user_t) - /// B channel at master port - `AXI_TYPEDEF_B_CHAN_T(mst_b_t, mst_id_t, user_t) - /// AR channel at master port - `AXI_TYPEDEF_AR_CHAN_T(mst_ar_t, addr_t, mst_id_t, user_t) - /// R channel at master port - `AXI_TYPEDEF_R_CHAN_T(mst_r_t, data_t, mst_id_t, user_t) - + /// Type for slave ID map typedef mst_id_t [2**AxiSlvPortIdWidth-1:0] slv_id_map_t; @@ -172,49 +104,70 @@ module axi_id_serialize #( /// Input-to-output ID map used localparam slv_id_map_t SlvIdMap = map_slv_ids(); - select_t slv_aw_select, slv_ar_select; + select_t slv_aw_select, slv_ar_select, slv_b_select, slv_r_select; assign slv_aw_select = select_t'(SlvIdMap[slv_req_i.aw.id]); assign slv_ar_select = select_t'(SlvIdMap[slv_req_i.ar.id]); slv_req_t [AxiMstPortMaxUniqIds-1:0] to_serializer_reqs; slv_resp_t [AxiMstPortMaxUniqIds-1:0] to_serializer_resps; - axi_demux #( - .AxiIdWidth ( AxiSlvPortIdWidth ), - .aw_chan_t ( slv_aw_t ), - .w_chan_t ( w_t ), - .b_chan_t ( slv_b_t ), - .ar_chan_t ( slv_ar_t ), - .r_chan_t ( slv_r_t ), - .axi_req_t ( slv_req_t ), - .axi_resp_t ( slv_resp_t ), - .NoMstPorts ( AxiMstPortMaxUniqIds ), - .MaxTrans ( AxiSlvPortMaxTxns ), - .AxiLookBits ( AxiSlvPortIdWidth ), - .AtopSupport ( AtopSupport ), - .SpillAw ( 1'b1 ), - .SpillW ( 1'b0 ), - .SpillB ( 1'b0 ), - .SpillAr ( 1'b1 ), - .SpillR ( 1'b0 ) - ) 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 ), - .slv_resp_o ( slv_resp_o ), - .mst_reqs_o ( to_serializer_reqs ), - .mst_resps_i ( to_serializer_resps ) + logic [AxiMstPortMaxUniqIds-1:0] to_serializer_resps_b_valid, + to_serializer_resps_r_valid; + + onehot_to_bin #( + .ONEHOT_WIDTH( AxiMstPortMaxUniqIds ) + ) i_slv_b_select ( + .onehot(to_serializer_resps_b_valid), + .bin (slv_b_select) ); + onehot_to_bin #( + .ONEHOT_WIDTH( AxiMstPortMaxUniqIds ) + ) i_slv_r_select ( + .onehot(to_serializer_resps_r_valid), + .bin (slv_r_select) + ); + + for (genvar i = 0; i < AxiMstPortMaxUniqIds; i++) begin + assign to_serializer_resps_b_valid[i] = to_serializer_resps[i].b_valid; + assign to_serializer_resps_r_valid[i] = to_serializer_resps[i].r_valid; + end + + // Due to static ID mapping, ID consistency checking is not needed. + always_comb begin + // AW, W, AR + for (int unsigned i = 0; i < AxiMstPortMaxUniqIds; i++) begin + to_serializer_reqs[i] = slv_req_i; // .aw, .w, .ar + to_serializer_reqs[i].aw_valid = '0; + to_serializer_reqs[i].w_valid = '0; + to_serializer_reqs[i].ar_valid = '0; + end + to_serializer_reqs[slv_aw_select].aw_valid = slv_req_i.aw_valid; + slv_resp_o.aw_ready = to_serializer_resps[slv_aw_select].aw_ready; + + slv_resp_o.w_ready = mst_resp_i.w_ready; + + to_serializer_reqs[slv_ar_select].ar_valid = slv_req_i.ar_valid; + slv_resp_o.ar_ready = to_serializer_resps[slv_ar_select].ar_ready; + + // B, R (these are passed through or both gated inside the serializer) + slv_resp_o.b_valid = |to_serializer_resps_b_valid; + slv_resp_o.b = to_serializer_resps[slv_b_select].b; + slv_resp_o.r_valid = |to_serializer_resps_r_valid; + slv_resp_o.r = to_serializer_resps[slv_r_select].r; + for (int unsigned i = 0; i < AxiMstPortMaxUniqIds; i++) begin + to_serializer_reqs[i].b_ready = slv_req_i.b_ready; + to_serializer_reqs[i].r_ready = slv_req_i.r_ready; + end + end + slv_req_t [AxiMstPortMaxUniqIds-1:0] tmp_serializer_reqs; slv_resp_t [AxiMstPortMaxUniqIds-1:0] tmp_serializer_resps; - ser_req_t [AxiMstPortMaxUniqIds-1:0] from_serializer_reqs; - ser_resp_t [AxiMstPortMaxUniqIds-1:0] from_serializer_resps; + mst_req_t [AxiMstPortMaxUniqIds-1:0] from_serializer_reqs; + mst_resp_t [AxiMstPortMaxUniqIds-1:0] from_serializer_resps; for (genvar i = 0; i < AxiMstPortMaxUniqIds; i++) begin : gen_serializers + // serializer takes care to ensure unique IDs for ATOPs axi_serializer #( .MaxReadTxns ( AxiMstPortMaxTxnsPerId ), .MaxWriteTxns ( AxiMstPortMaxTxnsPerId ), @@ -231,110 +184,65 @@ module axi_id_serialize #( ); always_comb begin `AXI_SET_REQ_STRUCT(from_serializer_reqs[i], tmp_serializer_reqs[i]) - // Truncate to ID width 1 as all requests have ID '0. - from_serializer_reqs[i].aw.id = tmp_serializer_reqs[i].aw.id[0]; - from_serializer_reqs[i].ar.id = tmp_serializer_reqs[i].ar.id[0]; + from_serializer_reqs[i].aw.id = i; + from_serializer_reqs[i].ar.id = i; `AXI_SET_RESP_STRUCT(tmp_serializer_resps[i], from_serializer_resps[i]) // Zero-extend response IDs. - tmp_serializer_resps[i].b.id = {{AxiSlvPortIdWidth-1{1'b0}}, from_serializer_resps[i].b.id}; - tmp_serializer_resps[i].r.id = {{AxiSlvPortIdWidth-1{1'b0}}, from_serializer_resps[i].r.id}; + tmp_serializer_resps[i].b.id = '0; + tmp_serializer_resps[i].r.id = '0; end end - mux_req_t axi_mux_req; - mux_resp_t axi_mux_resp; - - axi_mux #( - .SlvAxiIDWidth ( 32'd1 ), - .slv_aw_chan_t ( ser_aw_t ), - .mst_aw_chan_t ( mux_aw_t ), - .w_chan_t ( w_t ), - .slv_b_chan_t ( ser_b_t ), - .mst_b_chan_t ( mux_b_t ), - .slv_ar_chan_t ( ser_ar_t ), - .mst_ar_chan_t ( mux_ar_t ), - .slv_r_chan_t ( ser_r_t ), - .mst_r_chan_t ( mux_r_t ), - .slv_req_t ( ser_req_t ), - .slv_resp_t ( ser_resp_t ), - .mst_req_t ( mux_req_t ), - .mst_resp_t ( mux_resp_t ), - .NoSlvPorts ( AxiMstPortMaxUniqIds ), - .MaxWTrans ( AxiMstPortMaxTxnsPerId ), - .FallThrough ( 1'b0 ), - .SpillAw ( 1'b1 ), - .SpillW ( 1'b0 ), - .SpillB ( 1'b0 ), - .SpillAr ( 1'b1 ), - .SpillR ( 1'b0 ) - ) 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 ), - .mst_resp_i ( axi_mux_resp ) + logic [AxiMstPortMaxUniqIds-1:0] from_serializer_reqs_aw_valid, + from_serializer_reqs_ar_valid, + from_serializer_reqs_b_ready, + from_serializer_reqs_r_ready; + + select_t mst_aw_select, mst_ar_select; + + onehot_to_bin #( + .ONEHOT_WIDTH( AxiMstPortMaxUniqIds ) + ) i_mst_aw_select ( + .onehot(from_serializer_reqs_aw_valid), + .bin (mst_aw_select) ); - // Shift the ID one down if needed, as mux prepends IDs - if (MuxIdWidth > 32'd1) begin : gen_id_shift - always_comb begin - `AXI_SET_REQ_STRUCT(mst_req_o, axi_mux_req) - mst_req_o.aw.id = mst_id_t'(axi_mux_req.aw.id >> 32'd1); - mst_req_o.ar.id = mst_id_t'(axi_mux_req.ar.id >> 32'd1); - `AXI_SET_RESP_STRUCT(axi_mux_resp, mst_resp_i) - axi_mux_resp.b.id = mux_id_t'(mst_resp_i.b.id << 32'd1); - axi_mux_resp.r.id = mux_id_t'(mst_resp_i.r.id << 32'd1); + onehot_to_bin #( + .ONEHOT_WIDTH( AxiMstPortMaxUniqIds ) + ) i_mst_ar_select ( + .onehot(from_serializer_reqs_ar_valid), + .bin (mst_ar_select) + ); + + for (genvar i = 0; i < AxiMstPortMaxUniqIds; i++) begin + assign from_serializer_reqs_aw_valid[i] = from_serializer_reqs[i].aw_valid; + assign from_serializer_reqs_ar_valid[i] = from_serializer_reqs[i].ar_valid; + end + + always_comb begin + mst_req_o.aw_valid = |from_serializer_reqs_aw_valid; + mst_req_o.aw = from_serializer_reqs[mst_aw_select].aw; + mst_req_o.w_valid = slv_req_i.w_valid; + mst_req_o.w = slv_req_i.w; + mst_req_o.ar_valid = |from_serializer_reqs_ar_valid; + mst_req_o.ar = from_serializer_reqs[mst_ar_select].ar; + for (int unsigned i = 0; i < AxiMstPortMaxUniqIds; i++) begin + from_serializer_resps[i].aw_ready = mst_resp_i.aw_ready; + from_serializer_resps[i].ar_ready = mst_resp_i.ar_ready; end - end else begin : gen_no_id_shift - axi_id_prepend #( - .NoBus ( 32'd1 ), - .AxiIdWidthSlvPort ( MuxIdWidth ), - .AxiIdWidthMstPort ( AxiMstPortIdWidth ), - .slv_aw_chan_t ( mux_aw_t ), - .slv_w_chan_t ( w_t ), - .slv_b_chan_t ( mux_b_t ), - .slv_ar_chan_t ( mux_ar_t ), - .slv_r_chan_t ( mux_r_t ), - .mst_aw_chan_t ( mst_aw_t ), - .mst_w_chan_t ( w_t ), - .mst_b_chan_t ( mst_b_t ), - .mst_ar_chan_t ( mst_ar_t ), - .mst_r_chan_t ( mst_r_t ) - ) i_axi_id_prepend ( - .pre_id_i ( '0 ), - .slv_aw_chans_i ( axi_mux_req.aw ), - .slv_aw_valids_i ( axi_mux_req.aw_valid ), - .slv_aw_readies_o ( axi_mux_resp.aw_ready ), - .slv_w_chans_i ( axi_mux_req.w ), - .slv_w_valids_i ( axi_mux_req.w_valid ), - .slv_w_readies_o ( axi_mux_resp.w_ready ), - .slv_b_chans_o ( axi_mux_resp.b ), - .slv_b_valids_o ( axi_mux_resp.b_valid ), - .slv_b_readies_i ( axi_mux_req.b_ready ), - .slv_ar_chans_i ( axi_mux_req.ar ), - .slv_ar_valids_i ( axi_mux_req.ar_valid ), - .slv_ar_readies_o ( axi_mux_resp.ar_ready ), - .slv_r_chans_o ( axi_mux_resp.r ), - .slv_r_valids_o ( axi_mux_resp.r_valid ), - .slv_r_readies_i ( axi_mux_req.r_ready ), - .mst_aw_chans_o ( mst_req_o.aw ), - .mst_aw_valids_o ( mst_req_o.aw_valid ), - .mst_aw_readies_i ( mst_resp_i.aw_ready ), - .mst_w_chans_o ( mst_req_o.w ), - .mst_w_valids_o ( mst_req_o.w_valid ), - .mst_w_readies_i ( mst_resp_i.w_ready ), - .mst_b_chans_i ( mst_resp_i.b ), - .mst_b_valids_i ( mst_resp_i.b_valid ), - .mst_b_readies_o ( mst_req_o.b_ready ), - .mst_ar_chans_o ( mst_req_o.ar ), - .mst_ar_valids_o ( mst_req_o.ar_valid ), - .mst_ar_readies_i ( mst_resp_i.ar_ready ), - .mst_r_chans_i ( mst_resp_i.r ), - .mst_r_valids_i ( mst_resp_i.r_valid ), - .mst_r_readies_o ( mst_req_o.r_ready ) - ); + + for (int unsigned i = 0; i < AxiMstPortMaxUniqIds; i++) begin + from_serializer_reqs_b_ready[i] = from_serializer_reqs[i].b_ready; + from_serializer_reqs_r_ready[i] = from_serializer_reqs[i].r_ready; + from_serializer_resps[i].b_valid = '0; + from_serializer_resps[i].r_valid = '0; + from_serializer_resps[i].b = mst_resp_i.b; + from_serializer_resps[i].r = mst_resp_i.r; + end + from_serializer_resps[mst_resp_i.b.id].b_valid = mst_resp_i.b_valid; + mst_req_o.b_ready = from_serializer_reqs[mst_resp_i.b.id].b_ready; + from_serializer_resps[mst_resp_i.r.id].r_valid = mst_resp_i.r_valid; + mst_req_o.r_ready = from_serializer_reqs[mst_resp_i.r.id].r_ready; end // pragma translate_off From 04911ef2f24648c7b202f0ccb0d0a03145db7b29 Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Mon, 27 May 2024 17:32:05 +0200 Subject: [PATCH 41/62] Add spill for AR and AW --- src/axi_id_serialize.sv | 75 ++++++++++++++++++++++++++++++++++------- 1 file changed, 62 insertions(+), 13 deletions(-) diff --git a/src/axi_id_serialize.sv b/src/axi_id_serialize.sv index 0d1553b99..24898f65e 100644 --- a/src/axi_id_serialize.sv +++ b/src/axi_id_serialize.sv @@ -39,6 +39,10 @@ module axi_id_serialize #( parameter int unsigned AxiMstPortMaxUniqIds = 32'd0, /// Maximum number of in-flight transactions with the same ID at the master port. parameter int unsigned AxiMstPortMaxTxnsPerId = 32'd0, + /// Address width of both AXI4+ATOP ports + parameter int unsigned AxiAddrWidth = 32'd0, + /// User width of both AXI4+ATOP ports + parameter int unsigned AxiUserWidth = 32'd0, /// Request struct type of the AXI4+ATOP slave port parameter type slv_req_t = logic, /// Response struct type of the AXI4+ATOP slave port @@ -57,11 +61,11 @@ module axi_id_serialize #( parameter int unsigned IdMapNumEntries = 32'd0, /// Explicit ID map; index [0] in each entry is the input ID to match, index [1] the output ID. parameter int unsigned IdMap [IdMapNumEntries-1:0][0:1] = '{default: {32'b0, 32'b0}}, + /// Spill AR and AW + parameter bit SpillAx = 1'b1, // unused parameters, no longer needed, left for backwards-compatibility parameter int unsigned AxiSlvPortMaxTxns = 32'd0, // unused - parameter int unsigned AxiAddrWidth = 32'd0, parameter int unsigned AxiDataWidth = 32'd0, - parameter int unsigned AxiUserWidth = 32'd0, parameter bit AtopSupport = 1'b1 ) ( /// Rising-edge clock of both ports @@ -85,7 +89,16 @@ module axi_id_serialize #( /// ID at the master port typedef logic [AxiMstPortIdWidth-1:0] mst_id_t; - + /// Address in any AXI channel + typedef logic [AxiAddrWidth-1:0] addr_t; + /// User signal in any AXI channel + typedef logic [AxiUserWidth-1:0] user_t; + + /// AW channel at master port + `AXI_TYPEDEF_AW_CHAN_T(mst_aw_t, addr_t, mst_id_t, user_t) + /// AR channel at master port + `AXI_TYPEDEF_AR_CHAN_T(mst_ar_t, addr_t, mst_id_t, user_t) + /// Type for slave ID map typedef mst_id_t [2**AxiSlvPortIdWidth-1:0] slv_id_map_t; @@ -219,16 +232,19 @@ module axi_id_serialize #( assign from_serializer_reqs_ar_valid[i] = from_serializer_reqs[i].ar_valid; end + mst_req_t mst_req; + logic mst_aw_ready, mst_ar_ready; + always_comb begin - mst_req_o.aw_valid = |from_serializer_reqs_aw_valid; - mst_req_o.aw = from_serializer_reqs[mst_aw_select].aw; - mst_req_o.w_valid = slv_req_i.w_valid; - mst_req_o.w = slv_req_i.w; - mst_req_o.ar_valid = |from_serializer_reqs_ar_valid; - mst_req_o.ar = from_serializer_reqs[mst_ar_select].ar; + mst_req.aw_valid = |from_serializer_reqs_aw_valid; + mst_req.aw = from_serializer_reqs[mst_aw_select].aw; + mst_req.w_valid = slv_req_i.w_valid; + mst_req.w = slv_req_i.w; + mst_req.ar_valid = |from_serializer_reqs_ar_valid; + mst_req.ar = from_serializer_reqs[mst_ar_select].ar; for (int unsigned i = 0; i < AxiMstPortMaxUniqIds; i++) begin - from_serializer_resps[i].aw_ready = mst_resp_i.aw_ready; - from_serializer_resps[i].ar_ready = mst_resp_i.ar_ready; + from_serializer_resps[i].aw_ready = mst_aw_ready; + from_serializer_resps[i].ar_ready = mst_ar_ready; end for (int unsigned i = 0; i < AxiMstPortMaxUniqIds; i++) begin @@ -240,11 +256,44 @@ module axi_id_serialize #( from_serializer_resps[i].r = mst_resp_i.r; end from_serializer_resps[mst_resp_i.b.id].b_valid = mst_resp_i.b_valid; - mst_req_o.b_ready = from_serializer_reqs[mst_resp_i.b.id].b_ready; + mst_req.b_ready = from_serializer_reqs[mst_resp_i.b.id].b_ready; from_serializer_resps[mst_resp_i.r.id].r_valid = mst_resp_i.r_valid; - mst_req_o.r_ready = from_serializer_reqs[mst_resp_i.r.id].r_ready; + mst_req.r_ready = from_serializer_reqs[mst_resp_i.r.id].r_ready; end + spill_register #( + .T ( mst_aw_t ), + .Bypass( ~SpillAx ) + ) i_aw_spill_reg ( + .clk_i, + .rst_ni, + .valid_i( mst_req.aw_valid ), + .ready_o( mst_aw_ready ), + .data_i ( mst_req.aw), + .valid_o( mst_req_o.aw_valid ), + .ready_i( mst_resp_i.aw_ready ), + .data_o ( mst_req_o.aw ) + ); + + spill_register #( + .T ( mst_ar_t ), + .Bypass( ~SpillAx ) + ) i_ar_spill_reg ( + .clk_i, + .rst_ni, + .valid_i( mst_req.ar_valid ), + .ready_o( mst_ar_ready ), + .data_i ( mst_req.ar ), + .valid_o( mst_req_o.ar_valid ), + .ready_i( mst_resp_i.ar_ready ), + .data_o ( mst_req_o.ar ) + ); + + `AXI_ASSIGN_W_STRUCT(mst_req_o.w, mst_req.w) + assign mst_req_o.w_valid = mst_req.w_valid; + assign mst_req_o.b_ready = mst_req.b_ready; + assign mst_req_o.r_ready = mst_req.r_ready; + // pragma translate_off `ifndef VERILATOR initial begin : p_assert From 0015266aab74e8994d755591cf0a05aa1aa33023 Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Thu, 25 Jul 2024 11:15:24 +0200 Subject: [PATCH 42/62] axi_id_serializer: Add comments, update intf parameters --- src/axi_id_serialize.sv | 42 ++++++++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/src/axi_id_serialize.sv b/src/axi_id_serialize.sv index 24898f65e..4aa068683 100644 --- a/src/axi_id_serialize.sv +++ b/src/axi_id_serialize.sv @@ -64,7 +64,7 @@ module axi_id_serialize #( /// Spill AR and AW parameter bit SpillAx = 1'b1, // unused parameters, no longer needed, left for backwards-compatibility - parameter int unsigned AxiSlvPortMaxTxns = 32'd0, // unused + parameter int unsigned AxiSlvPortMaxTxns = 32'd0, parameter int unsigned AxiDataWidth = 32'd0, parameter bit AtopSupport = 1'b1 ) ( @@ -127,6 +127,7 @@ module axi_id_serialize #( logic [AxiMstPortMaxUniqIds-1:0] to_serializer_resps_b_valid, to_serializer_resps_r_valid; + // Convert B response valid to index for selection onehot_to_bin #( .ONEHOT_WIDTH( AxiMstPortMaxUniqIds ) ) i_slv_b_select ( @@ -134,6 +135,7 @@ module axi_id_serialize #( .bin (slv_b_select) ); + // Convert R response valid to index for selection onehot_to_bin #( .ONEHOT_WIDTH( AxiMstPortMaxUniqIds ) ) i_slv_r_select ( @@ -150,19 +152,24 @@ module axi_id_serialize #( always_comb begin // AW, W, AR for (int unsigned i = 0; i < AxiMstPortMaxUniqIds; i++) begin - to_serializer_reqs[i] = slv_req_i; // .aw, .w, .ar + to_serializer_reqs[i] = slv_req_i; // assigns.aw, .w, .ar to_serializer_reqs[i].aw_valid = '0; to_serializer_reqs[i].w_valid = '0; to_serializer_reqs[i].ar_valid = '0; end + + // Only pass AW to the selected serializer to_serializer_reqs[slv_aw_select].aw_valid = slv_req_i.aw_valid; slv_resp_o.aw_ready = to_serializer_resps[slv_aw_select].aw_ready; + // W is always in order (i.e., serialized) and does not have ID field, pass through slv_resp_o.w_ready = mst_resp_i.w_ready; + // Only pass AR to the selected serializer to_serializer_reqs[slv_ar_select].ar_valid = slv_req_i.ar_valid; slv_resp_o.ar_ready = to_serializer_resps[slv_ar_select].ar_ready; + // Recombine responses, only one will be active at a time // B, R (these are passed through or both gated inside the serializer) slv_resp_o.b_valid = |to_serializer_resps_b_valid; slv_resp_o.b = to_serializer_resps[slv_b_select].b; @@ -179,6 +186,7 @@ module axi_id_serialize #( mst_req_t [AxiMstPortMaxUniqIds-1:0] from_serializer_reqs; mst_resp_t [AxiMstPortMaxUniqIds-1:0] from_serializer_resps; + // One serializer per desired ouput ID for (genvar i = 0; i < AxiMstPortMaxUniqIds; i++) begin : gen_serializers // serializer takes care to ensure unique IDs for ATOPs axi_serializer #( @@ -195,6 +203,7 @@ module axi_id_serialize #( .mst_req_o ( tmp_serializer_reqs[i] ), .mst_resp_i ( tmp_serializer_resps[i] ) ); + // Assign desired output ID always_comb begin `AXI_SET_REQ_STRUCT(from_serializer_reqs[i], tmp_serializer_reqs[i]) from_serializer_reqs[i].aw.id = i; @@ -213,6 +222,7 @@ module axi_id_serialize #( select_t mst_aw_select, mst_ar_select; + // Convert AW request valid to index for selection onehot_to_bin #( .ONEHOT_WIDTH( AxiMstPortMaxUniqIds ) ) i_mst_aw_select ( @@ -220,6 +230,7 @@ module axi_id_serialize #( .bin (mst_aw_select) ); + // Convert AR request valid to index for selection onehot_to_bin #( .ONEHOT_WIDTH( AxiMstPortMaxUniqIds ) ) i_mst_ar_select ( @@ -236,17 +247,25 @@ module axi_id_serialize #( logic mst_aw_ready, mst_ar_ready; always_comb begin + // Recombine AW requests, only one active at a time mst_req.aw_valid = |from_serializer_reqs_aw_valid; mst_req.aw = from_serializer_reqs[mst_aw_select].aw; + + // W is always in order (i.e., serialized) and does not have ID field, pass through mst_req.w_valid = slv_req_i.w_valid; mst_req.w = slv_req_i.w; + + // Recombine AR requests, only one active at a time mst_req.ar_valid = |from_serializer_reqs_ar_valid; mst_req.ar = from_serializer_reqs[mst_ar_select].ar; + + // AW/AR ready distributed, only one request active at a time for (int unsigned i = 0; i < AxiMstPortMaxUniqIds; i++) begin from_serializer_resps[i].aw_ready = mst_aw_ready; from_serializer_resps[i].ar_ready = mst_ar_ready; end + // Distribute B and R responses to corresponding serializers for (int unsigned i = 0; i < AxiMstPortMaxUniqIds; i++) begin from_serializer_reqs_b_ready[i] = from_serializer_reqs[i].b_ready; from_serializer_reqs_r_ready[i] = from_serializer_reqs[i].r_ready; @@ -261,6 +280,7 @@ module axi_id_serialize #( mst_req.r_ready = from_serializer_reqs[mst_resp_i.r.id].r_ready; end + // Optional spill register to help prevent timing loops spill_register #( .T ( mst_aw_t ), .Bypass( ~SpillAx ) @@ -275,6 +295,7 @@ module axi_id_serialize #( .data_o ( mst_req_o.aw ) ); + // Optional spill register to help prevent timing loops spill_register #( .T ( mst_ar_t ), .Bypass( ~SpillAx ) @@ -326,13 +347,18 @@ endmodule /// See the documentation of the main module for the definition of ports and parameters. module axi_id_serialize_intf #( parameter int unsigned AXI_SLV_PORT_ID_WIDTH = 32'd0, - parameter int unsigned AXI_SLV_PORT_MAX_TXNS = 32'd0, parameter int unsigned AXI_MST_PORT_ID_WIDTH = 32'd0, parameter int unsigned AXI_MST_PORT_MAX_UNIQ_IDS = 32'd0, parameter int unsigned AXI_MST_PORT_MAX_TXNS_PER_ID = 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 AXI_USER_WIDTH = 32'd0, + parameter int unsigned MST_ID_BASE_OFFSET = 32'd0, + parameter int unsigned ID_MAP_NUM_ENTRIES = 32'd0, + parameter int unsigned ID_MAP [ID_MAP_NUM_ENTRIES-1:0][0:1] = '{default: {32'b0, 32'b0}}, + parameter bit SPILL_AX = 1'b1, + // Now unused, kept for backward compatibility + parameter int unsigned AXI_SLV_PORT_MAX_TXNS = 32'd0 ) ( input logic clk_i, input logic rst_ni, @@ -374,17 +400,19 @@ module axi_id_serialize_intf #( axi_id_serialize #( .AxiSlvPortIdWidth ( AXI_SLV_PORT_ID_WIDTH ), - .AxiSlvPortMaxTxns ( AXI_SLV_PORT_MAX_TXNS ), .AxiMstPortIdWidth ( AXI_MST_PORT_ID_WIDTH ), .AxiMstPortMaxUniqIds ( AXI_MST_PORT_MAX_UNIQ_IDS ), .AxiMstPortMaxTxnsPerId ( AXI_MST_PORT_MAX_TXNS_PER_ID ), .AxiAddrWidth ( AXI_ADDR_WIDTH ), - .AxiDataWidth ( AXI_DATA_WIDTH ), .AxiUserWidth ( AXI_USER_WIDTH ), .slv_req_t ( slv_req_t ), .slv_resp_t ( slv_resp_t ), .mst_req_t ( mst_req_t ), - .mst_resp_t ( mst_resp_t ) + .mst_resp_t ( mst_resp_t ), + .MstIdBaseOffset ( MST_ID_BASE_OFFSET ), + .IdMapNumEntries ( ID_MAP_NUM_ENTRIES ), + .IdMap ( ID_MAP ), + .SpillAx ( SPILL_AX ) ) i_axi_id_serialize ( .clk_i, .rst_ni, From bea405979f60c86e34ab8d38cad99a2dc875223f Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Thu, 25 Jul 2024 11:19:40 +0200 Subject: [PATCH 43/62] update CHANGELOG --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c00e5b7b..b240e23a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - `axi_dw_downsizer`: Fix `i_forward_b_beats_queue` underflow. - `axi_test`: Ensure random requests do not cross 4KiB page boundaries. +### Changed +- `axi_id_serializer`: Change internal design (and behavior) for simpler code, less hardware, and + less stalling. + ## 0.39.3 - 2024-05-08 ### Added - `axi_sim_mem`: Allow response data for uninitialized region to have configurable defined value. From 587355b77b8ce94dcd600efbd5d5bd118ff913a7 Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Thu, 25 Jul 2024 14:42:26 +0200 Subject: [PATCH 44/62] Release v0.39.4 --- CHANGELOG.md | 5 +++++ VERSION | 2 +- axi.core | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b240e23a3..96ee48c29 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## Unreleased + +## 0.39.4 - 2024-07-25 ### Added - `axi_sim_mem`: Increase number of request ports, add multiport interface variant. - `axi_bus_compare`: Optionally consider AXI `size` field to only compare used data. @@ -17,12 +19,15 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - `axi_to_detailed_mem`: Only respond with `exokay` if `lock` was set on the request. Bump `common_cells` for `mem_to_banks` fix. - `axi_dw_downsizer`: Fix `i_forward_b_beats_queue` underflow. +- `axi_atop_filter`: Add reset state to internal FSM to avoid simulation bug in XSIM. - `axi_test`: Ensure random requests do not cross 4KiB page boundaries. ### Changed - `axi_id_serializer`: Change internal design (and behavior) for simpler code, less hardware, and less stalling. +`v0.39.4` is fully **backward-compatible** to `v0.39.3`. + ## 0.39.3 - 2024-05-08 ### Added - `axi_sim_mem`: Allow response data for uninitialized region to have configurable defined value. diff --git a/VERSION b/VERSION index e0c2d6587..c02e508ca 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.39.3 +0.39.4 diff --git a/axi.core b/axi.core index 5c60a6969..5d17f61b9 100644 --- a/axi.core +++ b/axi.core @@ -1,6 +1,6 @@ CAPI=2: -name : pulp-platform.org::axi:0.39.3 +name : pulp-platform.org::axi:0.39.4 filesets: rtl: From 14fbbf59082c6b13e8820a71131b8f845e3a8683 Mon Sep 17 00:00:00 2001 From: Tim Fischer Date: Mon, 29 Jul 2024 15:11:05 +0200 Subject: [PATCH 45/62] axi_xbar_unmuxed: Disable interface variant for VCS VCS does not support multi-dimensional array of interfaces as of now --- src/axi_xbar_unmuxed.sv | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/axi_xbar_unmuxed.sv b/src/axi_xbar_unmuxed.sv index a25187702..325abd8d7 100644 --- a/src/axi_xbar_unmuxed.sv +++ b/src/axi_xbar_unmuxed.sv @@ -284,6 +284,8 @@ import cf_math_pkg::idx_width; // 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" @@ -295,10 +297,6 @@ import cf_math_pkg::idx_width; 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, @@ -307,11 +305,7 @@ import cf_math_pkg::idx_width; 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, -`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 ); typedef logic [Cfg.AxiIdWidthSlvPorts -1:0] id_t; @@ -371,3 +365,5 @@ import cf_math_pkg::idx_width; ); endmodule + +`endif From 81fd8f281a627956cb6ba7999a5fcf0fc5b89713 Mon Sep 17 00:00:00 2001 From: Tim Fischer Date: Mon, 29 Jul 2024 15:11:33 +0200 Subject: [PATCH 46/62] axi_xbar_unmuxed: Remove trailing whitespaces --- src/axi_xbar_unmuxed.sv | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/axi_xbar_unmuxed.sv b/src/axi_xbar_unmuxed.sv index 325abd8d7..32679900f 100644 --- a/src/axi_xbar_unmuxed.sv +++ b/src/axi_xbar_unmuxed.sv @@ -30,9 +30,9 @@ import cf_math_pkg::idx_width; 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. + /// 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. + /// 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, @@ -56,17 +56,17 @@ import cf_math_pkg::idx_width; ) ( /// 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 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 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 req_t [Cfg.NoMstPorts-1:0][Cfg.NoSlvPorts-1:0] mst_ports_req_o, - /// AXI4+ATOP responses to the master ports. + /// AXI4+ATOP responses to the master ports. input resp_t [Cfg.NoMstPorts-1:0][Cfg.NoSlvPorts-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. @@ -77,12 +77,12 @@ import cf_math_pkg::idx_width; `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`. + /// 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`. + /// When not used, tie to `'0`. input logic [Cfg.NoSlvPorts-1:0][idx_width(Cfg.NoMstPorts)-1:0] default_mst_port_i `endif ); From 41859549968db0147062b6c3cdbe4af00080cc09 Mon Sep 17 00:00:00 2001 From: Tim Fischer Date: Mon, 29 Jul 2024 15:11:40 +0200 Subject: [PATCH 47/62] doc: Update CHANGELOG --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 96ee48c29..ee650d9b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## Unreleased +### Fixed +- Disabled the interface variant of `axi_xbar_unmuxed` for VCS, as VCS does not support multi-dimensional arrays of interfaces yet. + ## 0.39.4 - 2024-07-25 ### Added - `axi_sim_mem`: Increase number of request ports, add multiport interface variant. From 34d2323c4134ae8afe1dcf1228a541223f512186 Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Tue, 30 Jul 2024 12:18:42 +0200 Subject: [PATCH 48/62] Fix Memora.yml --- .ci/Memora.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/.ci/Memora.yml b/.ci/Memora.yml index c8fd967de..a4504d448 100644 --- a/.ci/Memora.yml +++ b/.ci/Memora.yml @@ -83,6 +83,9 @@ artifacts: - src/axi_pkg.sv - src/axi_intf.sv - src/axi_test.sv + - src/axi_err_slv.sv + - src/axi_demux.sv + - src/axi_demux_simple.sv - src/axi_dw_downsizer.sv - src/axi_dw_converter.sv - test/tb_axi_dw_downsizer.sv @@ -97,6 +100,9 @@ artifacts: - src/axi_pkg.sv - src/axi_intf.sv - src/axi_test.sv + - src/axi_err_slv.sv + - src/axi_demux.sv + - src/axi_demux_simple.sv - src/axi_dw_upsizer.sv - src/axi_dw_converter.sv - test/tb_axi_dw_upsizer.sv @@ -125,6 +131,9 @@ artifacts: - src/axi_pkg.sv - src/axi_intf.sv - src/axi_test.sv + - src/axi_demux.sv + - src/axi_demux_simple.sv + - src/axi_err_slv.sv - src/axi_isolate.sv - test/tb_axi_isolate.sv outputs: @@ -141,6 +150,7 @@ artifacts: - src/axi_id_prepend.sv - src/axi_id_remap.sv - src/axi_demux.sv + - src/axi_demux_simple.sv - src/axi_serializer.sv - src/axi_mux.sv - src/axi_id_serialize.sv @@ -294,6 +304,7 @@ artifacts: - src/axi_intf.sv - src/axi_test.sv - src/axi_demux.sv + - src/axi_demux_simple.sv - src/axi_to_detailed_mem.sv - src/axi_to_mem.sv - src/axi_to_mem_banked.sv @@ -310,8 +321,11 @@ artifacts: - src/axi_intf.sv - src/axi_test.sv - src/axi_demux.sv + - src/axi_demux_simple.sv - src/axi_err_slv.sv - src/axi_mux.sv + - src/axi_multicut.sv + - src/axi_xbar_unmuxed.sv - src/axi_xbar.sv - test/tb_axi_xbar.sv outputs: From 3355c6bd85b060b326eec11ec813f4c42d86b7e9 Mon Sep 17 00:00:00 2001 From: Thomas Benz Date: Thu, 24 Oct 2024 18:05:01 +0200 Subject: [PATCH 49/62] Revert #342 (b9915f5) to temporarily fix `axi_id_serialize` --- src/axi_id_serialize.sv | 377 +++++++++++++++++++++------------------- 1 file changed, 196 insertions(+), 181 deletions(-) diff --git a/src/axi_id_serialize.sv b/src/axi_id_serialize.sv index 4aa068683..9a787dd25 100644 --- a/src/axi_id_serialize.sv +++ b/src/axi_id_serialize.sv @@ -12,7 +12,6 @@ // Authors: // - Andreas Kurth // - Paul Scheffler -// - Michael Rogenmoser `include "axi/assign.svh" `include "axi/typedef.svh" @@ -30,6 +29,9 @@ module axi_id_serialize #( /// ID width of the AXI4+ATOP slave port parameter int unsigned AxiSlvPortIdWidth = 32'd0, + /// Maximum number of transactions that can be in flight at the slave port. Reads and writes are + /// counted separately (except for ATOPs, which count as both read and write). + parameter int unsigned AxiSlvPortMaxTxns = 32'd0, /// ID width of the AXI4+ATOP master port parameter int unsigned AxiMstPortIdWidth = 32'd0, /// Maximum number of different IDs that can be in flight at the master port. Reads and writes @@ -41,8 +43,12 @@ module axi_id_serialize #( parameter int unsigned AxiMstPortMaxTxnsPerId = 32'd0, /// Address width of both AXI4+ATOP ports parameter int unsigned AxiAddrWidth = 32'd0, + /// Data width of both AXI4+ATOP ports + parameter int unsigned AxiDataWidth = 32'd0, /// User width of both AXI4+ATOP ports parameter int unsigned AxiUserWidth = 32'd0, + /// Enable support for AXI4+ATOP atomics + parameter bit AtopSupport = 1'b1, /// Request struct type of the AXI4+ATOP slave port parameter type slv_req_t = logic, /// Response struct type of the AXI4+ATOP slave port @@ -60,13 +66,7 @@ module axi_id_serialize #( /// Number of Entries in the explicit ID map (default: None) parameter int unsigned IdMapNumEntries = 32'd0, /// Explicit ID map; index [0] in each entry is the input ID to match, index [1] the output ID. - parameter int unsigned IdMap [IdMapNumEntries-1:0][0:1] = '{default: {32'b0, 32'b0}}, - /// Spill AR and AW - parameter bit SpillAx = 1'b1, - // unused parameters, no longer needed, left for backwards-compatibility - parameter int unsigned AxiSlvPortMaxTxns = 32'd0, - parameter int unsigned AxiDataWidth = 32'd0, - parameter bit AtopSupport = 1'b1 + parameter int unsigned IdMap [IdMapNumEntries-1:0][0:1] = '{default: {32'b0, 32'b0}} ) ( /// Rising-edge clock of both ports input logic clk_i, @@ -87,17 +87,72 @@ module axi_id_serialize #( /// Slice of slave port IDs that determines the master port ID typedef logic [SelectWidth-1:0] select_t; + /// ID width after the multiplexer + localparam int unsigned MuxIdWidth = (AxiMstPortMaxUniqIds > 32'd1) ? SelectWidth + 32'd1 : 32'd1; + + /// ID after serializer (i.e., with a constant value of zero) + typedef logic [0:0] ser_id_t; + /// ID after the multiplexer + typedef logic [MuxIdWidth-1:0] mux_id_t; + /// ID at the slave port + typedef logic [AxiSlvPortIdWidth-1:0] slv_id_t; /// ID at the master port typedef logic [AxiMstPortIdWidth-1:0] mst_id_t; - /// Address in any AXI channel + /// Address in any AXI channel typedef logic [AxiAddrWidth-1:0] addr_t; + /// Data in any AXI channel + typedef logic [AxiDataWidth-1:0] data_t; + /// Strobe in any AXI channel + typedef logic [AxiDataWidth/8-1:0] strb_t; /// User signal in any AXI channel typedef logic [AxiUserWidth-1:0] user_t; + /// W channel at any interface + `AXI_TYPEDEF_W_CHAN_T(w_t, data_t, strb_t, user_t) + + /// AW channel at slave port + `AXI_TYPEDEF_AW_CHAN_T(slv_aw_t, addr_t, slv_id_t, user_t) + /// B channel at slave port + `AXI_TYPEDEF_B_CHAN_T(slv_b_t, slv_id_t, user_t) + /// AR channel at slave port + `AXI_TYPEDEF_AR_CHAN_T(slv_ar_t, addr_t, slv_id_t, user_t) + /// R channel at slave port + `AXI_TYPEDEF_R_CHAN_T(slv_r_t, data_t, slv_id_t, user_t) + + /// AW channel after serializer + `AXI_TYPEDEF_AW_CHAN_T(ser_aw_t, addr_t, ser_id_t, user_t) + /// B channel after serializer + `AXI_TYPEDEF_B_CHAN_T(ser_b_t, ser_id_t, user_t) + /// AR channel after serializer + `AXI_TYPEDEF_AR_CHAN_T(ser_ar_t, addr_t, ser_id_t, user_t) + /// R channel after serializer + `AXI_TYPEDEF_R_CHAN_T(ser_r_t, data_t, ser_id_t, user_t) + /// AXI Requests from serializer + `AXI_TYPEDEF_REQ_T(ser_req_t, ser_aw_t, w_t, ser_ar_t) + /// AXI responses to serializer + `AXI_TYPEDEF_RESP_T(ser_resp_t, ser_b_t, ser_r_t) + + /// AW channel after the multiplexer + `AXI_TYPEDEF_AW_CHAN_T(mux_aw_t, addr_t, mux_id_t, user_t) + /// B channel after the multiplexer + `AXI_TYPEDEF_B_CHAN_T(mux_b_t, mux_id_t, user_t) + /// AR channel after the multiplexer + `AXI_TYPEDEF_AR_CHAN_T(mux_ar_t, addr_t, mux_id_t, user_t) + /// R channel after the multiplexer + `AXI_TYPEDEF_R_CHAN_T(mux_r_t, data_t, mux_id_t, user_t) + /// AXI requests from the multiplexer + `AXI_TYPEDEF_REQ_T(mux_req_t, mux_aw_t, w_t, mux_ar_t) + /// AXI responses to the multiplexer + `AXI_TYPEDEF_RESP_T(mux_resp_t, mux_b_t, mux_r_t) + /// AW channel at master port `AXI_TYPEDEF_AW_CHAN_T(mst_aw_t, addr_t, mst_id_t, user_t) + /// B channel at master port + `AXI_TYPEDEF_B_CHAN_T(mst_b_t, mst_id_t, user_t) /// AR channel at master port `AXI_TYPEDEF_AR_CHAN_T(mst_ar_t, addr_t, mst_id_t, user_t) + /// R channel at master port + `AXI_TYPEDEF_R_CHAN_T(mst_r_t, data_t, mst_id_t, user_t) /// Type for slave ID map typedef mst_id_t [2**AxiSlvPortIdWidth-1:0] slv_id_map_t; @@ -117,78 +172,49 @@ module axi_id_serialize #( /// Input-to-output ID map used localparam slv_id_map_t SlvIdMap = map_slv_ids(); - select_t slv_aw_select, slv_ar_select, slv_b_select, slv_r_select; + select_t slv_aw_select, slv_ar_select; assign slv_aw_select = select_t'(SlvIdMap[slv_req_i.aw.id]); assign slv_ar_select = select_t'(SlvIdMap[slv_req_i.ar.id]); slv_req_t [AxiMstPortMaxUniqIds-1:0] to_serializer_reqs; slv_resp_t [AxiMstPortMaxUniqIds-1:0] to_serializer_resps; - logic [AxiMstPortMaxUniqIds-1:0] to_serializer_resps_b_valid, - to_serializer_resps_r_valid; - - // Convert B response valid to index for selection - onehot_to_bin #( - .ONEHOT_WIDTH( AxiMstPortMaxUniqIds ) - ) i_slv_b_select ( - .onehot(to_serializer_resps_b_valid), - .bin (slv_b_select) - ); - - // Convert R response valid to index for selection - onehot_to_bin #( - .ONEHOT_WIDTH( AxiMstPortMaxUniqIds ) - ) i_slv_r_select ( - .onehot(to_serializer_resps_r_valid), - .bin (slv_r_select) + axi_demux #( + .AxiIdWidth ( AxiSlvPortIdWidth ), + .aw_chan_t ( slv_aw_t ), + .w_chan_t ( w_t ), + .b_chan_t ( slv_b_t ), + .ar_chan_t ( slv_ar_t ), + .r_chan_t ( slv_r_t ), + .axi_req_t ( slv_req_t ), + .axi_resp_t ( slv_resp_t ), + .NoMstPorts ( AxiMstPortMaxUniqIds ), + .MaxTrans ( AxiSlvPortMaxTxns ), + .AxiLookBits ( AxiSlvPortIdWidth ), + .AtopSupport ( AtopSupport ), + .SpillAw ( 1'b1 ), + .SpillW ( 1'b0 ), + .SpillB ( 1'b0 ), + .SpillAr ( 1'b1 ), + .SpillR ( 1'b0 ) + ) 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 ), + .slv_resp_o ( slv_resp_o ), + .mst_reqs_o ( to_serializer_reqs ), + .mst_resps_i ( to_serializer_resps ) ); - for (genvar i = 0; i < AxiMstPortMaxUniqIds; i++) begin - assign to_serializer_resps_b_valid[i] = to_serializer_resps[i].b_valid; - assign to_serializer_resps_r_valid[i] = to_serializer_resps[i].r_valid; - end - - // Due to static ID mapping, ID consistency checking is not needed. - always_comb begin - // AW, W, AR - for (int unsigned i = 0; i < AxiMstPortMaxUniqIds; i++) begin - to_serializer_reqs[i] = slv_req_i; // assigns.aw, .w, .ar - to_serializer_reqs[i].aw_valid = '0; - to_serializer_reqs[i].w_valid = '0; - to_serializer_reqs[i].ar_valid = '0; - end - - // Only pass AW to the selected serializer - to_serializer_reqs[slv_aw_select].aw_valid = slv_req_i.aw_valid; - slv_resp_o.aw_ready = to_serializer_resps[slv_aw_select].aw_ready; - - // W is always in order (i.e., serialized) and does not have ID field, pass through - slv_resp_o.w_ready = mst_resp_i.w_ready; - - // Only pass AR to the selected serializer - to_serializer_reqs[slv_ar_select].ar_valid = slv_req_i.ar_valid; - slv_resp_o.ar_ready = to_serializer_resps[slv_ar_select].ar_ready; - - // Recombine responses, only one will be active at a time - // B, R (these are passed through or both gated inside the serializer) - slv_resp_o.b_valid = |to_serializer_resps_b_valid; - slv_resp_o.b = to_serializer_resps[slv_b_select].b; - slv_resp_o.r_valid = |to_serializer_resps_r_valid; - slv_resp_o.r = to_serializer_resps[slv_r_select].r; - for (int unsigned i = 0; i < AxiMstPortMaxUniqIds; i++) begin - to_serializer_reqs[i].b_ready = slv_req_i.b_ready; - to_serializer_reqs[i].r_ready = slv_req_i.r_ready; - end - end - slv_req_t [AxiMstPortMaxUniqIds-1:0] tmp_serializer_reqs; slv_resp_t [AxiMstPortMaxUniqIds-1:0] tmp_serializer_resps; - mst_req_t [AxiMstPortMaxUniqIds-1:0] from_serializer_reqs; - mst_resp_t [AxiMstPortMaxUniqIds-1:0] from_serializer_resps; + ser_req_t [AxiMstPortMaxUniqIds-1:0] from_serializer_reqs; + ser_resp_t [AxiMstPortMaxUniqIds-1:0] from_serializer_resps; - // One serializer per desired ouput ID for (genvar i = 0; i < AxiMstPortMaxUniqIds; i++) begin : gen_serializers - // serializer takes care to ensure unique IDs for ATOPs axi_serializer #( .MaxReadTxns ( AxiMstPortMaxTxnsPerId ), .MaxWriteTxns ( AxiMstPortMaxTxnsPerId ), @@ -203,117 +229,113 @@ module axi_id_serialize #( .mst_req_o ( tmp_serializer_reqs[i] ), .mst_resp_i ( tmp_serializer_resps[i] ) ); - // Assign desired output ID always_comb begin `AXI_SET_REQ_STRUCT(from_serializer_reqs[i], tmp_serializer_reqs[i]) - from_serializer_reqs[i].aw.id = i; - from_serializer_reqs[i].ar.id = i; + // Truncate to ID width 1 as all requests have ID '0. + from_serializer_reqs[i].aw.id = tmp_serializer_reqs[i].aw.id[0]; + from_serializer_reqs[i].ar.id = tmp_serializer_reqs[i].ar.id[0]; `AXI_SET_RESP_STRUCT(tmp_serializer_resps[i], from_serializer_resps[i]) // Zero-extend response IDs. - tmp_serializer_resps[i].b.id = '0; - tmp_serializer_resps[i].r.id = '0; + tmp_serializer_resps[i].b.id = {{AxiSlvPortIdWidth-1{1'b0}}, from_serializer_resps[i].b.id}; + tmp_serializer_resps[i].r.id = {{AxiSlvPortIdWidth-1{1'b0}}, from_serializer_resps[i].r.id}; end end - logic [AxiMstPortMaxUniqIds-1:0] from_serializer_reqs_aw_valid, - from_serializer_reqs_ar_valid, - from_serializer_reqs_b_ready, - from_serializer_reqs_r_ready; - - select_t mst_aw_select, mst_ar_select; - - // Convert AW request valid to index for selection - onehot_to_bin #( - .ONEHOT_WIDTH( AxiMstPortMaxUniqIds ) - ) i_mst_aw_select ( - .onehot(from_serializer_reqs_aw_valid), - .bin (mst_aw_select) - ); - - // Convert AR request valid to index for selection - onehot_to_bin #( - .ONEHOT_WIDTH( AxiMstPortMaxUniqIds ) - ) i_mst_ar_select ( - .onehot(from_serializer_reqs_ar_valid), - .bin (mst_ar_select) - ); - - for (genvar i = 0; i < AxiMstPortMaxUniqIds; i++) begin - assign from_serializer_reqs_aw_valid[i] = from_serializer_reqs[i].aw_valid; - assign from_serializer_reqs_ar_valid[i] = from_serializer_reqs[i].ar_valid; - end - - mst_req_t mst_req; - logic mst_aw_ready, mst_ar_ready; - - always_comb begin - // Recombine AW requests, only one active at a time - mst_req.aw_valid = |from_serializer_reqs_aw_valid; - mst_req.aw = from_serializer_reqs[mst_aw_select].aw; - - // W is always in order (i.e., serialized) and does not have ID field, pass through - mst_req.w_valid = slv_req_i.w_valid; - mst_req.w = slv_req_i.w; - - // Recombine AR requests, only one active at a time - mst_req.ar_valid = |from_serializer_reqs_ar_valid; - mst_req.ar = from_serializer_reqs[mst_ar_select].ar; - - // AW/AR ready distributed, only one request active at a time - for (int unsigned i = 0; i < AxiMstPortMaxUniqIds; i++) begin - from_serializer_resps[i].aw_ready = mst_aw_ready; - from_serializer_resps[i].ar_ready = mst_ar_ready; - end - - // Distribute B and R responses to corresponding serializers - for (int unsigned i = 0; i < AxiMstPortMaxUniqIds; i++) begin - from_serializer_reqs_b_ready[i] = from_serializer_reqs[i].b_ready; - from_serializer_reqs_r_ready[i] = from_serializer_reqs[i].r_ready; - from_serializer_resps[i].b_valid = '0; - from_serializer_resps[i].r_valid = '0; - from_serializer_resps[i].b = mst_resp_i.b; - from_serializer_resps[i].r = mst_resp_i.r; - end - from_serializer_resps[mst_resp_i.b.id].b_valid = mst_resp_i.b_valid; - mst_req.b_ready = from_serializer_reqs[mst_resp_i.b.id].b_ready; - from_serializer_resps[mst_resp_i.r.id].r_valid = mst_resp_i.r_valid; - mst_req.r_ready = from_serializer_reqs[mst_resp_i.r.id].r_ready; - end - - // Optional spill register to help prevent timing loops - spill_register #( - .T ( mst_aw_t ), - .Bypass( ~SpillAx ) - ) i_aw_spill_reg ( + mux_req_t axi_mux_req; + mux_resp_t axi_mux_resp; + + axi_mux #( + .SlvAxiIDWidth ( 32'd1 ), + .slv_aw_chan_t ( ser_aw_t ), + .mst_aw_chan_t ( mux_aw_t ), + .w_chan_t ( w_t ), + .slv_b_chan_t ( ser_b_t ), + .mst_b_chan_t ( mux_b_t ), + .slv_ar_chan_t ( ser_ar_t ), + .mst_ar_chan_t ( mux_ar_t ), + .slv_r_chan_t ( ser_r_t ), + .mst_r_chan_t ( mux_r_t ), + .slv_req_t ( ser_req_t ), + .slv_resp_t ( ser_resp_t ), + .mst_req_t ( mux_req_t ), + .mst_resp_t ( mux_resp_t ), + .NoSlvPorts ( AxiMstPortMaxUniqIds ), + .MaxWTrans ( AxiMstPortMaxTxnsPerId ), + .FallThrough ( 1'b0 ), + .SpillAw ( 1'b1 ), + .SpillW ( 1'b0 ), + .SpillB ( 1'b0 ), + .SpillAr ( 1'b1 ), + .SpillR ( 1'b0 ) + ) i_axi_mux ( .clk_i, .rst_ni, - .valid_i( mst_req.aw_valid ), - .ready_o( mst_aw_ready ), - .data_i ( mst_req.aw), - .valid_o( mst_req_o.aw_valid ), - .ready_i( mst_resp_i.aw_ready ), - .data_o ( mst_req_o.aw ) + .test_i ( 1'b0 ), + .slv_reqs_i ( from_serializer_reqs ), + .slv_resps_o ( from_serializer_resps ), + .mst_req_o ( axi_mux_req ), + .mst_resp_i ( axi_mux_resp ) ); - // Optional spill register to help prevent timing loops - spill_register #( - .T ( mst_ar_t ), - .Bypass( ~SpillAx ) - ) i_ar_spill_reg ( - .clk_i, - .rst_ni, - .valid_i( mst_req.ar_valid ), - .ready_o( mst_ar_ready ), - .data_i ( mst_req.ar ), - .valid_o( mst_req_o.ar_valid ), - .ready_i( mst_resp_i.ar_ready ), - .data_o ( mst_req_o.ar ) - ); - - `AXI_ASSIGN_W_STRUCT(mst_req_o.w, mst_req.w) - assign mst_req_o.w_valid = mst_req.w_valid; - assign mst_req_o.b_ready = mst_req.b_ready; - assign mst_req_o.r_ready = mst_req.r_ready; + // Shift the ID one down if needed, as mux prepends IDs + if (MuxIdWidth > 32'd1) begin : gen_id_shift + always_comb begin + `AXI_SET_REQ_STRUCT(mst_req_o, axi_mux_req) + mst_req_o.aw.id = mst_id_t'(axi_mux_req.aw.id >> 32'd1); + mst_req_o.ar.id = mst_id_t'(axi_mux_req.ar.id >> 32'd1); + `AXI_SET_RESP_STRUCT(axi_mux_resp, mst_resp_i) + axi_mux_resp.b.id = mux_id_t'(mst_resp_i.b.id << 32'd1); + axi_mux_resp.r.id = mux_id_t'(mst_resp_i.r.id << 32'd1); + end + end else begin : gen_no_id_shift + axi_id_prepend #( + .NoBus ( 32'd1 ), + .AxiIdWidthSlvPort ( MuxIdWidth ), + .AxiIdWidthMstPort ( AxiMstPortIdWidth ), + .slv_aw_chan_t ( mux_aw_t ), + .slv_w_chan_t ( w_t ), + .slv_b_chan_t ( mux_b_t ), + .slv_ar_chan_t ( mux_ar_t ), + .slv_r_chan_t ( mux_r_t ), + .mst_aw_chan_t ( mst_aw_t ), + .mst_w_chan_t ( w_t ), + .mst_b_chan_t ( mst_b_t ), + .mst_ar_chan_t ( mst_ar_t ), + .mst_r_chan_t ( mst_r_t ) + ) i_axi_id_prepend ( + .pre_id_i ( '0 ), + .slv_aw_chans_i ( axi_mux_req.aw ), + .slv_aw_valids_i ( axi_mux_req.aw_valid ), + .slv_aw_readies_o ( axi_mux_resp.aw_ready ), + .slv_w_chans_i ( axi_mux_req.w ), + .slv_w_valids_i ( axi_mux_req.w_valid ), + .slv_w_readies_o ( axi_mux_resp.w_ready ), + .slv_b_chans_o ( axi_mux_resp.b ), + .slv_b_valids_o ( axi_mux_resp.b_valid ), + .slv_b_readies_i ( axi_mux_req.b_ready ), + .slv_ar_chans_i ( axi_mux_req.ar ), + .slv_ar_valids_i ( axi_mux_req.ar_valid ), + .slv_ar_readies_o ( axi_mux_resp.ar_ready ), + .slv_r_chans_o ( axi_mux_resp.r ), + .slv_r_valids_o ( axi_mux_resp.r_valid ), + .slv_r_readies_i ( axi_mux_req.r_ready ), + .mst_aw_chans_o ( mst_req_o.aw ), + .mst_aw_valids_o ( mst_req_o.aw_valid ), + .mst_aw_readies_i ( mst_resp_i.aw_ready ), + .mst_w_chans_o ( mst_req_o.w ), + .mst_w_valids_o ( mst_req_o.w_valid ), + .mst_w_readies_i ( mst_resp_i.w_ready ), + .mst_b_chans_i ( mst_resp_i.b ), + .mst_b_valids_i ( mst_resp_i.b_valid ), + .mst_b_readies_o ( mst_req_o.b_ready ), + .mst_ar_chans_o ( mst_req_o.ar ), + .mst_ar_valids_o ( mst_req_o.ar_valid ), + .mst_ar_readies_i ( mst_resp_i.ar_ready ), + .mst_r_chans_i ( mst_resp_i.r ), + .mst_r_valids_i ( mst_resp_i.r_valid ), + .mst_r_readies_o ( mst_req_o.r_ready ) + ); + end // pragma translate_off `ifndef VERILATOR @@ -347,18 +369,13 @@ endmodule /// See the documentation of the main module for the definition of ports and parameters. module axi_id_serialize_intf #( parameter int unsigned AXI_SLV_PORT_ID_WIDTH = 32'd0, + parameter int unsigned AXI_SLV_PORT_MAX_TXNS = 32'd0, parameter int unsigned AXI_MST_PORT_ID_WIDTH = 32'd0, parameter int unsigned AXI_MST_PORT_MAX_UNIQ_IDS = 32'd0, parameter int unsigned AXI_MST_PORT_MAX_TXNS_PER_ID = 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 MST_ID_BASE_OFFSET = 32'd0, - parameter int unsigned ID_MAP_NUM_ENTRIES = 32'd0, - parameter int unsigned ID_MAP [ID_MAP_NUM_ENTRIES-1:0][0:1] = '{default: {32'b0, 32'b0}}, - parameter bit SPILL_AX = 1'b1, - // Now unused, kept for backward compatibility - parameter int unsigned AXI_SLV_PORT_MAX_TXNS = 32'd0 + parameter int unsigned AXI_USER_WIDTH = 32'd0 ) ( input logic clk_i, input logic rst_ni, @@ -400,19 +417,17 @@ module axi_id_serialize_intf #( axi_id_serialize #( .AxiSlvPortIdWidth ( AXI_SLV_PORT_ID_WIDTH ), + .AxiSlvPortMaxTxns ( AXI_SLV_PORT_MAX_TXNS ), .AxiMstPortIdWidth ( AXI_MST_PORT_ID_WIDTH ), .AxiMstPortMaxUniqIds ( AXI_MST_PORT_MAX_UNIQ_IDS ), .AxiMstPortMaxTxnsPerId ( AXI_MST_PORT_MAX_TXNS_PER_ID ), .AxiAddrWidth ( AXI_ADDR_WIDTH ), + .AxiDataWidth ( AXI_DATA_WIDTH ), .AxiUserWidth ( AXI_USER_WIDTH ), .slv_req_t ( slv_req_t ), .slv_resp_t ( slv_resp_t ), .mst_req_t ( mst_req_t ), - .mst_resp_t ( mst_resp_t ), - .MstIdBaseOffset ( MST_ID_BASE_OFFSET ), - .IdMapNumEntries ( ID_MAP_NUM_ENTRIES ), - .IdMap ( ID_MAP ), - .SpillAx ( SPILL_AX ) + .mst_resp_t ( mst_resp_t ) ) i_axi_id_serialize ( .clk_i, .rst_ni, From 853ede23b2a9837951b74dbdc6d18c3eef5bac7d Mon Sep 17 00:00:00 2001 From: Thomas Benz Date: Thu, 24 Oct 2024 18:26:05 +0200 Subject: [PATCH 50/62] Release v0.39.5 --- CHANGELOG.md | 7 ++++++- VERSION | 2 +- axi.core | 2 +- ips_list.yml | 2 +- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ee650d9b5..7cf4ce384 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,10 +7,15 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## Unreleased +## 0.39.5 - 2024-10-24 + ### Fixed - Disabled the interface variant of `axi_xbar_unmuxed` for VCS, as VCS does not support multi-dimensional arrays of interfaces yet. -## 0.39.4 - 2024-07-25 +### Changed +- `axi_id_serialize`: Revert #342 to fix boot problems of CVA6 in Cheshire. + +## 0.39.4 - 2024-07-25 (Yanked 2024-10-23) ### Added - `axi_sim_mem`: Increase number of request ports, add multiport interface variant. - `axi_bus_compare`: Optionally consider AXI `size` field to only compare used data. diff --git a/VERSION b/VERSION index c02e508ca..adbb8d452 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.39.4 +0.39.5 diff --git a/axi.core b/axi.core index 5d17f61b9..eb38359ad 100644 --- a/axi.core +++ b/axi.core @@ -1,6 +1,6 @@ CAPI=2: -name : pulp-platform.org::axi:0.39.4 +name : pulp-platform.org::axi:0.39.5 filesets: rtl: diff --git a/ips_list.yml b/ips_list.yml index 7d797dea5..f47d6f660 100644 --- a/ips_list.yml +++ b/ips_list.yml @@ -1,5 +1,5 @@ common_cells: - commit: v1.31.1 + commit: v1.37.0 group: pulp-platform common_verification: From 1df5d5793f06ad8987d6e338e2908a105bad7e8b Mon Sep 17 00:00:00 2001 From: Nils Wistoff Date: Thu, 25 Jul 2024 20:54:59 +0200 Subject: [PATCH 51/62] axi_dw_upsizer: Make cases unique, add default Make the case statements in `axi_dw_upsizer` unique. Add default cases to prevent simulator warnings. Signed-off-by: Nils Wistoff --- src/axi_dw_upsizer.sv | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/src/axi_dw_upsizer.sv b/src/axi_dw_upsizer.sv index 9908b7860..6e96e98f4 100644 --- a/src/axi_dw_upsizer.sv +++ b/src/axi_dw_upsizer.sv @@ -359,7 +359,7 @@ module axi_dw_upsizer #( // Initialize r_data r_data = '0; - case (r_state_q) + unique case (r_state_q) R_IDLE : begin // Reset channels r_req_d.ar = '0; @@ -381,7 +381,7 @@ module axi_dw_upsizer #( r_req_d.burst_len = slv_req_i.ar.len ; r_req_d.orig_ar_size = slv_req_i.ar.size; - case (r_req_d.ar.burst) + unique case (r_req_d.ar.burst) axi_pkg::BURST_INCR: begin // Modifiable transaction if (modifiable(r_req_d.ar.cache)) begin @@ -413,6 +413,8 @@ module axi_dw_upsizer #( if (r_req_d.ar.len == '0) r_req_d.ar_throw_error = 1'b0; end + + default: ; endcase end end @@ -439,7 +441,7 @@ module axi_dw_upsizer #( // Default state r_state_d = R_PASSTHROUGH; - case (r_req_d.ar.burst) + unique case (r_req_d.ar.burst) axi_pkg::BURST_INCR: begin // Modifiable transaction if (modifiable(r_req_d.ar.cache)) begin @@ -471,6 +473,8 @@ module axi_dw_upsizer #( if (r_req_d.ar.len == '0) r_req_d.ar_throw_error = 1'b0; end + + default: ; endcase end @@ -499,22 +503,25 @@ module axi_dw_upsizer #( if (slv_r_ready_tran[t]) begin r_req_d.burst_len = r_req_q.burst_len - 1; - case (r_req_q.ar.burst) + unique case (r_req_q.ar.burst) axi_pkg::BURST_INCR: begin r_req_d.ar.addr = aligned_addr(r_req_q.ar.addr, r_req_q.orig_ar_size) + (1 << r_req_q.orig_ar_size); end axi_pkg::BURST_FIXED: begin r_req_d.ar.addr = r_req_q.ar.addr; end + default: ; endcase - case (r_state_q) + unique case (r_state_q) R_PASSTHROUGH: mst_r_ready_tran[t] = 1'b1; R_INCR_UPSIZE: if (r_req_q.burst_len == 0 || (aligned_addr(r_req_d.ar.addr, AxiMstPortMaxSize) != aligned_addr(r_req_q.ar.addr, AxiMstPortMaxSize))) mst_r_ready_tran[t] = 1'b1; + + default: ; endcase if (r_req_q.burst_len == '0) @@ -522,6 +529,8 @@ module axi_dw_upsizer #( end end end + + default: ; endcase end @@ -585,7 +594,7 @@ module axi_dw_upsizer #( w_req_d.aw_throw_error = 1'b0; end - case (w_state_q) + unique case (w_state_q) W_PASSTHROUGH, W_INCR_UPSIZE: begin // Got a grant on the W channel if (mst_req.w_valid && mst_resp.w_ready) begin @@ -617,16 +626,17 @@ module axi_dw_upsizer #( w_req_d.w.last = (w_req_q.burst_len == 0); w_req_d.w.user = slv_req_i.w.user ; - case (w_req_q.aw.burst) + unique case (w_req_q.aw.burst) axi_pkg::BURST_INCR: begin w_req_d.aw.addr = aligned_addr(w_req_q.aw.addr, w_req_q.orig_aw_size) + (1 << w_req_q.orig_aw_size); end axi_pkg::BURST_FIXED: begin w_req_d.aw.addr = w_req_q.aw.addr; end + default: ; endcase - case (w_state_q) + unique case (w_state_q) W_PASSTHROUGH: // Forward data as soon as we can w_req_d.w_valid = 1'b1; @@ -635,6 +645,7 @@ module axi_dw_upsizer #( // Forward when the burst is finished, or after filling up a word if (w_req_q.burst_len == 0 || (aligned_addr(w_req_d.aw.addr, AxiMstPortMaxSize) != aligned_addr(w_req_q.aw.addr, AxiMstPortMaxSize))) w_req_d.w_valid = 1'b1; + default: ; endcase end end @@ -645,6 +656,7 @@ module axi_dw_upsizer #( w_state_d = W_IDLE; end end + default: ; endcase // Can start a new request as soon as w_state_d is W_IDLE @@ -675,7 +687,7 @@ module axi_dw_upsizer #( w_req_d.burst_len = slv_req_i.aw.len ; w_req_d.orig_aw_size = slv_req_i.aw.size; - case (slv_req_i.aw.burst) + unique case (slv_req_i.aw.burst) axi_pkg::BURST_INCR: begin // Modifiable transaction if (modifiable(slv_req_i.aw.cache)) @@ -707,6 +719,8 @@ module axi_dw_upsizer #( if (slv_req_i.aw.len == '0) w_req_d.aw_throw_error = 1'b0; end + + default: ; endcase end end From 023859db1af967c492e60ccc4d848546072fedaa Mon Sep 17 00:00:00 2001 From: Olof Kindgren Date: Thu, 19 Sep 2024 14:25:43 +0200 Subject: [PATCH 52/62] Support connectivity in axi_intercon_gen This introduces support for partial connectivity in the axi_intercon generator. Also adds the missing PipelineStages parameter. --- axi.core | 5 +++++ scripts/axi_intercon_gen.py | 20 ++++++++++++++++---- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/axi.core b/axi.core index eb38359ad..d1a859168 100644 --- a/axi.core +++ b/axi.core @@ -137,11 +137,15 @@ generators: offset (int): Base address for the slave size (int): Size of the allocated memory map for the slave + slaves (list): List of device ports that this host is + connected to. A missing or empty list means + connection to all devices. Example usage: The following config will generate an interconnect wrapper to which two AXI4 master interfaces (dma and ibus) with different id widths are connected, and connects downstream to three AXI4 slaves (rom, gpio, ram) + The ibus port is only allowed to access the rom and ram ports. soc_intercon: generator: axi_intercon_gen @@ -151,6 +155,7 @@ generators: id_width : 1 ibus: id_width : 2 + slaves: [ram, rom] slaves: ram: offset : 0 diff --git a/scripts/axi_intercon_gen.py b/scripts/axi_intercon_gen.py index af5b3a209..c60c0f312 100644 --- a/scripts/axi_intercon_gen.py +++ b/scripts/axi_intercon_gen.py @@ -200,13 +200,12 @@ def load_dict(self, d): for key, value in d.items(): if key == 'slaves': # Handled in file loading, ignore here - continue - if key == 'id_width': + self.slaves = value + elif key == 'id_width': self.idw = value elif key == 'read_only': self.read_only = value else: - print(key) raise UnknownPropertyError( "Unknown property '%s' in master section '%s'" % ( key, self.name)) @@ -349,6 +348,7 @@ def write(self): MaxSlvTrans: 6, FallThrough: 1'b0, LatencyMode: axi_pkg::CUT_ALL_AX, + PipelineStages: 0, AxiIdWidthSlvPorts: AxiIdWidthMasters, AxiIdUsedSlvPorts: AxiIdUsed, UniqueIds: 1'b0, @@ -403,7 +403,18 @@ def write(self): raw += " mst_req_t [{}:0] slaves_req;\n".format(ns-1) raw += " mst_resp_t [{}:0] slaves_resp;\n".format(ns-1) - ns = len(self.slaves) + raw += f"\n localparam bit [{nm-1}:0][{ns-1}:0] connectivity = " + '{\n {' + connmap = [] + for master in reversed(self.masters): + connstr = f"{ns}'b" + if master.slaves: + for slave in reversed(self.slaves): + connstr += '1' if slave.name in master.slaves else '0' + else: + connstr += '1'*ns + connmap.append(connstr) + raw += "},\n {".join(connmap) + raw += "}};\n" raw += assigns(w, max_idw, self.masters, self.slaves) @@ -411,6 +422,7 @@ def write(self): parameters = [ Parameter('Cfg' , 'xbar_cfg' ), Parameter('ATOPs' , "1'b"+str(int(self.atop))), + Parameter('Connectivity' , 'connectivity'), Parameter('slv_aw_chan_t', 'aw_chan_mst_t'), Parameter('mst_aw_chan_t', 'aw_chan_slv_t'), Parameter('w_chan_t' , 'w_chan_t' ), From 58e7e2760a29353ca1be0d0decae1771ef8f7c29 Mon Sep 17 00:00:00 2001 From: Olof Kindgren Date: Thu, 19 Sep 2024 16:16:02 +0200 Subject: [PATCH 53/62] Use .sv suffix for generated axi_intercon file --- scripts/axi_intercon_gen.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/scripts/axi_intercon_gen.py b/scripts/axi_intercon_gen.py index c60c0f312..9e8e606d5 100644 --- a/scripts/axi_intercon_gen.py +++ b/scripts/axi_intercon_gen.py @@ -275,7 +275,7 @@ def construct_mapping(loader, node): print("Found slave " + k) self.slaves.append(Slave(k,v)) - self.output_file = config.get('output_file', 'axi_intercon.v') + self.output_file = config.get('output_file', 'axi_intercon.sv') self.atop = config.get('atop', False) def _dump(self): @@ -451,14 +451,15 @@ def write(self): _template_ports)) self.verilog_writer.write(file) - self.template_writer.write(file+'h') + template_file = file.split('.')[0]+'.vh' + self.template_writer.write(template_file) core_file = self.vlnv.split(':')[2]+'.core' vlnv = self.vlnv with open(core_file, 'w') as f: f.write('CAPI=2:\n') files = [{file : {'file_type' : 'systemVerilogSource'}}, - {file+'h' : {'is_include_file' : True, + {template_file : {'is_include_file' : True, 'file_type' : 'verilogSource'}} ] coredata = {'name' : vlnv, From c5ad81087956bff1e4eca2da101a264d5a385add Mon Sep 17 00:00:00 2001 From: Cyril Koenig Date: Fri, 25 Oct 2024 14:20:15 +0200 Subject: [PATCH 54/62] axi_pkg: Add iomsb to avoid underflow in array lengths --- src/axi_id_serialize.sv | 2 +- src/axi_pkg.sv | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/axi_id_serialize.sv b/src/axi_id_serialize.sv index 9a787dd25..671b38ad1 100644 --- a/src/axi_id_serialize.sv +++ b/src/axi_id_serialize.sv @@ -66,7 +66,7 @@ module axi_id_serialize #( /// Number of Entries in the explicit ID map (default: None) parameter int unsigned IdMapNumEntries = 32'd0, /// Explicit ID map; index [0] in each entry is the input ID to match, index [1] the output ID. - parameter int unsigned IdMap [IdMapNumEntries-1:0][0:1] = '{default: {32'b0, 32'b0}} + parameter int unsigned IdMap [axi_pkg::iomsb(IdMapNumEntries):0][0:1] = '{default: {32'b0, 32'b0}} ) ( /// Rising-edge clock of both ports input logic clk_i, diff --git a/src/axi_pkg.sv b/src/axi_pkg.sv index 4102be0e8..6e6450bbd 100644 --- a/src/axi_pkg.sv +++ b/src/axi_pkg.sv @@ -532,4 +532,9 @@ package axi_pkg; logic [31:0] end_addr; } xbar_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; + endfunction + endpackage From c51579377f77d74d9e114342dcca67b3c18062ff Mon Sep 17 00:00:00 2001 From: Aleksi Korsman <34690092+Roenski@users.noreply.github.com> Date: Mon, 4 Nov 2024 12:21:30 +0100 Subject: [PATCH 55/62] Fix write channel assertions --- src/axi_rw_split.sv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/axi_rw_split.sv b/src/axi_rw_split.sv index 6fa96dfa9..5301d0359 100644 --- a/src/axi_rw_split.sv +++ b/src/axi_rw_split.sv @@ -94,7 +94,7 @@ module axi_rw_split #( assign mst_write_req_o.r_ready = 1'b0; // check for R never to be valid - `ASSERT_NEVER(mst_read_resp_r_valid, mst_read_resp_i.r_valid, clk_i, !rst_ni) + `ASSERT_NEVER(mst_write_resp_r_valid, mst_write_resp_i.r_valid, clk_i, !rst_ni) // Write AW channel handshake assign mst_write_req_o.aw_valid = slv_req_i.aw_valid; From f162b4cc6c2e25eccc1055511c2beab2b2ef5f7a Mon Sep 17 00:00:00 2001 From: aottaviano Date: Fri, 15 Nov 2024 19:38:49 +0100 Subject: [PATCH 56/62] src/axi_isolate.sv: Tie unused demux port in passthrough termination --- src/axi_isolate.sv | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/axi_isolate.sv b/src/axi_isolate.sv index 6385b2633..b5596e7f9 100644 --- a/src/axi_isolate.sv +++ b/src/axi_isolate.sv @@ -142,6 +142,9 @@ module axi_isolate #( end else begin assign demux_req[0] = slv_req_i; assign slv_resp_o = demux_rsp[0]; + // In pass-through, silence the second demux port as it is not used + assign demux_req[1] = '0; + assign demux_rsp[1] = '0; end axi_isolate_inner #( From 93e8a6fda4199b504a089c601dc61002e1f3bfd1 Mon Sep 17 00:00:00 2001 From: Luca Rufer Date: Wed, 13 Nov 2024 13:43:16 +0100 Subject: [PATCH 57/62] VCS and Verilator support --- src/axi_sim_mem.sv | 4 ++-- src/axi_test.sv | 28 ++++++++++++++-------------- test/tb_axi_dw_pkg.sv | 2 +- test/tb_axi_xbar_pkg.sv | 2 +- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/axi_sim_mem.sv b/src/axi_sim_mem.sv index 9bf164229..e2aa5c985 100644 --- a/src/axi_sim_mem.sv +++ b/src/axi_sim_mem.sv @@ -116,8 +116,8 @@ module axi_sim_mem #( monitor_t [NumPorts-1:0] mon_w, mon_r; logic [7:0] mem[addr_t]; - axi_pkg::resp_t rerr[addr_t] = '{default: axi_pkg::RESP_OKAY}; - axi_pkg::resp_t werr[addr_t] = '{default: axi_pkg::RESP_OKAY}; + axi_pkg::resp_t rerr[addr_t] = '{default: 2'b0}; + axi_pkg::resp_t werr[addr_t] = '{default: 2'b0}; // error happened in write burst axi_pkg::resp_t [NumPorts-1:0] error_happened = axi_pkg::RESP_OKAY; diff --git a/src/axi_test.sv b/src/axi_test.sv index ce8638343..39c370945 100644 --- a/src/axi_test.sv +++ b/src/axi_test.sv @@ -226,9 +226,9 @@ package axi_test; /// The data transferred on a beat on the AW/AR channels. class axi_ax_beat #( - parameter AW = 32, - parameter IW = 8 , - parameter UW = 1 + parameter int AW = 32, + parameter int IW = 8 , + parameter int UW = 1 ); rand logic [IW-1:0] ax_id = '0; rand logic [AW-1:0] ax_addr = '0; @@ -246,8 +246,8 @@ package axi_test; /// The data transferred on a beat on the W channel. class axi_w_beat #( - parameter DW = 32, - parameter UW = 1 + parameter int DW = 32, + parameter int UW = 1 ); rand logic [DW-1:0] w_data = '0; rand logic [DW/8-1:0] w_strb = '0; @@ -257,8 +257,8 @@ package axi_test; /// The data transferred on a beat on the B channel. class axi_b_beat #( - parameter IW = 8, - parameter UW = 1 + parameter int IW = 8, + parameter int UW = 1 ); rand logic [IW-1:0] b_id = '0; axi_pkg::resp_t b_resp = '0; @@ -267,9 +267,9 @@ package axi_test; /// The data transferred on a beat on the R channel. class axi_r_beat #( - parameter DW = 32, - parameter IW = 8 , - parameter UW = 1 + parameter int DW = 32, + parameter int IW = 8 , + parameter int UW = 1 ); rand logic [IW-1:0] r_id = '0; rand logic [DW-1:0] r_data = '0; @@ -747,7 +747,7 @@ package axi_test; len_t max_len; burst_t allowed_bursts[$]; - semaphore cnt_sem; + std::semaphore cnt_sem; ax_beat_t aw_queue[$], w_queue[$], @@ -1037,7 +1037,7 @@ package axi_test; automatic addr_t addr_mask; // In an exclusive burst, the number of bytes to be transferred must be a power of 2, i.e., // 1, 2, 4, 8, 16, 32, 64, or 128 bytes, and the burst length must not exceed 16 transfers. - static int unsigned ul = (AXI_STRB_WIDTH < 8) ? 4 + $clog2(AXI_STRB_WIDTH) : 7; + int unsigned ul = (AXI_STRB_WIDTH < 8) ? 4 + $clog2(AXI_STRB_WIDTH) : 7; rand_success = std::randomize(n_bytes) with { n_bytes >= 1; n_bytes <= ul; @@ -1848,8 +1848,8 @@ package axi_test; typedef axi_driver_t::r_beat_t r_beat_t; axi_driver_t drv; - mailbox aw_mbx = new, w_mbx = new, b_mbx = new, - ar_mbx = new, r_mbx = new; + std::mailbox aw_mbx = new, w_mbx = new, b_mbx = new, + ar_mbx = new, r_mbx = new; function new( virtual AXI_BUS_DV #( diff --git a/test/tb_axi_dw_pkg.sv b/test/tb_axi_dw_pkg.sv index d211da2ae..439b78aac 100644 --- a/test/tb_axi_dw_pkg.sv +++ b/test/tb_axi_dw_pkg.sv @@ -134,7 +134,7 @@ package tb_axi_dw_pkg ; longint unsigned tests_expected; longint unsigned tests_conducted; longint unsigned tests_failed; - semaphore cnt_sem; + std::semaphore cnt_sem; // Queues and FIFOs to hold the expected AXIDs diff --git a/test/tb_axi_xbar_pkg.sv b/test/tb_axi_xbar_pkg.sv index fb7098998..3c90fcca1 100644 --- a/test/tb_axi_xbar_pkg.sv +++ b/test/tb_axi_xbar_pkg.sv @@ -101,7 +101,7 @@ package tb_axi_xbar_pkg; longint unsigned tests_expected; longint unsigned tests_conducted; longint unsigned tests_failed; - semaphore cnt_sem; + std::semaphore cnt_sem; //----------------------------------------- // Constructor From 8ea752f0658568c65fce4c03792108722fb1a58c Mon Sep 17 00:00:00 2001 From: Luca Rufer Date: Mon, 2 Dec 2024 17:10:50 +0100 Subject: [PATCH 58/62] Update parameters to 'int unsigned' in AXI_test --- src/axi_test.sv | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/axi_test.sv b/src/axi_test.sv index 39c370945..a6118b99a 100644 --- a/src/axi_test.sv +++ b/src/axi_test.sv @@ -226,9 +226,9 @@ package axi_test; /// The data transferred on a beat on the AW/AR channels. class axi_ax_beat #( - parameter int AW = 32, - parameter int IW = 8 , - parameter int UW = 1 + parameter int unsigned AW = 32, + parameter int unsigned IW = 8 , + parameter int unsigned UW = 1 ); rand logic [IW-1:0] ax_id = '0; rand logic [AW-1:0] ax_addr = '0; @@ -246,8 +246,8 @@ package axi_test; /// The data transferred on a beat on the W channel. class axi_w_beat #( - parameter int DW = 32, - parameter int UW = 1 + parameter int unsigned DW = 32, + parameter int unsigned UW = 1 ); rand logic [DW-1:0] w_data = '0; rand logic [DW/8-1:0] w_strb = '0; @@ -257,8 +257,8 @@ package axi_test; /// The data transferred on a beat on the B channel. class axi_b_beat #( - parameter int IW = 8, - parameter int UW = 1 + parameter int unsigned IW = 8, + parameter int unsigned UW = 1 ); rand logic [IW-1:0] b_id = '0; axi_pkg::resp_t b_resp = '0; @@ -267,9 +267,9 @@ package axi_test; /// The data transferred on a beat on the R channel. class axi_r_beat #( - parameter int DW = 32, - parameter int IW = 8 , - parameter int UW = 1 + parameter int unsigned DW = 32, + parameter int unsigned IW = 8 , + parameter int unsigned UW = 1 ); rand logic [IW-1:0] r_id = '0; rand logic [DW-1:0] r_data = '0; @@ -281,12 +281,12 @@ package axi_test; /// A driver for AXI4 interface. class axi_driver #( - parameter int AW = 32 , - parameter int DW = 32 , - parameter int IW = 8 , - parameter int UW = 1 , - parameter time TA = 0ns , // stimuli application time - parameter time TT = 0ns // stimuli test time + parameter int unsigned AW = 32 , + parameter int unsigned DW = 32 , + parameter int unsigned IW = 8 , + parameter int unsigned UW = 1 , + parameter time TA = 0ns , // stimuli application time + parameter time TT = 0ns // stimuli test time ); virtual AXI_BUS_DV #( .AXI_ADDR_WIDTH(AW), From 408c7fe463cf078257be20dbde31df4280fc1203 Mon Sep 17 00:00:00 2001 From: Luca Rufer Date: Mon, 2 Dec 2024 17:31:15 +0100 Subject: [PATCH 59/62] Add comments to axi_sim_mem --- src/axi_sim_mem.sv | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/axi_sim_mem.sv b/src/axi_sim_mem.sv index e2aa5c985..b6125ec38 100644 --- a/src/axi_sim_mem.sv +++ b/src/axi_sim_mem.sv @@ -116,8 +116,10 @@ module axi_sim_mem #( monitor_t [NumPorts-1:0] mon_w, mon_r; logic [7:0] mem[addr_t]; - axi_pkg::resp_t rerr[addr_t] = '{default: 2'b0}; - axi_pkg::resp_t werr[addr_t] = '{default: 2'b0}; + axi_pkg::resp_t rerr[addr_t] = '{default: 2'b0}; // default: 'axi_pkg::RESP_OKAY' + axi_pkg::resp_t werr[addr_t] = '{default: 2'b0}; // default: 'axi_pkg::RESP_OKAY' + // Verilator cannot determine the type of 'axi_pkg::RESP_OKAY' in this context. + // The 'axi_pkg::RESP_OKAY' is expanded to 0 for Verilator compatibility. // error happened in write burst axi_pkg::resp_t [NumPorts-1:0] error_happened = axi_pkg::RESP_OKAY; From 509e0fbdada19152c5055811ae7f82fe1f86b75e Mon Sep 17 00:00:00 2001 From: Luca Rufer Date: Mon, 2 Dec 2024 17:39:38 +0100 Subject: [PATCH 60/62] Fix verilator comment --- src/axi_sim_mem.sv | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/axi_sim_mem.sv b/src/axi_sim_mem.sv index b6125ec38..4080e361c 100644 --- a/src/axi_sim_mem.sv +++ b/src/axi_sim_mem.sv @@ -118,8 +118,8 @@ module axi_sim_mem #( logic [7:0] mem[addr_t]; axi_pkg::resp_t rerr[addr_t] = '{default: 2'b0}; // default: 'axi_pkg::RESP_OKAY' axi_pkg::resp_t werr[addr_t] = '{default: 2'b0}; // default: 'axi_pkg::RESP_OKAY' - // Verilator cannot determine the type of 'axi_pkg::RESP_OKAY' in this context. - // The 'axi_pkg::RESP_OKAY' is expanded to 0 for Verilator compatibility. + // - Verilator cannot determine the type of 'axi_pkg::RESP_OKAY' in this context. + // The 'axi_pkg::RESP_OKAY' is expanded to 0 for Verilator compatibility. // error happened in write burst axi_pkg::resp_t [NumPorts-1:0] error_happened = axi_pkg::RESP_OKAY; From 39f5f2d51c5e524f6fc5cf8b6e901f7dcc5622d7 Mon Sep 17 00:00:00 2001 From: Thomas Benz Date: Wed, 4 Dec 2024 14:10:16 +0100 Subject: [PATCH 61/62] Release v0.39.6 --- Bender.yml | 2 +- CHANGELOG.md | 14 ++++++++++++++ VERSION | 2 +- axi.core | 4 ++-- ips_list.yml | 2 +- 5 files changed, 19 insertions(+), 5 deletions(-) diff --git a/Bender.yml b/Bender.yml index f30fcff2d..9dbf0e6ad 100644 --- a/Bender.yml +++ b/Bender.yml @@ -20,7 +20,7 @@ package: dependencies: common_cells: { git: "https://github.com/pulp-platform/common_cells.git", version: 1.37.0 } - common_verification: { git: "https://github.com/pulp-platform/common_verification.git", version: 0.2.3 } + common_verification: { git: "https://github.com/pulp-platform/common_verification.git", version: 0.2.4 } tech_cells_generic: { git: "https://github.com/pulp-platform/tech_cells_generic.git", version: 0.2.2 } export_include_dirs: diff --git a/CHANGELOG.md b/CHANGELOG.md index 7cf4ce384..351a5b5ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,20 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## Unreleased +## 0.39.6 - 2024-12-04 +### Added +- Support connectivity in `axi_intercon_gen`. #351 +- Add `iomsb` function to avoid underflow in array lengths to `axi_pkg`. #355 + +### Fixed +- Make the case statements in `axi_dw_upsizer` unique. Add default cases to prevent simulator warnings. #348 +- Fix write channel assertions in `axi_rw_split`. #357 +- Tie unused `demux` port in pass-through termination in `axi_isolate`. #359 + +### Changed +- Improve VCS and Verilator support treewide. #358 +- Update `common_verification` to `v0.2.4` to include Verilator fixes. + ## 0.39.5 - 2024-10-24 ### Fixed diff --git a/VERSION b/VERSION index adbb8d452..e5d9eb181 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.39.5 +0.39.6 diff --git a/axi.core b/axi.core index d1a859168..4f83844ba 100644 --- a/axi.core +++ b/axi.core @@ -1,6 +1,6 @@ CAPI=2: -name : pulp-platform.org::axi:0.39.5 +name : pulp-platform.org::axi:0.39.6 filesets: rtl: @@ -109,7 +109,7 @@ filesets: - test/tb_axi_xbar.sv file_type : systemVerilogSource depend : - - ">=pulp-platform.org::common_verification:0.2.3" + - ">=pulp-platform.org::common_verification:0.2.4" generators: axi_intercon_gen: diff --git a/ips_list.yml b/ips_list.yml index f47d6f660..c0f7edb06 100644 --- a/ips_list.yml +++ b/ips_list.yml @@ -3,7 +3,7 @@ common_cells: group: pulp-platform common_verification: - commit: v0.2.3 + commit: v0.2.4 group: pulp-platform tech_cells_generic: From 14b59d8ab1f16a5aad70ea9f3654edb3dd593672 Mon Sep 17 00:00:00 2001 From: Thomas Benz Date: Tue, 10 Dec 2024 21:56:29 +0100 Subject: [PATCH 62/62] Add random user signal generation for llc-partition test (#315) * Add random user signal generation for llc-partition test * AX User Randomization: Change previous user_rand function to a more compatible version. Add two ports for axi_rand_master class: AX_USER_RANGE for configuring the range of randomizing the aw/ar user signal, and AX_USER_RAND to turn on/off the random user signal functionality. The function is set as default-off. * Rebase on to latest main. --------- Co-authored-by: Diyou Shen --- src/axi_test.sv | 56 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 42 insertions(+), 14 deletions(-) diff --git a/src/axi_test.sv b/src/axi_test.sv index a6118b99a..5300a86b2 100644 --- a/src/axi_test.sv +++ b/src/axi_test.sv @@ -712,7 +712,10 @@ package axi_test; // same direction // Dependent parameters, do not override. parameter int AXI_STRB_WIDTH = DW/8, - parameter int N_AXI_IDS = 2**IW + parameter int N_AXI_IDS = 2**IW, + parameter int AX_USER_RANGE = 1, // The upper limit of randomized ax user signal + parameter bit AX_USER_RAND = 0 // set to 1 to enable randomize aw/ar user signal + // 0 <= user < AX_USER_RANGE ); typedef axi_test::axi_driver #( .AW(AW), .DW(DW), .IW(IW), .UW(UW), .TA(TA), .TT(TT) @@ -832,7 +835,26 @@ package axi_test; max_cprob = traffic_shape[$].cprob; endfunction : add_traffic_shaping_with_size - function ax_beat_t new_rand_burst(input logic is_read); + /// Cache-Partition + // This function is used to generate a random PatID every time send a + // burst of R/W requests down to the cache. Therefore, within one test, + // its PatID will be fixed and we can call multiple tests to test the + // partition functionalities. + function user_t rand_user(input int unsigned user_range, input logic user_rand); + static logic rand_success; + automatic user_t user; + if (user_rand) begin + rand_success = std::randomize(user) with { + user >= 0; user < user_range; + }; assert(rand_success); + end else begin + user = '0; + end + return user; + endfunction + + // Cache-Partition: add user signal as an input + function ax_beat_t new_rand_burst(input logic is_read, input user_t user); automatic logic rand_success; automatic ax_beat_t ax_beat = new; automatic addr_t addr; @@ -946,10 +968,11 @@ package axi_test; // 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 - task rand_atop_burst(inout ax_beat_t beat); + task rand_atop_burst(inout ax_beat_t beat, input user_t user); automatic logic rand_success; forever begin beat.ax_atop[5:4] = $random(); @@ -1021,13 +1044,13 @@ package axi_test; axi_pkg::beat_addr(beat.ax_addr, beat.ax_size, beat.ax_len, beat.ax_burst, beat.ax_len) >> 12) begin break; end else begin - beat = new_rand_burst(1'b0); + beat = new_rand_burst(1'b0, user); end end end endtask - function void rand_excl_ar(inout ax_beat_t ar_beat); + function void rand_excl_ar(inout ax_beat_t ar_beat, input user_t user); forever begin ar_beat.ax_lock = $random(); if (ar_beat.ax_lock) begin @@ -1059,7 +1082,7 @@ package axi_test; axi_pkg::beat_addr(ar_beat.ax_addr, ar_beat.ax_size, ar_beat.ax_len, ar_beat.ax_burst, ar_beat.ax_len) >> 12) begin break; end else begin - ar_beat = new_rand_burst(1'b1); + ar_beat = new_rand_burst(1'b1, user); end end endfunction @@ -1142,16 +1165,17 @@ package axi_test; cnt_sem.put(); endtask - task send_ars(input int n_reads); + // Cache-Partition: add user signal as an input + task send_ars(input int n_reads, input user_t user); automatic logic rand_success; repeat (n_reads) begin automatic id_t id; - automatic ax_beat_t ar_beat = new_rand_burst(1'b1); + automatic ax_beat_t ar_beat = new_rand_burst(1'b1, user); while (tot_r_flight_cnt >= MAX_READ_TXNS) begin rand_wait(1, 1); end if (AXI_EXCLS) begin - rand_excl_ar(ar_beat); + rand_excl_ar(ar_beat, user); end legalize_id(1'b1, ar_beat); rand_wait(AX_MIN_WAIT_CYCLES, AX_MAX_WAIT_CYCLES); @@ -1184,7 +1208,8 @@ package axi_test; end endtask - task create_aws(input int n_writes); + // Cache-Partition: add user signal as an input + task create_aws(input int n_writes, input user_t user); automatic logic rand_success; repeat (n_writes) begin automatic bit excl = 1'b0; @@ -1193,8 +1218,8 @@ package axi_test; if (excl) begin aw_beat = excl_queue.pop_front(); end else begin - aw_beat = new_rand_burst(1'b0); - if (AXI_ATOPS) rand_atop_burst(aw_beat); + aw_beat = new_rand_burst(1'b0, user); + if (AXI_ATOPS) rand_atop_burst(aw_beat, user); end while (tot_w_flight_cnt >= MAX_WRITE_TXNS) begin rand_wait(1, 1); @@ -1268,18 +1293,21 @@ package axi_test; end endtask + // Cache-Partition: add user signal as an input // Issue n_reads random read and n_writes random write transactions to an address range. task run(input int n_reads, input int n_writes); automatic logic ar_done = 1'b0, aw_done = 1'b0; fork + // Cache-Partition: randomize the patid + automatic user_t ax_user = rand_user(AX_USER_RANGE, AX_USER_RAND); begin - send_ars(n_reads); + send_ars(n_reads, ax_user); ar_done = 1'b1; end recv_rs(ar_done, aw_done); begin - create_aws(n_writes); + create_aws(n_writes, ax_user); aw_done = 1'b1; end send_aws(aw_done);