TA的每日心情 | 擦汗 2014-2-12 10:49 |
---|
签到天数: 150 天 连续签到: 1 天 [LV.7]常住居民III
|
FIFO(First In First Out ) 先进先出是一个常用于数据缓存的一个数据缓冲器。
fifo主要有WRREQ(写信号)WRclk(写时钟)data(写数据)wrfull(写满标志)wrempty(写空标志)wrusedw(告知里面还有多少数据)
Rdreq(读信号)rdclk(读时钟)rdfull(读满标志)rdempty(读空标志)rdusedw(告知里面数据个数)
以上所有信号全是高电平有效。
在项目设计中,我们通常需要在两个模块之间传输数据,如果两个模块的数据处理速率相同,那么自然没有什么问题,直接进行数据之间的对接就可以,可若是两个模块的数据处理速度不同呢?如果说数据接收模块和数据发送模块的速度不一致的话,必然会导致采集数据出现遗漏的现象,那么又该如何解决这一问题呢?
这里教大家一种比较简单的方法就是引用FIFO(先进先出)数据缓冲器,所有数据都先经过缓存器去缓存,然后再输入数据接收模块。这样就通过一个数据缓存的方法解决了速度不一致而导致的遗漏数据的问题。
- 如何在quarters和ISE里调用FIFO IP核
先主要说一下quarters里面的调用,在IP核搜索区找到fifo选项,
然后写入IP核的名字,点击NEXT就可以进入配置页面,
在这里可以定义位宽和数据深度,因为同步FIFO用的不多,所以主要说一下异步FIFO,在下方的图片中可以定义写空写满和读空读满信号以及写使能和读使能等等。
其余几个页面不需要配置什么直接点击NEXT就可以。
另外需要注意的是: 读端口和写端口的输出会有几个时间差,这是由FIFO内部的结构导致的。
系统框架:
三个输入线和一个输出线
总共需要三个模块和一个顶层连线
代码展示:
写控制:- module FIFO_wr(
- input wire wclk,
- input wire rst_n,
- input wire wrfull,
- input wire wrempty,
- output reg [7:0]wrdata,
- output reg wrreq
- );
- reg [7:0] state;
- always @(posedge wclk or negedge rst_n)
- begin
- if(!rst_n)
- begin
- wrdata<=0;
- wrreq<=0;
- state<=0;
- end
- else
- begin
- case(state)
- 0:begin
- if(wrempty)
- begin
- wrreq<=1 ;
- wrdata<=0;
- state<=1 ;
- end
- else
- state<=0;
-
- end
- 1:begin
- if(wrfull)
- begin
- state<=0;
- wrreq<=0;
- wrdata<=0;
- end
- else
- begin
- wrreq<=1;
- wrdata<=wrdata+1'b1;
- end
- end
- default: state<=0;
- endcase
- end
- end
- endmodule
复制代码 读控制:- module FIFO_rd(
- input wire rdclk,
- input wire rst_n,
- input wire rdempty,
- input wire rdfull,
- output reg rdreq
- );
- reg[2:0]state;
- always@(posedge rdclk or negedge rst_n)
- begin
- if(!rst_n)
- begin
- state<=0;
- rdreq<=0;
-
- end
- else
- begin
- case (state)
- 0:begin
- if(rdfull)
- begin
- state<=1;
- rdreq<=1;
- end
- else
- state <=0;
- end
- 1:begin
- if(rdempty==0)
- begin
- state<=1;
- rdreq<=1;
- end
- else
- begin
- rdreq<=0;
- state<=0;
- end
- end
- default: state<=0;
- endcase
- end
- end
- endmodule
复制代码 顶层连线:- module fifo_top(
- input wire wrclk,
- input wire rst_n,
- input wire rdclk,
- output wire [7:0]rdata
- );
-
- wire wrfull;
- wire wrreq;
- wire [7:0]wrdata;
- wire wrempty;
- wire rdfull;
- wire rdempty;
- wire rdreq;
-
- FIFO_wr U1 (
- .wclk(wrclk) ,
- .rst_n(rst_n) ,
- .wrfull(wrfull) ,
- .wrdata(wrdata) ,
- .wrreq(wrreq) ,
- .wrempty(wrempty)
- );
- FIFO_rd U2(
- .rdclk (rdclk) ,
- .rst_n (rst_n) ,
- .rdempty(rdempty) ,
- .rdreq (rdreq) ,
- .rdfull (rdfull)
- );
- my_fifo U3(
- .data(wrdata) ,
- .rdclk(rdclk) ,
- .rdreq(rdreq) ,
- .wrclk(wrclk) ,
- .wrreq(wrreq) ,
- .q(rdata) ,
- .rdempty(rdempty) ,
- .rdfull(rdfull) ,
- .wrempty(wrempty) ,
- .wrfull(wrfull)
- );
-
- endmodule
复制代码 测试文件:- module fifo_top_tb;
- reg wrclk;
- reg rdclk;
- reg rst_n;
- wire [7:0] rdata;
- initial
- begin
- wrclk=1;
- rdclk=1;
- rst_n=0;
- #1000
- rst_n=1;
- #100000 $stop;
- end
- always #10 wrclk=~wrclk;
- always #20 rdclk=~rdclk;
- fifo_top U1(
- .wrclk (wrclk) ,
- .rst_n (rst_n) ,
- .rdclk (rdclk) ,
- .rdata (rdata)
- );
- endmodule
复制代码 仿真波形:
可以看到:
当复位结束之前,写空标志为高电平,当有第一个数据写进去的时候,写空标志拉低,当数据写完的时候,写满标志拉高,延时了几拍后,读满标志拉高,当有第一个数据读出来以后,读满标志拉低,当数据读完后,读空标志由低变高,延时几拍后会出现写空标志,进行下一循环。
由上可以看到当读和写的时钟不一样的时候也能很方便的达到数据缓存的目的,不至于数据丢失。
|
|