FIFO verilog

来源:互联网 发布:二手房房源软件 编辑:程序博客网 时间:2024/06/05 07:05
首先要明白这里的同步FIFO和异步FIFO的使用场合。当你的设计中只有一个时钟信号的时候,所有的寄存器都使用同一个时钟,他们之间不会产生传输速度不匹配的情况;而当你的设计中存在多个时钟信号,并且需要在这几个时钟域之间传输数据的时候,寄存器会由于时钟信号的频率不匹配而产生数据丢失等情况,这个时候需要用异步FIFO来进行缓存,保证数据能够正确传输,因此一般异步FIFO会包含一个双端口的RAM,用于数据记录,详细地可以参考FIFO的相关资料。这里的异步指的是不同频率/不同相位的时钟信号。而同步FIFO一般只用来作buffer。


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

FIFO的一些重要参数

FIFO的宽度:也就是英文资料里常看到的THE WIDTH,它指的是FIFO一次读写操作的数据位,就像MCU8位和16位,ARM 32位等等。

FIFO的深度:THE DEEPTH,它指的是FIFO可以存储多少个N位的数据(如果宽度为N)。如一个8位的FIFO,若深度为8,它可以存储88位的数据,深度为12,就可以存储128位的数据。

    满标志:FIFO已满或将要满时由FIFO的状态电路送出的一个信号,以阻止FIFO的写操作继续向FIFO中写数据而造成溢出(overflow)。

    空标志:FIFO已空或将要空时由FIFO的状态电路送出的一个信号,以阻止FIFO的读操作继续从FIFO中读出数据而造成无效数据的读出(underflow)。

 读指针:指向下一个读出地址。读完后自动加1

 写指针:指向下一个要写入的地址的,写完自动加1

 

    对于FIFO,读写指针都指向一个内存的初始位置,每进行一次读写操作,相应的指针就递增一次,指向下一个内存位置。当指针移动到了内存的最后一个位置时,它又重新跳回初始位置。在FIFO非满或非空的情况下,这个过程将随着读写控制信号的变化一直进行下去。如果FIFO处于空的状态,下一个读动作将会导致向下溢(underflow),一个无效的数据被读人;同样,对于一个满了的FIFO,进行写动作将会导致向上溢出(overflow),一个有用的数据被新写入的数据覆盖。这两种情况都属于误动作,因此需要设置满和空两个信号,对满信号置位表示FIFO处于满状态,对满信号复位表示FIFO非满,还有空间可以写入数据;对空信号置位表示FIFO处于空状态,对空信号复位表示FIFO非空,还有有效的数据可以读出。

`timescale 1ns / 1ps
module fifo
# (
parameter B=8,
W=4 )
(
input wire clk, reset,
input wire rd, wr,        //
读信号和写信号
input wire [B-1:0] w_data,
output wire empty, full,   //
空标志和满标志
output wire [B-1:0] r_data
);

reg [B-1:0] array_reg [2**W-1:0] ; //定义了array_reg为2的四次方个8位存储器
reg [W-1:0] w_ptr_reg, w_ptr_next , w_ptr_succ;
reg [W-1:0] r_ptr_reg , r_ptr_next , r_ptr_succ ;
reg full_reg, empty_reg, full_next, empty_next;

wire wr_en;

// body
// r e g i s t e r f i l e w r i t e o p e r a t i o n
always @ ( posedge clk)
if (wr_en)            //
写使能
array_reg [w_ptr_reg] <= w_data ;         //
写入

assign r_data = array_reg [r_ptr_reg] ;

assign wr_en = wr & ~full_reg;   //不满和写信号同时成立时写使能

// f i f o c o n t r o l l o g i c
// r e g i s t e r f o r r e a d and w'rite p o i n t e r s
always @ ( posedge clk or negedge reset)
if (!reset)
begin
w_ptr_reg <= 0;
r_ptr_reg <= 0;
full_reg <= 1'b0;
empty_reg <= 1'b1;
end
else
begin
w_ptr_reg <= w_ptr_next ;
r_ptr_reg <= r_ptr_next;
full_reg <= full_next;
empty_reg <= empty_next ;
end

// n e x t - s t a t e l o g i c f o r read and w r i t e p o i n t e r s
always @*
begin
// s u c c e s s i v e  p o i n t e r  v a l u e s
w_ptr_succ = w_ptr_reg + 1;
r_ptr_succ = r_ptr_reg + 1;

w_ptr_next = w_ptr_reg;
r_ptr_next = r_ptr_reg;
full_next = full_reg;
empty_next = empty_reg;

  case ({wr, rd})

2'b01: // r e a d
if (~empty_reg) // n o t empty
begin
r_ptr_next = r_ptr_succ ;
full_next = 1'b0;
if (r_ptr_succ==w_ptr_reg)
empty_next = 1'b1;
end

2'b10: // w r i t e
if (~full_reg) // not f u l l
begin
w_ptr_next = w_ptr_succ ;
empty_next = 1'b0  ;
if (w_ptr_succ==r_ptr_reg)
full_next = 1'b1;
end
2'b11: // w r i t e and read
begin
 w_ptr_next = w_ptr_succ;
r_ptr_next = r_ptr_succ ;
end
endcase
end

// output
assign full = full_reg;
assign empty = empty_reg;
endmodule

 

 

 

下面是testbench

 

`timescale 1ns / 1ps

