Quartus 不允许在 Verilog 中使用生成块
Quartus does not allow using a Generate block in Verilog
很简单的问题。给定以下代码:
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 个不当兄弟姐妹):
Error (10028): Can't resolve multiple constant drivers for net "ram[63][14]" at main.v(42)
但是如果我手动展开生成循环:
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
分析和合成步骤一切都会好起来的。
获得生成循环的治疗方法是什么 运行?
我认为正确的方法是在这个问题中解释的内容:Using a generate with for loop in verilog
这将像这样转移到您的代码中:
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
中的相同地址可以由两个 always 块分配。更糟糕的是,如果 wren
的两个位都为高且两个地址相同但数据不同,则结果无法确定。 Verilog LRM 声明寄存器上的最后一次分配获胜,并且始终可以按任何顺序评估具有相同触发器的块。
综合要求对寄存器的分配是确定性的。两个(或更多)always 块对同一位具有写访问权限是非法的,因为它是不确定的。如果展开的是正确合成的,那么这意味着在所示模块之外的 wren
和 addr
上存在常量,这使得写入冲突在逻辑上是不可能的;由于某种原因,生成循环版本没有得到相同的优化。允许优化以防止 multi-always 块写入访问的约束示例:
- 一个
wren
被硬编码为0。因此只有一个块具有独占访问权
- 地址具有不重叠的可能值集。例如
addr[0]
只能是偶数而 addr[1]
只能是奇数,或者 addr[0] < 2**(ADDR_WIDTH/2)
和 addr[1] >= 2**(ADDR_WIDTH/2)
。
综合可以 dOut
分配给两个 always 块,因为每个块都对其目标位(不重叠的可能地址值集)具有独占写访问权限。
mcleod_ideafix 答案中的单一始终块是首选解决方案。如果 wren
的两位都为高且两个地址相同,则 wren[1]
将始终获胜。如果 wren[0]
应该有优先权,那么让 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];
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 个不当兄弟姐妹):
Error (10028): Can't resolve multiple constant drivers for net "ram[63][14]" at main.v(42)
但是如果我手动展开生成循环:
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
分析和合成步骤一切都会好起来的。
获得生成循环的治疗方法是什么 运行?
我认为正确的方法是在这个问题中解释的内容:Using a generate with for loop in verilog
这将像这样转移到您的代码中:
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
中的相同地址可以由两个 always 块分配。更糟糕的是,如果 wren
的两个位都为高且两个地址相同但数据不同,则结果无法确定。 Verilog LRM 声明寄存器上的最后一次分配获胜,并且始终可以按任何顺序评估具有相同触发器的块。
综合要求对寄存器的分配是确定性的。两个(或更多)always 块对同一位具有写访问权限是非法的,因为它是不确定的。如果展开的是正确合成的,那么这意味着在所示模块之外的 wren
和 addr
上存在常量,这使得写入冲突在逻辑上是不可能的;由于某种原因,生成循环版本没有得到相同的优化。允许优化以防止 multi-always 块写入访问的约束示例:
- 一个
wren
被硬编码为0。因此只有一个块具有独占访问权 - 地址具有不重叠的可能值集。例如
addr[0]
只能是偶数而addr[1]
只能是奇数,或者addr[0] < 2**(ADDR_WIDTH/2)
和addr[1] >= 2**(ADDR_WIDTH/2)
。
综合可以 dOut
分配给两个 always 块,因为每个块都对其目标位(不重叠的可能地址值集)具有独占写访问权限。
mcleod_ideafix 答案中的单一始终块是首选解决方案。如果 wren
的两位都为高且两个地址相同,则 wren[1]
将始终获胜。如果 wren[0]
应该有优先权,那么让 for 循环倒计时。