blob: dd56537422ba20ba9740a07642bd1397a088133e (
plain) (
blame)
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
|
`timescale 1ns / 1ps
module fifo_buffer (
input wire wr_clk,
input wire [7:0] wr_data,
input wire wr_valid,
output wire wr_ready,
input wire rd_clk,
output wire [7:0] rd_data,
output wire rd_valid,
input wire rd_ready,
input wire rst_n,
output wire fifo_empty,
output wire fifo_full,
output wire [7:0] fifo_level
);
parameter DEPTH = 512;
parameter ADDR_WIDTH = 9;
reg [7:0] mem [0:DEPTH-1];
reg [ADDR_WIDTH:0] wr_ptr;
reg [ADDR_WIDTH:0] wr_ptr_gray;
reg [ADDR_WIDTH:0] wr_ptr_gray_sync1;
reg [ADDR_WIDTH:0] wr_ptr_gray_sync2;
reg [ADDR_WIDTH:0] rd_ptr;
reg [ADDR_WIDTH:0] rd_ptr_gray;
reg [ADDR_WIDTH:0] rd_ptr_gray_sync1;
reg [ADDR_WIDTH:0] rd_ptr_gray_sync2;
wire [ADDR_WIDTH:0] wr_ptr_bin;
wire [ADDR_WIDTH:0] rd_ptr_bin;
wire [ADDR_WIDTH:0] fifo_count;
reg wr_en;
reg rd_en;
reg [7:0] rd_data_reg;
reg rd_valid_reg;
assign wr_ready = ~fifo_full;
always @(posedge wr_clk or negedge rst_n) begin
if (!rst_n) begin
wr_ptr <= 0;
wr_ptr_gray <= 0;
wr_en <= 1'b0;
end else begin
wr_en <= wr_valid && wr_ready;
if (wr_en) begin
mem[wr_ptr[ADDR_WIDTH-1:0]] <= wr_data;
wr_ptr <= wr_ptr + 1;
end
wr_ptr_gray <= binary_to_gray(wr_ptr);
end
end
always @(posedge wr_clk or negedge rst_n) begin
if (!rst_n) begin
rd_ptr_gray_sync1 <= 0;
rd_ptr_gray_sync2 <= 0;
end else begin
rd_ptr_gray_sync1 <= rd_ptr_gray;
rd_ptr_gray_sync2 <= rd_ptr_gray_sync1;
end
end
assign rd_data = rd_data_reg;
assign rd_valid = rd_valid_reg;
always @(posedge rd_clk or negedge rst_n) begin
if (!rst_n) begin
rd_ptr <= 0;
rd_ptr_gray <= 0;
rd_en <= 1'b0;
rd_data_reg <= 8'h00;
rd_valid_reg <= 1'b0;
end else begin
rd_en <= rd_ready && ~fifo_empty;
if (rd_en) begin
rd_data_reg <= mem[rd_ptr[ADDR_WIDTH-1:0]];
rd_valid_reg <= 1'b1;
rd_ptr <= rd_ptr + 1;
end else if (rd_ready) begin
rd_valid_reg <= 1'b0;
end
rd_ptr_gray <= binary_to_gray(rd_ptr);
end
end
always @(posedge rd_clk or negedge rst_n) begin
if (!rst_n) begin
wr_ptr_gray_sync1 <= 0;
wr_ptr_gray_sync2 <= 0;
end else begin
wr_ptr_gray_sync1 <= wr_ptr_gray;
wr_ptr_gray_sync2 <= wr_ptr_gray_sync1;
end
end
assign wr_ptr_bin = gray_to_binary(wr_ptr_gray_sync2);
assign rd_ptr_bin = gray_to_binary(rd_ptr_gray_sync2);
wire [ADDR_WIDTH:0] fifo_count_wr;
assign fifo_count_wr = wr_ptr - gray_to_binary(rd_ptr_gray_sync2);
wire [ADDR_WIDTH:0] fifo_count_rd;
assign fifo_count_rd = gray_to_binary(wr_ptr_gray_sync2) - rd_ptr;
assign fifo_full = (fifo_count_wr >= DEPTH);
assign fifo_empty = (fifo_count_rd == 0);
reg [7:0] fifo_level_reg;
always @(*) begin
if (fifo_count_wr > DEPTH)
fifo_level_reg = DEPTH;
else
fifo_level_reg = fifo_count_wr[7:0];
end
assign fifo_level = fifo_level_reg;
function [ADDR_WIDTH:0] binary_to_gray;
input [ADDR_WIDTH:0] binary;
begin
binary_to_gray = binary ^ (binary >> 1);
end
endfunction
function [ADDR_WIDTH:0] gray_to_binary;
input [ADDR_WIDTH:0] gray;
reg [ADDR_WIDTH:0] binary;
integer i;
begin
binary[ADDR_WIDTH] = gray[ADDR_WIDTH];
for (i = ADDR_WIDTH-1; i >= 0; i = i - 1)
binary[i] = binary[i+1] ^ gray[i];
gray_to_binary = binary;
end
endfunction
integer i;
initial begin
for (i = 0; i < DEPTH; i = i + 1)
mem[i] = 8'h00;
end
endmodule
|