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”, 可获得源码