【问题标题】:Verilog generate/genvar in an always block始终块中的 Verilog 生成/genvar
【发布时间】:2012-09-20 00:59:23
【问题描述】:

我试图让一个模块通过 ISE 12.4 中的语法检查,它给了我一个我不明白的错误。先来个代码sn-p:

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

当我尝试语法检查时,我收到以下错误消息:

ERROR:HDLCompiler:731 - "test.v" 第 46 行:程序分配给 非注册 是不允许的。

我真的不明白它为什么抱怨。 “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

拜托,没有生成器如何更容易编写此内容。这是一段更复杂的代码的简化示例,其中涉及多个 if 和对“temp”的非阻塞分配。另外,不要只告诉我有更新版本的 ISE,我已经知道了。 OTOH,如果您知道它已在更高版本的 ISE 中得到修复,请告诉我您知道哪个版本有效。

【问题讨论】:

    标签: verilog


    【解决方案1】:

    您需要反转生成块内的嵌套:

    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 块:

    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 循环描述了在时钟的每个边沿发生的操作,而不是可以在设计细化期间静态扩展的操作。

    【讨论】:

    • 感谢您的快速回复。我害怕会是这样。部分问题是我想使用 for 循环生成一系列 if 语句或 case 选择器,这不能在单独的 always 块中完成。
    • 有没有办法在一个 always 块中生成所有代码,还是 genvar 无法做到这一点?
    【解决方案2】:

    如果您希望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
    

    【讨论】:

      【解决方案3】:

      如果您不介意编译/生成文件,那么您可以使用预处理技术。这为您提供了生成的强大功能,但会生成一个干净的 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
      

      【讨论】:

        【解决方案4】:

        在一个模块中,Verilog 基本上包含两个结构:项目和语句。语句总是出现在过程上下文中,包括介于 begin..end、函数、任务、always 块和初始块之间的任何内容。诸如生成构造之类的项目直接在模块中列出。 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
        

        【讨论】:

          【解决方案5】:

          verilog 就可以了

          parameter ROWBITS = 4;
          reg [ROWBITS-1:0] temp;
          always @(posedge sysclk) begin
            temp <= {ROWBITS{1'b0}}; // fill with 0
          end
          

          【讨论】:

            【解决方案6】:

            简单地说,你不要在always进程中使用generate,而是使用generate来创建参数化进程或实例化特定模块,你可以在其中组合if-elsecase。所以你可以移动这个生成并创建一个特定的进程或实例化,例如,

            module #(
            parameter XLEN = 64,
            parameter USEIP = 0
            )
            (
             input clk,
            input rstn,
            input [XLEN-1:0] opA,
            input [XLEN-1:0] opB,
            input [XLEN-1:0] opR,
            input en
            );
            
            generate 
            case(USEIP)
            0:begin
            always @(posedge clk or negedge rstn)
            begin
            if(!rstn)
            begin
             opR <= '{default:0};
            end
            else
            begin
            if(en)
             opR <= opA+opB;
            else
            opR <= '{default:0};
            end
            end
            end
            1:begin
              superAdder #(.XLEN(XLEN)) _adder(.clk(clk),.rstm(rstn), .opA(opA), .opB(opB), .opR(opR), .en(en));
            end
            endcase
            
            endmodule
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2011-11-12
              • 1970-01-01
              • 2019-09-11
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多