Verilog同步FIFO的电路设计

先入先出(FIFO:First In First Out)存储器是一种常用的数据缓冲器件,它没有外部读写地址线,使用起来非常简单,但缺点是只能顺序写入数据,顺序读出数据,其数据读写顺序由内部读写指针自动控制确定。

外部连接关系
同步FIFO外部连接关系图

电路结构
FIFO内部电路结构图

设计代码

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2020/07/27 09:29:18
// Design Name: 
// Module Name: Test0929
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 



module Test0929(clk,reset,wr_en,din,rd_en,dout,full,empty,afull,aempty,cnt);
input clk;
input reset;
input wr_en;
input rd_en;
input [7:0] din;
output [7:0] dout;
reg [7:0] dout;
output empty,full;
output aempty,afull;
output [4:0] cnt;
reg [4:0] cnt;
reg [7:0] fifo_ram[0:15];
reg [3:0] wr_pointer,rd_pointer;
wire full,empty;
wire afull,aempty;

/*下面的always块用于根据当前指针值执行数据写入操作*/
/*当时钟上升沿出现时,如果wr_en为1,则将数据写入到以wr_pointer为地址的fifo_ram空间中*/
always @(posedge clk)
   begin 
      if(wr_en)
         fifo_ram[wr_pointer]<=din;
   end

/*下面的always块用于根据当前指针值执行数据读出操作*/
/*当时钟上升沿出现时,如果rd_en为1,则将以rd_pointer为地址的fifo_ram的数据读出,并通过dout输出*/
always @(posedge clk)
   begin
      if(rd_en)
         dout<=fifo_ram[rd_pointer];
   end

/*下面的always块用于进行写指针更新*/
/*当时钟上升沿出现时,如果wr_en为1并且fifo_ram没有满,则wr_pointer增加1,wr_pointer的值在0000~1111之间进行循环计数*/
always @(posedge clk)
   begin
      if(reset)
         wr_pointer<=0;
      else
         wr_pointer<=(wr_en&(!full))?wr_pointer+1:wr_pointer;
   end

/*下面的always块用于进行读指针更新*/
/*当时钟上升沿出现时,如果rd_en为1并且fifo_ram非空,则rd_pointer增加1,rd_pointer的值在0000~1111之间进行循环计数*/
always @(posedge clk)
   begin
      if(reset)
         rd_pointer<=0;
      else
         rd_pointer<=(rd_en&(!empty))?rd_pointer+1:rd_pointer;
   end

/*下面的always块用于进行数据深度计数器值更新*/
/*当时钟上升沿出现时,有效的读写操作都会带来cnt数值的增加或减少*/
always @(posedge clk)
   begin
      if(reset)
         cnt<=0;
      else
      
      case({
    
    wr_en,rd_en})
         2'b00,2'b11:cnt<=cnt;
         2'b01:cnt<=(cnt==0)?0:cnt-1;
         2'b10:cnt<=(cnt==16)?16:cnt+1;
      endcase
   end

/*下面的语句用于根据fifo中的数据深度产生模块用户所关心的状态信息*/
assign afull=(cnt==15);//深度为15时指示 “将满”
assign aempty=(cnt==1);//深度为1时指示 “将空”
assign empty=(cnt==0);//深度为0时指示 “空”
assign full=(cnt==16);//深度为16时指示 “满”
endmodule

测试代码

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2020/07/27 09:53:14
// Design Name: 
// Module Name: Test0953
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module Test0953;
reg clk,reset,wr_en,rd_en;
reg [7:0] din;
wire [7:0] dout;
wire full,empty,afull,aempty;
wire [4:0] cnt;
reg [7:0] i;
always begin
   #10 clk=1;
   #10 clk=0;
end

initial begin
   clk=0;
   reset=1;
   wr_en=0;
   din=0;
   rd_en=0;
   i=0;
   #100;
   reset=0;
   //for循环控制连续写入16个数据
   for(i=1;i<=16;i=i+1)
      begin
         repeat(1)@(posedge clk)
         #2;
         din=i;
         wr_en=1;
      end
      repeat(1)@(posedge clk)
      #2;
      wr_en=0;
   //for循环控制连续读出16个数据
   for(i=1;i<=16;i=i+1)
      begin
         repeat(1)@(posedge clk)
         #2;
         rd_en=1;
      end
      repeat(1)@(posedge clk)
      #2;
      rd_en=0;
end
Test0929 x1(.clk(clk),
            .reset(reset),
            .wr_en(wr_en),
            .din(din),
            .rd_en(rd_en),
            .dout(dout),
            .full(full),
            .empty(empty),
            .afull(afull),
            .aempty(aempty),
            .cnt(cnt));
endmodule

仿真波形
仿真波形
仿真在vivado上成功运行,具体波形信息可以对照设计代码中的注释信息进行分析。
后面会写一篇由FIFO存储器所构成的接收串/并变换电路。

猜你喜欢

转载自blog.csdn.net/Hennys/article/details/107610260