FPGA之FIFO详解,读写位宽不同
2022/2/9 23:14:05
本文主要是介绍FPGA之FIFO详解,读写位宽不同,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
这篇博客里,通过两个练习来总结在FPGA设计中FIFO读写位宽不同的情况下,我们应该去如何设计时序逻辑,因为在现实工程中FIFO读写位宽不同也是经常出现的情况。
练习1
设计一个模块包含读写位宽是32bit、读写深度是64的异步时钟FIFO,其中输入数据信号din和输入 数据指示信号din_vld是属于clk_in时钟域的,上游模块会负责写数据到本模块的FIFO中,当本模块FIFO写端口已写入了60个数据,也就是FIFO快要写满溢出的时候,这时上游模块仍有数据要写入FIFO则直接丢弃该数据。下游模块负责从本模块的FIFO中读数据,当下游模块输入rdy信号时表示下游模块已准备好可以接收FIFO中的数据了,这时如果FIFO中有数据,那么就把FIFO中的数据赋值给输出数据信号dout送至下游模块并同时拉高dout_vld输出数据指示信号,其中输出数据信号dout和输出数据指示信号dout_vld则是属于clk_out时钟域的,上游模块din信号的写位宽是32bit,下游模块dout信号的读位宽是8bit,表1为练习1的信号列表。
信号列表 | ||
信号名 | I/O | 位宽 |
clk_in | I | 1 |
rst_n | I | 1 |
rdy | I | 1 |
din | I | 32 |
din_vld | I | 1 |
clk_out | I | 1 |
dout | O | 8 |
dout_vld | O | 1 |
fifo_empty | O | 1 |
表1 FIFO IP练习1设计中的信号列表
我们来思考下练习1功能模块的代码设计,其实不同的地方主要在于上游模块的写位宽din是32bit,而下游模块的读位宽dout是8bit,两者位宽是不一致的,同样的方法我们也在Vivado下初始化一个读写位宽是32bit、读写深度是64的异步时钟FIFO,因为FIFO读写位宽都是32bit,所以上游模块直接写入FIFO即可,这里和练习1中的方法完全一样,但是在读取FIFO的时候,又因为下游模块的读位宽是8bit,而一次性从FIFO中读出的数据是32bit,我们就需要用一个cnt计数器去计数拆分32bit的数据,dout再依次去输出从32bit数据拆分来的数据,同时也拉高dout_vld指示信号,如图1所示FIFO IP练习1的代码设计,具体细节笔者就不再赘述了。
对于FIFO IP练习1的Testbench,其实和FIFO读写位宽相同的设计也大同小异,先模拟上游模块向本模块的写入数据,再模拟输入下游模块准备就绪的rdy信号,这里只补充说明一点,因为FIFO写端口的输入时钟是50Mhz,而读端口的输出时钟是100Mhz,其中上游模块的写位宽din是32bit,下游模块的读位宽dout是8bit,所以给出120个时钟的rdy高电平,大家可以简单计算下,写端口属于clk_in时钟域,120个clk_in应该是120*20ns=2400ns。而读端口属于clk_out时钟域,2400ns就是对应写端口的2400ns/10ns=240个时钟周期,因为下游模块的读位宽是8bit,所以说要输出完32bit*60的数据,需要32bit*60/8bit也就是240个时钟周期,如图2是FIFO IP练习1的输入信号激励设计。
大家打开Vivado环境,添加好功能文件和测试文件后,启动Modelsim进行仿真,如图3是FIFO IP练习1的仿真结果,可以清楚地观察到当fifo_empty为高时,即FIFO当前已经没有数据了,此时恰好dout输出FIFO中的最后一个数据,且dout_vld被拉高,和我们预期的设计效果完全相符。
图1 FIFO IP练习1的代码设计
图2 FIFO IP练习1的输入信号激励设计
图3 FIFO IP练习1的仿真结果
练习2
设计一个模块包含读写位宽是32bit、读写深度是64的异步时钟FIFO,其中输入数据信号din和输入数据指示信号din_vld是属于clk_in时钟域的,上游模块会负责写数据到本模块的FIFO中,当本模块FIFO写端口已写入了60个数据,也就是FIFO快要写满溢出的时候,这时上游模块仍有数据要写入FIFO则直接丢弃该数据。下游模块负责从本模块的FIFO中读数据,当下游模块输入rdy信号时表示下游模块已准备好可以接收FIFO中的数据了,这时如果FIFO中有数据,那么就把FIFO中的数据赋值给输出数据信号dout送至下游模块并同时拉高dout_vld输出数据指示信号,其中输出数据信号dout和输出数据指示信号dout_vld则是属于clk_out时钟域的,上游模块din信号的写位宽是8bit,下游模块dout信号的读位宽是32bit,表2为练习2的信号列表。
信号列表 | ||
信号名 | I/O | 位宽 |
clk_in | I | 1 |
rst_n | I | 1 |
rdy | I | 1 |
din | I | 8 |
din_vld | I | 1 |
clk_out | I | 1 |
dout | O | 32 |
dout_vld | O | 1 |
fifo_empty | O | 1 |
表2 FIFO IP练习2设计中的信号列表
练习2和练习1一样都是在FIFO相同读写位宽的基础上的延伸扩展,当然Vivado环境下完全支持异步时钟FIFO配置成位宽不同的读写端口,实际工作中也有不少FPGA工程师习惯性去把异步时钟FIFO读写端口根据需求人为配置成位宽不同的,但是笔者还是推荐大家把读写位宽都配置成相同的,这样在程序设计上也更简便不需要再去考虑一些其他因素影响,这里练习1和练习2其实把现实工作中上游模块输入信号din和下游模块输出信号dout的两种可能情况都包括在内了,所以大家实践过这两个练习,在实际项目中完全可以灵活应用,就可以达到二次开发的效果,练习2是输入信号din位宽是32bit,输出信号dout位宽是8bit,所以我们需要对FIFO的输出进行拆分,而练习2相反的是输入信号din位宽是8bit,输出信号dout位宽是32bit,所以我们需要对FIFO的输入进行拼接,练习1和练习2中包含了对数据拼接和拆分的一般性方法,有很强的代表性,如图4所示FIFO IP练习2的代码设计。
对于FIFO IP练习2的Testbench,其实类似练习1,在练习2中因为FIFO写端口的输入时钟是50Mhz,读端口的输出时钟是100Mhz,这里上游模块的写位宽din是8bit,下游模块的读位宽dout是32bit,所以也给出了240个时钟周期的din_vld信号用以模拟上游模块向本模块写入240个8bit的数据,之后再去给出30个clk_in时钟周期的rdy高电平模拟下游模块读数据,这里30个clk_in是30*20ns=600ns,读端口在clk_out时钟域,600ns就对应读端口的600ns/10ns=60个时钟周期,因为下游模块的读位宽是32bit,所以说要输出完32bit*60的数据,需要60个时钟周期,如图5是FIFO IP练习2的输入信号激励设计。如图6 FIFO IP练习2的仿真结果,大家代入Modelsim下可以观察到和预期的设计效果完全一致。
图4 FIFO IP练习2的代码设计
图5 FIFO IP练习2的输入信号激励设计
图6 FIFO IP练习2的仿真结果
这篇关于FPGA之FIFO详解,读写位宽不同的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-25JAVA语音识别项目项目实战入门教程
- 2024-11-25JAVA云原生项目实战入门教程
- 2024-11-25Java语音识别项目入门:新手必读指南
- 2024-11-25Java语音识别项目入门:轻松开始你的第一个语音识别项目
- 2024-11-25Java语音识别项目入门详解
- 2024-11-25Java语音识别项目教程:从零开始的详细指南
- 2024-11-25JAVA语音识别项目教程:初学者指南
- 2024-11-25Java语音识别项目教程:初学者指南
- 2024-11-25JAVA云原生入门:新手指南与基础教程
- 2024-11-25Java云原生入门:从零开始的全面指南