当前位置:   article > 正文

两种简单的同步fifo(不同的输出时序)_同步fifo时序图

同步fifo时序图

简单fifo的设计在这推一波西南交通大学邸志雄老师的课

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代码:

  1. module fifo#(
  2. parameter RAM_WIDTH = 6'd32,
  3. parameter RAM_DEPTH = 4'd8,
  4. parameter ADDR_WIDTH = 3'd4
  5. )(
  6. input clock,
  7. input resetn,
  8. input [RAM_WIDTH-1:0] data_in,
  9. input write_en,
  10. input read_en,
  11. output [RAM_WIDTH-1:0] data_out,
  12. output full,
  13. output empty
  14. );
  15. reg [ADDR_WIDTH-1:0] write_addr;
  16. reg [ADDR_WIDTH-1:0] read_addr;
  17. reg [RAM_WIDTH-1:0] RAM[RAM_DEPTH-1:0];
  18. always@(posedge clock or negedge resetn)
  19. if(!resetn)
  20. write_addr <= 'b0;
  21. else if(full == 1'b0 && write_en == 1'b1)
  22. write_addr <= write_addr + 1'b1;
  23. else
  24. write_addr <= write_addr;
  25. always@(posedge clock or negedge resetn)
  26. if(!resetn)
  27. read_addr <= 'b0;
  28. else if(empty == 1'b0 && read_en == 1'b1)
  29. read_addr <= read_addr + 1'b1;
  30. else
  31. read_addr <= read_addr;
  32. always@(posedge clock)begin
  33. if(full == 1'b0 && write_en == 1'b1)
  34. RAM[write_addr[2:0]] <= data_in;
  35. // if(empty == 1'b0 && read_en == 1'b1) //延时一拍后输出,需要把data_out改成output reg类型
  36. // data_out <= RAM[read_addr[2:0]];
  37. end
  38. assign data_out = (empty == 1'b0 && read_en == 1'b1)?RAM[read_addr[2:0]]:'b0;//组合逻辑输出
  39. assign empty = (write_addr == read_addr)?1'b1:1'b0;//空信号判断
  40. 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;//满信号判断
  41. endmodule

Simulation:

testbench随便写写吧。。。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/206729?site
推荐阅读
相关标签
  

闽ICP备14008679号