diff --git a/Bender.yml b/Bender.yml index 5c1f43a14..dd3365ef2 100644 --- a/Bender.yml +++ b/Bender.yml @@ -17,7 +17,7 @@ package: - "Florian Zaruba " dependencies: - common_cells: { git: "https://github.com/pulp-platform/common_cells.git", version: 1.26.0 } + common_cells: { git: "https://github.com/pulp-platform/common_cells.git", rev: mem_to_banks-tbenz } 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 686794c1b..27d771590 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - `axi_xbar`: Add parameter `PipelineStages` to `axi_pkg::xbar_cfg_t`. This adds `axi_multicuts` in the crossed connections in the xbar between the demuxes and muxes. - `axi_pkg`: Add documentation to `xbar_cfg_t`. +- Move `mem_to_banks` to `common_cells`. +- Update `common_cells` from version `v1.26.0` to `v1.xx.yy`. - `axi_pkg`: Define `localparams` to define AXI type widths. ### Fixed diff --git a/src/axi_to_mem.sv b/src/axi_to_mem.sv index 1b8fd590e..03d2caf26 100644 --- a/src/axi_to_mem.sv +++ b/src/axi_to_mem.sv @@ -350,12 +350,13 @@ module axi_to_mem #( // Split single memory request to desired number of banks. mem_to_banks #( - .AddrWidth ( AddrWidth ), - .DataWidth ( DataWidth ), - .NumBanks ( NumBanks ), - .HideStrb ( HideStrb ), - .MaxTrans ( BufDepth ), - .FifoDepth ( OutFifoDepth ) + .AddrWidth ( AddrWidth ), + .DataWidth ( DataWidth ), + .NumBanks ( NumBanks ), + .HideStrb ( HideStrb ), + .MaxTrans ( BufDepth ), + .FifoDepth ( OutFifoDepth ), + .atop_t ( axi_pkg::atop_t ) ) i_mem_to_banks ( .clk_i, .rst_ni, @@ -557,202 +558,3 @@ module axi_to_mem_intf #( .mem_rdata_i ); endmodule - -/// Split memory access over multiple parallel banks, where each bank has its own req/gnt -/// request and valid response direction. -module mem_to_banks #( - /// Input address width. - parameter int unsigned AddrWidth = 32'd0, - /// Input data width, must be a power of two. - parameter int unsigned DataWidth = 32'd0, - /// Number of banks at output, must evenly divide `DataWidth`. - parameter int unsigned NumBanks = 32'd0, - /// Remove transactions that have zero strobe - parameter bit HideStrb = 1'b0, - /// Number of outstanding transactions - parameter int unsigned MaxTrans = 32'b1, - /// FIFO depth, must be >=1 - parameter int unsigned FifoDepth = 1, - /// Dependent parameter, do not override! Address type. - localparam type addr_t = logic [AddrWidth-1:0], - /// Dependent parameter, do not override! Input data type. - localparam type inp_data_t = logic [DataWidth-1:0], - /// Dependent parameter, do not override! Input write strobe type. - localparam type inp_strb_t = logic [DataWidth/8-1:0], - /// Dependent parameter, do not override! Output data type. - localparam type oup_data_t = logic [DataWidth/NumBanks-1:0], - /// Dependent parameter, do not override! Output write strobe type. - localparam type oup_strb_t = logic [DataWidth/NumBanks/8-1:0] -) ( - /// Clock input. - input logic clk_i, - /// Asynchronous reset, active low. - input logic rst_ni, - /// Memory request to split, request is valid. - input logic req_i, - /// Memory request to split, request can be granted. - output logic gnt_o, - /// Memory request to split, request address, byte-wise. - input addr_t addr_i, - /// Memory request to split, request write data. - input inp_data_t wdata_i, - /// Memory request to split, request write strobe. - input inp_strb_t strb_i, - /// Memory request to split, request Atomic signal from AXI4+ATOP. - input axi_pkg::atop_t atop_i, - /// Memory request to split, request write enable, active high. - input logic we_i, - /// Memory request to split, response is valid. Required for read and write requests - output logic rvalid_o, - /// Memory request to split, response read data. - output inp_data_t rdata_o, - /// Memory bank request, request is valid. - output logic [NumBanks-1:0] bank_req_o, - /// Memory bank request, request can be granted. - input logic [NumBanks-1:0] bank_gnt_i, - /// Memory bank request, request address, byte-wise. Will be different for each bank. - output addr_t [NumBanks-1:0] bank_addr_o, - /// Memory bank request, request write data. - output oup_data_t [NumBanks-1:0] bank_wdata_o, - /// Memory bank request, request write strobe. - output oup_strb_t [NumBanks-1:0] bank_strb_o, - /// Memory bank request, request Atomic signal from AXI4+ATOP. - output axi_pkg::atop_t [NumBanks-1:0] bank_atop_o, - /// Memory bank request, request write enable, active high. - output logic [NumBanks-1:0] bank_we_o, - /// Memory bank request, response is valid. Required for read and write requests - input logic [NumBanks-1:0] bank_rvalid_i, - /// Memory bank request, response read data. - input oup_data_t [NumBanks-1:0] bank_rdata_i -); - - localparam DataBytes = $bits(inp_strb_t); - localparam BitsPerBank = $bits(oup_data_t); - localparam BytesPerBank = $bits(oup_strb_t); - - typedef struct packed { - addr_t addr; - oup_data_t wdata; - oup_strb_t strb; - axi_pkg::atop_t atop; - logic we; - } req_t; - - logic req_valid; - logic [NumBanks-1:0] req_ready, - resp_valid, resp_ready; - req_t [NumBanks-1:0] bank_req, - bank_oup; - logic [NumBanks-1:0] bank_req_internal, bank_gnt_internal, zero_strobe, dead_response; - logic dead_write_fifo_full; - - function automatic addr_t align_addr(input addr_t addr); - return (addr >> $clog2(DataBytes)) << $clog2(DataBytes); - endfunction - - // Handle requests. - assign req_valid = req_i & gnt_o; - for (genvar i = 0; unsigned'(i) < NumBanks; i++) begin : gen_reqs - assign bank_req[i].addr = align_addr(addr_i) + i * BytesPerBank; - assign bank_req[i].wdata = wdata_i[i*BitsPerBank+:BitsPerBank]; - assign bank_req[i].strb = strb_i[i*BytesPerBank+:BytesPerBank]; - assign bank_req[i].atop = atop_i; - assign bank_req[i].we = we_i; - stream_fifo #( - .FALL_THROUGH ( 1'b1 ), - .DATA_WIDTH ( $bits(req_t) ), - .DEPTH ( FifoDepth ), - .T ( req_t ) - ) i_ft_reg ( - .clk_i, - .rst_ni, - .flush_i ( 1'b0 ), - .testmode_i ( 1'b0 ), - .usage_o (), - .data_i ( bank_req[i] ), - .valid_i ( req_valid ), - .ready_o ( req_ready[i] ), - .data_o ( bank_oup[i] ), - .valid_o ( bank_req_internal[i] ), - .ready_i ( bank_gnt_internal[i] ) - ); - assign bank_addr_o[i] = bank_oup[i].addr; - assign bank_wdata_o[i] = bank_oup[i].wdata; - assign bank_strb_o[i] = bank_oup[i].strb; - assign bank_atop_o[i] = bank_oup[i].atop; - assign bank_we_o[i] = bank_oup[i].we; - - assign zero_strobe[i] = (bank_oup[i].strb == '0); - - if (HideStrb) begin - assign bank_req_o[i] = (bank_oup[i].we && zero_strobe[i]) ? 1'b0 : bank_req_internal[i]; - assign bank_gnt_internal[i] = (bank_oup[i].we && zero_strobe[i]) ? 1'b1 : bank_gnt_i[i]; - end else begin - assign bank_req_o[i] = bank_req_internal[i]; - assign bank_gnt_internal[i] = bank_gnt_i[i]; - end - end - - // Grant output if all our requests have been granted. - assign gnt_o = (&req_ready) & (&resp_ready) & !dead_write_fifo_full; - - if (HideStrb) begin : gen_dead_write_fifo - fifo_v3 #( - .FALL_THROUGH ( 1'b1 ), - .DEPTH ( MaxTrans+1 ), - .DATA_WIDTH ( NumBanks ) - ) i_dead_write_fifo ( - .clk_i, - .rst_ni, - .flush_i ( 1'b0 ), - .testmode_i ( 1'b0 ), - .full_o ( dead_write_fifo_full ), - .empty_o (), - .usage_o (), - .data_i ( bank_we_o & zero_strobe ), - .push_i ( req_i & gnt_o ), - .data_o ( dead_response ), - .pop_i ( rvalid_o ) - ); - end else begin - assign dead_response = '0; - assign dead_write_fifo_full = 1'b0; - end - - // Handle responses. - for (genvar i = 0; unsigned'(i) < NumBanks; i++) begin : gen_resp_regs - stream_fifo #( - .FALL_THROUGH ( 1'b1 ), - .DATA_WIDTH ( $bits(oup_data_t) ), - .DEPTH ( FifoDepth ), - .T ( oup_data_t ) - ) i_ft_reg ( - .clk_i, - .rst_ni, - .flush_i ( 1'b0 ), - .testmode_i ( 1'b0 ), - .usage_o (), - .data_i ( bank_rdata_i[i] ), - .valid_i ( bank_rvalid_i[i] ), - .ready_o ( resp_ready[i] ), - .data_o ( rdata_o[i*BitsPerBank+:BitsPerBank] ), - .valid_o ( resp_valid[i] ), - .ready_i ( rvalid_o & !dead_response[i] ) - ); - end - assign rvalid_o = &(resp_valid | dead_response); - - // Assertions - // pragma translate_off - `ifndef VERILATOR - initial begin - assume (DataWidth != 0 && (DataWidth & (DataWidth - 1)) == 0) - else $fatal(1, "Data width must be a power of two!"); - assume (DataWidth % NumBanks == 0) - else $fatal(1, "Data width must be evenly divisible over banks!"); - assume ((DataWidth / NumBanks) % 8 == 0) - else $fatal(1, "Data width of each bank must be divisible into 8-bit bytes!"); - end - `endif - // pragma translate_on -endmodule