同步FIFO

本文介绍了一种同步FIFO的设计方法,包括其工作原理、关键参数及其在Verilog中的实现方式。同步FIFO适用于同一时钟域内,用于解决数据缓存问题,避免数据冲突。文章还提供了一个具体的8x8同步FIFO实例代码及仿真测试。
摘要由CSDN通过智能技术生成


异步FIFO请看: 异步FIFO
===========------------------
👉注:本文所使用的的所有代码均已编译并仿真通过,仿真结果附于文中。
👉注:更多精彩请看: 面试常问的verilog代码汇总 一文
===========------------


前言

FIFO是英文First In First Out 的缩写,是一种先进先出的数据缓存器,他与普通存储器的区别是没有外部读写地址线,,但缺点就是只能顺序写入数据,顺序的读出数据,其数据地址由内部读写指针自动加1完成,不能像普通存储器那样可以由地址线决定读取或写入某个指定的地址。

FIFO使用场景

  • 异步FIFO一般用于不同时钟域之间的数据传输,在两个时钟域之间采用FIFO作为数据缓冲;
  • 对于不同宽度的数据接口也可以用FIFO,例如单片机位8位数据输出,而DSP可能是16位数据输入,在单片机与DSP连接时就可以使用FIFO来达到数据匹配的目的。

