FIFO 是FPGA设计中最有用的模块之一。FIFO 在模块之间提供简单的握手和同步机制,是设计人员将数据从一个模块传输到另一个模块的常用选择。
在这篇文章中,展示了一个简单的 RTL 同步 FIFO,可以直接在自己的设计中配置和使用它,该设计是完全可综合的。
为什么要自己设计FIFO
那么,为什么呢?网上有很多关于 FIFO 的 Verilog/VHDL 代码的资源,过去,我自己也使用过其中的一些。但令人沮丧的是,它们中的大多数都存在问题,尤其是在上溢出和下溢出条件下。所以想一劳永逸地解决这些问题。
FIFO 规格性能
同步,单时钟。
基于寄存器的 FIFO,适用于中小型 FIFO。
Full、Empty、Almost-full、Almost-empty 标志。
完全可配置的数据宽度、深度和标志。
完全可综合的系统 Verilog 代码。
?
/*=============================================================================================================================== ???Design???????:?Single-clock?Synchronous?FIFO ???Description??:?Fully?synthesisable,?configurable?Single-clock?Synchronous?FIFO?based?on?registers. ??????????????????-?Configurable?Data?width. ??????????????????-?Configurable?Depth. ??????????????????-?Configurable?Almost-full?and?Almost-empty?signals.? ===============================================================================================================================*/ module?my_fifo?#( ???????????????????parameter?DATA_W???????????=?4??????,????????//?Data?width ???????????????????parameter?DEPTH????????????=?8??????,????????//?Depth?of?FIFO??????????????????? ???????????????????parameter?UPP_TH???????????=?4??????,????????//?Upper?threshold?to?generate?Almost-full ???????????????????parameter?LOW_TH???????????=?2???????????????//?Lower?threshold?to?generate?Almost-empty ????????????????) ????????????????( ???????????????????input???????????????????clk?????????,????????//?Clock ???????????????????input???????????????????rstn????????,????????//?Active-low?Synchronous?Reset ??????????????????? ???????????????????input???????????????????i_wren??????,????????//?Write?Enable ???????????????????input??[DATA_W?-?1?:?0]?i_wrdata????,????????//?Write-data ???????????????????output??????????????????o_alm_full??,????????//?Almost-full?signal ???????????????????output??????????????????o_full??????,????????//?Full?signal ???????????????????input???????????????????i_rden??????,????????//?Read?Enable ???????????????????output?[DATA_W?-?1?:?0]?o_rddata????,????????//?Read-data ???????????????????output??????????????????o_alm_empty?,????????//?Almost-empty?signal ???????????????????output??????????????????o_empty??????????????//?Empty?signal ????????????????); /*------------------------------------------------------------------------------------------------------------------------------- ???Internal?Registers/Signals -------------------------------------------------------------------------------------------------------------------------------*/ logic?[DATA_W?-?1????????:?0]?data_rg?[DEPTH]?;????????//?Data?array logic?[$clog2(DEPTH)?-?1?:?0]?wrptr_rg????????;????????//?Write?pointer logic?[$clog2(DEPTH)?-?1?:?0]?rdptr_rg????????;????????//?Read?pointer logic?[$clog2(DEPTH)?????:?0]?dcount_rg???????;????????//?Data?counter ?????? logic?????????????????????????wren_s??????????;????????//?Write?Enable?signal?generated?iff?FIFO?is?not?full logic?????????????????????????rden_s??????????;????????//?Read?Enable?signal?generated?iff?FIFO?is?not?empty logic?????????????????????????full_s??????????;????????//?Full?signal logic?????????????????????????empty_s?????????;????????//?Empty?signal /*------------------------------------------------------------------------------------------------------------------------------- ???Synchronous?logic?to?write?to?and?read?from?FIFO -------------------------------------------------------------------------------------------------------------------------------*/ always?@?(posedge?clk)?begin ???if?(!rstn)?begin????? ?????????? ??????data_rg???<=?'{default:?'0}?; ??????wrptr_rg??<=?0??????????????; ??????rdptr_rg??<=?0??????????????;?????? ??????dcount_rg?<=?0??????????????; ???end ???else?begin ??????ready_rg?<=?1'b1?; ?????? ??????/*?FIFO?write?logic?*/???????????? ??????if?(wren_s)?begin?????????????????????????? ????????? ?????????data_rg?[wrptr_rg]?<=?i_wrdata?;????????//?Data?written?to?FIFO ?????????if?(wrptr_rg?==?DEPTH?-?1)?begin ????????????wrptr_rg?<=?0???????????????;????????//?Reset?write?pointer?? ?????????end ?????????else?begin ????????????wrptr_rg?<=?wrptr_rg?+?1????;????????//?Increment?write?pointer???????????? ?????????end ??????end ??????/*?FIFO?read?logic?*/ ??????if?(rden_s)?begin????????? ?????????if?(rdptr_rg?==?DEPTH?-?1)?begin ????????????rdptr_rg?<=?0???????????????;????????//?Reset?read?pointer ?????????end ?????????else?begin ????????????rdptr_rg?<=?rdptr_rg?+?1????;????????//?Increment?read?pointer???????????? ?????????end ??????end ??????/*?FIFO?data?counter?update?logic?*/ ??????if?(wren_s?&&?!rden_s)?begin???????????????//?Write?operation ?????????dcount_rg?<=?dcount_rg?+?1?; ??????end???????????????????? ??????else?if?(!wren_s?&&?rden_s)?begin??????????//?Read?operation ?????????dcount_rg?<=?dcount_rg?-?1?;????????? ??????end ???end end /*------------------------------------------------------------------------------------------------------------------------------- ???Continuous?Assignments -------------------------------------------------------------------------------------------------------------------------------*/ //?Full?and?Empty?internal assign?full_s??????=?(dcount_rg?==?DEPTH)???1'b1?:?0?; assign?empty_s?????=?(dcount_rg?==?0????)???1'b1?:?0?; //?Write?and?Read?Enables?internal assign?wren_s??????=?i_wren?&?!full_s????????????????;?? assign?rden_s??????=?i_rden?&?!empty_s???????????????; //?Full?and?Empty?to?output assign?o_full??????=?full_s??????????????????????????; assign?o_empty?????=?empty_s?????????????????????????; //?Almost-full?and?Almost?Empty?to?output assign?o_alm_full??=?(dcount_rg?>?UPP_TH)???1'b1?:?0?; assign?o_alm_empty?=?(dcount_rg??
基于 RAM 的 FIFO
在上面的步骤中,我们看到了一个基于寄存器的同步FIFO。接下来,我们来看看基于 RAM 的 FIFO。该 FIFO 在 RAM 而不是寄存器上实现其数据阵列。这适用于在硬件上实现大型 FIFO ;特别是在 FPGA 上,FPGA 里有大量的Block RAM 可用。这将降低资源利用率,也可以获得更好的时序性能。
审核编辑:刘清
评论