我正在尝试让一个模块在ISE 12.4中通过语法检查,它给了我一个我不明白的错误。首先是一个代码片段:
parameter ROWBITS = 4;
reg [ROWBITS-1:0] temp;
genvar c;
generate
always @(posedge sysclk) begin
for (c = 0; c < ROWBITS; c = c + 1) begin: test
temp[c] <= 1'b0;
end
end
endgenerate
当我尝试语法检查时,收到以下错误消息:
错误:HDLC编译器:731 - “test.v”第46行:程序分配给a 非注册&lt; c&gt;是不允许的。
我真的不明白为什么抱怨。 “c”不是电线,它是一种genvar。这应该等同于完全合法的语法:
reg [3:0] temp;
always @(posedge sysclk) begin
temp[0] <= 1'b0;
temp[1] <= 1'b0;
temp[2] <= 1'b0;
temp[3] <= 1'b0;
end
请不要评论如何在没有生成的情况下更容易地编写它。这是一个更复杂的代码片段的简化示例,涉及对“temp”的多个ifs和非阻塞赋值。另外,不要只告诉我有更新版本的ISE,我已经知道了。 OTOH,如果您知道它已在更高版本的ISE中修复,请告诉我您知道哪个版本有效。
答案 0 :(得分:17)
您需要反转生成块内的嵌套:
genvar c;
generate
for (c = 0; c < ROWBITS; c = c + 1) begin: test
always @(posedge sysclk) begin
temp[c] <= 1'b0;
end
end
endgenerate
从技术上讲,这会生成四个始终的块:
always @(posedge sysclk) temp[0] <= 1'b0;
always @(posedge sysclk) temp[1] <= 1'b0;
always @(posedge sysclk) temp[2] <= 1'b0;
always @(posedge sysclk) temp[3] <= 1'b0;
在这个简单的例子中,四个always块和一个包含四个赋值的always块之间的行为没有区别,但在其他情况下可能会有。
在构造设计的内存中表示时(在模拟器的情况下)或映射到逻辑门(在综合工具的情况下),需要解决与genvar相关的操作。在设计运行之前,always @posedge
没有意义。
受限于某些限制,您可以在always块中放置for循环,即使是可合成代码也是如此。对于合成,循环将展开。但是,在这种情况下,for循环需要使用reg
,integer
或类似内容。它不能使用genvar
,因为在always块中包含for循环描述了在时钟的每个边缘发生的操作,而不是在设计细化期间可以静态扩展的操作。
答案 1 :(得分:6)
如果您希望在同一个中分配的temp
的所有位始终阻止,则不需要生成块。
parameter ROWBITS = 4;
reg [ROWBITS-1:0] temp;
always @(posedge sysclk) begin
for (integer c=0; c<ROWBITS; c=c+1) begin: test
temp[c] <= 1'b0;
end
end
或者,如果您的模拟器支持IEEE 1800(SytemVerilog),那么
parameter ROWBITS = 4;
reg [ROWBITS-1:0] temp;
always @(posedge sysclk) begin
temp <= '0; // fill with 0
end
end
答案 2 :(得分:4)
如果您不介意编译/生成文件,那么您可以使用预处理技术。这为您提供了生成的强大功能,但却产生了一个干净的Verilog文件,该文件通常更容易调试,并且可以减少模拟器问题。
我使用RubyIt使用ERB(嵌入式Ruby)从模板生成verilog文件。
parameter ROWBITS = <%= ROWBITS %> ;
always @(posedge sysclk) begin
<% (0...ROWBITS).each do |addr| -%>
temp[<%= addr %>] <= 1'b0;
<% end -%>
end
使用以下命令生成module_name.v文件:
$ ruby_it --parameter ROWBITS=4 --outpath ./ --file ./module_name.rv
生成的module_name.v
parameter ROWBITS = 4 ;
always @(posedge sysclk) begin
temp[0] <= 1'b0;
temp[1] <= 1'b0;
temp[2] <= 1'b0;
temp[3] <= 1'b0;
end
答案 3 :(得分:2)
在一个模块中,Verilog基本上包含两个结构:items和statements。语句总是在过程上下文中找到,其中包括begin..end,函数,任务,始终块和初始块之间的任何内容。诸如generate构造之类的项目直接列在模块中。 for循环和大多数变量/常量声明都可以存在于两个上下文中。
在您的代码中,您似乎希望将for循环计算为生成项,但循环实际上是always块的过程上下文的一部分。要将for循环视为生成循环,它必须位于模块上下文中。 generate..endgenerate关键字完全是可选的(某些工具需要它们)并且没有任何效果。有关如何评估生成循环的示例,请参阅this answer。
//Compiler sees this
parameter ROWBITS = 4;
reg [ROWBITS-1:0] temp;
genvar c;
always @(posedge sysclk) //Procedural context starts here
begin
for (c = 0; c < ROWBITS; c = c + 1) begin: test
temp[c] <= 1'b0; //Still a genvar
end
end
答案 4 :(得分:0)
对于verilog来说
parameter ROWBITS = 4;
reg [ROWBITS-1:0] temp;
always @(posedge sysclk) begin
temp <= {ROWBITS{1'b0}}; // fill with 0
end
答案 5 :(得分:0)
简单地说,您不需要在始终进程中使用generate
,而是使用generate创建参数化的进程或实例化特定的模块,您可以在其中组合if-else
或{{1} }。因此,您可以移动此生成并创建特定的流程或实例化,例如
case