////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date:   18:35:10 11/09/2012
// Design Name:   fifo
// Module Name:   D:/FPGA project/uartnew/fifo_test.v
// Project Name:  uartnew
// Target Device: 
// Tool versions: 
// Description:
//
// Verilog Test Fixture created by ISE for module: fifo
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
////////////////////////////////////////////////////////////////////////////////

module fifo_test;

 // Inputs
 reg clk;
 reg reset;
 reg rd;
 reg wr;
 reg [7:0] w_data;

 // Outputs
 wire empty;
 wire full;
 wire [7:0] r_data;

 // Instantiate the Unit Under Test (UUT)
 fifo uut (
  .clk(clk),
  .reset(reset),
  .rd(rd),
  .wr(wr),
  .w_data(w_data),
  .empty(empty),
  .full(full),
  .r_data(r_data)
 );
 
 task read_word;
begin
   @(negedge clk);
   rd = 1;
   @(posedge clk) #5;
   rd = 0;
end
endtask
  
task write_word;
input [7:0] value;
begin
   @(negedge clk);
   w_data = value;
   wr = 1;
   @(posedge clk);
   #5;
   w_data = 16'hzzzz;
   wr= 0;
end
endtask

 

  

 


 initial begin
  // Initialize Inputs
  clk = 0;
  reset = 0;
  #10clk=1;
      #10clk=0;
      #10clk=1;
      reset=1;
  rd = 0;
  wr = 0;
  w_data = 0;

  // Wait 100 ns for global reset to finish
  #100;
      forever begin
      #10 clk = 1;
      #10 clk = 0;
     end
  // Add stimulus here

 end
     
  
  initial begin
    test1;
   test2;  //
调用测试模块2
  
end

task test1;
begin
  
   write_word (8'h11);
   write_word (8'h22);
   write_word (8'h33);   //
写入3个数据
   read_word;
   read_word;               //读两个
   write_word (8'h44);   //在写一个数据
   repeat (6) begin
      read_word;
   end
   
 write_word (8'h01);
   write_word (8'h02);
   write_word (8'h03);
   write_word (8'h04);
   write_word (8'h05);
   write_word (8'h06);
   write_word (8'h07);
   write_word (8'h08);
repeat (6) begin
      read_word;
   end
end
endtask
 
task test2;
reg [15:0] writer_counter;
begin
   writer_counter = 16'h0001;
  
   fork
     //写数据
    begin
         repeat (500) begin
            @(negedge clk);
            if (full == 1'b0) begin
               write_word (writer_counter);
               #5;
               writer_counter = writer_counter + 1;
            end
               #50;
         end
    end
     
  //读数据
      begin
         forever begin
            @(negedge clk);
            if (empty == 1'b0) begin
               read_word;
            end 
          #50;
         end
      end
   join
end
endtask

 

endmodule

0 0
原创粉丝点击