同步FIFO的设计(计数器和高位扩展法)

1,FIFO

是一种先进的数据缓

存器,一般分两种同步和异步,先说同步,在设计中同步FIFO是只有一个时钟信号,所以要考虑到的是读空,和写满两个状态的判断。

常见参数:

FIFO的宽度,一次读写操的数据位

FIFO的深度,可以存储多少个位宽的数据

满标志,已满或者将要满是FIFO会发送一个信号,防止继续写,造成数据的溢出

空标志,已空或者将要空时FIFO会发送一个信号,防止继续读,造成无效数据读出

读写时钟(同步是一个时钟)

2.2

FIFO的设计的关键:

        产生可靠的FIFO读写地址并且生成FIFO“空/满”状态标志。

        当读写地址相同时,表明FIFO为空,这种情况发生在复位,或者读指针读出最后一个数据,追上了写指针。

        当读写指针再次相同时,表明FIFO为满,这种情况发生在写指针转了一圈,回来追上了读指针。

2.1计数器方法

构建一个计数器,该计数器fifo_cnt用来指示当前FIFO中的数据的个数:

复位时:该计数器为0,FIFO中的数据为0

当读写使能信号都有效时,说明又读又写,计数器不变,FIFO中的数据个数没有变化

当写使能有效且fifo非满,则fifo_cnt+1,表示写操作,fifo中的数据个数加1

当读使能有效且FIFO非空,则fifo_cnt- 1 ,表示读操作,FIFO中的数据个数减1

FIFO为空 empty = 1,fifo_cnt = 0,    fifo为满 full fifo_cnt为FIFO深度最大值

2.2verilog实现

module sync_fifo_cnt

#(
	parameter DATA_WIDTH = 'd8 ,
	parameter DATA_DEPTH = 'd16 ,
	parameter DATA_ADDR  = 'd4

)
(

	input     						 clk  ,
	input    						 rst_n ,
	input [DATA_WIDTH - 1 : 0]   	 data_in ,
	input     						 rd_en ,
	input 							 wr_en ,
	
	output 	reg  [DATA_WIDTH-1 :0]   data_out ,
	output 							 empty  ,
	output 							 full  ,
	output reg   [DATA_ADDR :0 ]	 fifo_cnt ,
	

);
reg [DATA_WIDTH-1 :0 ] fifo_buff [DATA_DEPTH - 1 :0] ;
reg [DATA_ADDR - 1 :0]  wr_addr ;
reg [DATA_ADDR - 1 :0]  rd_addr ;

//读操作
always@(posedge clk or negedge rst_n)begin
		if(!rst_n)
		rd_addr <= 1'b0 ;
		else if (!empty && rd_en)begin
			rd_addr <= rd_addr+1'b1;
			data_out <= fifo_buff[rd_addr] ;
			end
end 
//写操作

always@(posedge clk or negedge rst_n)begin
		if(!rst_n )
		wr_addr <= 1'b0;
		else if(!full&&wr_en)begin
		wr_addr <= wr_addr +1'b1;
		fifo_buff[wr_addr] <= data_in ;
		
		end 
end 

//计数器
always@(posedge clk or negedge rst_n )begin
			if(!rst_n)
				fifo_cnt <= 1'b0;
			else begin
				case ({wr_en,rd_en})
				2'b00 :fifo_cnt <= fifo_cnt ;
				2'b01 :		
					if(fifo_cnt!= 0)
					fifo_cnt <= fifo_cnt -1'b1;
				2'b10:
					if(fifo_cnt != DATA_DEPTH)
					fifo_cnt <= fifo_cnt +1'b1;
				2'b11:
				fifo_cnt <= fifo_cnt ;
				endcase 
			end 
		end 

assign full = (fifo_cnt == DATA_DEPTH) ? 1'b1 :1'b0;
assign empty = fifo_cnt == 0 ? 1'b1 :1'b0;

endmodule 

 2.2.1测试仿真

例化一个深度为8 ,位宽为8 的同步FIFO

先对FIFO 进行写操作,知道写满,写书数据随机

然后对FIFO读操作,知道读空

然后在对FIFO写入4 个数据,同时读写操作

   

