在SystemVerilog中的for循环中使用总线的正确方法?

时间:2019-11-27 00:45:51

标签: verilog system-verilog

我正在尝试在SystemVerilog中创建一个模块,该模块可以找到两个向量之间的点积,最多可包含8个8位值。我正在尝试使其灵活适用于不同长度的向量,因此我有一个称为EN的输入,该输入为3位,并确定要执行的乘法次数。

因此,如果EN == 3'b101,则每个向量的前五个值将相乘并相加,然后输出为32位值。现在,我正在尝试这样做:

int acc = 0;

always_comb
begin
for(int i = 0; i < EN; i++) begin
    acc += A[i] * B[i];
    end
end
assign OUT = acc;

其中A和B是两个输入向量。但是,SystemVerilog告诉我,i和EN之间正在进行非法比较。

所以我的问题是:

1)这是在SystemVerilog中具有可变矢量“长度”的正确方法吗?

2)如果是这样,那么迭代n次的正确方法是什么,其中n是总线上的值?

谢谢!

1 个答案:

答案 0 :(得分:0)

我必须在这里猜测,但是我假设它是一个合成器,抱怨该代码。我使用的合成器接受了稍作修改的代码,但是由于循环不能静态展开,所以可能无法全部接受(请注意,我有input logic [2:0] EN,也许input int EN不能正常工作,因为最大循环数)。循环本身(问题2)就可以了。

int acc;
always_comb
begin
// If acc is not reset always_comb tries to update on its old value and puts
// it in sensitivity list, halting simulation... also no initialization to variable
// used in always_comb is allowed.
acc = 0;
...

这是抱怨您本来非常好的代码的一个体面的原因,并且该工具并未假设在这种特定情况下生成所有可能的循环是“合理的”(如果您的芯片是EN为无符号整数)毕竟会非常愚蠢):您可以强制该工具通过如下所示推断所有可能性:

module test (
    input int A[8],
    input int B[8],
    input logic [2:0] EN,
    output int OUT
);

    int acc[8];  // 8 accumulators

    always_comb begin
        acc[0] = A[0] * B[0];  // acc[-1] does not exist, different formula!
        for (int i = 1; i < 8; i++) begin
            // Each partial sum builds on previous one.
            acc[i] = acc[i-1] + (A[i] * B[i]);
        end
    end

    assign OUT = acc[EN];  // EN used as selector for a multiplexer on partial sums

endmodule: test

上面的模块是对我的合成器推断出的“并行循环”的明确描述。

关于您的问题1,答案是“取决于”。在硬件中没有可变长度,因此除非您将迭代次数固定为参数(而不是输入),否则您将具有最大大小并忽略某些值,或者使用指向某些内存的指针遍历多个周期。如果要在测试中使用可变的矢量长度(不使用芯片),则可以声明一个“动态数组”,可以随意调整其大小(IEEE 1800-2017,7.5:动态数组):

int dyn_vec[];

最后一点要注意的是,int不好的integer对于不是测试台的所有内容都有好处,以便捕获X的值并避免RTL合成不匹配。