当前位置: 代码迷 >> 综合 >> 关于fifo设计(同步和异步fifo)
  详细解决方案

关于fifo设计(同步和异步fifo)

热度:7   发布时间:2024-02-07 06:14:39.0

/*    fifo设计的核心就是空满信号的产生。其他类似于bram*/
/*同步fifo设计
使用爽口bram,读写指针代表数据位置,counter代码目前bram是否写满或者写空。
*/

module fifo(
input clk,
input rst,
input wr_en,
input rd_en,
input  [7:0]data_in,//输入数据
output [7:0]data_out,//输出数据
output empty,
output full,//空满标志
);
reg [7:0] ram[15:0];
reg [3:0] wr_ptr,rd_ptr;
reg [3:0] counter;
always@(posedge clk)begin
if(!rst)begin
counter<=4'b0;
data_out<=8'd0;
wr_ptr<=4'b0;
rd_ptr<=4'b0;
end
end
else begin case(wr_en,rd_en)
2'b00:counter<=counter;  
2'b01:begin //需要加空判断
data_out<=ram[rd_ptr];
counter<=counter-1;
rd_ptr<=(rd_ptr)?0:rd_ptr+1;
end
2'b10:begin
counter<=counter+1; //需要加满判断
ram[wr_ptr]<=data_in;
wr_ptr<=(wr_ptr==15)?0:wr_ptr+1;
end
2'b11:begin
ram[wr_ptr]=data_in;
data_out=ram[rd_ptr];
wr_ptr<=wr_ptr+1; //循环
rd_ptr<=rd_ptr+1;
end
end
assign empty =(counter ==0)?1:0;
assign full =(counter==15)?1:0
endmodule

//异步fifo,空满判断。
/**读写指针相同时,触发空满判断,如果高位为0,即读空。如果高位为1,即写满,只适用于二进制*/
/*1、使用格雷码,应该判断最高位和此高位是否相等,当最高位和此高位相同,认为读空,当最高位和此高位不同,则认为写满。
需要参照格雷码来写,也就是剩余位相同的情况下,判断写高位和读的此高位是否相同*/

/*关于亚稳态:因为读写时钟不同,则空满写好读写时会产生亚稳态,二级缓存适合单bit数据跳变,多bit数据跳变容易产生毛刺,
所以,写指针和读指针需要使用格雷码作为状态跳转。*/

/*2、将写指针同步到读时钟,判断空。因为两拍延迟,所以不会产生空读信号。
将读指针同步到写时钟,判断满。因为两拍延迟,所以不会产生写满信号。 但是会产生额外开销,不可避免。*/

/*注:同步过程中,快时钟到满时钟丢掉了怎么办,丢掉的数据是否会对结果产生影响?会导致fifo资源变小。所以会根据时钟要求,在同步快时钟时,将快时钟同步展宽。*/
/*不带复位*/
module afifo(
input clk15M, //写时钟
input  clk20M,
input rst,
input wr_en,
input rd_en,
input  [7:0]data_in,//输入数据
output [7:0]data_out,//输出数据
output empty,
output full,//空满标志
);
reg [7:0] ram[15:0];
reg [3:0] wr_ptr,rd_ptr;

reg[3:0] gray_rd;
reg [3:0] gray_wr;

/*写数据*/
always@(posedge  clk15M)begin
if(wr_en&&~full)begin
ram[wr_ptr] <=data_in;
wr_ptr <=wr_ptr+1;
end    
end
/*读数据*/
always@(posedge  clk20M)begin
if(rd_en&&~empty)begin
data_out<=ram[rd_ptr];
rd_ptr<=(rd_ptr)?0:rd_ptr+1;
end    
end
/*把读指针同步到写时钟域*/
always@(posedge  clk15M)begin
rd_ptr1 <=gray_rd;
rd_ptr2 <=rd_ptr1;
end
/*把写指针同步到读时钟域*/
always@(posedge  clk20M)begin
wr_ptr1 <=gray_wr;
wr_ptr2 <=wr_ptr1;
end

/*产生格雷码*/
assign gray_rd = rd_ptr^(rd_ptr>>2);
assign gray_wr = wr_ptr^(wr_ptr>>2);
assign  full= (rd_ptr2[2]!=wr_ptr2[3])?((wr_ptr2[1:0]==rd_ptr2[1:0])?1:0) :0;
assign  empty=(rd_ptr2[2]==wr_ptr2[3])?((wr_ptr2[1:0]==rd_ptr2[1:0])?1:0) :0;

 

综上所述,fifo设计类似于bram的使用,不过因为不能循环,且尽可能在设计过程中,不产生空满信号。空满信号就已经有数据丢失了。

思考:

该怎么完成一个简单设计?

各个信号之间,该怎么通过控制信号完成数据交互。