3

当我从事基于 SystemVerilog 的 FPGA 设计时,我遇到了一种情况,我必须计算时钟沿上 4 个元素的数组的总和。我能够使用带有非阻塞分配语句的 for 循环来做到这一点。

该设计在 Quartus 15.0 上成功合成,但是当我尝试在 Modelsim Altera 上使用相同的 RTL 运行仿真时,结果出乎意料。我写了一个示例代码来说明这一点。

module schedule;

logic [7:0] abc [0:3];
logic [7:0] sum=0;
logic clk=0;

always begin 
   #5.0ns clk <= ~clk; 
end

initial begin
    abc = '{1,3,5,6};
end

initial @(posedge clk) begin
    for(int i = 0; i <= 3;i++ ) begin
        sum <= sum + abc[i];
    end
end

initial 
$monitor("Sum is %d",sum);

endmodule

此图显示了模拟结果。

在此示例代码中,总和是使用非阻塞分配计算的。它的目的是在 clk 的第一个 posedge 上具有 (1+3+5+6)=15 的值;我在原始硬件中观察到。但在模拟中,在 clk(即abc[3])的 posedge 处,结果为 6。由于 systemverilog 模拟器安排了非阻塞语句的分配,我相信创建了 4 个 sum 实例,即。

sum <= sum + abc[0];
sum <= sum + abc[1];
sum <= sum + abc[2];
sum <= sum + abc[3];

由于所有计划的分配同时发生,可能是最后一个实例更新的总和,我们的总和 <= 0 + 6 的值。如果我错了,请纠正我。

现在我的问题是如何让模拟器按顺序安排这些分配,以便即使在模拟中也能得到 15 的值?由于在综合中阻止分配不是一个选项,我找不到任何方法来保持 RTL 一致。谢谢。

4

3 回答 3

3

您的分析似乎是正确的。您是否尝试过以下方法?

logic [7:0] temp;
always@(*) begin
    temp = 0;
    for (int i = 0; i < 4; i = i + 1) 
        temp = temp + abc[i];
end

always @(posedge clk)
    sum <= temp;

这样,sum仅在时钟沿更新,但我们仍然可以for在组合块中展开循环(因此添加仍应按预期工作)。

于 2016-02-19T16:09:38.647 回答
2

SystemVerilog 有一个内置的求和数组归约运算符,无需 for 循环

sum <= abc.sum() with (8'(item));

需要转换为 8 位,因为默认情况下,结果的类型与数组元素类型相同。

于 2016-02-19T17:51:42.987 回答
0

我想,您可以在另一个始终块(对时钟边缘不敏感,组合块)中使用阻塞分配,并且您可以sumposedge clk

reg [7:0] temp_sum;

always @ (*)
begin
  temp_sum = abc[0];
  temp_sum = temp_sum + abc[1];
  temp_sum = temp_sum + abc[2];
  temp_sum = temp_sum + abc[3];
end

always @ (posedge clk)
  sum <= temp_sum;

我想,这可能会奏效。

于 2016-02-21T15:10:40.600 回答