3.6 握手信号方法

1)X将数放在数据总线上兵发出xreq信号,表示有效数据已经发到接收器Y的数据总线上。

2)xreq信号同步到接收器时钟域ylk上。

3)Y在识别xreq同步的信号yreq2后,锁存数据总线上信号。

4)Y发出确认信号yack,表示其已经接收了数据。

5)yack同步到发送时钟xclk上。

6)X识别到同步的xack2信号后,将下一个数据放到数据总线上。

如图,安全地将一个数据从发送器传输到接收器需要5个时钟周期。

3.6.1 握手信号的要求

数据应在发送时钟域内稳定至少两个时钟上升沿。

xreq宽度应该超过两个上升沿时钟,否则从高速时钟域到低速时钟域传递可能无法捕捉到该信号。

3.6.2 握手信号缺点

传输单个数据延迟比FIFO传输同样的数据大得多。

3.7 使用同步FIFO传输数据3.7.1 同步FIFO架构

写指针指向下一个要写的地址,读指针指向下一个要读的地址。写使能使写指针递增,读使能使读指针递增。

根据读写指针可以产生空信号和满信号,也可以对FIFO内数据进行计数。

DPRAM可以同步读取或者异步读取。同步读时,应在FIFO输出有效前给都信号。异步读时,输出不会寄存。数据只要一写入就可用。

3.7.2 同步FIFO的工作方式3.7.2.1 FIFO空满的产生

图中为FIFO满的情况,当读指针等于写指针加一并进行写操作,FIFO满。

同样,当读操作使两个指针在下个周期相等时,FIFO变空。

3.7.2.2 另一种方法

另一种方法使使用计数器来指示FIFO中空或满位置的个数。写入数据时计数器加一,读取数据时计数器减一。

这种方法原理上简单,但是要增加额外的硬件(比较器)。FIFO深度增加,比较器宽度也会增加,这最终会降低FIFO操作的最高频率。

`timescale 1ns / 1psmodule FIFO#(    parameter WIDTH=16,    parameter DEPTH=8)(    input clk,    input reset_n,    input [WIDTH-1:0]wr_data,    input wr_en,    input rd_en,    output reg[WIDTH-1:0]rd_data,    output reg fifo_full,    output reg fifo_empty    );    localparam  RAM_SIZE=(1<<DEPTH);    reg [DEPTH-1:0]rd_ptr,wr_ptr;    reg [WIDTH-1:0]DPRAM[RAM_SIZE-1:0];    always @(posedge clk or negedge reset_n) begin        if(~reset_n)            rd_data <= 'd0;        else begin            if(wr_en && ~fifo_full)                DPRAM[wr_ptr] <= wr_data;            if(rd_en && ~fifo_empty)                rd_data <= DPRAM[rd_ptr];        end    end    always @(posedge clk or negedge reset_n)     begin:fifo_full_gen        if(~reset_n)            fifo_full <= 1'b0;        else if(wr_en && rd_en)        ;//do nothing        else if(rd_en)            fifo_full <= 1'b0;        else if(wr_en && (rd_ptr == wr_ptr +1'b1))            fifo_full <= 1'b1;    end    always @(posedge clk or negedge reset_n)    begin:fifo_empty_gen        if(~reset_n)            fifo_empty <= 1'b1;        else if(wr_en && rd_en)        ;//do nothing        else if(wr_en)            fifo_empty <= 1'b0;        else if(rd_en && (wr_ptr == rd_ptr +1'b1))            fifo_empty <= 1'b1;    end    always @(posedge clk or negedge reset_n)    begin:rd_ptr_gen        if(~reset_n)            rd_ptr <= 'd0;        else if(rd_en && ~fifo_empty)            rd_ptr <= rd_ptr +1'b1;    end    always @(posedge clk or negedge reset_n)    begin:wr_ptr_gen        if(~reset_n)            wr_ptr <= 'd0;        else if(wr_en && ~fifo_full)            wr_ptr <= wr_ptr +1'b1;    end    endmodule

testbench

`timescale 1ns / 1psmodule tb_fifo();reg clk,rst_n,wr_en,rd_en;wire full,empty;reg [15:0]wr_data;wire [15:0]rd_data;initial begin    clk = 0;    rst_n = 0;    wr_en = 0;    rd_en = 0;    wr_data = 0;    #100 rst_n = 1;    while(~full) begin        #20        wr_en <= 1'b1;        wr_data <= wr_data + 1'b1;    end    repeat(100)    begin        @(posedge clk)begin            wr_en = {$random} %2;            rd_en = {$random} %2;        end    end    $finish;endalways #10 clk = ~clk;FIFO my_fifo(    .clk(clk),    .reset_n(rst_n),    .wr_data(wr_data),    .wr_en(wr_en),    .rd_en(rd_en),    .rd_data(rd_data),    .fifo_full(full),    .fifo_empty(empty)    );endmodule

仿真结果: