一水寒

从同步FIFO看模块化设计风格

0
阅读(2928)

这两天抽时间把FIFO好好看了下,异步FIFO空满标志的算法值得深究,同步FIFO虽然用的不是很多,但是对于理解fifo的原理还是非常有益的,写异步FIFO也是先从写好同步fifo开始,下面贴出同步fifo代码,备忘...层次化设计是把更成细分为很多的小功能模块,设计思路非常清晰,代码简洁易懂,好的设计风格是每个模块代码都不要超过50-80行,,
层次化设计,原理图如下:一个顶层模块,四个功能模块分别是写地址发生器,读地址发生器,一个fifo标志位发生器,一个双口ram,首先划分功能模块,然后详细规划每个模块的接口设计,接口设计好了以后,用原理图把框架搭好,如下图所示,然后再往每个模块里面填代码。

第一个代码module是顶层模块,对应下面顶层原理图,第二个module是下面四个小模块的例化,最后四个模块是功能模块代码。



顶层代码,用四个例化功能模块组成我们的同步FIFO,对应上面第一张图。其实这个模块是可以要也可以不要的,可以就用下面的my_fifo做顶层也是可以的,只是这样更清晰一些,等于把my_fifo再打一次包,我习惯这样。

module syn_fifo(//顶层 clk, rst_n, rd_en, wr_en, data_in, empty, full, data_out ); input wire clk; input wire rst_n; input wire rd_en; input wire wr_en; input wire [7:0] data_in; output wire empty; output wire full; output wire [7:0] data_out; my_fifo b2v_inst( .clk(clk), .rst_n(rst_n), .rd_en(rd_en), .wr_en(wr_en), .data_in(data_in), .empty(empty), .full(full), .data_out(data_out)); endmodule 下面是四个功能模块的例化,对应上面第二张图。
module my_fifo( clk, rst_n, rd_en, wr_en, data_in, empty, full, data_out); input wire clk; input wire rst_n; input wire rd_en; input wire wr_en; input wire [7:0] data_in; output wire empty; output wire full; output wire [7:0] data_out; wire empty_wire; wire full_wire; wire [3:0] rd_addr; wire [3:0] wr_addr; wr_addr_gen b2v_inst( .clk(clk), .rst_n(rst_n), .wr_en(wr_en), .full(full_wire), .wr_addr(wr_addr)); rd_addr_gen b2v_inst1( .clk(clk), .rst_n(rst_n), .rd_en(rd_en), .empty(empty_wire), .rd_addr(rd_addr)); flag_gen b2v_inst2( .clk(clk), .rst_n(rst_n), .rd_en(rd_en), .wr_en(wr_en), .full(full_wire), .empty(empty_wire)); ram b2v_inst3( .clk(clk), .rst_n(rst_n), .wr_en(wr_en), .rd_en(rd_en), .data_in(data_in), .rd_addr(rd_addr), .wr_addr(wr_addr), .data_out(data_out)); defparam b2v_inst3.depth = 16; assign empty = empty_wire; assign full = full_wire; endmodule
写地址发生器,当写使能信号为1而且fifo非满的时候写地址加1; module wr_addr_gen(clk, rst_n,wr_en, full, wr_addr); input clk; input rst_n; input full; input wr_en; output reg[3:0] wr_addr; always@(posedge clk or negedge rst_n) if(~rst_n) wr_addr<=4'b0000; else if(~full&wr_en) wr_addr<=wr_addr+1; else wr_addr<=4'b0; endmodule
module rd_addr_gen(clk, rst_n,rd_en, empty, rd_addr); input clk; input rst_n; input empty; input rd_en; output reg[3:0] rd_addr; always@(posedge clk or negedge rst_n) if(~rst_n) rd_addr<=4'b0000; else if(~empty&rd_en) rd_addr<=rd_addr+1; else rd_addr<=4'b0000; endmodule
module flag_gen(clk, rst_n, rd_en, wr_en, full, empty); input clk; input rst_n; input rd_en; input wr_en; output reg full; output reg empty; reg [4:0]fifo_cnt; always@(posedge clk or negedge rst_n) if(~rst_n)fifo_cnt<=0; else if(wr_en&rd_en) fifo_cnt<=fifo_cnt; else if(wr_en&~rd_en&~(fifo_cnt==16))//only write and fifo_cnt must <16; fifo_cnt<=fifo_cnt+1; //the data number in fifo will add 1; else if(~wr_en&rd_en&(fifo_cnt>0)) //only read and fifo_cnt must >0; fifo_cnt<=fifo_cnt-1; //the data number in fifo will subtract 1; always@(posedge clk) if(~rst_n) begin full<=0; empty<=0; end else if(fifo_cnt==0) begin empty<=1; full<=0; end else if(fifo_cnt==16) begin empty<=0; full<=1; end else begin empty<=0; full<=0; end endmodule
module ram(clk, rst_n, wr_en, rd_en, wr_addr, rd_addr, data_in, data_out); input clk; input rst_n; input wr_en; input rd_en; input [3:0] wr_addr; input [3:0] rd_addr; input [7:0] data_in; output reg[7:0] data_out; parameter depth=16; reg[7:0]fifo_data[depth-1:0]; always@(posedge clk or negedge rst_n) if(rst_n==0)data_out<=8'hzz; else begin if(wr_en) fifo_data[wr_addr]<=data_in; if(rd_en) data_out<=fifo_data[rd_addr]; //before this "if" can not add a "else" else //you can also write two block of 'always' data_out<=8'hzz; end endmodule

下面是我用的tsetbench,测试还算是全面的,,

`timescale 1 ns/ 1 ps module syn_fifo_tb(); reg clk; reg [7:0] data_in; reg rd_en; reg rst_n; reg wr_en; wire [7:0] data_out; wire empty; wire full; my_fifo i1 ( .clk(clk), .data_in(data_in), .data_out(data_out), .empty(empty), .full(full), .rd_en(rd_en), .rst_n(rst_n), .wr_en(wr_en) ); initial begin clk=0;rst_n=0;wr_en=0;rd_en=0;data_in=0; #20 rst_n=1; #20 wr_en=1;data_in=10; #20 wr_en=1;data_in=11; #20 wr_en=1;data_in=12; #20 wr_en=1;data_in=13; #20 wr_en=1;data_in=14; #20 wr_en=1;data_in=15; #20 wr_en=1;data_in=16; #20 wr_en=1;data_in=17; #20 wr_en=1;data_in=18; #20 wr_en=1;data_in=19; #20 wr_en=1;data_in=1; #20 wr_en=1;data_in=2; #20 wr_en=1;data_in=3; #20 wr_en=1;data_in=4; #20 wr_en=1;data_in=5; #20 wr_en=1;data_in=6; #20 wr_en=1;data_in=7; #20 rd_en=1;wr_en=0; #20 rd_en=1; #100 rd_en=1; #20 rd_en=0; #20 wr_en=1;data_in=30; #20 wr_en=1;data_in=29; #20 wr_en=1;data_in=28; #20 wr_en=1;data_in=27; #140 data_in=24; #100 rd_en=1; #20 wr_en=1;data_in=40; #20 wr_en=1;data_in=39; #20 wr_en=1;data_in=38; #20 wr_en=1;data_in=37; #20 wr_en=1;data_in=40; #20 wr_en=1;data_in=39; #20 wr_en=1;data_in=38; #20 wr_en=1;data_in=37; #40 wr_en=0; end always #10 clk=~clk; endmodule
Baidu
map