英文:
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'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 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
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 = '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
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] <= fifo_data_in;
end
end
always_ff @(posedge clk_i)begin
if(revent) begin
fifo_data_out <= fifo_storage[fifo_rptr];
end
end
namely that the vectors I'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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论