Ring FIFO 模拟中未定义的输出

问题描述 投票:0回答:1

我一直在为 SystemVerilog 开发 FIFO。第一次模拟结果很好。然而,在扩展模拟以尝试使其达到极限并考虑极端情况时,我遇到了一些问题。虽然我已经能够解决大部分问题,但仍有一个问题我无法解决。

//This fifo implements a Circular Buffer topology
//Note: The way the fifo is defined it is impossible to have a depth of 1
//This is because the pointers will always be on the same position
//The fifo is therefore always "empty"
module i2s_fifo #(
    parameter WIDTH = 16,
    parameter DEPTH = 10
)(
    input logic clk_i,
    input logic rst_ni,

    //Write Communication Signals
    output logic wready,
    input logic wvalid,
    input logic [WIDTH-1:0] fifo_data_in,

    //Read Communication Signals
    input logic rready,
    output logic rvalid,
    output logic [WIDTH-1:0] fifo_data_out,

    //Debuging
    output logic [$clog2(DEPTH)-1:0]wptr_tb,
    output logic [$clog2(DEPTH)-1:0] rptr_tb
);
    //This returns how many bits are needed to add and address of X size
    //For example. $clog2(7) = 3. We need three bits to access a memory of 7 values.
    //Basically converts from an integer to bits
    localparam int unsigned byte_depth = $clog2(DEPTH);

    //Pointers
    logic [byte_depth-1:0] fifo_rptr, fifo_wptr; 
    assign wptr_tb = fifo_wptr;
    assign rptr_tb = fifo_rptr;
    
    //We cannot read if the FIFO is empty
    //We cannot write if the FIFO is full
    logic fifo_empty;
    logic fifo_full;

    always_comb begin : fifo_state   
        if(fifo_rptr == fifo_wptr) begin
            assign fifo_empty = 1'b1;
        end else begin
            assign fifo_empty = 1'b0;
        end

        if(fifo_wptr == DEPTH)begin //Pointer is at the edge of fifo
            if (fifo_rptr == 0) begin 
                fifo_full <= 1'b1;
            end else begin
                fifo_full <= 1'b0;
            end
        end else if (fifo_wptr+1 == fifo_rptr)begin
            fifo_full <= 1'b1;
        end else begin
            fifo_full <= 1'b0;
        end
    end

    //Handshake
    logic revent, wevent;

    assign rvalid = !fifo_empty;
    assign revent = rvalid & rready;

    assign wready = !fifo_full;
    assign wevent = wvalid & wready;

    //INCREASE POINTER POSSITION
    always_ff @(posedge clk_i) begin
        if(!rst_ni)begin
            fifo_rptr <= {(byte_depth){1'b0}};
        end else if (revent) begin
            if (fifo_rptr == DEPTH) begin
                fifo_rptr <= {(byte_depth){1'b0}};
            end else begin
                fifo_rptr <= fifo_rptr+1;
            end
        end
    end

    always_ff @(posedge clk_i) begin
        if(!rst_ni)begin
            fifo_wptr <= {(byte_depth){1'b0}};
        end else if (wevent) begin
            if (fifo_wptr == DEPTH) begin
                fifo_wptr <= {(byte_depth){1'b0}};
            end else begin
                fifo_wptr <= fifo_wptr+1;
            end
        end
    end

    //Write and Save data
    //data_type  [rows][columns] array_name;
    logic [DEPTH-1:0] [(WIDTH-1):0] fifo_storage;

    always_ff @(posedge clk_i)begin
        if(wevent) begin
            //This access the row dictated by the pointer
            fifo_storage[fifo_wptr] <= fifo_data_in;
        end
    end

    always_ff @(posedge clk_i)begin
        if(revent) begin
            fifo_data_out <= fifo_storage[fifo_rptr];
        end
    end    
endmodule

这是测试台

module i2s_fifo_tb(

);
    localparam WIDTH = 16;
    localparam DEPTH = 10;
    logic clk;
    logic rst;
    logic wready;
    logic wvalid;
    logic [WIDTH-1:0]fifo_data_in;
    logic rready;
    logic rvalid;
    logic [WIDTH-1:0]fifo_data_out;
    logic [$clog2(DEPTH)-1:0]rptr_tb;
    logic [$clog2(DEPTH)-1:0]wptr_tb;
    i2s_fifo #(
        .WIDTH(16),
        .DEPTH(10)
    )UUT(
        .clk_i(clk),
        .rst_ni(rst),
        .wready,
        .wvalid,
        .fifo_data_in,
        .fifo_data_out,
        .rready,
        .rvalid,
        .rptr_tb,
        .wptr_tb
    );
    always begin
        clk = '1;
        #10000;
        clk = '0;
        #10000;
    end
    
    initial begin
        rst = '0;
        rready = '0;
        wvalid = 0;
        fifo_data_in = 16'd0;
        #20000;
        //Fill FIFO
        rst = 1;
        wvalid = 1;
        fifo_data_in = 16'h1111;
        #20000;
        fifo_data_in = 16'h2222;
        #20000;
        fifo_data_in = 16'h3333;
        #20000;
        fifo_data_in = 16'h4444;
        #20000;
        fifo_data_in = 16'h5555;
        #20000;
        fifo_data_in = 16'h6666;
        #20000;
        fifo_data_in = 16'h7777;
        #20000;
        fifo_data_in = 16'h8888;
        #20000;
        fifo_data_in = 16'h9999;
        #20000;
        fifo_data_in = 16'haaaa;
        #20000;
        fifo_data_in = 16'hbbbb;
        #20000;
        fifo_data_in = 16'hcccc;
        #20000;
        //Read FIFO
        wvalid = '0;
        rready = '1;
        #100000;
        //Pause Reading
        rready= 0;
        #100000;
        //Resume Reading
        rready = 1;
        #160000;
        //Check correct writing
        rready = 0;
        fifo_data_in = 16'h1111;
        #20000;
        fifo_data_in = 16'h2222;
        #20000;
        fifo_data_in = 16'h3333;
        #20000;
        fifo_data_in = 16'h4444;
        #20000;
        wvalid = 1;
        fifo_data_in = 16'h5555;
        #20000;
        fifo_data_in = 16'h6666;
        #20000;
        fifo_data_in = 16'h7777;
        #20000;
        wvalid = 0;
        rready = 1;
        #80000;
        //Multiple Writing and reading
        rready = 0;
        wvalid = 1;
        fifo_data_in = 16'h1111;
        #20000;
        fifo_data_in = 16'h2222;
        #20000;
        fifo_data_in = 16'h3333;
        #20000;
        rready = 1;
        fifo_data_in = 16'h4444;
        #20000;
        fifo_data_in = 16'h5555;
        #20000;
        fifo_data_in = 16'h6666;
        #20000;
        wvalid = 0;
        //Fill it again, different point
        #60000;
        rready = 0;
        wvalid = 1;
        fifo_data_in = 16'h1111;
        #20000
        fifo_data_in = 16'h2222;
        #20000
        fifo_data_in = 16'h3333;
        #20000
        fifo_data_in = 16'h4444;
        #20000
        fifo_data_in = 16'h5555;
        #20000
        fifo_data_in = 16'h6666;
        #20000
        fifo_data_in = 16'h7777;
        #20000
        fifo_data_in = 16'h8888;
        #20000
        fifo_data_in = 16'h9999;
        #20000
        fifo_data_in = 16'haaaa;
        #20000
        fifo_data_in = 16'hbbbb;
        #20000
        fifo_data_in = 16'hcccc;
        #20000
        wvalid = 0;
        rready = 1;
        #600000
        $finish;
    end

endmodule

基本上在测试平台上,我只是输入大量数据并检查 fifo 是否表现得相应。然而。在模拟中,我观察到每当读取指针指向零位置时,输出都未定义。

起初我认为这可能是时序问题,在模拟开始时我根本没有在零位置上写入任何内容,因此,当第一次尝试读取 int 时,我有一个未定义的状态。因此,我决定进一步进行模拟。然而,我观察到,每当读指针查看零位置时,状态都是未定义的。

我的假设是这部分有问题

    //Write and Save data
    //data_type  [rows][columns] array_name;
    logic [DEPTH-1:0] [(WIDTH-1):0] fifo_storage;

    always_ff @(posedge clk_i)begin
        if(wevent) begin
            //This acces the row dictated by the pointer
            fifo_storage[fifo_wptr] <= fifo_data_in;
        end
    end

    always_ff @(posedge clk_i)begin
        if(revent) begin
            fifo_data_out <= fifo_storage[fifo_rptr];
        end
    end    

即我用来分配数据的向量是错误的。但是,我无法确定确切的问题。

我希望得到一些帮助。

以下是模拟中的两个捕获:

Simulation 1

Simulation 2

simulation system-verilog fifo
1个回答
0
投票

问题是当您从 FIFO 读取时,读指针超出范围,这会导致您从 FIFO 读取时出现未知值。

您将 FIFO

DEPTH
设置为 10,这意味着您的读指针至少需要 4 位,并且您正确地将指针声明为
[3:0]
。但是,指针的某些可能值是非法的,即 10 到 15。只有从 0 到 9 的指针值才是合法的。您的仿真波形清楚地表明,当
a
为 1 时,指针到达值 10(十六进制
revent
)。这就是
fifo_data_out
信号变得未知的原因。

请注意,输出信号是未知的,因为它是在指针采样为 10 时更新的。

为了防止这种情况发生,您可以考虑更改:

        if (fifo_rptr == DEPTH) begin

至:

        if (fifo_rptr == (DEPTH-1)) begin

但是,您需要确保您的设计正常工作。

© www.soinside.com 2019 - 2024. All rights reserved.