繁体   English   中英

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

[英]Verilog generate/genvar in an always block

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

请不要评论如何在没有生成的情况下更容易地编写它。 这是一个更复杂的代码片段的简化示例,涉及对“temp”的多个ifs和非阻塞赋值。 另外,不要只告诉我有更新版本的ISE,我已经知道了。 OTOH,如果您知道它已在ISE的更高版本中修复,请告诉我您知道哪个版本有效。

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

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

如果希望在同一个块中分配的所有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

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

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

对于verilog来说

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

简单地说,你不使用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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM