Verilog在一个始终块中生成/ genvar

时间:2012-09-20 00:59:24

标签: verilog

我正在尝试让一个模块在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中修复,请告诉我您知道哪个版本有效。

6 个答案:

答案 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循环需要使用reginteger或类似内容。它不能使用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