Ring FIFO 模拟中的未定义输出

huangapple go评论57阅读模式
英文:

Undefined output in Ring FIFO simulation

问题

这是您提供的SystemVerilog代码的翻译部分:

我一直在为SystemVerilog编写FIFO。最初的模拟结果还不错。然而,当我扩展模拟以尝试将其推向极限并考虑边界情况时,我遇到了一些问题。尽管我已经能够解决其中大多数,但有一个问题我一直没有解决。

//此FIFO实现了循环缓冲拓扑结构
//注意:FIFO的定义方式使得深度为1是不可能的
//这是因为指针将始终位于相同的位置
//因此FIFO始终是"空的"
module i2s_fifo #(
    parameter WIDTH = 16,
    parameter DEPTH = 10
)(
    input logic clk_i,
    input logic rst_ni,

    //写通信信号
    output logic wready,
    input logic wvalid,
    input logic [WIDTH-1:0] fifo_data_in,

    //读通信信号
    input logic rready,
    output logic rvalid,
    output logic [WIDTH-1:0] fifo_data_out,

    //调试
    output logic [$clog2(DEPTH)-1:0] wptr_tb,
    output logic [$clog2(DEPTH)-1:0] rptr_tb
);
    //这返回需要添加X大小的地址所需的位数
    //例如,$clog2(7) = 3。我们需要三位来访问7个值的存储器。
    //基本上是从整数转换为位数
    localparam int unsigned byte_depth = $clog2(DEPTH);

    //指针
    logic [byte_depth-1:0] fifo_rptr, fifo_wptr; 
    assign wptr_tb = fifo_wptr;
    assign rptr_tb = fifo_rptr;
    

    //如果FIFO为空,我们不能读取
    //如果FIFO已满,我们不能写入
    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 //指针位于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

    //握手
    logic revent, wevent;

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

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

    //增加指针位置
    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

    //写入和保存数据
    //数据类型  [行][列] 数组名称;
    logic [DEPTH-1:0] [(WIDTH-1):0] fifo_storage;

    always_ff @(posedge clk_i)begin
        if(wevent) begin
            //这访问由指针指定的行
            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;
        //填充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;


<details>
<summary>英文:</summary>

I have been working on a FIFO for SystemVerilog.  The first simulations turned out good.  However, upon expanding the simulation to try to bring it to its limit and account for corner cases, I have encountered a few issues. Although I have been able to solve most of them there is one that I have not been able to solve.

