同步FIFO(Verilog)

简介:

       同步 FIFO 是采用 EDA 技术设计的一种先进先出的模块接口电路,它与普通存储器的区别是没有外部读写地址线,使用起来非常简单,缺点是只能顺序读写,而不能随机读写。同步FIFO电路设计主要由存储器(用 SRAM 代替)、计数器、比较器、锁存器结合实现。

电路接口:

       控制电路将信号分为写入数据信号、读出数据信号、满信号、空信号、读使能信号、写使能信号、复位信号、时钟信号等。

信号名称

I/O

描述

备注

clk

I

输入时钟,频率50hz

rst_n

I

复位清零

低有效

data_in

I

输入数据信号

wr_en

I

写使能信号

高有效

rd_en

I

读使能信号

高有效

data_out

O

输出数据信号

data_cnt

O

FIFO内数据数量

full

O

满信号,时钟上升沿为满

高有效

empty

O

空信号,时钟上升沿为空

高有效

设计思路: 

       读指针:总是指向下一个将要被写入的单元,复位时,指向第1个单元(编号为0)。

       写指针:总是指向当前要被读出的数据,复位时,指向第1个单元(编号为0)。

       当读写指针相等时,表明FIFO为空,这种情况发生在复位操作时,或者当读指针读出FIFO中最后一个字后,追赶上了写指针时,如下图所示:

       当读写指针再次相等时,表明 FIFO 为满,这种情况发生在,当写指针转了一圈,折回来(wrapped around)又追上了读指针,如下图:

 为了区分到底是满状态还是空状态,可以采用以下方法:

      在 FIFO 中添加一个 data_cnt(数据计数器),当 data_cnt 为 0 时,FIFO 此时为空;当 data_cnt 为 DATA_DEPTH 时,FIFO 此时为满。

电路图:

编译代码:

module fifo_8_256
 #(parameter 
   DATA_WIDTH = 8,
   DATA_DEPTH = 256,
   ADDR_WIDTH = 8)
 (
     clk,
     rst_n,

     wr_en,
     rd_en,
     data_in,

     full,
     empty,
     data_cnt,
     data_out
 );


//**********************Port definition***********************//

           input wr_en;
           input rd_en;
           input [DATA_WIDTH-1:0] data_in;
 
           input clk;
           input rst_n;
 
           output full;
           output empty;
           output reg [7:0] data_cnt;
           output reg [DATA_WIDTH-1:0] data_out;