FIFO参数

  • 宽度:THE WIDTH,是FIFO一次读写操作的数据位宽
  • 深度:THE DEEPTH,是FIFO可以存储多少个N位的数据(如果宽度为N)。如一个8位的FIFO,若深度为8,它可以存储8个8位的数据,深度为12 ,就可以存储12个8位的数据
  • 满标志:FIFO已满或将要满时由FIFO的状态电路送出的一个信号,以阻止FIFO的写操作继续向FIFO中写数据而造成溢出(overflow
  • 空标志:FIFO已空或将要空时由FIFO的状态电路送出的一个信号,以阻止FIFO的读操作继续从FIFO中读出数据而造成无效数据的读出(underflow)
  • 读时钟:读操作所遵循的时钟,在每个时钟沿来临时读数据
  • 写时钟:写操作所遵循的时钟,在每个时钟沿来临时写数据
  • 读指针:指向下一个读出地址。读完后自动加1
  • 写指针:指向下一个要写入的地址的,写完自动加1。

读写指针其实就是读写的地址,只不过这个地址不能任意选择,而是连续的。

同步FIFO

同步FIFO的读写指令由同一个时钟控制,主要由两个模块构成:控制模块和RAM。

  • 控制模块:地址控制模块可以根据读写指令,生成RAM地址;
  • RAM:根据控制模块生成的地址信号进行数据的存储和读取操作;
  • 用计数器进行空满标志的判断

读写过程:

  • 堆栈空:读指针和写指针指向第一个存储单元;
  • 写数据:当写入一个数据时,写数据指针指向下一个存储单元;经过(深度 -1)次写数据操作后,写指针指向最后一个存储单元;当经过写操作次数为FIFO深度时,写指针将回到第一个存储单元,并且显示堆栈为满。
  • 读操作:类似于写操作,当读出全部数据后,指针指向首单元。

下面是一个8x8同步FIFO的verilog代码:

module syn_fifo(clk,rst_n,write_to_stack,read_from_stack,data_in,data_out);
   parameter	stack_width = 8;//FIFO宽度
   parameter	stack_heigh = 8;//FIFO深度
   parameter	stack_addr_width =3;//读写地址位宽
   
   input  		clk,rst_n;
   input 		write_to_stack,read_from_stack;//数据读写使能信号
   input		[stack_width-1:0]data_in;//写入FIFO的数据
   output		[stack_width-1:0]data_out;//读出FIFO的数据

   reg			[stack_width-1:0]data_out;	
   reg			[stack_addr_width-1:0]write_ptr;//每写一次,加1
   reg			[stack_addr_width-1:0]read_ptr;//每读一次,加1
   reg			[stack_addr_width:0]gap_ptr;//计数器,FIFO内部数据量
   reg			[7:0]raml[7:0];// 8*8 bit寄存器
 	
   //空满逻辑生成
   wire		    stack_full,stack_empty;
   assign		stack_full  = (gap_ptr == stack_heigh);//当数据存储量为堆栈深度时,此时堆栈满
   assign		stack_empty = (gap_ptr == 0);//当数据存储量为0时,此时堆栈空
   
   //写操作
   always@(posedge clk or negedge rst_n) begin
       if(!rst_n) begin
           write_ptr <= 0;
           gap_ptr   <= 0;   
       end
       //如果堆栈不满,并且此时写指令有效 ———>写操作
       else if(write_to_stack && (!stack_full) ) begin
           write_ptr <= write_ptr + 1;//写指针加1
           gap_ptr   <= gap_ptr + 1;//FIFO内部数据数量加1
           raml[write_ptr] <= data_in;
       end        
   end
   //读操作
  always@(posedge clk or negedge rst_n) begin
       if(!rst_n) begin
           read_ptr  <= 0;
           gap_ptr   <= 0;  
       end
      //如果堆栈不空,并且读指令有效 ———>读操作
       else if( (!stack_empty) && read_from_stack) begin
       	   read_ptr <= read_ptr + 1;//读指针加1
           gap_ptr  <= gap_ptr - 1;//FIFO内部数据数量减1
           data_out <= raml[read_ptr];
       end       
   end   
endmodule

//------------------TB-----------------------
`timescale 1ns/1ps
module TB;
	reg  		clk,rst_n;
    reg 		write_to_stack,read_from_stack;//数据读写使能信号
    reg			[7:0]data_in;
    wire		[7:0]data_out;
	
	FIFO_buffer dut(.clk(clk),
					.rst_n(rst_n),
					.write_to_stack(write_to_stack),
					.read_from_stack(read_from_stack),
					.data_in(data_in),
					.data_out(data_out)
					);
	
	initial begin
		clk <= 0;
		forever begin
			#5 clk <= ~clk;	
		end		
	end
	
	initial begin
	   rst_n <= 0;
	#5 rst_n <= 1;
	end
	
	initial begin
	#10 write_to_stack  <= 1;
		read_from_stack <= 0;
		repeat(7) begin
	      @(posedge clk);
	      data_in = #(0.01) $random;    
		end
		data_in = #(0.01) $random;
		write_to_stack  <= 0;
		read_from_stack <= 1;
		repeat(8) begin
	      @(posedge clk);
		end
		write_to_stack  <= 0;
		read_from_stack <= 0;
		
		rst_n <= 0;
		repeat(2) begin
	      @(posedge clk);
		end
		rst_n <= 1;
		
	#5  write_to_stack  <= 1;
		read_from_stack <= 0;
		repeat(10) begin
	      @(posedge clk);
	      data_in = #(0.01) $random;    
		end
		write_to_stack  <= 0;
		read_from_stack <= 1;
		repeat(10) begin
	      @(posedge clk);
		end
		rst_n <= 0;
		repeat(2) begin
	      @(posedge clk);
		end
		rst_n <= 1;
		
	#5  write_to_stack  <= 1;
		read_from_stack <= 1;
		repeat(10) begin
	      @(posedge clk);
	      data_in = #(0.01) $random;    
		end
		data_in = #(0.01) $random;
		write_to_stack  <= 0;
		read_from_stack <= 1;
		repeat(10) begin
	      @(posedge clk);
		end
		write_to_stack  <= 0;
		read_from_stack <= 0;
		
	#200 $finish();
	end
	
endmodule

下图测试:为连续写入7个数据,再读出。
结果:FIFO存储数据一致,空满标致正常;
在这里插入图片描述
下图测试:为写入10个数据,再读出。

在这里插入图片描述

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小小verifier

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值