//This fifo implements a Circular Buffer topology
//Note: The way the fifo is defined it is imposible 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 Comunication Signals
output logic wready,
input logic wvalid,
input logic [WIDTH-1:0] fifo_data_in,
//Read Comunication 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 adress of X size
//For example. $clog2(7) = 3. We need three bits to access a memory of 7 values.
//Basically converts from an interger 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&#39;b1;
end else begin
assign fifo_empty = 1&#39;b0;
end
if(fifo_wptr == DEPTH)begin //Pointer is at the edge of fifo
if (fifo_rptr == 0) begin 
fifo_full &lt;= 1&#39;b1;
end else begin
fifo_full &lt;= 1&#39;b0;
end
end else if (fifo_wptr+1 == fifo_rptr)begin
fifo_full &lt;= 1&#39;b1;
end else begin
fifo_full &lt;= 1&#39;b0;
end
end
//Handshake
logic revent, wevent;
assign rvalid = !fifo_empty;
assign revent = rvalid &amp; rready;
assign wready = !fifo_full;
assign wevent = wvalid &amp; wready;
//INCREASE POINTER POSSITION
always_ff @(posedge clk_i) begin
if(!rst_ni)begin
fifo_rptr &lt;= {(byte_depth){1&#39;b0}};
end else if (revent) begin
if (fifo_rptr == DEPTH) begin
fifo_rptr &lt;= {(byte_depth){1&#39;b0}};
end else begin
fifo_rptr &lt;= fifo_rptr+1;
end
end
end
always_ff @(posedge clk_i) begin
if(!rst_ni)begin
fifo_wptr &lt;= {(byte_depth){1&#39;b0}};
end else if (wevent) begin
if (fifo_wptr == DEPTH) begin
fifo_wptr &lt;= {(byte_depth){1&#39;b0}};
end else begin
fifo_wptr &lt;= 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 acces the row dictated by the pointer
fifo_storage[fifo_wptr] &lt;= fifo_data_in;
end
end
always_ff @(posedge clk_i)begin
if(revent) begin
fifo_data_out &lt;= fifo_storage[fifo_rptr];
end
end    

endmodule


And this is the testbench

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 = &#39;0;
rready = &#39;0;
wvalid = 0;
fifo_data_in = 16&#39;d0;
#20000;
//Fill FIFO
rst = 1;
wvalid = 1;
fifo_data_in = 16&#39;h1111;
#20000;
fifo_data_in = 16&#39;h2222;
#20000;
fifo_data_in = 16&#39;h3333;
#20000;
fifo_data_in = 16&#39;h4444;
#20000;
fifo_data_in = 16&#39;h5555;
#20000;
fifo_data_in = 16&#39;h6666;
#20000;
fifo_data_in = 16&#39;h7777;
#20000;
fifo_data_in = 16&#39;h8888;
#20000;
fifo_data_in = 16&#39;h9999;
#20000;
fifo_data_in = 16&#39;haaaa;
#20000;
fifo_data_in = 16&#39;hbbbb;
#20000;
fifo_data_in = 16&#39;hcccc;
#20000;
//Read FIFO
wvalid = &#39;0;
rready = &#39;1;
#100000;
//Pause Reading
rready= 0;
#100000;
//Resume Reading
rready = 1;
#160000;
//Check correct writing
rready = 0;
fifo_data_in = 16&#39;h1111;
#20000;
fifo_data_in = 16&#39;h2222;
#20000;
fifo_data_in = 16&#39;h3333;
#20000;
fifo_data_in = 16&#39;h4444;
#20000;
wvalid = 1;
fifo_data_in = 16&#39;h5555;
#20000;
fifo_data_in = 16&#39;h6666;
#20000;
fifo_data_in = 16&#39;h7777;
#20000;
wvalid = 0;
rready = 1;
#80000;
//Multiple Writing and reading
rready = 0;
wvalid = 1;
fifo_data_in = 16&#39;h1111;
#20000;
fifo_data_in = 16&#39;h2222;
#20000;
fifo_data_in = 16&#39;h3333;
#20000;
rready = 1;
fifo_data_in = 16&#39;h4444;
#20000;
fifo_data_in = 16&#39;h5555;
#20000;
fifo_data_in = 16&#39;h6666;
#20000;
wvalid = 0;
//Fill it again, different point
#60000;
rready = 0;
wvalid = 1;
fifo_data_in = 16&#39;h1111;
#20000
fifo_data_in = 16&#39;h2222;
#20000
fifo_data_in = 16&#39;h3333;
#20000
fifo_data_in = 16&#39;h4444;
#20000
fifo_data_in = 16&#39;h5555;
#20000
fifo_data_in = 16&#39;h6666;
#20000
fifo_data_in = 16&#39;h7777;
#20000
fifo_data_in = 16&#39;h8888;
#20000
fifo_data_in = 16&#39;h9999;
#20000
fifo_data_in = 16&#39;haaaa;
#20000
fifo_data_in = 16&#39;hbbbb;
#20000
fifo_data_in = 16&#39;hcccc;
#20000
wvalid = 0;
rready = 1;
#600000
$finish;
end

endmodule

Basically on the testbench I simply input a lot of data and check whether the fifo behaves accordingly. However. On the simulation I have observed that whenever the read pointer points to the zero position, the output is not define.
At first I thought it may have been an issue with timing, that at the beginning of the simulation I simply did not write anything on the position zero and thus, when attempting to read int for the first time I have an undefined state. Thus, I decided to further the simulation. However, I have observed that any time the read pointer looks at the zero position, the state is undefined.
My hypothesis is that there is some problem in this part
//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] &lt;= fifo_data_in;
end
end
always_ff @(posedge clk_i)begin
if(revent) begin
fifo_data_out &lt;= fifo_storage[fifo_rptr];
end
end    
namely that the vectors I&#39;m using to assign the data are wrong. But, I cannot pinpoint the  exact issue.
I would appreciate some help.
Here are two captures from the simulation:
![Simulation 1](https://i.stack.imgur.com/N1LkN.png)
![Simulation 2](https://i.stack.imgur.com/y1WVA.png)
</details>
# 答案1
**得分**: 0
问题在于当您从FIFO中读取数据时,读指针会超出范围,导致从FIFO中读取数据时出现未知值。
您将FIFO的深度设置为10,这意味着您的读指针至少需要4位,并且您正确地声明了指针为`[3:0]`。然而,指针的一些可能值是非法的,即从10到15。只有从0到9的指针值是合法的。您的仿真波形清楚地显示,当`revent`为1时,指针达到值10(十六进制为`a`),这就是为什么`fifo_data_out`信号变为未知的原因。
请注意,输出信号是未知的,因为它在采样指针为10时更新了。
为了防止这种情况发生,您可以考虑将以下代码:
```verilog
if (fifo_rptr == DEPTH) begin

更改为:

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

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

英文:

The problem is that your read pointer goes out of range when you are reading from the FIFO, which results in unknown values when you read from the FIFO.

You set the FIFO DEPTH to 10, which means your read pointer needs at least 4 bits, and you properly declared the pointer as [3:0]. However, some of the possible values of the pointer are illegal, namely 10 through 15. Only pointer values from 0 to 9 are legal. Your simulation waveforms clearly show that the pointer reaches the value 10 (hexadecimal a) when revent is 1. This is why the fifo_data_out signals becomes unknown.

Note that the output signal is unknown because it was updated when the pointer was sampled as 10.

To prevent that from happening, you could consider changing:

        if (fifo_rptr == DEPTH) begin

to:

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

But, you need to make sure your design works properly.

huangapple
  • 本文由 发表于 2023年7月10日 19:04:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/76653086.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定