Quartus不允许在Verilog中使用Generate block



非常简单的问题。给定以下代码:

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( 上网络"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 中使用 generate with 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。

生成循环和展开版本都不应该通过合成。在这两种情况下,ram中的相同地址都可以由两个始终块分配。更糟糕的是,如果wren的两个位都很高,两个地址相同且数据不同,则结果是不确定的。Verilog LRM 声明寄存器上的最后一个分配获胜,并且始终可以按任何顺序评估具有相同触发器的块。

综合要求寄存器的赋值是确定性的。两个(或更多(始终阻止对同一位进行写入访问是非法的,因为不确定。如果展开的合成正确,则意味着在显示的模块之外的wrenaddr上存在常量,这使得写入冲突在逻辑上是不可能的;由于某种原因,生成循环版本没有得到相同的优化。允许优化以防止多始终阻止写入访问的约束示例:

  1. 一个wren硬编码为 0。因此只有一个块具有独占访问权限
  2. 地址具有不重叠的可能值集。Exaddr[0]只能是偶数,而addr[1]只能是奇数,或addr[0] < 2**(ADDR_WIDTH/2)addr[1] >= 2**(ADDR_WIDTH/2)

合成可以由两个始终块分配dOut因为每个块对其目标位(可能地址值的非重叠集(具有独占写入访问权限。

答案中的单个始终块mcleod_ideafix是首选解决方案。如果两个wren位都很高,并且两个地址相同,那么wren[1]将始终获胜。如果wren[0]应该具有优先级,则使 for 循环倒计时。

最新更新