23

我试图让一个模块通过 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

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

错误:HDLCompiler:731 - “test.v” 第 46 行:不允许对非寄存器 <c> 进行程序分配。

我真的不明白它为什么抱怨。“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 中修复,请告诉我您知道哪个版本有效。

4

6 回答 6

27

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

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 循环需要与 a reginteger或类似内容一起使用。它不能使用 a genvar,因为在 always 块中使用 for 循环描述了在时钟的每个边沿发生的操作,而不是可以在设计的详细说明期间静态扩展的操作。

于 2012-09-20T01:15:51.940 回答
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
于 2013-07-02T00:12:21.930 回答
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
于 2012-09-21T14:55:22.023 回答
2

在一个模块中,Verilog 本质上包含两个结构:项目和语句。语句总是出现在过程上下文中,包括介于 begin..end、函数、任务、always 块和初始块之间的任何内容。诸如生成构造之类的项目直接在模块中列出。For 循环和大多数变量/常量声明可以存在于这两种上下文中。

在您的代码中,您似乎希望将 for 循环评估为生成项,但该循环实际上是 always 块的过程上下文的一部分。对于要被视为生成循环的 for 循环,它必须位于模块上下文中。generate..endgenerate 关键字完全是可选的(某些工具需要它们)并且没有效果。有关如何评估生成循环的示例,请参见此答案。

//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
于 2012-09-20T05:42:20.077 回答
0

对于verilog 就做

parameter ROWBITS = 4;
reg [ROWBITS-1:0] temp;
always @(posedge sysclk) begin
  temp <= {ROWBITS{1'b0}}; // fill with 0
end
于 2014-12-12T10:37:54.420 回答
0

简而言之,您不要generate在 always 进程中使用,而是使用 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
于 2019-01-30T19:21:28.037 回答