设计一个同步FIFO?
请设计一个宽度为8,深度为16的同步FIFO?
FIFO( First Input First Output)简单说就是指先进先出。由于微电子技术的飞速发展,新一代FIFO芯片容量越来越大,体积越来越小,价格越来越便宜。作为一种新型大规模集成电路,FIFO芯片以其灵活、方便、高效的特性,逐渐在高速数据采集、高速数据处理、高速数据传输以及多机处理系统中得到越来越广泛的应用。 来自FIFO存储器_百度百科 (baidu.com)。
FIFO分为同步FIFO和异步FIFO,本文主要介绍同步FIFO。
同步 FIFO 有一个时钟信号,读和写逻辑全部使用这一个时钟信号,FIFO 与普通存储器 RAM 的区别是没有外部读写地址线,使用起来非常简单,但缺点就是只能顺序写 入数据,顺序的读出数据,其数据地址由内部读写指针自动加 1 完成,不能像普通存储器那样可以由地址线 决定读取或写入某个指定的地址。 FIFO 本质上是由 RAM 加读写控制逻辑构成的一种先进先出的数据缓冲器。
FIFO设计的关键:产生可靠的 FIFO 读写指针和生成 FIFO“空”/“满”状态标志。
同步FIFO的框图&设计代码&激励&仿真波形:
module syn_fifo #( parameter DATA_WIDTH = 8 , //定义FIFO参数 宽度 和深度 parameter DATA_DEPTH = 16 , parameter PTR_WIDTH = 4 // 定义指针宽度 2^PTR_WIDTH=DATA_DEPTH ) ( input sys_clk , input sys_rst_n , input w_en , input r_en , input [DATA_WIDTH-1:0] data_in , output full , output empty , output reg [DATA_WIDTH-1:0] data_out ); reg [DATA_WIDTH-1:0] D_ram [DATA_DEPTH-1:0] ; //构造一个双端口 ram reg [PTR_WIDTH-1:0] w_ptr ; //写指针 reg [PTR_WIDTH-1:0] r_ptr ; //读指针 reg [PTR_WIDTH:0] cnt_num ; //FIFO中数据个数计数器 wire w_ram_en ; //ram写使能 wire r_ram_en ; //ram读使能 assign w_ram_en =w_en&&(!full); //写有信号有效 并未满时 ram写使能 有效 assign r_ram_en =r_en&&(!empty); //读有信号有效 并未空时 ram读使能 有效 //写控制模块 always@(posedge sys_clk or negedge sys_rst_n) begin if(!sys_rst_n) w_ptr<='d0; else if(w_ram_en) //在ram写使能有效 写时针+1 即 写地址+1 w_ptr<=w_ptr+'d1; else w_ptr<=w_ptr; end //读控制模块 always@(posedge sys_clk or negedge sys_rst_n) begin if(!sys_rst_n) r_ptr<='d0; else if(r_ram_en) //在ram读使能有效 读时针+1 即 读地址+1 r_ptr<=r_ptr+'d1; else r_ptr<=r_ptr; end //空满信号判断 //满信号 判断为 当前 未读 且 当前个数计数器 达到DATA_DEPTH-1的时候,拉高 FULL信号 //空信号 判断为 当前 未写 且 当前个数计数器 达到0的时候, 拉高 EMPTY信号 assign full =((!r_en)&&((cnt_num==DATA_DEPTH-1&&w_en)||(cnt_num==DATA_DEPTH-1)))?1'b1:1'b0; assign empty =((!w_en)&&((cnt_num=='d0&&r_en)|| (cnt_num=='d0)))?1'b1:1'b0; //当前FIFO中数据个数统计 always@(posedge sys_clk or negedge sys_rst_n) begin if(!sys_rst_n) cnt_num<='d0; else if(r_ram_en&&w_ram_en) //在写使能和读使能都有效情况下 个数保持不变 cnt_num<=cnt_num; else if(w_ram_en&&!r_ram_en) //在写使能有效、读使能无效情况下 个数+1 cnt_num<=cnt_num+'d1; else if(!w_ram_en&&r_ram_en) //在读使能有效、写使能无效情况下 个数-1 cnt_num<=cnt_num-'d1; else cnt_num<=cnt_num; end //读操作 always@(posedge sys_clk or negedge sys_rst_n) begin if(!sys_rst_n) data_out<='d0; else if(r_ram_en) data_out<=D_ram[r_ptr]; //在读使能有效情况下 将RAM中数据输出 先进先出 else data_out<=data_out; end //写操作 always@(posedge sys_clk or negedge sys_rst_n) begin if(!sys_rst_n) D_ram[w_ptr]<='d0; else if(w_ram_en) D_ram[w_ptr]<=data_in; //在写使能有效情况下 将数据输入RAM中 先进先出 else D_ram[w_ptr]<=D_ram[w_ptr]; end endmodule
`timescale 1ns/1ns module tb_syn_fifo(); reg sys_clk ; reg sys_rst_n ; reg r_en ; reg w_en ; reg [7:0] data_in ; wire full ; wire empty ; wire [7:0] data_out ; initial begin //仿真激励 sys_clk<=1'b0; sys_rst_n<=1'b0; r_en<=1'b0; w_en<=1'b0; data_in<=8'd0; #20 sys_rst_n<=1'b1; #10 w_en<=1'b1; #320 w_en<=1'b0; r_en<=1'b1; #300 r_en<=1'b0; w_en<=1'b1; #200 w_en<=1'b0; #100 r_en<=1'b1; #50 w_en<=1'b0; #100 r_en<=1'b0; #20 w_en<=1'b1; #10 r_en<=1'b1; #1000 w_en<=1'b0; #200 r_en<=1'b0; #200 r_en<=1'b0; w_en<=1'b0; #20 w_en<=1'b1; #300 w_en<=1'b0; #20 r_en<=1'b0; #100 r_en<=1'b1; #100 w_en<=1'b1; #200 r_en<=1'b1; #300 w_en<=1'b0; #50 r_en<=1'b0; end always # 20 data_in<=data_in+1'b1; always # 10 sys_clk<=~sys_clk ; syn_fifo #( .DATA_WIDTH( 8 ) , .DATA_DEPTH( 16) , .PTR_WIDTH ( 4 ) //2^PTR_WIDTH=DATA_DEPTH ) syn_fifo_inst ( .sys_clk (sys_clk ) , .sys_rst_n(sys_rst_n) , .w_en (w_en ) , .r_en (r_en ) , .data_in (data_in ) , .full (full ) , .empty (empty ) , .data_out (data_out ) ); endmodule
以下是深度为8,宽度为8的同步FIFO仿真波形。
若有不对的地方,敬请指正,万分感谢。
参考资料:
1、正点原子逻辑设计指南设计同步FIFO
2、【数字IC】同步FIFO设计详解(含源码) - 知乎 (zhihu.com)