【IC设计】同步FIFO

FIFO是一个先进先出的数据结构,顺序写入,顺序读出。

FIFO的输入端口有:时钟与复位信号(clk、rst_n)、读写使能信号(write_sig、read_sig)、写数据信号(data_write)。

FIFO的输出端口有:数据读出信号(data_read)、判空信号(empty_sig)、判满信号(full_sig)。

FIFO的内部存储模块可以使用RAM进行建模,数据写入和读出都是对这个RAM进行操作,同时,FIFO内部还要有两个指针,用于指示写入数据的位置(write_pointer)和读出数据的位置(read_pointer),此外这两个指针的相对位置还可以用来判断空满。

同步FIFO如何判断空满?

使用扩展位来判断FIFO的空满,当读写指针的扩展位(最高位)不同,而剩余低位相同时,FIFO满。当读写指针的大小相等时,FIFO为空。

这个结论是怎么来呢?

假设一个FIFO的深度为4,按理说读写指针的长度为2就够用了,但考虑有指针读或者写到最高地址后会回到最低地址位继续读或写,也就意味着需要一个扩展位来指示指针是否已经先写完一轮了,为1的时候表示该指针已经相对在第二轮了。读或者写都不可能连续超过两轮,也就是不会出现写第三轮的情况,因此读写情况就可以分为如下四种情况:

(1)读指针和写指针都在第一轮,最高位都等于0,那么只有当读写指针相等的时候,才为空,不可能出现满的情况。

 (2)写指针在开始进入第二轮,其最高位变为1,而读还在第一轮,最高位仍为0,这种情况下只有读写指针的低位地址相等时,才为满,不可能出现空的情况。

(3)读写指针均进入第二轮,最高位都为1,此时读写指针的大小相等的时候,才为空,不可能出现满的情况。

(4)当写指针回到第一轮的时候,最高位变为0,读指针还在第二轮,最高位为1,这种情况下,当读写指针的低位地址相等时,才为满。不可能出现空的情况。

 

总的来说,判空就是读指针追上了写指针,而判满就是写指针追上了读指针。

 同FIFO设计代码

`timescale 1ns/1ns
module SYN_FIFO #(parameter DEPTH=16,
                   WIDTH=8,
                   P_WIDTH=5)
        (input clk,
         input rst_n,
         input write_sig,
         input read_sig,
         input [WIDTH-1:0] data_write,
    
         output [WIDTH-1:0] data_read,
         output full_sig,
         output empty_sig
);

reg [WIDTH-1:0]   RAM [DEPTH-1:0];
reg [P_WIDTH-1:0] pointer_write;
reg [P_WIDTH-1:0] pointer_read;
reg [WIDTH-1:0]   rdata_read;

assign data_read=rdata_read;
assign full_sig=((pointer_write[P_WIDTH-1]!=pointer_read[P_WIDTH-1])&&(pointer_write[P_WIDTH-2:0]==pointer_read[P_WIDTH-2:0]))?1:0;
assign empty_sig=(pointer_write[P_WIDTH-1:0]==pointer_read[P_WIDTH-1:0])?1:0;

always@(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
       pointer_write<=0;
       pointer_read<=0;
       rdata_read<=0;
    end
    else 
    if(!empty_sig&&!full_sig&&write_sig&&read_sig)begin
       RAM[pointer_write[P_WIDTH-2:0]]<=data_write;
       rdata_read<=RAM[pointer_read[P_WIDTH-2:0]];
       pointer_write<=pointer_write+1;
       pointer_read<=pointer_read+1;
    end
    else
    if(!empty_sig&&read_sig)begin
       rdata_read<=RAM[pointer_read[P_WIDTH-2:0]];
       pointer_read<=pointer_read+1;
    end
    else
    if(!full_sig&&write_sig)begin
       RAM[pointer_write[P_WIDTH-2:0]]<=data_write;
       pointer_write<=pointer_write+1;
    end
end
endmodule

Testbench

`timescale 1ns/1ns

module Syn_FIFO_tb;

parameter DEPTH = 16;
parameter WIDTH = 8;
parameter P_WIDTH = 5;

reg clk;
reg rst_n;
reg Write_Sig;
reg Read_Sig;
reg [7:0] Data_Write;
wire [7:0] Data_Read;
integer i;

wire Full_Sig;
wire Empty_Sig;

Syn_FIFO #(
		.DEPTH(DEPTH),
		.WIDTH(WIDTH),
		.P_WIDTH(P_WIDTH)
	) inst_Syn_FIFO (
		.rst_n      (rst_n),
		.clk        (clk),
		.Data_Write (Data_Write),
		.Write_Sig  (Write_Sig),
		.Read_Sig   (Read_Sig),
		.Data_Read  (Data_Read),
		.Full_Sig   (Full_Sig),
		.Empty_Sig  (Empty_Sig)
	);

always #5
	clk = ~clk;

initial begin
	clk = 1'b0;
	rst_n = 1'b1;
	@(posedge clk)
	#5 rst_n = 1'b0;
	@(posedge clk)
	#5 rst_n = 1'b1;
end 


initial begin	
	i = 4'd0;
	Write_Sig = 1'd0;
	Read_Sig = 1'd0;
	Data_Write = 8'd0;

	repeat(5) @(posedge clk);

	for(i=0; i<19; i=i+1) 
		Write_Data(1'd1, 12*(i+1));
	for(i=0; i<19; i=i+1)
		Read_Data(1'd1);

	for(i=0; i<19; i=i+1) 
		Write_Data(1'd1, 12*(i+1));
	for(i=0; i<8; i=i+1)
		Read_Data(1'd1);
	@(posedge clk)		
		Read_Sig <= 1'b0;
	for(i=0; i<19; i=i+1) 
		Write_Data(1'd1, 12*(i+1));

	for(i=0; i<19; i=i+1)
		Read_Data(1'd1);

	@(posedge clk)
	Write_Sig <= 1'b1;
	Data_Write <= 8'd3;
	@(posedge clk)
	Write_Sig <= 1'b1;
	Data_Write <= 8'd5;	

	@(posedge clk)
	Write_Sig <= 1'b1;
	Data_Write <= 8'd7;	
	Read_Sig <= 1'b1;

	@(posedge clk)
	Write_Sig <= 1'b0;
	Data_Write <= 8'd0;	
	Read_Sig <= 1'b1;

	@(posedge clk)		
	Read_Sig <= 1'b1;

	@(posedge clk)		
	Read_Sig <= 1'b1;

	@(posedge clk)		
	Read_Sig <= 1'b0;

	#30 $stop;
end 

task Write_Data(input reg Write_en,input reg [7:0] Data_in);
	begin
		@(posedge clk)
		if(Full_Sig) begin 
			Write_Sig <= 1'b0;
			Data_Write <= 8'd0;
		end
		else begin 
			Write_Sig <= Write_en;
			Data_Write <= Data_in;
		end
	end
endtask

task Read_Data(input reg Read_en);
	begin
		@(posedge clk)
		if(Empty_Sig) 
			Read_Sig <= 1'b0;
		else Read_Sig <= Read_en;
	end
endtask

endmodule

  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值