博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
异步FIFO总结
阅读量:4353 次
发布时间:2019-06-07

本文共 17252 字,大约阅读时间需要 57 分钟。

异步FIFO总结

异步FIFO的基本概念


异步FIFO读写分别采用相互异步的不同时钟,使用异步FIFO可以在两个不同时钟系统之间快速而方便地传输实时数据

FIFO的常见参数


FIFO的宽度:即FIFO一次读写操作的数据位;

FIFO的深度:指的是FIFO可以存储多少个N位的数据(如果宽度为N)。
满标志:FIFO已满或将要满时由FIFO的状态电路送出的一个信号,以阻止FIFO的写操作继续向FIFO中写数据而造成溢出(overflow)。
空标志:FIFO已空或将要空时由FIFO的状态电路送出的一个信号,以阻止FIFO的读操作继续从FIFO中读出数据而造成无效数据的读出(underflow)。
读时钟:读操作所遵循的时钟,在每个时钟沿来临时读数据。
写时钟:写操作所遵循的时钟,在每个时钟沿来临时写数据。

异步FIFO的设计难点


如何同步异步信号,使触发器不产生亚稳态

如何正确地设计空、满以及几乎满等信号的控制电路

亚稳态问题的解决


对写地址/读地址采用格雷码

采用触发器来同步异步输入信号

空/满标志的产生


空/满标志产生的原则是:写满不溢出,读空不多读

FIFO的缓冲空间是有限的,在设计中需要考虑缓冲区的溢出和空情况。

缓冲区满,产生FULL信号,以阻塞数据继续向FIFO写入;
缓冲区空,产生EMPTY信号,以阻塞数据继续从FIFO读出。

方法:

1.采用握手协议

2.读时钟采样写指针,写时钟采样读指针,采样的写指针和读指针判断是否为EMPTY,采样的读指针和写指针判断是否为FULL

Gray code counter


847278-20170709140813712-1434036200.png

FIFO 框图


847278-20170709140823056-413548009.png

847278-20170709141613478-881872345.png

VCS仿真结果


847278-20170709140829509-2001917175.png

异步FIFO代码(verilog)


RTL描述


fifoif.v

module fifoif       (       fifo_flush,       data_out,       full_out,       empty_out,       data_in,       wren_in, wclk, wclr_in,       rden_in, rclk, rclr_in,       fifo_waddr, fifo_raddr,       ram_douta,       ram_dinb,       ram_ada,       ram_adb,       ram_cena,       ram_cenb,       ram_clka,       ram_clkb       );parameter DSIZE = 32;parameter ASIZE = 7;input              fifo_flush;output [DSIZE-1:0] data_out;output             full_out;output             empty_out;input  [DSIZE-1:0] data_in;input              wren_in, wclk, wclr_in;input              rden_in, rclk, rclr_in;output [ASIZE-1:0] fifo_waddr, fifo_raddr;input  [DSIZE-1:0] ram_douta;output [DSIZE-1:0] ram_dinb;output [ASIZE-1:0] ram_ada;output [ASIZE-1:0] ram_adb;output             ram_cena;output             ram_cenb;output             ram_clka;output             ram_clkb;wire   [DSIZE-1:0] ram_douta;wire   [DSIZE-1:0] ram_dinb;wire   [ASIZE-1:0] ram_ada;wire   [ASIZE-1:0] ram_adb;wire               ram_cena;wire               ram_cenb;wire               ram_clka;wire               ram_clkb;wire  [DSIZE-1:0] data_out;wire  [ASIZE-1:0] waddr;wire  [ASIZE-1:0] raddr;wire    [ASIZE:0] wptr;wire    [ASIZE:0] rptr;wire    [ASIZE:0] wq2_rptr;wire    [ASIZE:0] rq2_wptr;wire  [ASIZE-1:0] fifo_waddr = waddr;wire  [ASIZE-1:0] fifo_raddr = raddr;sync_r2w #(ASIZE) u_sync_r2w(    .wq2_rptr     (wq2_rptr),    .rptr         (rptr),    .wclk         (wclk),    .wrst_n       (wclr_in),    .wflush       (fifo_flush));sync_w2r #(ASIZE) u_sync_w2r(    .rq2_wptr     (rq2_wptr),    .wptr         (wptr),    .rclk         (rclk),    .rrst_n       (rclr_in),    .rflush       (fifo_flush));fifomem #(DSIZE, ASIZE) u_fifomem(    .rdata        (data_out),    .wdata        (data_in),    .waddr        (waddr),    .raddr        (raddr),    .wren         (wren_in),    .wclk         (wclk),    .rden         (rden_in),    .rclk         (rclk),    .ram_douta    (ram_douta),    .ram_dinb     (ram_dinb),    .ram_ada      (ram_ada),    .ram_adb      (ram_adb),    .ram_cena     (ram_cena),    .ram_cenb     (ram_cenb),    .CLKA         (ram_clka),    .CLKB         (ram_clkb)    );rptr_empty #(ASIZE) u_rptr_empty(    .rempty       (empty_out),    .raddr        (raddr),    .rptr         (rptr),    .rq2_wptr     (rq2_wptr),    .rinc         (rden_in),    .rclk         (rclk),    .rrst_n       (rclr_in),    .rflush       (fifo_flush)    );wptr_full #(ASIZE) u_wptr_full(    .wfull        (full_out),    .waddr        (waddr),    .wptr         (wptr),    .wq2_rptr     (wq2_rptr),    .winc         (wren_in),    .wclk         (wclk),    .wrst_n       (wclr_in),    .wflush       (fifo_flush)    );endmodule

