ALTERA FIFO 读写verilog代码
2014-04-25 14:26
302 查看
ALTERA FIFO 读写verilog代码
FIFO,在FPGA中是一种非常基本,使用非常广泛的模块。FPGA高手可能觉得不值一提,但对于像我这样的新手,有时却是个大问题,弄了一个多月,总算有所进展,希望把自己的一些总结写下来,一方面希望对其他入门者有所帮助,另一方面希望看到的高手们批评指正。另外得特别感谢特权同学的教程。在大学中编了两年单片机(断断续续),C语言的串行思维深入人心,一下子转换到FPGA并行的工作方式和有些奇异的编程风格,一开始还真有点处理不好。另一方面,对FPGA各种延迟非常困惑,比如RAM模块读取延迟,FIFO读取数据延迟等,常常不知道如何处理。下面说说我现在的理解和解决办法。
FPGA写入数据
写入相对简单,只需要在时钟上升沿来临之时使能wrreq和写入data,当然还需要判断FIFO full信号。时序图如下,在第一个时钟之前使能wrreq信号,在第一个时钟及以后的几个时钟上升沿FIFO判断wrreq有效并且读入数据。(图片为转载并 编辑)
一份参考的代码如下
reg [7:0] fifo_wcnt; always @(posedge led or negedge rst) begin if (~rst) begin fifo_wreq<=1'b0; fifo_wdat<=0; fifo_wcnt<=0;//测试数据 end else begin if(~fifo_wfull)begin//FIFO没有写满的时候就写入数据 fifo_wcnt<=fifo_wcnt+1'b1; fifo_wreq<=1'b1; fifo_wdat<=fifo_wcnt+8'd2; end else begin fifo_wreq<=1'b0; end end end
这里fifo_wfull值得注意,在没有延迟的时候这个信号可以直接为FIFO直接输出的full信号,但实际中通常都会有一个或者多个时钟的延迟。可以结合使用wrusedw信号对FIFO保留一定的余量,比如FIFO容量为1024,定义如下:
assign wfifo_full =(recFIFO_WCnt>1000)|recFIFO_wfull;
FIFO读出数据
时序图如下,在第二个时钟上升沿来临后使能rdreq信号,第三个时钟FIFO判断rdreq信号,然后第四个时钟来临时方可读取数据(在empty信号表示FIFO飞空的时候有效)。因此需要注意这两个时钟的延迟,但是我们的重点应该放在获取、处理数据上,而不应该是处理这些烦心的时序操作上。
一份可用的代码如下
assign rfifo_ren= ~rfifo_empty; reg canread; //fifo read always @(posedge clk or negedge rst) begin if(~rst)begin canread<=1'b0; endelse begin canread<=rfifo_ren; end end reg [7:0] readcnt;//读出计数 reg [7:0] dispdata;//读出数据显示 always @(posedge clk or negedge rst) begin if(~rst)begin readcnt<=0; dispdata<=0; endelse begin if(canread)begin readcnt<=readcnt+1'b1; dispdata<=rfifo_rdata; endelse begin end end end
解释:empty为0后,ren随之变为1,使能FIFO读出信号(不是上述时序图内容)。下一个时钟来临时FIFO判断ren使能,同时这个时钟之后canread方才读入~empty信号为1使能。再下一个时钟来临时,FIFO输出信号,而canread已经有效,外设读取数据。
比较奇怪的是ALTERA的文档中并没说empty有延迟,对FIFO直接的操作中也并没有发现这个延迟,也就是说本来FIFO已经读空了,但是FIFO的empty信号并没有有效,如果完全按照empty信号读取会导致多读出一个或多个数据。在随后的一个cy68013 USB2.0接口实现实际用FIFO时发现了empty具有一个时钟的延迟,发送256组数据却显示读取了257组数据。但是这里如果像full一样采取保留一定余量的方法会导致FIFO中始终会暂留有一些数据,除非你知道你自己发送了多少个数据。
上面的代码中使用这种流水线式寄存器转移方法很好的处理了FIFO信号延迟的问题,同样使用它还可以轻易的解决empty延迟一个时钟的问题,只需稍微改一下上面的代码。不过若是延迟多个时钟???还的看看具体的场合。
wire rfifo_ren; reg rfifo_ren1; assign rfifo_ren= ~rfifo_empty; always @(posedge clk or negedge rst) begin if(~rst) begin rfifo_ren1<=1'b0; endelse begin rfifo_ren1<=rfifo_ren; end end assign canread =rfifo_ren1&rfifo_ren;//因为ren会多延迟一个时钟失效 reg [7:0] readcnt;//读出计数 reg [7:0] dispdata;//读出数据显示 always @(posedge clk or negedge rst) begin if(~rst)begin readcnt<=0; dispdata<=0; endelse begin if(canread)begin readcnt<=readcnt+1'b1; dispdata<=rfifo_rdata; endelse begin end end end
解释:加了读取保护功能的FIFO在empty使能之后rfifo_ren使能也不会有问题,关键是canread信号。empty信号为1后,rfifo_ren随即为0,在下一个时钟来临时FIFO输出一个数据(上一个时钟rfifo_ren还是有效的)并判断rfifo_ren失能,停止输出数据。但是由于empty多延迟了一个时钟,因此这个数据是不需要的,如果& 上~empty则可以使canread在这个时钟来临前失能。
相关文章推荐
- VC++ 获取文件属性创建时间、修改时间和访问时间
- java 重定向和转发的区别
- failed to create the java virtual machine
- Java包命名规则引发的思考Java包命名规则引发的思考
- 嵌入式编程里的面向对象技术
- spring 任务调度 Quartz 表达式
- PHP的学习--cookie和session
- C#里,如何模拟DataGridView里的一个Cell的Click事件。
- DirectX编程:[初级]C# 中利用 DirectSound 录音
- C++获取文件的各种属性
- 安卓开发向服务发送请求,出现java java.lang.IllegalArgumentException的问题
- 解决maven与eclipse中@override出现must override a superclass method错误
- ny独木舟上的旅行java
- VC++程序设计基础认识
- Ice中间件学习 04 【slice2java编译.ice文件详解】
- 数字图像和视频处理的基础-第4周运动估计matlab练习题
- VC++如何判断当前操作系统是32位还是64位
- Project facet Java version 1.7 is not supported.
- 鼠标截取图像c++风格
- PHP包含文件