Verilog异步FIFO实现

Verilog异步FIFO实现

实现

`timescale 1ns/1ps

module asyn_fifo#(
      parameter data_width = 16,
      parameter ram_depth = 256,
      parameter ram_addr_width = 8
) 
(

                  input                           rst,
                  input                           wr_clk,
                  input                           wr_en,
                  input      [data_width-1:0]     din,         
                  input                           rd_clk,
                  input                           rd_en,
                  output reg                      valid,
                  output reg [data_width-1:0]     dout,
                  output                          empty,
                  output                          full

);

reg[ram_addr_width: 0] wr_addr_ptr;
reg[ram_addr_width: 0] rd_addr_ptr;
wire[ram_addr_width - 1: 0] wr_addr;
wire[ram_addr_width - 1: 0] rd_addr;

wire[ram_addr_width: 0] wr_addr_ptr_gray;
wire[ram_addr_width: 0] rd_addr_ptr_gray;

reg[ram_addr_width: 0] wr_addr_ptr_gray_d1;
reg[ram_addr_width: 0] wr_addr_ptr_gray_d2;

reg[ram_addr_width: 0] rd_addr_ptr_gray_d1;
reg[ram_addr_width: 0] rd_addr_ptr_gray_d2;

reg[data_width - 1: 0] fifo_ram[ram_depth - 1: 0]; //ram

//initail ram
//generate 256 block
genvar i;
  generate
  for (i = 0; i < ram_depth; i  = i  + 1) begin:write_fifo
always@ (posedge wr_clk or negedge rst) begin
  if (!rst) 
     fifo_ram[i] <= 'h0;
    else if (wr_en && (~full) && wr_addr == i)// attention multi-driver
      fifo_ram[i] <= din;
    else
      fifo_ram[i] <= fifo_ram[i];
  end
end
endgenerate

// read  data
always@(posedge rd_clk or negedge rst)
   begin
      if(!rst)
         begin
            dout <= 'h0;
            valid <= 1'b0;
         end
      else if(rd_en && (~empty))
         begin
            dout <= fifo_ram[rd_addr];
            valid <= 1'b1;
         end
      else
         begin
            dout <=   'h0;
            valid <= 1'b0;
         end
   end

//write prt incr
always@ (posedge wr_clk or negedge rst) begin
  if(!rst)
    wr_addr_ptr <= 'h0;
  else if(wr_en && (~full))
    wr_addr_ptr <= wr_addr_ptr + 1'b1;
  else wr_addr_ptr <= wr_addr_ptr;
end

//read prt incr
always@ (posedge rd_clk or negedge rst) begin
  if(!rst)
    rd_addr_ptr <= 'h0;
  else if(rd_en && (~empty))
    rd_addr_ptr <= rd_addr_ptr + 1'b1;
  else 
    rd_addr_ptr <= rd_addr_ptr;
end

//remove MSB 
assign wr_addr = wr_addr_ptr[ram_addr_width - 1: 0];
assign rd_addr = rd_addr_ptr[ram_addr_width - 1: 0];

//syschronize r and w
always@ (posedge rd_clk) begin
    wr_addr_ptr_gray_d1 <= wr_addr_ptr_gray;
    wr_addr_ptr_gray_d2 <= wr_addr_ptr_gray_d1;

end
always@ (posedge wr_clk) begin
    rd_addr_ptr_gray_d1 <= rd_addr_ptr_gray;
    rd_addr_ptr_gray_d2 <= rd_addr_ptr_gray_d1;

end

//gray tansfer
assign wr_addr_ptr_gray = (wr_addr_ptr >> 1) ^ wr_addr_ptr; 
assign rd_addr_ptr_gray = (rd_addr_ptr >> 1) ^ rd_addr_ptr; 

//flag 
assign full = (wr_addr_ptr_gray == {~(rd_addr_ptr_gray_d2[ram_addr_width-:2]),rd_addr_ptr_gray_d2[ram_addr_width-2:0]}) ; //w faster than r
assign empty = ( rd_addr_ptr_gray == wr_addr_ptr_gray_d2 );// r faster than
endmodule 

测试

`timescale 1ns/1ps
module fif0_test();
      parameter data_width = 16;
      parameter ram_depth = 256;
      parameter ram_addr_width = 8;
    
                  reg                      rst;
                  reg                      wr_clk;
                  reg                      wr_en;
                  reg [data_width-1:0]     din;       
                  reg                      rd_clk;
                  reg                      rd_en;
                  wire                      valid;
                  wire [data_width-1:0]     dout;
                  wire                      empty;
                  wire                      full;
asyn_fifo #
(
  
       .data_width (16),
       .ram_depth  (256),
       .ram_addr_width (8)
)
(       .rst(rst),
        .wr_clk (wr_clk),
        .wr_en(wr_en),
        .din(din),         
        .rd_clk(rd_clk),
        .rd_en(rd_en),
        .valid(valid),
        .dout(dout),
        .empty(empty),
        .full(full)

);

//rst
initial begin
  rst = 1'b1;
  #10 rst = 1'b0;
  #20 rst = 1'b1;
  wr_en = 1'b1;
  rd_en = 1'b1;
  
  #5000 rst = 1'b0;
  #50   rst = 1'b1;
  #9000 $finish;
end

//w_clk
initial begin
  wr_clk = 1'b1;
  forever #5 wr_clk = ~wr_clk;
end
//r_clk
initial begin
  rd_clk = 1'b1;
  forever #20 rd_clk = ~rd_clk;
end

//data 
initial begin
  #10 din = 1'b0;
  forever #10 din = din + 1'b1;
end

//ifdef DUMP_FSDB

  initial begin
  $fsdbDumpfile("asyn_fifo.fsdb");
  $fsdbDumpvars;
 end
 
//endif

endmodule

仿真

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值