fifomem.v

module fifomem(       rdata, wdata, waddr, raddr, wren, wclk, rden, rclk,       //memory interface       ram_douta, ram_dinb, ram_ada, ram_adb, ram_cena, ram_cenb,       CLKA, CLKB       );parameter DATASIZE = 32; // Memory data word widthparameter ADDRSIZE = 7; // Number of mem address bitsoutput [DATASIZE-1:0] rdata;input  [DATASIZE-1:0] wdata;input  [ADDRSIZE-1:0] waddr, raddr;input                 wren, wclk;input                 rden, rclk;input  [DATASIZE-1:0] ram_douta;output [DATASIZE-1:0] ram_dinb;output [ADDRSIZE-1:0] ram_ada;output [ADDRSIZE-1:0] ram_adb;output                ram_cena;output                ram_cenb;output                CLKA;output                CLKB;wire                ram_cena,ram_cenb;wire                CLKA;wire                CLKB;wire [DATASIZE-1:0] ram_dinb,ram_douta;wire [ADDRSIZE-1:0] ram_ada, ram_adb;wire [DATASIZE-1:0] rdata,wdata;assign ram_cena = ~rden;assign ram_ada  = raddr;assign ram_cenb = ~wren;assign ram_adb  = waddr;assign ram_dinb = wdata;assign CLKA     = rclk;assign CLKB     = wclk;assign rdata    = ram_douta;endmodule

ram_dp.v

module ram_dp #(                parameter DATA_WIDTH = 32,                parameter ADDR_WIDTH = 7,                parameter RAM_DEPTH = 1 << ADDR_WIDTH                )                (                 output  reg    [DATA_WIDTH-1:0]     data_out     ,                 input          [DATA_WIDTH-1:0]     data_in      ,                 input          [ADDR_WIDTH-1:0]     addr_a       ,                 input          [ADDR_WIDTH-1:0]     addr_b       ,                 input                               web          , //Write Enable/Read Enable,addr_b write enable, low active                 input                               clka         , // write  Clock Input                 input                               clkb         , // read   Clock Input                 input                               cena         , //Chip Select                 input                               cenb           //Chip Select                ); //--------------Internal variables---------------- reg [DATA_WIDTH-1:0] mem [0:RAM_DEPTH-1];reg                  oe_r;//--------------Code Starts Here------------------ // Memory Write Block // Write Operation : When web = 0, cenb = 1always @ (posedge clkb)begin : MEM_WRITE   if ((~cenb) && (~web) ) begin       mem[addr_b] = data_in;   endend// Memory Read Block // Read Operation : When web = 1, cena = 1always @ (posedge clka)begin : MEM_READ  if ((~cena) && web) begin    data_out = mem[addr_a];  endendendmodule // End of Module ram_dp

sync_r2w.v

module sync_r2w        #(parameter ADDRSIZE = 4)       (        output reg  [ADDRSIZE:0]    wq2_rptr,        input       [ADDRSIZE:0]    rptr,        input                       wclk,        input                       wrst_n,        input                       wflush       );reg    [ADDRSIZE:0] wq1_rptr;always @(posedge wclk or negedge wrst_n)  if (!wrst_n)       {wq2_rptr,wq1_rptr} <= 0;  else if(wflush)       {wq2_rptr,wq1_rptr} <= 0;  else       {wq2_rptr,wq1_rptr} <= {wq1_rptr,rptr};endmodule

sync_w2r.v

module sync_w2r        #(parameter ADDRSIZE = 4)       (        output    reg    [ADDRSIZE:0]   rq2_wptr,        input            [ADDRSIZE:0]   wptr,        input                           rclk,        input                           rrst_n,        input                           rflush       );reg              [ADDRSIZE:0]   rq1_wptr;always @(posedge rclk or negedge rrst_n)  if (!rrst_n)       {rq2_wptr,rq1_wptr} <= 0;  else if(rflush)       {rq2_wptr,rq1_wptr} <= 0;  else       {rq2_wptr,rq1_wptr} <= {rq1_wptr,wptr};endmodule

rptr_empty.v

module rptr_empty       #(parameter ADDRSIZE = 4)       (        output    reg                    rempty,        output          [ADDRSIZE-1:0]   raddr,        output    reg   [ADDRSIZE :0]    rptr,        input           [ADDRSIZE :0]    rq2_wptr,        input                            rinc,        input                            rclk,        input                            rrst_n,        input                            rflush       );reg      [ADDRSIZE:0] rbin;wire     [ADDRSIZE:0] rgraynext, rbinnext;//-------------------// GRAYSTYLE2 pointer//-------------------always @(posedge rclk or negedge rrst_n)  if (!rrst_n)       {rbin, rptr} <= 0;  else if(rflush)       {rbin, rptr} <= 0;  else       {rbin, rptr} <= {rbinnext, rgraynext};// Memory read-address pointer (okay to use binary to address memory)assign raddr = rbin[ADDRSIZE-1:0];assign rbinnext = rbin + (rinc & ~rempty);assign rgraynext = (rbinnext>>1) ^ rbinnext;//---------------------------------------------------------------// FIFO empty when the next rptr == synchronized wptr or on reset//---------------------------------------------------------------wire rempty_val = (rgraynext == rq2_wptr);always @(posedge rclk or negedge rrst_n)  if (!rrst_n)       rempty <= 1'b1;  else       rempty <= rempty_val;endmodule

wptr_full.v

module wptr_full       #(parameter ADDRSIZE = 4)       (        output   reg                      wfull,        output          [ADDRSIZE-1:0]    waddr,        output   reg    [ADDRSIZE :0]     wptr,        input           [ADDRSIZE :0]     wq2_rptr,        input                             winc,        input                             wclk,        input                             wrst_n,        input                             wflush       );reg             [ADDRSIZE:0]      wbin;wire            [ADDRSIZE:0]      wgraynext, wbinnext;// GRAYSTYLE2 pointeralways @(posedge wclk or negedge wrst_n)  if (!wrst_n)       {wbin, wptr} <= 0;  else if(wflush)       {wbin, wptr} <= 0;  else       {wbin, wptr} <= {wbinnext, wgraynext};// Memory write-address pointer (okay to use binary to address memory)assign waddr = wbin[ADDRSIZE-1:0];assign wbinnext = wbin + (winc & ~wfull);assign wgraynext = (wbinnext>>1) ^ wbinnext;//------------------------------------------------------------------// Simplified version of the three necessary full-tests:// assign wfull_val=((wgnext[ADDRSIZE]    !=wq2_rptr[ADDRSIZE]  ) &&//                   (wgnext[ADDRSIZE-1]  !=wq2_rptr[ADDRSIZE-1]) &&//                   (wgnext[ADDRSIZE-2:0]==wq2_rptr[ADDRSIZE-2:0]));//------------------------------------------------------------------wire wfull_val = (wgraynext=={~wq2_rptr[ADDRSIZE:ADDRSIZE-1],                               wq2_rptr[ADDRSIZE-2:0]});always @(posedge wclk or negedge wrst_n)  if (!wrst_n)       wfull <= 1'b0;  else       wfull <= wfull_val;endmodule

testbench


fifo_tb.v

module fifo_tb;reg                          fifo_flush;wire       [31:0]            data_out;wire                         full_out;wire                         empty_out;wire       [31:0]            data_in;wire                         wren_in;wire                         wclk;wire                         wr_rst_n;wire                         rd_rst_n;wire                         rden_in;wire                         rclk;wire       [6:0]             fifo_waddr;wire       [6:0]             fifo_raddr;// memory interface signalwire       [31:0]            if_ram_douta;wire       [31:0]            if_ram_dinb;wire       [6:0]             if_ram_ada;wire       [6:0]             if_ram_adb;wire                         if_ram_cena;wire                         if_ram_cenb;wire                         if_ram_clka;wire                         if_ram_clkb;//******************************************************************//  generate clk//******************************************************************clock #(.CLK_FREQ(100.0))    u_clock_wr (                .clk    (   wclk  )               );clock #(.CLK_FREQ(70.0))    u_clock_rd (                .clk    (   rclk  )               );assign  if_ram_clka  = rclk;assign  if_ram_clkb  = wclk;//******************************************************************//  generate read and write data//******************************************************************fifo_data #(.DATA_WIDTH(8))             u_fifo_data (                          .wr_rst_n   (   wr_rst_n    ),                          .wr_clk     (   wclk        ),                          .wr_en      (   wren_in     ),                          .wr_data    (   data_in     ),                          .wr_full    (   full_out    ),                          .rd_rst_n   (   rd_rst_n    ),                          .rd_clk     (   rclk        ),                          .rd_en      (   rden_in     ),                          .rd_empty   (   empty_out   )                         );//******************************************************************//  creat FSDB//******************************************************************initial begin    $fsdbDumpfile("tb.fsdb");    $fsdbDumpvars();end//===================================================// u_fifoif from rtl/fifoif.v                        //===================================================fifoif u_fifoif (    .fifo_flush                 ( 1'b0 ),    .data_out                   ( data_out ),    .full_out                   ( full_out ),    .empty_out                  ( empty_out ),    .data_in                    ( data_in ),    .wren_in                    ( wren_in ),    .wclk                       ( wclk ),    .wclr_in                    ( wr_rst_n ),    .rden_in                    ( rden_in ),    .rclk                       ( rclk ),    .rclr_in                    ( rd_rst_n ),    .fifo_waddr                 ( fifo_waddr ),    .fifo_raddr                 ( fifo_raddr ),     // Memory interface    .ram_douta                  ( if_ram_douta ),    .ram_dinb                   ( if_ram_dinb ),    .ram_ada                    ( if_ram_ada ),    .ram_adb                    ( if_ram_adb ),    .ram_cena                   ( if_ram_cena ),    .ram_cenb                   ( if_ram_cenb ),    .ram_clka                   ( if_ram_clka ),    .ram_clkb                   ( if_ram_clkb ));ram_dp u_ram_dp(                .data_out           (if_ram_douta[31:0]), //A data output, 32 bits                .data_in            (if_ram_dinb[31:0]),  //B data input , 32 bits                .addr_a             (if_ram_ada[6:0]),    //A adress, 7 bits                .addr_b             (if_ram_adb[6:0]),    //B adress, 7 bits                .web                (if_ram_cenb),        //Write Enable/Read Enable,addr_b write enable, low active                .clka               (if_ram_clka),        // write  Clock Input                .clkb               (if_ram_clkb),        // read   Clock Input                .cena               (if_ram_cena),        //Chip Select ,low active                .cenb               (if_ram_cenb)         //Chip Select ,low active                ); endmodule

clock.v

module clock #(parameter   CLK_FREQ = 100.0)  //MHz           (            output    reg   clk            );    localparam  CLK_CYCLE = 1000.0 / CLK_FREQ;        initial    begin        clk = 0;        forever #(CLK_CYCLE/2)            clk = ~clk;    end    endmodule

fifo_data.v

module fifo_data #(parameter DATA_WIDTH = 8)                (                 output reg                      wr_rst_n,                 input                           wr_clk,                 output reg                      wr_en,                 output reg  [DATA_WIDTH-1:0]    wr_data,                 input                           wr_full,                 output reg                      rd_rst_n,                 input                           rd_clk,                 output reg                      rd_en,                 input                           rd_empty                );            reg             normal_wr;    reg             normal_rd;        initial    begin        wr_rst_n  = 1'b0;        rd_rst_n  = 1'b0;        normal_wr = 1'b0;        normal_rd = 1'b0;        #492;        wr_rst_n  = 1'b1;        rd_rst_n  = 1'b1;        #100;        //only write FIFO        normal_rd = 1'b0;        normal_wr = 1'b1;        repeat(500) @(negedge wr_clk);                //only read FIFO        normal_wr = 1'b0;        normal_rd = 1'b1;        repeat(500) @(negedge rd_clk);                //read and write FIFO        normal_rd = 1'b0;        normal_wr = 1'b0;        normal_wr = 1'b1;        normal_rd = 1'b1;        repeat(1000) @(negedge wr_clk);                normal_wr = 1'b0;        normal_rd = 1'b0;        repeat(50) @(negedge rd_clk);        $finish;    end        //******************************************************************    //  write FIFO data generate    //******************************************************************    always @(negedge wr_clk or negedge wr_rst_n)    begin        if(wr_rst_n == 1'b0)        begin            wr_en   <= 1'b0;            wr_data <= {(DATA_WIDTH){1'b0}};        end        else if(normal_wr == 1'b1)        begin            if(wr_full == 1'b0)            begin                wr_en   <= 1'b1;                wr_data <= {$random%((1 << (DATA_WIDTH-1)))};                //wr_data <= $random;            end            else            begin                wr_en   <= 1'b0;                wr_data <= {(DATA_WIDTH){1'b0}};            end        end        else        begin            wr_en   <= 1'b0;            wr_data <= {(DATA_WIDTH){1'b0}};        end    end        //******************************************************************    //  read FIFO data generate    //******************************************************************    always @(negedge wr_clk or negedge wr_rst_n)    begin        if(wr_rst_n == 1'b0)            rd_en   <= 1'b0;        else if(normal_rd == 1'b1)        begin            if(rd_empty == 1'b0)                rd_en   <= 1'b1;            else                rd_en   <= 1'b0;        end        else            rd_en   <= 1'b0;    end    endmodule

参考资料


[0].

[1].
[2].
[3].
[4].
[5].

转载于:https://www.cnblogs.com/OneFri/p/7141368.html

你可能感兴趣的文章
保持一个乐观的心态
查看>>
最佳实践(二)
查看>>
【Windows】线程漫谈——线程同步之信号量和互斥量
查看>>
对理想团队模式构建的设想以及对软件流程的理解
查看>>
hadoop多机安装YARN
查看>>
如何使用看门狗
查看>>
Windows 10 代理上网用户的正确使用姿势
查看>>
flask install
查看>>
js闭包的使用
查看>>
Codeforces Round #569 (Div. 2)
查看>>
解决session过期不能跳出iframe的问题
查看>>
C1驾考总结
查看>>
第十四章-MySQL
查看>>
mac下java的安装和升级以及相关环境设置
查看>>
ldap客户端工具ldap admin tool
查看>>
DSP编译错误
查看>>
python yaml用法详解
查看>>
Js 删除前弹出确认框
查看>>
springboot项目获取resource下的文件
查看>>
PHP添加Redis模块及连接
查看>>