Verilog同步FIFO

来源:互联网 发布:淘宝店铺的链接在哪里 编辑:程序博客网 时间:2024/05/17 08:29

关键:本文简单说明了FIFO的实现方式,同步FIFO,判断full或者empty方法使用FIFO内容计数器,设置一个变量fifo_cnt记录存储器中数据个数:

        //判断空满
assign buf_empty = (fifo_cnt == 0);  //buf_empty若是reg类型则错,不能使用assign持续赋值
assign buf_full  = (fifo_cnt == `BUF_SIZE);


Implementing a FIFO using Verilog

    FIFO uses a dual port memory and there will be two pointers to point read and write addresses. Here is a generalized block diagram of FIFO. 简单来说,FIFO就是一个双口RAM加上两个读写指针。


Generally fifos are implementedusing rotating pointers. We can call write and read pointers of a FIFO as headand tail of data area. Initially read and write pointers of the FIFO will pointto the same location

一般FIFO使用循环指针(计数溢出自动归零)。一般可以称写指针为头head,读指针为尾tail。初始化时,读写指针指向同一数据地址。

Here is an example to explain howFIFO uses the memory. This is a fifo of length 8, WP and RP are the locationswhere write pointer and read pointer points. Shaded area in the diagram isfilled with data.

下图可见,FIFO初始化时,WPRP指针指向同一数据单元。WP指向下一个将要写入的数据单元,RP指向将要读出的数据单元


When ever FIFO counter becomes zeroor BUF_LENGTH, empty or full flags will beset.

使用fifo_counter记录FIFO RAM中的数据个数,等于0时,给出empty信号,等于BUF_LENGTH时,给出full信号

fifo_counter is incremented ifwrite takes place and buffer is not full and will be decremented id read takesplace and buffer is not empty. If both read and write takes place, counter willremain the same.

fifo_counter写而未满时增加1,读而未空时减1。同时发生读写操作时,fifo_counter不变。

rd_ptr and wr_ptr are read andwrite pointers. Since we selected the bits in these registers same as addresswidth of buffer, when buffer overflows, values will overflow and become 0.

读写指针宽度与地址宽度相当,地址增加而溢出后,自动变成0。循环指针,此处地质变化:0-7-0-7-0

程序代码:

`define BUF_WIDTH   4     //地址宽度为3+1,`define BUF_SIZE    8    //数据个数,FIFO深度module fifo_counter( clk,rst_n,buf_in,buf_out,wr_en,rd_en,buf_empty,buf_full,fifo_cnt);input clk,rst_n;input wr_en,rd_en;input [7:0] buf_in;             // data input to be pushed to bufferoutput reg [7:0] buf_out;       // port to output the data using pop.output wire buf_empty,buf_full;  // buffer empty and full indication output reg [`BUF_WIDTH-1:0] fifo_cnt;  // number of data pushed in to buffer                                         //写入数据等于8时,满reg [`BUF_WIDTH-2:0] rd_ptr,wr_ptr;  //这个很重要,数据指针3位宽度,0-7索引,8个数据深度,循环指针0-7-0-7reg [7:0] buf_mem[0:`BUF_SIZE-1];//判断空满assign buf_empty = (fifo_cnt == 0);  //buf_empty若是reg类型则错,不能使用assign持续赋值assign buf_full  = (fifo_cnt == `BUF_SIZE);always @(posedge clk or negedge rst_n)beginif(!rst_n)fifo_cnt <= 0;else if((!buf_full&&wr_en)&&(!buf_empty&&rd_en)) //同时读写,数量不变fifo_cnt <= fifo_cnt;else if(!buf_full && wr_en)          //写数据fifo_cnt <= fifo_cnt + 1;else if(!buf_empty && rd_en)         //读数据fifo_cnt <= fifo_cnt-1;else fifo_cnt <= fifo_cnt;endalways @(posedge clk or negedge rst_n) begin   //读数据if(!rst_n)buf_out <= 0;if(rd_en && !buf_empty)buf_out <= buf_mem[rd_ptr];endalways @(posedge clk) beginif(wr_en && !buf_full)buf_mem[wr_ptr] <= buf_in;endalways @(posedge clk or negedge rst_n) beginif(!rst_n) beginwr_ptr <= 0;rd_ptr <= 0;endelse beginif(!buf_full && wr_en)wr_ptr <= wr_ptr + 1;if(!buf_empty && rd_en)rd_ptr <= rd_ptr + 1;endendendmodule 

使用Modelsim仿真的程序:

`define BUF_WIDTH   4     //地址宽度为3+1,`define BUF_SIZE    (8)    //数据个数,FIFO深度module tb_fifo_counter;reg clk,rst_n;reg wr_en,rd_en;reg [7:0] buf_in;             // data input to be pushed to bufferwire [7:0] buf_out;       // port to output the data using pop.    wire buf_empty,buf_full;  // buffer empty and full indication wire [`BUF_WIDTH-1:0] fifo_cnt;  // number of data pushed in to buffer fifo_counter dut(clk,rst_n,buf_in,buf_out,wr_en,rd_en,buf_empty,buf_full,fifo_cnt);always #10 clk = ~clk;reg [7:0] tempdata = 0;initial beginclk = 0;rst_n = 0;wr_en = 0;rd_en = 0;buf_in = 0;#15;rst_n = 1;push(1);        fork           push(2);           pop(tempdata);        join              //push and pop together           push(10);        push(20);        push(30);        push(40);        push(50);        push(60);        push(70);        push(80);        push(90);        push(100);        push(110);        push(120);        push(130);        pop(tempdata);        push(tempdata);        pop(tempdata);        pop(tempdata);        pop(tempdata);        pop(tempdata);push(140);        pop(tempdata);        push(tempdata);//        pop(tempdata);        pop(tempdata);        pop(tempdata);        pop(tempdata);        pop(tempdata);        pop(tempdata);        pop(tempdata);        pop(tempdata);        pop(tempdata);        pop(tempdata);        pop(tempdata);        push(5);        pop(tempdata);endtask push (input [7:0] data);if(buf_full)$display("---Cannot push %d: Buffer Full---",data);else begin$display("Push",,data);buf_in = data;wr_en = 1;@(posedge clk);#5 wr_en = 0;endendtasktask pop(output[7:0] data);if(buf_empty)$display("---Cannot Pop: Buffer Empty---");else beginrd_en = 1;@(posedge clk);#3 rd_en = 0;data = buf_out;$display("------Poped:",,data);endendtaskendmodule 

程序仿真打印结果:

# Push   1# Push   2# ------Poped:   1# Push  10# Push  20# Push  30# Push  40# Push  50# Push  60# Push  70# ---Cannot push  80: Buffer Full---# ---Cannot push  90: Buffer Full---# ---Cannot push 100: Buffer Full---# ---Cannot push 110: Buffer Full---# ---Cannot push 120: Buffer Full---# ---Cannot push 130: Buffer Full---# ------Poped:   2# Push   2# ------Poped:  10# ------Poped:  20# ------Poped:  30# ------Poped:  40# Push 140# ------Poped:  50# Push  50# ------Poped:  60# ------Poped:  70# ------Poped:   2# ------Poped: 140# ------Poped:  50# ---Cannot Pop: Buffer Empty---# ---Cannot Pop: Buffer Empty---# ---Cannot Pop: Buffer Empty---# ---Cannot Pop: Buffer Empty---# ---Cannot Pop: Buffer Empty---# ---Cannot Pop: Buffer Empty---# Push   5# ------Poped:   5


程序仿真图:






1 0