1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
|
/////////////////////////////////////////////////////////////////////
//
// Copyright 2017 Ettus Research, A National Instruments Company
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Module: axi_fifo_2clk.v
//
// Purpose:
// An asynchronous clock crossing for AXI-Stream buses
// The width (WIDTH) and depth (SIZE) of the FIFO is configurable
// For depths less than the technology's SRL threshold, an SRL
// will be instantiated. For depths less the minimum RAM block
// depth (that corresponds to the max width), a single BRAM block
// will be instantiated. For other larger depths, a BRAM block
// plus a regular axi_fifo will be instantiated. The depth of the
// combined FIFO in that case will be larger than the user request.
//
// Requirements:
// Implementation for fifo_short_2clk, fifo_4k_2clk that infer SRL
// and BRAM based clock-crossing FIFOs respectively
//
//////////////////////////////////////////////////////////////////////
module axi_fifo_2clk #(
parameter WIDTH = 69, // Width of input/output data word
parameter SIZE = 9, // log2 of the depth of the FIFO
parameter PIPELINE = "NONE", // Which ports to pipeline? {NONE, IN, OUT, INOUT}
parameter DEVICE = "7SERIES" // FPGA technology identifier (for optimal inference)
)(
input wire reset,
input wire i_aclk,
input wire [WIDTH-1:0] i_tdata,
input wire i_tvalid,
output wire i_tready,
input wire o_aclk,
output wire [WIDTH-1:0] o_tdata,
output wire o_tvalid,
input wire o_tready
);
wire i_arst, o_arst;
synchronizer #(.INITIAL_VAL(1'b1)) i_rst_sync_i (
.clk(i_aclk), .rst(1'b0), .in(reset), .out(i_arst)
);
synchronizer #(.INITIAL_VAL(1'b1)) o_rst_sync_i (
.clk(o_aclk), .rst(1'b0), .in(reset), .out(o_arst)
);
//----------------------------------------------
// Pipeline Logic
//----------------------------------------------
wire [WIDTH-1:0] i_pipe_tdata, o_pipe_tdata;
wire i_pipe_tvalid, o_pipe_tvalid;
wire i_pipe_tready, o_pipe_tready;
generate
if (PIPELINE == "IN" || PIPELINE == "INOUT") begin
axi_fifo_flop2 #(.WIDTH(WIDTH)) in_pipe_i (
.clk(i_aclk), .reset(i_arst), .clear(1'b0),
.i_tdata(i_tdata), .i_tvalid(i_tvalid), .i_tready(i_tready),
.o_tdata(i_pipe_tdata), .o_tvalid(i_pipe_tvalid), .o_tready(i_pipe_tready),
.space(), .occupied()
);
end else begin
assign {i_pipe_tdata, i_pipe_tvalid} = {i_tdata, i_tvalid};
assign i_tready = i_pipe_tready;
end
if (PIPELINE == "OUT" || PIPELINE == "INOUT") begin
axi_fifo_flop2 #(.WIDTH(WIDTH)) out_pipe_i (
.clk(o_aclk), .reset(o_arst), .clear(1'b0),
.i_tdata(o_pipe_tdata), .i_tvalid(o_pipe_tvalid), .i_tready(o_pipe_tready),
.o_tdata(o_tdata), .o_tvalid(o_tvalid), .o_tready(o_tready),
.space(), .occupied()
);
end else begin
assign {o_tdata, o_tvalid} = {o_pipe_tdata, o_pipe_tvalid};
assign o_pipe_tready = o_tready;
end
endgenerate
//----------------------------------------------
// FIFO Logic
//----------------------------------------------
wire [WIDTH-1:0] o_ext_tdata;
wire o_ext_tvalid;
wire o_ext_tready;
// Ideally the following parameters should be technology
// specific. For now these values have been optimized for
// 7Series FPGAs. They also work for Spartan6 but may not
// be optimal. For future generations, make these values
// depend on the DEVICE parameter.
localparam BASE_WIDTH = 72;
localparam SRL_THRESHOLD = 5;
localparam RAM_THRESHOLD = 9;
// How many parallel FIFOs to instantiate to fit WIDTH
localparam NUM_FIFOS = ((WIDTH-1)/BASE_WIDTH)+1;
localparam INT_WIDTH = BASE_WIDTH * NUM_FIFOS;
wire [INT_WIDTH-1:0] wr_data, rd_data;
wire [NUM_FIFOS-1:0] full, empty;
wire wr_en, rd_en;
// Read/write logic for FIFO sections
assign wr_data = {{(INT_WIDTH-WIDTH){1'b0}}, i_pipe_tdata};
assign wr_en = i_pipe_tready & i_pipe_tvalid;
assign i_pipe_tready = &(~full);
assign o_ext_tdata = rd_data[WIDTH-1:0];
assign o_ext_tvalid = &(~empty);
assign rd_en = o_ext_tready & o_ext_tvalid;
// FIFO IP instantiation
genvar i;
generate
for (i = 0; i < NUM_FIFOS; i = i + 1) begin: fifo_section
if (SIZE <= SRL_THRESHOLD) begin
fifo_short_2clk impl_srl_i (
.rst (i_arst),
.wr_clk (i_aclk),
.din (wr_data[((i+1)*BASE_WIDTH)-1:i*BASE_WIDTH]),
.wr_en (wr_en),
.full (full[i]),
.wr_data_count(),
.rd_clk (o_aclk),
.dout (rd_data[((i+1)*BASE_WIDTH)-1:i*BASE_WIDTH]),
.rd_en (rd_en),
.empty (empty[i]),
.rd_data_count()
);
end else begin
fifo_4k_2clk impl_bram_i (
.rst (i_arst),
.wr_clk (i_aclk),
.din (wr_data[((i+1)*BASE_WIDTH)-1:i*BASE_WIDTH]),
.wr_en (wr_en),
.full (full[i]),
.wr_data_count(),
.rd_clk (o_aclk),
.dout (rd_data[((i+1)*BASE_WIDTH)-1:i*BASE_WIDTH]),
.rd_en (rd_en),
.empty (empty[i]),
.rd_data_count()
);
end
end
endgenerate
//----------------------------------------------
// Extension FIFO (for large sizes)
//----------------------------------------------
generate
if (SIZE > RAM_THRESHOLD) begin
wire [WIDTH-1:0] ext_pipe_tdata;
wire ext_pipe_tvalid;
wire ext_pipe_tready;
// Add a register slice between BRAM cascades
axi_fifo_flop2 #(.WIDTH(WIDTH)) ext_fifo_pipe_i (
.clk(o_aclk), .reset(o_arst), .clear(1'b0),
.i_tdata(o_ext_tdata), .i_tvalid(o_ext_tvalid), .i_tready(o_ext_tready),
.o_tdata(ext_pipe_tdata), .o_tvalid(ext_pipe_tvalid), .o_tready(ext_pipe_tready),
.space(), .occupied()
);
// Bolt on an extension FIFO if the requested depth is larger than the BRAM
// 2clk FIFO primitive (IP)
axi_fifo_bram #(.WIDTH(WIDTH), .SIZE(SIZE)) ext_fifo_i (
.clk(o_aclk), .reset(o_arst), .clear(1'b0),
.i_tdata(ext_pipe_tdata), .i_tvalid(ext_pipe_tvalid), .i_tready(ext_pipe_tready),
.o_tdata(o_pipe_tdata), .o_tvalid(o_pipe_tvalid), .o_tready(o_pipe_tready),
.space(), .occupied()
);
end else begin
assign {o_pipe_tdata, o_pipe_tvalid} = {o_ext_tdata, o_ext_tvalid};
assign o_ext_tready = o_pipe_tready;
end
endgenerate
endmodule
|