【从零开始のIC学习笔记】同步FIFO

前言

FIFO是数字IC中常用的模块,本文介绍同步FIFO的概念及Verilog代码实现


一、同步FIFO是什么?

FIFO(Fist in Fist Out)是先入先出的存储模块,主要进行数据缓存,进行速率匹配,上下游数据速率不同时进行匹配,同步是指具有一定相位关系的时钟,同步FIFO的读时钟和写时钟为同一个时钟。

二、同步FIFO的组成

 同步FIFO由三部分组成:1.FIFO写控制逻辑 2.FIFO读控制逻辑 3.FIFO存储实体

FIFO写控制逻辑主要功能:产生FIFO写地址、写有效有信号,同时产生FIFO写满、写错等状态信号

FIFO读控制逻辑主要功能:产生FIFO读地址、读有效信号,同时产生FIFO读空、读错等状态信号

二、同步FIFO代码

1.信号定义

同步FIFO具有以下引脚

信号名方向说明
clkinput系统时钟
rst_ninput复位信号,低有效
wr_eninput写使能信号
rd_eninput读使能信号
wr_datainput写入的数据
rd_dataoutput读出的数据
emptyoutputFIFO中没有数据,空信号
fulloutputFIFO中写满数据,满信号
fifo_cntoutput

FIFO中的数据数量

(非必要,可用于判断空满,可用于一些特殊应用)

其中使用参数化,DATA_WIDTH指的是数据的位宽,这里设置为8,即一个数据最大为256

                             FIFO_DEPTH指的是FIFO的深度,这里设置为16,即FIFO最大能容纳16个数

module sync_fifo #(parameter DATA_WIDTH = 8,
                   parameter FIFO_DEPTH = 16)
       ( //system signal
        input                            clk,       //sys clock
        input                            rst_n,     //reset signal ,low active
        
        //write and read signal
        input                            wr_en,    //write enable
        input                            rd_en,    //read  enable
        input      [DATA_WIDTH-1:0]      wr_data,  //write data
        output reg [DATA_WIDTH-1:0]      rd_data,  //read data
 
       //flag signal
       output                             empty,    //fifo empty
       output                             full,     //fifo full
       output reg  [$clog2(FIFO_DEPTH):0] fifo_cnt  //fifo data number
      );

2.变量定义

localparam ADDR_WIDTH = $clog2(FIFO_DEPTH)-1; //地址的位宽,深度16的FIFO宽度为3
reg [ADDR_WIDTH:0] rd_ptr;                    //读指针(地址),大小为3,即[2:0]        
reg [ADDR_WIDTH:0] wr_ptr;                    //写指针(地址),大小为3,即[2:0]

3.读写指针

always@(posedge clk or negedge rst_n)
	if(!rst_n)
		rd_ptr <= {ADDR_WIDTH{1'b0}}; //读指针复位为0
	else if(rd_ptr==FIFO_DEPTH-1)
		rd_ptr <= {ADDR_WIDTH{1'b0}};//当计数到最大,读指针恢复为0,若最大值与位宽对应,可不写
	else if(rd_en && !empty)
		rd_ptr <= rd_ptr + 1'b1;      //读使能且FIFO非空,读指针+1

always@(posedge clk or negedge rst_n)
	if(!rst_n)
		wr_ptr <= {ADDR_WIDTH{1'b0}};//写指针复位为0
	else if(wr_ptr==FIFO_DEPTH-1)
		wr_ptr <= {ADDR_WIDTH{1'b0}};//当计数到最大,写指针恢复为0,若最大值与位宽对应,可不写
	else if(wr_en && !wfull)
		wr_ptr <= wr_ptr + 1'b1;      //写使能且FIFO非满,写指针+1

4.空满信号

空满信号的判断有两种方式:

a.通过对FIFO中的数据进行计数,若计数值为0,则空;若计数值等于FIFO深度,则满,本文使用这种方式

always@(posedge clk or negedge rst_n)
	if(!rst_n)
	    fifo_cnt <= {(ADDR_WIDTH+1){1'b0}};     //复位将计数值清零
    else if(wr_en && rd_en)
        fifo_cnt <= fifo_cnt;               //当同时进行读写时,计数值不变
    else if(wr_en && !full)          
        fifo_cnt <= fifo_cnt + 1'b1;        //当进行写时,计数值+1
    else if(rd_en && !empty)                
        fifo_cnt <= fifo_cnt - 1'b1;        //当进行读时,计数值-1

assign full = (fifo_cnt == FIFO_DEPTH);     //当计数值为FIFO深度时,表示已满
assign empty= (fifo_cnt == 0);              //当计数值为0时,表示已空

b.通过是否“套圈”来判断空满。当写指针写满一圈又和读指针相同时,已经写满。可通过增加读写指针位宽,利用最高位来指示是否"套圈"

reg rd_flag;
reg wr_flag;

always@(posedge clk or negedge rst_n)
	if(!rst_n)
		rd_flag <= 1'b0;                //读标志复位为0
	else if(rd_ptr == FIFO_DEPTH-1)  
		rd_flag = ~rd_flag;             //每当读到最大值,读标志翻转

always@(posedge clk or negedge rst_n)
	if(!rst_n)
		wr_flag <= 1'b0;                //写标志复位为0
	else if(wr_ptr == FIFO_DEPTH-1)
		wr_flag = ~wr_flag;             //每当写到最大值,写标志翻转

always@(posedge clk or negedge rst_n)
	if(!rst_n)
		empty <= 1'b0;
	else if(rd_flag==wr_flag && wr_ptr==rd_ptr)  //若读写标志相同,且读写指针相同,空
		empty <= 1'b1;
	else
		empty <= 1'b0;
	
always@(posedge clk or negedge rst_n)
	if(!rst_n)
		full <= 1'b0;
	else if(rd_flag!=wr_flag && wr_ptr==rd_ptr) //若读写标志不同,且读写指针相同,满
		full <= 1'b1;
	else
		full <= 1'b0;

4.FIFO实体(RAM)

本文例化双端口RAM,双端口RAM链接如下:双端口RAM​​​​​​​

需要注意的是,对于双端口RAM的读写使能,需要判断空满状态

dual_port_RAM RAM1(
    .rst_n(rst_n),
	.wr_clk(clk),
	.wr_en(wr_en & !full),
	.wr_addr(wr_r_ptr),  
	.wr_data(wdata),      	
	.rd_clk(clk),
	.rd_en(rd_en & !empty),
	.rd_addr(rd_ptr), 
	.rd_data(rdata) 		
);

总结

本文介绍了同步FIFO的基本概念以及参数化的verilog代码实现,对于空满判断,介绍了两种方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值