Quartus不允许在Verilog中使用Generate块。

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

很简单的问题。考虑到以下代码,quarus 13.0sp1给出了这个错误。

module main(
    output reg  [1:0][DATA_WIDTH-1:0] dOut,
    input  wire [1:0][DATA_WIDTH-1:0] dIn,
    input  wire [1:0][ADDR_WIDTH-1:0] addr,
    input  wire [1:0] wren,
    input  wire clk
);
    parameter DATA_WIDTH = 16;
    parameter ADDR_WIDTH = 6;

    reg [DATA_WIDTH-1:0] ram [2**ADDR_WIDTH-1:0];

    generate
        genvar k;
        for(k=0; k<2; k=k+1) begin: m
            always @(posedge clk) begin
                if(wren[k])
                    ram[addr[k]] <= dIn[k];
                dOut[k] <= ram[addr[k]];
            end
        end
    endgenerate
endmodule

quarus 13.0sp1给出了这个错误(以及其他20个兄弟姐妹的错误):

错误(10028)。无法解决main.v(42)处的net "ram[63][14]"的多个常量驱动。

但如果我手动取消生成循环。

module main(
    output reg  [1:0][DATA_WIDTH-1:0] dOut,
    input  wire [1:0][DATA_WIDTH-1:0] dIn,
    input  wire [1:0][ADDR_WIDTH-1:0] addr,
    input  wire [1:0] wren,
    input  wire clk
);
    parameter DATA_WIDTH = 16;
    parameter ADDR_WIDTH = 6;

    reg [DATA_WIDTH-1:0] ram [2**ADDR_WIDTH-1:0];

    always @(posedge clk) begin
        if(wren[0])
            ram[addr[0]] <= dIn[0];
        dOut[0] <= ram[addr[0]];
    end

    always @(posedge clk) begin
        if(wren[1])
            ram[addr[1]] <= dIn[1];
        dOut[1] <= ram[addr[1]];
    end
endmodule

在分析&合成步骤中,一切都变得很好。

有什么办法能让生成循环运行起来呢?

verilog fpga hdl quartus intel-fpga
1个回答
4
投票

我认为正确的方法是按照这个问题中解释的思路。在verilog中使用for循环的生成方法

这将会被转移到你的代码中,就像这样。

module main(
    output reg  [1:0][DATA_WIDTH-1:0] dOut,
    input  wire [1:0][DATA_WIDTH-1:0] dIn,
    input  wire [1:0][ADDR_WIDTH-1:0] addr,
    input  wire [1:0] wren,
    input  wire clk
);
    parameter DATA_WIDTH = 16;
    parameter ADDR_WIDTH = 6;

    reg [DATA_WIDTH-1:0] ram [2**ADDR_WIDTH-1:0];    
    integer k;

    always @(posedge clk) begin
      for(k=0; k<2; k=k+1) begin:
        if(wren[k])
          ram[addr[k]] <= dIn[k];
        dOut[k] <= ram[addr[k]];
      end
    end
endmodule

把所有对双端口RAM的访问都保存在一个地方 always 块是方便的,这样合成器就可以安全地检测到你在寄存器中有效地使用了双端口RAM。ram.


1
投票

生成循环和未滚动的版本都不应该通过合成。在这两种情况下,相同地址的 ram 可以由两个总是块分配。更糟糕的是,如果两个位的 wren 为高,而两个地址相同,数据不同,那么结果是无法确定的。Verilog LRM规定一个寄存器上的最后一次赋值获胜,总是具有相同触发器的块可以以任何顺序进行评估。

合成要求对寄存器的赋值是确定的。两个(或多个)总是块对同一位有写访问是非法的,因为是非确定性的。如果解卷的合成是正确的,那么就意味着有常量对 wrenaddr 外的约束条件,使得它在逻辑上不可能发生写冲突;由于某些原因,生成循环版本没有得到同样的优化。可以让优化防止多总是块写访问的约束条件的例子。

  1. 一个 wren 是硬编码为0,因此只有一个区块有独占的权限
  2. 地址具有非重叠的可能值集。例如 addr[0] 扯平 addr[1] 只能是奇数,或者 addr[0] < 2**(ADDR_WIDTH/2)addr[1] >= 2**(ADDR_WIDTH/2).

合成没问题 dOut 因为每个块都有专属的写访问目标位(非重叠的可能地址值集),所以被两个总是块分配。

mcleod_ideafix答案中的单块始终是首选的解决方案。如果两个位的 wren 为高,且两个地址相同,则 wren[1] 将永远是赢家。如果 wren[0] 应该有优先权,然后把for-loop做成倒计时。

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