赞
踩
fifo的输入输出端口如上图所示。
本次设计fifo输入输出32位,深度为8,读写信号由上游发送,空满信号由fifo产生。
设计要点:
1.在实际应用中,write信号和read信号由上游模块给出,有可能存在fifo满了,write信号还没有拉低的情况;或者说上游节点write信号不拉低,只是说收到了full信号后当前数据不发生变化,这就需要考虑到full信号拉高的时候的时序问题,如果没处理好就可能会丢失掉最后一个数据,就如下图所示。
假设fifo深度为n,如果使用时序逻辑,full信号在第n个时钟上升沿拉高,但要下一个时钟上升沿才能检测到,然后write信号才能拉低。此时的第n+1个数据已经发送出去了,fifo又满了,无法写入,就会造成数据丢失。此处可以用almost_full解决这个问题,在fifo快满的时候提示上游节点别发送新数据。本设计没使用almost_full信号,使用了组合逻辑:用full信号取反&w_en信号,用这个条件来控制fifo是否继续写入。此时write信号拉低与否就跟我fifo是否写入没有太大关系了:write信号就算拉高我也不一定写,write信号拉低我一定不写。组合结果就如上图红笔所示,写使能信号在full信号拉低后自己马上拉低,上游节点可以通过这个信号来判断是否继续发送数据,就不会造成数据丢失。(注,时序逻辑的情况下,write信号就是写使能信号,用组合逻辑full信号取反&w_en信号才是写使能)
2.在read方面,也有两种读的方式。假如同时读写,第一种情况是写入的数据马上能读出,使用组合逻辑;第二种情况就是写进去的数据,至少要在下一个时钟沿的时候才能读,使用时序逻辑,具体实现见代码。
3.读写与空满的情况。读写与空满有四种组合:读空(读信号有效与fifo空,后面类似),读满,写空,写满。读满和写空两种情况基本不用考虑,一定能成功,主要是看写满,读空的情况,这两种情况又主要是看读写指针的位置,如何判断空满参考上面推荐的课程(免费的),讲的很仔细。
RTL代码:
- module fifo#(
- parameter RAM_WIDTH = 6'd32,
- parameter RAM_DEPTH = 4'd8,
- parameter ADDR_WIDTH = 3'd4
- )(
- input clock,
- input resetn,
- input [RAM_WIDTH-1:0] data_in,
- input write_en,
- input read_en,
- output [RAM_WIDTH-1:0] data_out,
- output full,
- output empty
- );
- reg [ADDR_WIDTH-1:0] write_addr;
- reg [ADDR_WIDTH-1:0] read_addr;
- reg [RAM_WIDTH-1:0] RAM[RAM_DEPTH-1:0];
- always@(posedge clock or negedge resetn)
- if(!resetn)
- write_addr <= 'b0;
- else if(full == 1'b0 && write_en == 1'b1)
- write_addr <= write_addr + 1'b1;
- else
- write_addr <= write_addr;
-
- always@(posedge clock or negedge resetn)
- if(!resetn)
- read_addr <= 'b0;
- else if(empty == 1'b0 && read_en == 1'b1)
- read_addr <= read_addr + 1'b1;
- else
- read_addr <= read_addr;
-
- always@(posedge clock)begin
- if(full == 1'b0 && write_en == 1'b1)
- RAM[write_addr[2:0]] <= data_in;
- // if(empty == 1'b0 && read_en == 1'b1) //延时一拍后输出,需要把data_out改成output reg类型
- // data_out <= RAM[read_addr[2:0]];
- end
- assign data_out = (empty == 1'b0 && read_en == 1'b1)?RAM[read_addr[2:0]]:'b0;//组合逻辑输出
- assign empty = (write_addr == read_addr)?1'b1:1'b0;//空信号判断
- assign full = ((write_addr[ADDR_WIDTH-1] != read_addr[ADDR_WIDTH-1]) && (write_addr[ADDR_WIDTH-2:0] == read_addr[ADDR_WIDTH-2:0]))?1'b1:1'b0;//满信号判断
-
- endmodule
Simulation:
testbench随便写写吧。。。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。