verilog设计

同步FIFO设计

image-20251011153414040

[!note]

同步FIFO可以解决位宽,速率的匹配

image-20251011161050214

[!note]

重点在于读写指针的控制

image-20251011163759156

[!important]

怎么具体判断FIFO是空还是满:

  • 方法1

设计fifo_cnt,当为深度的时候,为满

wr_en的时候+1,rd_en的时候-1,wr_en和rd_en同时为高的时候counter不变

当fifo_cnt等于DEPTH的时候为满,否则为空

  • 方法2

指针多扩展1bit,当标志位不一样的时候就是满标志,否则是空标志

image-20251011175845148

补充

当FIFO的读写位宽不匹配的时候

  • 16to8,即写是16bit,读是8bit的时候

[!important]

  • mem声明的时候应该声明成8bit的位宽

  • 单次写入的时候,wr_ptr一次不是加1,而是加2,单次读出的时候,cnt-1

  • 同时读写的时候,cnt+1

实现代码示例

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
`timescale 1ns/1ns

/**********************************RAM************************************/
module dual_port_RAM #(parameter DEPTH = 16,
parameter WIDTH = 8)(
input wclk
,input wenc
,input [$clog2(DEPTH)-1:0] waddr
,input [WIDTH-1:0] wdata
,input rclk
,input renc
,input [$clog2(DEPTH)-1:0] raddr
,output reg [WIDTH-1:0] rdata
);

reg [WIDTH-1:0] RAM_MEM [0:DEPTH-1];

always @(posedge wclk) begin
if(wenc)
RAM_MEM[waddr] <= wdata;
end

always @(posedge rclk) begin
if(renc)
rdata <= RAM_MEM[raddr];
end

endmodule

/**********************************SFIFO************************************/
module sfifo#(
parameter WIDTH = 8,
parameter DEPTH = 16
)(
input clk ,
input rst_n ,
input winc ,
input rinc ,
input [WIDTH-1:0] wdata ,

output reg wfull ,
output reg rempty ,
output wire [WIDTH-1:0] rdata
);

localparam AWIDTH = $clog2(DEPTH);


reg [AWIDTH:0] fifo_wr_addr;
reg [AWIDTH:0] fifo_rd_addr;

wire fifo_wren ;

assign fifo_wren = winc & !wfull;
assign fifo_rden = rinc & !rempty;

always @(posedge clk or negedge rst_n)begin
if(!rst_n)
rempty <= 1'b0;
else if((fifo_wr_addr[AWIDTH] == fifo_rd_addr[AWIDTH]) && (fifo_rd_addr[AWIDTH-1:0] == fifo_wr_addr[AWIDTH-1: 0]))
rempty <= 1'b1;
else
rempty <= 1'b0;
end

always @(posedge clk or negedge rst_n)begin
if(!rst_n)
wfull <= 1'b0;
else if((fifo_wr_addr[AWIDTH] != fifo_rd_addr[AWIDTH]) && (fifo_rd_addr[AWIDTH-1:0] == fifo_wr_addr[AWIDTH-1: 0]))
wfull <= 1'b1;
else
wfull <= 1'b0;
end

always @(posedge clk or negedge rst_n)begin
if(!rst_n)
fifo_wr_addr <= {AWIDTH+1{1'B0}};
else if(winc && !wfull)
fifo_wr_addr <= fifo_wr_addr + 1'b1;
else
fifo_wr_addr <= fifo_wr_addr;
end

always @(posedge clk or negedge rst_n)begin
if(!rst_n)
fifo_rd_addr <= {AWIDTH+1{1'B0}};
else if(rinc && !rempty)
fifo_rd_addr <= fifo_rd_addr + 1'b1;
else
fifo_rd_addr <= fifo_rd_addr;
end

dual_port_RAM #(
.DEPTH ( DEPTH ),
.WIDTH ( WIDTH )
)fifo_ram(
.wclk ( clk ),
.wenc ( fifo_wren ),
.waddr ( fifo_wr_addr[AWIDTH-1: 0] ),
.wdata ( wdata ),
.rclk ( clk ),
.renc ( fifo_rden ),
.raddr ( fifo_rd_addr[AWIDTH-1: 0] ),
.rdata ( rdata )

);

endmodule