Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
// Copyright 2018 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.
//
// Fabian Schuiki <fschuiki@iis.ee.ethz.ch>
/// A clock domain crossing FIFO, using 2-phase hand shakes.
///
/// This FIFO has its push and pop ports in two separate clock domains. Its size
/// can only be powers of two, which is why its depth is given as 2**LOG_DEPTH.
/// LOG_DEPTH must be at least 1.
///
/// CONSTRAINT: See the constraints for `cdc_2phase`. An additional maximum
/// delay path needs to be specified from fifo_data_q to dst_data_o.
module cdc_fifo_2phase #(
/// The data type of the payload transported by the FIFO.
parameter type T = logic,
/// The FIFO's depth given as 2**LOG_DEPTH.
parameter int LOG_DEPTH = 3
)(
input logic src_rst_ni,
input logic src_clk_i,
input T src_data_i,
input logic src_valid_i,
output logic src_ready_o,
input logic dst_rst_ni,
input logic dst_clk_i,
output T dst_data_o,
output logic dst_valid_o,
input logic dst_ready_i
);
// Check the invariants.
//pragma translate_off
initial begin
assert(LOG_DEPTH > 0);
end
//pragma translate_on
localparam int PTR_WIDTH = LOG_DEPTH+1;
typedef logic [PTR_WIDTH-1:0] pointer_t;
typedef logic [LOG_DEPTH-1:0] index_t;
localparam pointer_t PTR_FULL = (1 << LOG_DEPTH);
localparam pointer_t PTR_EMPTY = '0;
// Allocate the registers for the FIFO memory with its separate write and read
// ports. The FIFO has the following ports:
//
// - write: fifo_widx, fifo_wdata, fifo_write, src_clk_i
// - read: fifo_ridx, fifo_rdata
index_t fifo_widx, fifo_ridx;
logic fifo_write;
T fifo_wdata, fifo_rdata;
T fifo_data_q [2**LOG_DEPTH];
assign fifo_rdata = fifo_data_q[fifo_ridx];
for (genvar i = 0; i < 2**LOG_DEPTH; i++) begin : g_word
always_ff @(posedge src_clk_i, negedge src_rst_ni) begin
if (!src_rst_ni)
fifo_data_q[i] <= '0;
else if (fifo_write && fifo_widx == i)
fifo_data_q[i] <= fifo_wdata;
end
end
// Allocate the read and write pointers in the source and destination domain.
pointer_t src_wptr_q, dst_wptr, src_rptr, dst_rptr_q;
always_ff @(posedge src_clk_i, negedge src_rst_ni) begin
if (!src_rst_ni)
src_wptr_q <= 0;
else if (src_valid_i && src_ready_o)
src_wptr_q <= src_wptr_q + 1;
end
always_ff @(posedge dst_clk_i, negedge dst_rst_ni) begin
if (!dst_rst_ni)
dst_rptr_q <= 0;
else if (dst_valid_o && dst_ready_i)
dst_rptr_q <= dst_rptr_q + 1;
end
// The pointers into the FIFO are one bit wider than the actual address into
// the FIFO. This makes detecting critical states very simple: if all but the
// topmost bit of rptr and wptr agree, the FIFO is in a critical state. If the
// topmost bit is equal, the FIFO is empty, otherwise it is full.
assign src_ready_o = ((src_wptr_q ^ src_rptr) != PTR_FULL);
assign dst_valid_o = ((dst_rptr_q ^ dst_wptr) != PTR_EMPTY);
// Transport the read and write pointers across the clock domain boundary.
cdc_2phase #(pointer_t) i_cdc_wptr (
.src_rst_ni ( src_rst_ni ),
.src_clk_i ( src_clk_i ),
.src_data_i ( src_wptr_q ),
.src_valid_i ( 1'b1 ),
.src_ready_o ( ),
.dst_rst_ni ( dst_rst_ni ),
.dst_clk_i ( dst_clk_i ),
.dst_data_o ( dst_wptr ),
.dst_valid_o ( ),
.dst_ready_i ( 1'b1 )
);
cdc_2phase #(pointer_t) i_cdc_rptr (
.src_rst_ni ( dst_rst_ni ),
.src_clk_i ( dst_clk_i ),
.src_data_i ( dst_rptr_q ),
.src_valid_i ( 1'b1 ),
.src_ready_o ( ),
.dst_rst_ni ( src_rst_ni ),
.dst_clk_i ( src_clk_i ),
.dst_data_o ( src_rptr ),
.dst_valid_o ( ),
.dst_ready_i ( 1'b1 )
);
// Drive the FIFO write and read ports.
assign fifo_widx = src_wptr_q;
assign fifo_wdata = src_data_i;
assign fifo_write = src_valid_i && src_ready_o;
assign fifo_ridx = dst_rptr_q;
assign dst_data_o = fifo_rdata;
endmodule
5a7cab001This file is pinned to the selected release. Download the original to open it in your design tool.