同步FIFO的verilog描述

 1 /******************************************************
 2 A fifo controller verilog description.
 3 ******************************************************/
 4 module fifo(datain, rd, wr, rst, clk, dataout, full, empty);
 5 input [7:0] datain;
 6 input rd, wr, rst, clk;
 7 output [7:0] dataout;
 8 output full, empty;
 9 wire [7:0] dataout;
10 reg full_in, empty_in;
11 reg [7:0] mem [15:0];
12 reg [3:0] rp, wp;//其实是一个循环读写的过程,4位二进制数刚好16个状态,也即指示16个深度
13 assign full = full_in;
14 assign empty = empty_in;
15 // memory read out
16 assign dataout = mem[rp];
17 // memory write in
18 always@(posedge clk) begin
19     if(wr && ~full_in) mem[wp]<=datain;
20 end
21 // memory write pointer increment
22 always@(posedge clk or negedge rst) begin
23     if(!rst) wp<=0;
24     else begin
25       if(wr && ~full_in) wp<= wp+1'b1;
26     end
27 end
28 // memory read pointer increment
29 always@(posedge clk or negedge rst)begin
30     if(!rst) rp <= 0;
31     else begin
32       if(rd && ~empty_in) rp <= rp + 1'b1;
33     end
34 end
35 // Full signal generate
36 always@(posedge clk or negedge rst) begin
37     if(!rst) full_in <= 1'b0;
38     else begin
39       if( (~rd && wr)&&((wp==rp-1)||(rp==4'h0&&wp==4'hf)))
40           full_in <= 1'b1;
41       else if(full_in && rd) full_in <= 1'b0;
42     end
43 end
44 // Empty signal generate
45 always@(posedge clk or negedge rst) begin
46     if(!rst) empty_in <= 1'b1;
47     else begin
48       if((rd&&~wr)&&(rp==wp-1 || (rp==4'hf&&wp==4'h0)))
49         empty_in<=1'b1;
50       else if(empty_in && wr) empty_in<=1'b0;
51     end
52 end
53 endmodule 
同步FIFO

  同步FIFO相对简单,但稍微复杂点儿的就是full和empty信号的产生,有两种方法上述代码是常用的,但不很容易理解,解释下,FIFO先入先出,可知读写地址都是从零开始递增,这样才能满足先写进的将来会被先读出来。对于同步FIFO来说,时钟是同一个,如果同时读写,那么FIFO永远都不会满。因为当写指针到FIFO尽头时,会继续从零地址开始写(假设零地址的数据已经被读出,当然就可以覆盖了),如此循环往复。那么到底空满标志如何产生:

  最直观的一种情况,对于full来说,假如一直写,都还没读,此时当wrp=FIFO深度时,应该产生满标志,如果继续写,就会覆盖还未读出的数据,从而使数据失效。

           对于empty来说,假如wrp=0,而rdp=FIFO深度时,应该产生空标志,如果继续读。就会从零地址开始读,而零地址要么是以前的数据要么是空的,所以…

  第二种情况:wrp与rdp之间差值为1,rdp-wrp=1时如果没有读,继续写的话会发生数据覆盖;wrp-rdp=1时如果没有写继续读,会读出错误数据。

  这就是程序中标志位表达形式的原因。

  还有一种简单的方法产生空满标志:

并不用读写地址判定FIFO是否空满。设计一个计数器,该计数器(pt_cnt)用于指示当前周期中FIFO中数据的个数。由于FIFO中最多只有16个数据,因此采用5位计数器来指示FIFO中数据个数。具体计算如下:

l  复位的时候,pt_cnt=0;

l  如果wr_en和rd_en同时有效的时候,pt_cnt不加也不减;表示同时对FIFO进行读写操作的时候,FIFO中的数据个数不变。

l  如果wr_en有效且full=0,则pt_cont+1;表示写操作且FIFO未满时候,FIFO中的数据个数增加了1;

l  如果rd_en有效且empty=0,则pt_cont-1; 表示读操作且FIFO未满时候,FIFO中的数据个数减少了1;

l  如果pt_cnt=0的时候,表示FIFO空,需要设置empty=1;如果pt_cnt=16的时候,表示FIFO现在已经满,需要设置full=1。

该模块的程序:

 1 module flag_gen(clk,rst,full,emptyp,wr_en,rd_en);
 2 input clk,rst;
 3 input rd_en;
 4 input wr_en;
 5 output full,emptyp;
 6 reg full,emptyp;
 7 reg[4:0]count;
 8 parameter max_count=5'b01111;
 9 always @ (posedge clk or negedge rst)
10 begin
11   if(!rst)
12    count<=0;
13   else
14    begin
15    case({wr_en,rd_en})
16    2'b00:count<=count;
17    2'b01:
18        if(count!==5'b00000)
19        count<=count-1;
20    2'b10:
21        if(count!== max_count)   
22         count<=count+1;
23    2'b11:count<=count;
24    endcase
25    end
26 end
27 always @(count)
28 begin
29    if(count==5'b00000)
30     emptyp<=1;
31    else
32     emptyp<=0;
33 end
34 always @(count)
35 begin
36    if(count== max_count)
37    full<=1;
38    else
39    full<=0;                                 
40 end
41 endmodule
full、empty标志位的产生

我们又一次见证了位拼接运算符的强大。

原文地址:https://www.cnblogs.com/fkl523/p/4046755.html