Verilog RTL 设计:同步FIFO的设计与验证 方法一
最近在学习FIFO,于是将学习成果记录一下。
仿真工具为VCS,并用DVE观测波形。
FIFO 表示先入先出,它是一种存储器结构,被广泛的应用与芯片设计中。FIFO分为同步FIFO和异步FIFO,本次记录同步FIFO的设计和验证。
在同步FIFO中,单一时钟同时用于写入和读取数据操作。FIFO的设计原则:满不能写,空不能读。
以下是FIFO的结构框图:
设计的关键: 如何产生empty和full信号。
方法一:采用一个计数器,当执行一次写操作时,计数器加1,执行一次读操作时,计数器减一。
当计数器为0时,说明FIFO为空,或者计数器为1时,此时正在执行读操作,都说明FIFO为空。此时empty拉高。
当计数器为最大FIFO深度时,说明FIFO为满,或者计数器差一个到最大FIFO深度,而此时正在写操作,都说明FIFO为满,此时full拉高。
在后续会采用另外一种方法来实现FIFO的空满信号的产生。
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-1:0] wr_addr,rd_addr; 15 //memory 16 reg[DATA_WIDTH-1:0] mem[DATA_DEPTH-1:0]; 17 //counter 18 reg[ADDR_WIDTH-1:0] count; 19 20 wire rd_allow = rd_en && !empty; 21 wire wr_allow = wr_en && !full; 22 23 24 //empty 25 always @(posedge clk or negedge rst_n) 26 if (!rst_n) 27 empty <= 1'b1; 28 else 29 empty <= (!wr_en && count[ADDR_WIDTH-1:1]=='b0) && (count[0]==1'b0 || rd_en); 30 31 //full 32 always @(posedge clk or negedge rst_n) 33 if (!rst_n) 34 full <= 1'b0; 35 else 36 full <= (!rd_en && count[ADDR_WIDTH-1:1]=={ADDR_WIDTH-1{1'b1}}) && (count[0]==1'b1 || wr_en); 37 38 //rd_addr 39 always @(posedge clk or negedge rst_n) 40 if (!rst_n) 41 rd_addr <= 'd0; 42 else if(rd_allow) begin 43 rd_data <= mem[rd_addr]; 44 rd_addr <= rd_addr + 1'b1; 45 end 46 47 48 //wr_addr 49 always @(posedge clk or negedge rst_n) 50 if (!rst_n) 51 wr_addr <= 'd0; 52 else if(wr_allow) begin 53 mem[wr_addr] <= wr_data; 54 wr_addr <= wr_addr + 1'b1; 55 end 56 57 always @(posedge clk or negedge rst_n) 58 if (!rst_n) 59 count <= 'd0; 60 else if ( (!rd_allow && wr_allow) || (rd_allow && !wr_allow) ) begin 61 if( wr_allow ) 62 count <= count + 1'b1; 63 else 64 count <= count - 1'b1; 65 end 66 67 endmodule
testbench设计:
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 #20 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 rd_en = 1; 61 wr_en = 0; 62 #400 63 $finish; 64 end 65 66 endmodule
DVE仿真:
此次记录同步FIFO的设计。
关注公众号,回复“sync_fifo_1” 可获源码。