FIFO 的 verilog 代码(先进先出)没有显示正确的结果?

verilog code of FIFO (first in first out) is not showing the proper result?

我想设计一个有一定深度和宽度的FIFO。 FIFO的Verilog代码是用Vivado 2017.4写的。该代码能够读取输入数据,但它只显示 XX 作为输出。下面给出了 FIFO 的设计源和测试平台。帮我找出问题所在。

module fifo #(parameter WIDTH=8, parameter DEPTH=8) (
    input wire [WIDTH-1:0] data_in,
    output reg [WIDTH-1:0] data_out,
        output reg data_valid,
        input wire reset,
    input wire clk
    );
        function integer clog2(input reg [32-1:0] value); 
        begin 
            value = value-1;
            for (clog2=0; value>0; clog2=clog2+1)
                value = value>>1;
        end 
    endfunction
        reg [WIDTH-1:0] data [DEPTH-1:0];
    reg [clog2(DEPTH)-1:0] write_pointer;
    reg [clog2(DEPTH)-1:0] read_pointer;
        always @(posedge clk) begin
        if (reset == 1'b0) begin
            write_pointer <= 0;
            read_pointer <= 1;
            data_valid <= 0;
        end else begin
            if (write_pointer == DEPTH-1) write_pointer <= 0;
            else write_pointer <= write_pointer + 1;
                if (read_pointer == DEPTH-1) read_pointer <= 0;
            else read_pointer <= read_pointer + 1;
                data[write_pointer] <= data_in;
            data_out <= data[read_pointer];
        end
            if (read_pointer == 0) data_valid <= 1'b1;
    end
    endmodule

测试台

`timescale 1ns / 1ps
module fifo_tb;
    parameter WIDTH = 16;
    parameter DEPTH = 8;
    reg reset;
    reg clk;
reg [(WIDTH-1):0] data_in;
    wire [(WIDTH-1):0] data_out;
    wire data_valid;    
   fifo #(WIDTH,DEPTH) U0(data_in,data_out,data_valid,reset,clk);
     initial begin
        clk = 0;
        reset = 1;
        #1 reset = 0;
        #1 reset = 1;

    end

    // Create clock
    always
    #5 clk = ~clk;

reg signed [15:0] rom_memory [4096-1:0];
integer i=0;
initial 
begin
    $readmemh("C:\Users\input_7_zz.txt",rom_memory);

end

always@(posedge clk )
begin
    if(~reset)
    begin
    data_in <= 0;
    end
    else
    begin
      data_in <= rom_memory[i];
     i <= i+ 1;
 end

end
endmodule

在您的测试台代码中,时钟每 5 个刻度更改一次:

// Create clock
always
    #5 clk = ~clk;

RTL中的reset使用这个时钟的posedge:

always @(posedge clk) begin
    if (reset == 1'b0) begin
        write_pointer <= 0;
        read_pointer <= 1;
        data_valid <= 0;

因此,只有在复位期间检测到posedge clk 时,复位动作才会发生。换句话说,你有一个同步重置。

尽管如此,在您的测试台代码中,您的重置只持续了一个滴答声:

initial begin
    clk = 0;
    reset = 1;
    #1 reset = 0;
    #1 reset = 1; // << one tick after the reset was asserted.
end

您可能有 2 种可能的解决方案。

1) 保持同步复位,但要保证在复位过程中能检测到clk的posedge。所以,让它大于一个时钟周期(或者至少半个时钟周期,如果你确定它什么时候到来的话)。像 5 这样的东西应该适用于你的情况。将其设置为 10 或更多以确保任意起点。

initial begin
    clk = 0;
    reset = 1;
    #1 reset = 0;
    #5 reset = 1; // << 5 tick after the reset was asserted. 

上面的重置将从时间 1 持续到时间 6。第一个 posegde 将在时间 5 发生。因此,对您的情况来说应该足够了。

2) 您可以在 RTL 中使用异步复位,如下所示:

always @(posedge clk or reset) begin
    if (reset == 1'b0) begin
        write_pointer <= 0;
        read_pointer <= 1;
        data_valid <= 0;

在上面的例子中,只要 'reset' 发生变化,就会执行 always 块。但是,您必须注意那里其他任务的时间安排。当您取消断言 reset 与 posedge clk 有一些偏移时,它们可能会发生。