zxopenljx 发表于 2021-3-29 15:59:08

至芯FPGA初级课程之 FIFO

原文链接:https://mp.weixin.qq.com/s/e3DJ2cgAIhXI1B_Z4bq7gw
今天讲课的题目是:FIFO。
本节课我先简要地介绍一下FIFO(先进先出存储器)的基本概念,然后实际演示一下应用FIFO的IP核来进行FIFO逻辑电路的建模与仿真,并通过仿真查看效果。
FIFO是First Input First Output的缩写,先进先出队列,这是一种传统的按序执行方法,是一种先进先出的数据缓存器,它与普通存储器的区别是没有外部读写地址线,这样使用起来非常简单,但缺点就是只能顺序写入数据,顺序读出数据,其数据地址由内部读写指针自动加1完成,不能像普通存储器那样可以由地址线决定读取或写入某个指定的地址。
接下来我们学习如何在Quartus中使用FIFO IP核,我们常用的FIFO为双时钟的异步FIFO,在这里为了较为简单,方便大家理解,虽然我们使用的是异步FIFO,但两个时钟端口使用的确是同一个时钟。
图片
恰当地使用各种已有IP核资源,能使您的设计事半功倍,实现高效开发。
FIFO不同于堆栈,堆栈操作是后进先出(LIFO),相同的地方是二者都是顺序操作,只不过FIFO是在一端写入,另一端读出,而堆栈是只在一端进行读写操作。
普通存储器需要由地址线决定读取或写入某个指定的地址,FIFO和堆栈则不然,都是对地址进行顺序操作。这也是FIFO作为先进先出存储器的基本特性。
下面我们就来使用FIFO的IP核设计一个FIFO写入和FIFO读出的逻辑,然后检查读出结果是否正确。FIFO的基本概念既然已经清楚,我们下面来进行系统设计。
命名FIFO的逻辑为my_fifo。
后面还要建一个fifo逻辑用于调用这个my_fifo逻辑和fifo_write写控制逻辑、fifo_read读控制逻辑。
my_fifo架构图如下所示。
图片
在my_fifo逻辑的前级添加fifo_write写控制逻辑、fifo_read读控制逻辑之后,完整的演示程序fifo.v逻辑架构如下图所示。
图片
新建工程文件夹fifo。
打开Quartus II软件,打开新工程向导。
新建逻辑模块fifo.v。
搭建逻辑框架。
module fifo (clk, rst_n, q);
      input clk, rst_n;
      
      output q;
endmodule
下一步用IP核管理工具生成my_fifo逻辑。
进入主菜单选择IP核管理界面。
图片
IP核管理界面p1。
默认为新建,点击Next。
图片
IP核管理界面p2a。
在左上方搜索框内输入fifo,点击Memory Compiler下方出现的FIFO,右侧矩形框内输入输出文件的名称my_fifo,点击Next。
图片
IP核管理界面p3。
检查q为8 bits,FIFO deep为256 words,选No使用分开(respectively)的rdclk和wrclk。
点击Next。直接跳到IP核管理界面p5。
图片
IP核管理界面p4。
点击Next。
图片
IP核管理界面p5。
检查Read-side和Write-side两栏中的full和empty均已选中。
点击Nex
图片
IP核管理界面p6.
点击Next。
图片
IP核管理界面p7。
点击Next
图片
IP核管理界面p8。
点击Next。
图片
IP核管理界面p9。
选中最后两行my_fifo_inst.v和my_fifo_bb.v。
点击Finish,完成IP核管理界面的设置,总计10个设置页面
图片
这时检查工程导航一栏,发现Files一项中已经自动生成对应的IP核文件my_fifo.qip。
打开下一级的my_fifo.v,可以看到其封装代码。
图片
在资源管理器的工程文件夹下找到已经生成的my_fifo_inst.v文件,打开该文件。
my_fifo      my_fifo_inst (
      .data ( data_sig ),
      .rdclk ( rdclk_sig ),
      .rdreq ( rdreq_sig ),
      .wrclk ( wrclk_sig ),
      .wrreq ( wrreq_sig ),
      .q ( q_sig ),
      .rdempty ( rdempty_sig ),
      .rdfull ( rdfull_sig ),
      .wrempty ( wrempty_sig ),
      .wrfull ( wrfull_sig )
      );
将my_fifo_inst.v代码拷贝粘贴到fifo.v模块中,修改实例化的信号名。
新建fifo_write和fifo_read控制模块,编写框架代码。
在fifo.v模块中放入fifo_write和fifo_read控制模块,对其进行实例化操作。
编写fifo.v模块如下。
module fifo (clk, rst_n, q);
      input clk, rst_n;
      
      output q;
      
      wire wrreq, rdreq;
      wire wrfull, wrempty, rdfull, rdempty;
      wire data;
      fifo_write fifo_write_inst (
                        .clk(clk),
                        .rst_n(rst_n),
                        .wrfull(wrfull),
                        .wrempty(wrempty),
                        .wrreq(wrreq),
                        .data(data)
                );
      fifo_read fifo_read_inst (
                        .clk(clk),
                        .rst_n(rst_n),
                        .rdfull(rdfull),
                        .rdempty(rdempty),
                        .rdreq(rdreq)
                );
      my_fifo      my_fifo_inst (
                        .data ( data ),
                        .rdclk ( clk ),
                        .rdreq ( rdreq ),
                        .wrclk ( clk ),
                        .wrreq ( wrreq ),
                        .q ( q ),
                        .rdempty ( rdempty ),
                        .rdfull ( rdfull ),
                        .wrempty ( wrempty ),
                        .wrfull ( wrfull )
                );
endmodule
继续完成fifo_write控制模块。
编写fifo_write控制模块代码如下。
module fifo_write (clk, rst_n, wrfull, wrempty, wrreq, data);
      input clk, rst_n;
      input wrfull, wrempty;
      
      output reg wrreq;
      output reg data;
      
      reg state;
      
      always @ (posedge clk or negedge rst_n)
                begin
                        if (!rst_n)
                              begin
                                        wrreq <= 0;
                                        data <= 0;
                                        state <= 0;
                              end
                        else
                              begin
                                        case (state)
                                        0      :      begin
                                                                if (wrempty)
                                                                        begin
                                                                              wrreq <= 1;
                                                                              data <= 0;
                                                                              state <= 1;
                                                                        end
                                                                else
                                                                        begin
                                                                              state <= 0;
                                                                        end
                                                      end
                                                      
                                        1      :      begin
                                                                if (wrfull)
                                                                        begin
                                                                              wrreq <= 0;
                                                                              data <= 0;
                                                                              state <= 0;
                                                                        end
                                                                else
                                                                        begin
                                                                              wrreq <= 1;
                                                                              data <= data + 8'd1;
                                                                              state <= 1;
                                                                        end
                                                      end
                                                      
                                        default      :      state <= 0;
                                       
                                        endcase
                              end
                end
endmodule
继续完成fifo_read控制模块。
编写fifo_read控制模块代码如下。
module fifo_read (clk, rst_n, rdfull, rdempty, rdreq);
      input clk, rst_n;
      input rdfull, rdempty;
      
      output reg rdreq;
      
      reg state;
      
      always @ (posedge clk or negedge rst_n)
                begin
                        if (!rst_n)
                              begin
                                        rdreq <= 0;
                                        state <= 0;
                              end
                        else
                              begin
                                        case (state)
                                        0      :      begin
                                                                if (rdfull)
                                                                        begin
                                                                              rdreq <= 1;
                                                                              state <= 1;
                                                                        end
                                                                else
                                                                        begin
                                                                              state <= 0;
                                                                        end
                                                      end
                                                      
                                        1      :      begin
                                                                if (rdempty)
                                                                        begin
                                                                              rdreq <= 0;
                                                                              state <= 0;
                                                                        end
                                                                else
                                                                        begin
                                                                              rdreq <= 1;
                                                                              state <= 1;
                                                                        end
                                                      end
                                                      
                                        default      :      state <= 0;
                                       
                                        endcase
                              end
                end
endmodule
新建仿真模块Testbench。
新建fifo_tb.v模块,编写代码如下。
`timescale 1ns/1ps
module fifo_tb;
      reg clk, rst_n;
      
      wire q;
      
      fifo dut (.clk(clk), .rst_n(rst_n), .q(q));
      initial
                begin
                        clk = 1;
                        rst_n = 0;
                        #200.1
                        rst_n = 1;
                     
                        #20_000 $stop;
                end
               
      always #10 clk = ~clk;
      
endmodule
仿真运行结果
设置好仿真之后,可以看到仿真结果。
可以看到复位完成后,data依次写入0~255,然后q依次读出0~255,依次循环。
观察FIFO为读空(rdempty)的状态。
FIFO在复位完成后或者读出255后,rdempty为高,然后rdreq置0。随后wrempty变高(FIFO自身特性),然后wrreq置1,写入一个数据后,wrempty马上变低。
图片
观察FIFO为写满(wrfull)的状态。
FIFO在写入255时,下一时钟wrfull变高,然后wrreq置0。随后rdfull变高(FIFO自身特性),然后rdreq置1,读出一个数据后,rdfull马上变低。
图片
仿真运行结果表明读出结果与写入数据一致,与设计要求相符。
查看RTL视图——dcfifo
图片
通过今天的课程,我们学习了FIFO(先进先出存储器)的基本概念,然后实际演示了一下应用FIFO的IP核来进行FIFO逻辑电路的建模与仿真,并通过仿真查看效果。
希望大家掌握FIFO的基本概念,并熟练运用Verilog语言调用对应的IP核编写相关逻辑。

zhangyukun 发表于 2021-3-30 09:14:01

至芯FPGA初级课程之 FIFO
页: [1]
查看完整版本: 至芯FPGA初级课程之 FIFO