Verilog RTL 设计:同步FIFO的设计与验证 方法二

接上一篇同步FIFO的设计。其中产生空、满信号的方法是采用一个计数器,判断计数器中的数来确定FIFO的空满状态。这次采用另外一种方法设计同步FIFO。

方法二:将FIFO的读写地址分别拓展一个高位。当拓展的地址最高位相同,其余低位相同时,说明读写地址相同,此时FIFO内没有数据,即产生empty信号。

                                                                             当拓展的地址最高位相反,其余低位相同时,说明读写地址相距最远,此时FIFO内充满了数据,即产生full信号。

RTL:

 1 module    sync_fifo #(parameter     DATA_WIDTH = 8,
 2                                     DATA_DEPTH = 16,
 3                                     ADDR_WIDTH = 4)
 4 (   input    wire                    clk,
 5     input    wire                    rst_n,
 6     input    wire                    wr_en,
 7     input    wire[DATA_WIDTH-1:0]    wr_data,
 8     input    wire                    rd_en,
 9     output   reg [DATA_WIDTH-1:0]    rd_data,
10     output   reg                     full,
11     output   reg                     empty
12 );
13 //addr
14 reg [ADDR_WIDTH:0]      wr_addr_a,rd_addr_a;
15 wire[ADDR_WIDTH-1:0]    wr_addr = wr_addr_a[ADDR_WIDTH-1:0];
16 wire[ADDR_WIDTH-1:0]    rd_addr = rd_addr_a[ADDR_WIDTH-1:0];
17 //memory
18 reg [DATA_WIDTH-1:0]    mem[DATA_DEPTH-1:0];
19 
20 wire                    rd_allow = rd_en && !empty;
21 wire                    wr_allow = wr_en && !full;
22 
23 //read data
24 always @(posedge clk or negedge rst_n)
25     if(rst_n==1'b0)
26         rd_addr_a <= 'b0;
27     else if(rd_allow)   begin
28         rd_data <= mem[rd_addr];
29         rd_addr_a <= rd_addr_a + 1'b1;
30     end
31         
32 //read data
33 always @(posedge clk or negedge rst_n)
34     if(rst_n==1'b0)
35         wr_addr_a <= 'b0;
36     else if(wr_allow)   begin
37         mem[wr_addr] <= wr_data;
38         wr_addr_a <= wr_addr_a + 1'b1;
39     end
40 
41 assign  empty = (rd_addr_a == wr_addr_a);
42 assign  full  = (rd_addr_a[ADDR_WIDTH] != wr_addr_a[ADDR_WIDTH]) && (rd_addr_a[ADDR_WIDTH-1:0] == wr_addr_a[ADDR_WIDTH-1:0]);
43 
44 endmodule

testbech :和方法一的一样。

 1 `timescale 1ns/1ps
 2 module sync_fifo_tb;
 3 
 4 parameter        DATA_WIDTH = 8,
 5                 DATA_DEPTH = 16,
 6                 ADDR_WIDTH = 4,
 7                 PERIOD       = 20;
 8 
 9 
10 reg                        clk,rst_n,wr_en,rd_en;
11 reg[DATA_WIDTH-1:0]        wr_data;
12 wire                    full,empty;
13 wire[DATA_WIDTH-1:0]    rd_data;
14 
15 sync_fifo #(.DATA_WIDTH(DATA_WIDTH),
16             .DATA_DEPTH(DATA_DEPTH),
17             .ADDR_WIDTH(ADDR_WIDTH)
18             )
19 sync_fifo_inst(    
20     .clk    (clk) ,
21     .rst_n  (rst_n) ,
22     .wr_en  (wr_en) ,
23     .wr_data(wr_data) ,
24     .rd_en  (rd_en) ,
25     .rd_data(rd_data) ,
26     .full   (full) ,
27     .empty  (empty) 
28 );
29 
30 initial begin
31     rst_n = 0;
32     clk = 0;
33     #5
34     rst_n = 1;
35 end
36 
37 always #(PERIOD/2)    clk=~clk;
38 
39 initial begin
40     wr_en = 0;
41     rd_en = 0;
42     #5
43     wr_en = 1;
44     wr_data = 8'h0;
45     #20    wr_data = 8'h1;
46     #20    wr_data = 8'h2;
47     #20    wr_data = 8'h3;
48     #20    wr_data = 8'h4;
49     #20    wr_data = 8'h5;
50     #20    wr_data = 8'h6;
51     #20    wr_data = 8'h7;
52     #20    wr_data = 8'h8;
53     #20    wr_data = 8'h9;
54     #20    wr_data = 8'hA;
55     #20    wr_data = 8'hB;
56     #20    wr_data = 8'hC;
57     #20    wr_data = 8'hD;
58     #20    wr_data = 8'hE;
59     #20    wr_data = 8'hF;
60   #20 wr_en = 0;
61     #20 rd_en = 1;
62     #400
63     $finish;
64 end
65 
66 `include "vpd.inc"
67 
68 endmodule

DVE仿真波形

 

 

从代码设计的角度,采用拓展一位地址的方法比方法一简单,也更好理解。

此次记录同步FIFO的方法二的设计和验证结果。

 

关注公众号,回复“sync_fifo_2”, 可获得源码

 

posted @ 2021-03-15 00:57  辰风阆苑  阅读(331)  评论(0编辑  收藏  举报