1 |
2 |
AlexRayne |
/*
|
2 |
|
|
Clock Domain Crossing micro FIFO
|
3 |
|
|
Copyright (C) 2010 Alexandr Litjagin (aka AlexRayne) AlexRaynePE196@lavabit.com
|
4 |
|
|
AlexRaynePE196@hotbox.ru
|
5 |
|
|
|
6 |
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
7 |
|
|
you may not use this file except in compliance with the License.
|
8 |
|
|
You may obtain a copy of the License at
|
9 |
|
|
|
10 |
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
11 |
|
|
|
12 |
|
|
Unless required by applicable law or agreed to in writing, software
|
13 |
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
14 |
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15 |
|
|
See the License for the specific language governing permissions and
|
16 |
|
|
limitations under the License.
|
17 |
|
|
*/
|
18 |
|
|
|
19 |
|
|
/*
|
20 |
|
|
cdc_ufifo generate an minimalist fifo. it can be 4 cells minimum.
|
21 |
|
|
by default used implementation without ram only standart cells used
|
22 |
|
|
, and it can be selected if need. most slowest stage is the output multiplexor.
|
23 |
|
|
shadowed outputs - provide an registes after multiplexer to remove data unsynchronized
|
24 |
|
|
changes from outputs when skiped some cycles.
|
25 |
|
|
|
26 |
|
|
parameters:
|
27 |
|
|
shadowed - "FALSE|TRUE" is buffered output or not
|
28 |
|
|
realization - "RAM|REGS" - style of buffer implemented
|
29 |
|
|
="RAM" - default implementation of ram
|
30 |
|
|
="REGS" (default) - force use registers set for buffer
|
31 |
|
|
*/
|
32 |
|
|
module cdc_ufifo( d, in_clk, denable, reset
|
33 |
|
|
, q, q_clk, qenable, ready
|
34 |
|
|
);
|
35 |
|
|
|
36 |
|
|
parameter lpm_width = 8;
|
37 |
|
|
parameter lpm_depth = 2;
|
38 |
|
|
parameter shadowed = "FALSE";
|
39 |
|
|
parameter realization = "REGS";
|
40 |
|
|
|
41 |
|
|
`include "StdUtils.vh"
|
42 |
|
|
|
43 |
|
|
`define lpm_size (lpm_depth*2)
|
44 |
|
|
`define ptr_size clog2(`lpm_size)
|
45 |
|
|
|
46 |
|
|
input in_clk, denable, q_clk, qenable, reset;
|
47 |
|
|
input [lpm_width-1:0] d;
|
48 |
|
|
output logic [lpm_width-1:0] q;
|
49 |
|
|
output ready;
|
50 |
|
|
|
51 |
|
|
typedef logic [lpm_width-1:0] data_wire;
|
52 |
|
|
typedef logic [`ptr_size-1:0] buf_ptr;
|
53 |
|
|
|
54 |
|
|
data_wire bufer[0:`lpm_size-1];
|
55 |
|
|
buf_ptr rd_node_ptr;
|
56 |
|
|
buf_ptr rd_next_ptr;
|
57 |
|
|
buf_ptr wr_node_ptr;
|
58 |
|
|
buf_ptr wr_next_ptr;
|
59 |
|
|
|
60 |
|
|
buf_ptr rd_node_grey;
|
61 |
|
|
buf_ptr rd_next_grey;
|
62 |
|
|
buf_ptr wr_node_grey;
|
63 |
|
|
buf_ptr wr_next_grey;
|
64 |
|
|
|
65 |
|
|
assign rd_node_ptr = rd_node_grey;
|
66 |
|
|
assign rd_next_ptr = rd_next_grey;
|
67 |
|
|
assign wr_node_ptr = wr_node_grey;
|
68 |
|
|
assign wr_next_ptr = wr_next_grey;
|
69 |
|
|
|
70 |
|
|
logic wr_enable;
|
71 |
|
|
logic rd_enable;
|
72 |
|
|
|
73 |
|
|
graycntr WrSwitch(.clk(in_clk), .inc(wr_enable), .rst_n(~reset), .gray(wr_node_grey), .gnext(wr_next_grey));
|
74 |
|
|
defparam WrSwitch.lpm_width = `ptr_size;
|
75 |
|
|
graycntr RdSwitch(.clk(q_clk), .inc(rd_enable), .rst_n(~reset), .gray(rd_node_grey), .gnext(rd_next_grey));
|
76 |
|
|
defparam RdSwitch.lpm_width = `ptr_size;
|
77 |
|
|
|
78 |
|
|
buf_ptr rd_cdc_grey;
|
79 |
|
|
buf_ptr wr_cdc_grey;
|
80 |
|
|
|
81 |
|
|
delay_pulse_ff cdc_stamp_wr(.clock(q_clk), .d(wr_node_grey), .q(wr_cdc_grey), .enable(1'b1), .clrn(~reset));
|
82 |
|
|
defparam cdc_stamp_wr.delay = 1;//lpm_depth;
|
83 |
|
|
defparam cdc_stamp_wr.lpm_width = $bits(wr_node_grey);
|
84 |
|
|
|
85 |
|
|
delay_pulse_ff cdc_stamp_rd(.clock(in_clk), .d(rd_node_grey), .q(rd_cdc_grey), .enable(1'b1), .clrn(~reset));
|
86 |
|
|
defparam cdc_stamp_rd.delay = 1;//(lpm_depth /2);
|
87 |
|
|
defparam cdc_stamp_rd.lpm_width = $bits(rd_node_grey);
|
88 |
|
|
|
89 |
|
|
|
90 |
|
|
logic data_avail;
|
91 |
|
|
logic data_free;
|
92 |
|
|
assign data_avail = (wr_cdc_grey != rd_node_grey);
|
93 |
|
|
assign data_free = (rd_cdc_grey != wr_next_grey);
|
94 |
|
|
assign wr_enable = denable & data_free;
|
95 |
|
|
assign rd_enable = data_avail;
|
96 |
|
|
|
97 |
|
|
wire [lpm_width-1:0] selQ;
|
98 |
|
|
|
99 |
|
|
genvar i;
|
100 |
|
|
generate
|
101 |
|
|
if (realization == "REGS")
|
102 |
|
|
for (i = 0; i < `lpm_size; i++) begin : buffer_node
|
103 |
|
|
wire WrCellSel = (wr_node_ptr == i);
|
104 |
|
|
prim_dffe buf_data( .clk(in_clk), .d(d), .ena( wr_enable & WrCellSel ), .q( bufer[i] ), .clrn(~reset), .prn(1'b1) );
|
105 |
|
|
defparam buf_data.lpm_width = lpm_width;
|
106 |
|
|
assign selQ = (rd_node_ptr == i)? bufer[i] : {lpm_width{1'bz}};
|
107 |
|
|
end
|
108 |
|
|
else begin
|
109 |
|
|
always @(posedge in_clk) begin : bufer_latch
|
110 |
|
|
if (wr_enable)
|
111 |
|
|
bufer[wr_node_ptr] <= d;
|
112 |
|
|
end
|
113 |
|
|
|
114 |
|
|
assign selQ = bufer[rd_node_ptr];
|
115 |
|
|
end
|
116 |
|
|
endgenerate
|
117 |
|
|
|
118 |
|
|
|
119 |
|
|
assign ready = rd_enable;
|
120 |
|
|
|
121 |
|
|
generate if (shadowed == "TRUE") begin
|
122 |
|
|
always @(posedge q_clk) if (rd_enable) q <= selQ;
|
123 |
|
|
end
|
124 |
|
|
else
|
125 |
|
|
assign q = selQ;
|
126 |
|
|
endgenerate
|
127 |
|
|
|
128 |
|
|
|
129 |
|
|
endmodule
|