同步FIFO的Verilog实现(转载)

关键:本文简单说明了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初始化时,WP和RP指针指向同一数据单元。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 buffer
output 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-<span class="hljs-number">2</span>:<span class="hljs-number">0</span>] rd_ptr,wr_ptr;  <span class="hljs-comment">//这个很重要,数据指针3位宽度,0-7索引,8个数据深度,循环指针0-7-0-7</span>
reg [<span class="hljs-number">7</span>:<span class="hljs-number">0</span>] buf_mem[<span class="hljs-number">0</span>:`BUF_SIZE-<span class="hljs-number">1</span>];

<span class="hljs-comment">//判断空满</span>
assign buf_empty = (fifo_cnt == <span class="hljs-number">0</span>);  <span class="hljs-comment">//buf_empty若是reg类型则错,不能使用assign持续赋值</span>
assign buf_full  = (fifo_cnt == `BUF_SIZE);

always @(posedge clk <span class="hljs-keyword">or</span> negedge rst_n)<span class="hljs-keyword">begin</span>
	<span class="hljs-keyword">if</span>(!rst_n)
		fifo_cnt &lt;= <span class="hljs-number">0</span>;
	<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>((!buf_full&amp;&amp;wr_en)&amp;&amp;(!buf_empty&amp;&amp;rd_en)) <span class="hljs-comment">//同时读写,数量不变</span>
		fifo_cnt &lt;= fifo_cnt;
	<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(!buf_full &amp;&amp; wr_en)          <span class="hljs-comment">//写数据</span>
		fifo_cnt &lt;= fifo_cnt + <span class="hljs-number">1</span>;
	<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(!buf_empty &amp;&amp; rd_en)         <span class="hljs-comment">//读数据</span>
		fifo_cnt &lt;= fifo_cnt-<span class="hljs-number">1</span>;
	<span class="hljs-keyword">else</span> 
		fifo_cnt &lt;= fifo_cnt;
<span class="hljs-keyword">end</span>

always @(posedge clk <span class="hljs-keyword">or</span> negedge rst_n) <span class="hljs-keyword">begin</span>   <span class="hljs-comment">//读数据</span>
	<span class="hljs-keyword">if</span>(!rst_n)
		buf_out &lt;= <span class="hljs-number">0</span>;
	<span class="hljs-keyword">if</span>(rd_en &amp;&amp; !buf_empty)
		buf_out &lt;= buf_mem[rd_ptr];
<span class="hljs-keyword">end</span>

always @(posedge clk) <span class="hljs-keyword">begin</span>
	<span class="hljs-keyword">if</span>(wr_en &amp;&amp; !buf_full)
		buf_mem[wr_ptr] &lt;= buf_in;
<span class="hljs-keyword">end</span>

always @(posedge clk <span class="hljs-keyword">or</span> negedge rst_n) <span class="hljs-keyword">begin</span>
	<span class="hljs-keyword">if</span>(!rst_n) <span class="hljs-keyword">begin</span>
		wr_ptr &lt;= <span class="hljs-number">0</span>;
		rd_ptr &lt;= <span class="hljs-number">0</span>;
	<span class="hljs-keyword">end</span>
	<span class="hljs-keyword">else</span> <span class="hljs-keyword">begin</span>
		<span class="hljs-keyword">if</span>(!buf_full &amp;&amp; wr_en)
			wr_ptr &lt;= wr_ptr + <span class="hljs-number">1</span>;
		<span class="hljs-keyword">if</span>(!buf_empty &amp;&amp; rd_en)
			rd_ptr &lt;= rd_ptr + <span class="hljs-number">1</span>;
	<span class="hljs-keyword">end</span>
<span class="hljs-keyword">end</span>

endmodule

使用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 buffer
wire [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

<span class="hljs-function">fifo_counter <span class="hljs-title">dut</span>(<span class="hljs-params">clk,rst_n,buf_in,buf_out,wr_en,rd_en,buf_empty,buf_full,fifo_cnt</span>)</span>;

always <span class="hljs-meta">#10 clk = ~clk;</span>

reg [<span class="hljs-number">7</span>:<span class="hljs-number">0</span>] tempdata = <span class="hljs-number">0</span>;
initial begin
	clk = <span class="hljs-number">0</span>;
	rst_n = <span class="hljs-number">0</span>;
	wr_en = <span class="hljs-number">0</span>;
	rd_en = <span class="hljs-number">0</span>;
	buf_in = <span class="hljs-number">0</span>;
	<span class="hljs-meta">#15;</span>
	rst_n = <span class="hljs-number">1</span>;
	
	push(<span class="hljs-number">1</span>);
    <span class="hljs-function">fork
       <span class="hljs-title">push</span>(<span class="hljs-params"><span class="hljs-number">2</span></span>)</span>;
       pop(tempdata);
    <span class="hljs-keyword">join</span>              <span class="hljs-comment">//push and pop together   </span>
    push(<span class="hljs-number">10</span>);
    push(<span class="hljs-number">20</span>);
    push(<span class="hljs-number">30</span>);
    push(<span class="hljs-number">40</span>);
    push(<span class="hljs-number">50</span>);
    push(<span class="hljs-number">60</span>);
    push(<span class="hljs-number">70</span>);
    push(<span class="hljs-number">80</span>);
    push(<span class="hljs-number">90</span>);
    push(<span class="hljs-number">100</span>);
    push(<span class="hljs-number">110</span>);
    push(<span class="hljs-number">120</span>);
    push(<span class="hljs-number">130</span>);

    pop(tempdata);
    push(tempdata);
    pop(tempdata);
    pop(tempdata);
    pop(tempdata);
    pop(tempdata);
	push(<span class="hljs-number">140</span>);
    pop(tempdata);
    push(tempdata);<span class="hljs-comment">//</span>
    pop(tempdata);
    pop(tempdata);
    pop(tempdata);
    pop(tempdata);
    pop(tempdata);
    pop(tempdata);
    pop(tempdata);
    pop(tempdata);
    pop(tempdata);
    pop(tempdata);
    pop(tempdata);
    push(<span class="hljs-number">5</span>);
    pop(tempdata);
	
<span class="hljs-function">end

task <span class="hljs-title">push</span> (<span class="hljs-params">input [<span class="hljs-number">7</span>:<span class="hljs-number">0</span>] data</span>)</span>;
	<span class="hljs-keyword">if</span>(buf_full)
		$display(<span class="hljs-string">"---Cannot push %d: Buffer Full---"</span>,data);
	<span class="hljs-keyword">else</span> begin
		$display(<span class="hljs-string">"Push"</span>,,data);
		buf_in = data;
		wr_en = <span class="hljs-number">1</span>;
		@(posedge clk);
		<span class="hljs-meta">#5 wr_en = 0;</span>
	<span class="hljs-function">end
endtask

task <span class="hljs-title">pop</span>(<span class="hljs-params">output[<span class="hljs-number">7</span>:<span class="hljs-number">0</span>] data</span>)</span>;
	<span class="hljs-keyword">if</span>(buf_empty)
		$display(<span class="hljs-string">"---Cannot Pop: Buffer Empty---"</span>);
	<span class="hljs-keyword">else</span> begin
		rd_en = <span class="hljs-number">1</span>;
		@(posedge clk);
		<span class="hljs-meta">#3 rd_en = 0;</span>
		data = buf_out;
		$display(<span class="hljs-string">"------Poped:"</span>,,data);
	end		
endtask

endmodule

程序仿真打印结果:

# 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
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值