Skip to content

Commit

Permalink
mem_to_banks: Move from axi to common_cells
Browse files Browse the repository at this point in the history
  • Loading branch information
thommythomaso committed Dec 6, 2022
1 parent 15d7610 commit 9c1dba8
Show file tree
Hide file tree
Showing 3 changed files with 10 additions and 206 deletions.
2 changes: 1 addition & 1 deletion Bender.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ package:
- "Florian Zaruba <[email protected]>"

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 }

Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
212 changes: 7 additions & 205 deletions src/axi_to_mem.sv
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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

0 comments on commit 9c1dba8

Please sign in to comment.