`timescal 1ns/1ns
module tb_sync_fifo_cnt (
    
);
parameter  DATA_WIDTH   =  8 ;
parameter  DATA_DEPTH   = 8  ;
reg                     clk ;
reg                     rst_n ;
reg [DATA_WIDTH - 1 :0] data_in ;
reg                     rd_en ;
reg                     wr_en ;


wire [DATA_WIDTH - 1: 0]  data_out;
wire                        empty ;
wire                          full;
wire [4:0]                  fifo_cnt ;

sync_fifo_cnt 
#(
    .DATA_WIDTH(DATA_WIDTH),
    .DATA_DEPTH(DATA_DEPTH)
)
sync_fifo_cnt_inst(
    .clk(clk),
    .rst_n(rst_n),
    .data_in(data_in),
    .rd_en(rd_en),
    .wr_en(wr_en),
    .data_out(data_out),
    .empty(empty),
    .full(full),
    .fifo_cnt(fifo_cnt)

);

initial begin
	clk = 1'b0;							//初始时钟为0
	rst_n <= 1'b0;						//初始复位
	data_in <= 'd0;		
	wr_en <= 1'b0;		
	rd_en <= 1'b0;
//重复8次写操作,让FIFO写满 	
	repeat(8) begin		
		@(negedge clk)begin		
			rst_n <= 1'b1;				
			wr_en <= 1'b1;		
			data_in <= $random;			//生成8位随机数
		end
	end
//重复8次读操作,让FIFO读空	
	repeat(8) begin
		@(negedge clk)begin		
			wr_en <= 1'b0;
			rd_en <= 1'd1;
		end
	end
//重复4次写操作,写入4个随机数据	
	repeat(4) begin
		@(negedge clk)begin		
			wr_en <= 1'b1;
			data_in <= $random;	//生成8位随机数
			rd_en <= 1'b0;
		end
	end
//持续同时对FIFO读写,写入数据为随机数据	
	forever begin
		@(negedge clk)begin		
			wr_en <= 1'b1;
			data_in <= $random;	//生成8位随机数
			rd_en <= 1'b1;
		end
	end
end
//------------<设置时钟>----------------------------------------------
always #10 clk = ~clk;			//系统时钟周期20ns

endmodule

   3,高位扩展法

例如3bit的地址,我们扩展成4bit 地址区间从3‘b000-3’b111变成4‘b0000-4'b1111,假设不看最高位的话,地址区间任然是3’b000-3'b111,所以,最高位就可以看作是指示位

总结:

当最高位不同,且其他位相同,则写指针多跑了一圈,表示写满了

当最高位相同,且其他位也相同,说明读指针追上了写指针,表示读空了。

3.1Verilog实现

module sync_fifo_ptr
# (
    parameter DATA_WIDTH = 'd8 ,
    parameter DATA_DEPTH = 'd16
)
(
    input  clk ,
    input rst_n ,
    input [DATA_WIDTH - 1 : 0] data_in ,
    input   rd_en ,
    input    wr_en,


    output   reg [DATA_WIDTH-1 :0] data_out ,
    output empty ,
    output full 

);

reg [DATA_WIDTH - 1 : 0] fifo_buffer [DATA_DEPTH - 1 :0];
reg [4:0] wr_ptr ;
reg [4:0] rd_ptr ;


wire [3:0]   wr_ptrt_true ;
wire [3:0]   rd_ptr_true ;
wire         wr_ptr_msb ;
wire         rd_ptr_msb ;

assign {wr_ptr_msb,wr_ptrt_true} = wr_ptr;
assign {rd_ptr_msb,rd_ptr_true } = rd_ptr ;


//read
always@(posedge clk or negedge rst_n)begin
    if(!rst_n)
    rd_ptr<= 1'b0;
    else if(rd_en && !empty)begin
    data_out <= fifo_buffer[rd_ptr];
    rd_ptr <= rd_ptr +1'b1;

end 
end

//write 
always@(posedge clk or negedge rst_n )begin
    if(!rst_n )
    wr_ptr<= 1'b0;
    else if(wr_en && !full)begin
        wr_ptr <= wr_ptr +1'b1;
        fifo_buffer[wr_ptr ] <= data_in ;
    end 
end

//
assign empty =(wr_ptr == rd_ptr )? 1'b1:1'b0;
assign full = (wr_ptr_msb != rd_ptr_msb) && (wr_ptrt_true == rd_ptr_true) ? 1'b1 :1'b0 ;

endmodule



 

测试与上面经测试一样,这边就不再演示了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
FIFO中添加计数器可以用于跟踪FIFO的状态。计数器可以记录FIFO的当前状态,例如FIFO中的元素数量或空闲空间。这些计数器可以帮助诊断FIFO中的问题并进行性能优化。 以下是一种实现FIFO计数器的方: 1. 在FIFO数据结构中添加两个变量:一个表示当前FIFO中的元素数量,另一个表示FIFO的总容量。 ```c++ typedef struct { int *buffer; int size; int head; int tail; int count; int capacity; } fifo_t; ``` 2. 在FIFO的初始化函数中将计数器变量初始化为0。 ```c++ void fifo_init(fifo_t *fifo, int *buffer, int size) { fifo->buffer = buffer; fifo->size = size; fifo->head = 0; fifo->tail = 0; fifo->count = 0; fifo->capacity = size; } ``` 3. 在FIFO的插入函数中,在成功插入元素后增加计数器的值。 ```c++ int fifo_put(fifo_t *fifo, int value) { if (fifo->count == fifo->capacity) { return -1; // FIFO已满 } fifo->buffer[fifo->tail] = value; fifo->tail = (fifo->tail + 1) % fifo->size; fifo->count++; return 0; // 插入成功 } ``` 4. 在FIFO的弹出函数中,在成功弹出元素后减少计数器的值。 ```c++ int fifo_get(fifo_t *fifo, int *value) { if (fifo->count == 0) { return -1; // FIFO为空 } *value = fifo->buffer[fifo->head]; fifo->head = (fifo->head + 1) % fifo->size; fifo->count--; return 0; // 弹出成功 } ``` 通过这种方,可以轻松地实现FIFO计数器功能。在需要监视FIFO状态时,只需读取计数器变量的值即可。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值