//******************write address generation******************//

             reg [ADDR_WIDTH-1:0] waddr; 
     always@(posedge clk or negedge rst_n)
            if(!rst_n)
               waddr <= 'd0; 
            else if((full == 'd0) && (wr_en))begin
               if(waddr >= 'd255)
                  waddr <= 'd0;
               else
                  waddr <= waddr + 1'd1;
            end
            else 
               waddr <= waddr;

//******************read address generation*******************//

             reg [ADDR_WIDTH-1:0] raddr;
     always@(posedge clk or negedge rst_n)
            if(!rst_n)
               raddr <= 'd0; 
            else if((empty == 'd0) && (rd_en))begin
               if(raddr >= 'd255)
                  raddr <= 'd0;
               else
                  raddr <= raddr + 1'd1;
            end
            else 
               raddr <= raddr;

//***********************Data counters***********************//

     always@(posedge clk or negedge rst_n)
           if(!rst_n)
              data_cnt <= 'd0;
           else if (wr_en && rd_en)
              data_cnt <= data_cnt;
           else if (!full && wr_en)
              data_cnt <= data_cnt + 1'b1;
           else if (!empty && rd_en)
              data_cnt <= data_cnt - 1'b1;
           else
              data_cnt <= data_cnt;

//****************empty full signal generation****************//
    
      assign full  = (data_cnt == DATA_DEPTH-1 && (rst_n))?'d1:'d0;
      assign empty = (data_cnt == 'd0 && (rst_n))?'d1:'d0;         
      
//***********************write to fifo************************//

              integer i;
              reg [ADDR_WIDTH-1:0] sram [0:DATA_DEPTH-1];
      always@(posedge clk or negedge rst_n)
            if(!rst_n)begin            
              for(i = 0; i < DATA_DEPTH;i = i + 1) begin
               sram[i] <= 'd0;
              end
            end
            else if(wr_en && (!full))
               sram[waddr] <= data_in;

//*******************read out of the fifo*********************//

      always@(posedge clk or negedge rst_n)
             if(!rst_n)
                data_out <= 0;
             else if(rd_en && (!empty))
                data_out <= sram[raddr];
             else 
                data_out <= data_out;

endmodule	

仿真代码: 

`timescale 1ns/1ps
`define clk_period 20
module fifo_8_256_tb();

           reg wr_en;
           reg rd_en;
           reg [7:0] data_in;
 
           reg clk;
           reg rst_n;
 
           wire full;
           wire empty;
           wire [7:0] data_cnt;
           wire [7:0] data_out;

  fifo_8_256  u1(
          .clk(clk),
          .rst_n(rst_n),

          .wr_en(wr_en),
          .rd_en(rd_en),
          .data_in(data_in),

          .full(full),
          .empty(empty),
          .data_cnt(data_cnt),
          .data_out(data_out)
 );

 initial clk = 1;
 always # 10 clk = ~ clk;

 initial begin
   rst_n = 'd0;
   wr_en = 'd0;
   rd_en = 'd0;
   data_in = 'd0;
   
   #(`clk_period*10+1);

   rst_n = 'd1;

   #(`clk_period*10);
   
   data_in = 'd0;
   
   repeat(255)begin
   wr_en = 'd1;
   data_in = data_in + 'd1;
   #(`clk_period);  
   end
   wr_en = 'd0;
   
   #(`clk_period*100);  
   
   repeat(255)begin
   rd_en = 'd1;
   #(`clk_period);  
   end
   rd_en = 'd0;

   #(`clk_period*10);

   wr_en = 'd1;
   
   #(`clk_period*10);

   wr_en = 'd0;

   #(`clk_period*100);  
 
   $finish;
 end

initial begin
$fsdbDumpfile("./fifo_8_256_tb.fsdb");
$fsdbDumpvars(0,"fifo_8_256_tb"); 
$fsdbDumpSVA();
end
endmodule

仿真波形:

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的同步 FIFO Verilog 代码: ```verilog module sync_fifo ( input clk, input rst, input wr, input rd, input [7:0] data_in, output [7:0] data_out, output empty, output full ); parameter depth = 16; reg [7:0] mem [0:depth-1]; reg [3:0] wr_ptr = 0; reg [3:0] rd_ptr = 0; wire [3:0] next_wr_ptr = (wr_ptr == depth-1) ? 0 : wr_ptr+1; wire [3:0] next_rd_ptr = (rd_ptr == depth-1) ? 0 : rd_ptr+1; reg [3:0] count = 0; always @(posedge clk) begin if (rst) begin wr_ptr <= 0; rd_ptr <= 0; count <= 0; end else begin if (wr && !full) begin mem[wr_ptr] <= data_in; wr_ptr <= next_wr_ptr; count <= count + 1; end if (rd && !empty) begin data_out <= mem[rd_ptr]; rd_ptr <= next_rd_ptr; count <= count - 1; end end end assign empty = (count == 0); assign full = (count == depth); endmodule ``` 该 FIFO 模块包含一个输入时钟 clk 和一个异步复位信号 rst。还有其他几个输入和输出端口,包括 wr 和 rd 信号,用于指示写入和读取数据,以及 data_in 和 data_out 端口,用于传输数据。此外,还有 empty 和 full 信号,用于指示 FIFO 是否为空或已满。 FIFO 深度由 depth 参数指定,可以根据需要进行更改。该 FIFO 使用了一个简单的循环缓冲区来存储数据。wr_ptr 和 rd_ptr 变量指示下一个写入或读取数据的位置。count 变量跟踪 FIFO 中当前存储的元素数量。当 FIFO 为空或已满时,empty 和 full 信号分别设置为 1。 在时钟上升沿时,FIFO 模块执行以下操作: - 如果复位信号 rst 为 1,则将 wr_ptr,rd_ptr 和 count 变量重置为 0。 - 如果 wr 信号为 1 并且 FIFO 不满,则将 data_in 写入 mem 数组中的 wr_ptr 位置,并将 wr_ptr 更新为下一个位置,同时将 count 增加 1。 - 如果 rd 信号为 1 并且 FIFO 不为空,则将 mem 数组中的 rd_ptr 位置的数据读入 data_out,并将 rd_ptr 更新为下一个位置,同时将 count 减少 1。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值