【问题标题】:Using a for loop inside a clocked process: "Cannot generate logic"在时钟进程中使用 for 循环:“无法生成逻辑”
【发布时间】:2014-06-24 15:24:50
【问题描述】:

我想在一个时钟进程中生成一些语句,如下所示:

    parameter C_INPUT_LENGTH      = 32;
    parameter C_OUTPUT_NUM_BITS   = 5;

    reg [C_OUTPUT_NUM_BITS-1:0]        address;
    reg [C_INPUT_LENGTH-1:0]           vector_i;

    always@(posedge clk) begin        
       if(rst) begin
          address <= 0;
       end 
       else begin

         if (vector_i[0] == 1) begin
            address <= 0;
         end

         if (vector_i[1] == 1) begin
            address <= 1;
         end

         ...

         if (vector_i[C_INPUT_LENGTH-1] == 1) begin
            address <= C_INPUT_LENGTH-1;
         end

       end
    end // always@ (posedge clk)

我是这样做的:

    integer                            forcount;
    always@(posedge clk) begin        
       if(rst) begin
          address <= 0;
       end 
       else begin

          for (forcount = 0;forcount <= C_INPUT_LENGTH-1 ;forcount = forcount + 1) begin
             if (vector_i[forcount] == 1) begin <--
                address <= forcount;
             end
          end 

       end
    end // always@ (posedge clk)

Xilinx vivado (2014.1) 给出以下错误,参考上面指出的行:

[Synth 8-903] failed to generate logic

我在过去使用类似的方法之前已经这样做了,它已经奏效了,我做错了什么?如何生成这些 if 语句?

【问题讨论】:

  • 合成工具展开循环。根据C_INPUT_LENGTH 的值和您的时钟周期时间限制,展开的逻辑可能不适合一个时钟周期。您是否尝试过增加时钟周期时间或减少C_INPUT_LENGTH
  • @Ari 即使 for 循环不适合单个时钟周期,也不会阻止它进行合成。
  • 另外,您可能想尝试分离组合逻辑块和顺序逻辑块。我会将 for 循环放在一个 always_comb 块中,并将其输出分配给 always(@posedge clk) 中的 address。看起来你想在单个周期中找到第一个 1 位,无论如何这是一个组合逻辑。
  • 见这里:forums.xilinx.com/xlnx/board/…。尝试:if (vector_i[forcount] == 1'b1) 而不是 if (vector_i[forcount] == 1)
  • @ari 你指的是什么组合代码?一切都在一个 always 块中。

标签: verilog


【解决方案1】:

根据 Xilinx,这是 CR 801365 下记录的一个已知错误。在某些情况下,使用整数作为循环计数器会导致此问题。它应该在 vivado 2014.3 中修复。

解决方案是将整数替换为适当大小的信号类型 reg。

【讨论】:

    【解决方案2】:

    你的输入 vector_i 是 one-hot 吗?您编写的代码不能保证地址只会被写入一个值。试试这个:

    for (forcount = 0;forcount <= C_INPUT_LENGTH-1 ;forcount = forcount + 1) begin
      if (vector_i[forcount] == 1) begin
         address <= forcount;
         break;
      end
    end 
    

    添加 break 语句将在第一次条件为真时跳出 for 循环。请注意,这会生成一些进位链逻辑,使用case statement 可能会得到更好的结果。

    【讨论】:

    • 不是one-hot,目标是给高地址优先级。我希望较高的地址覆盖较低的地址。这是一款领先的检测器。
    • 那么你要么需要if else 要么你肯定需要使用break
    • 我希望高位地址覆盖低位。它是故意这样设计的,并按照我想要的方式工作。
    【解决方案3】:

    作为临时解决方法,您可以考虑使用 generate 语句。

    例如:

    genvar i;
    
    always @(posedge clk) begin
      if (rst) begin
        address <= 0;
      end else begin
         generate 
           for (i = 0; i < C_INPUT_LENGTH; i = i + 1) begin: foreach_input
             if (vector_i[i]) address <= i;
           end
         endgenerate
       end // if (rst)
     end  // always @(posedge clk)
    

    编辑:哦,没关系——我错过了上面的一点,Xilinx 推荐的解决方法是简单地使用有维度的变量而不是“整数”作为迭代器。那会更容易!

    【讨论】:

    • +1 因为我还没有看到以这种方式使用的生成。
    • @StaceyAnne,您确实看到了generate 以这种方式使用,因为这种语法是非法的。对于 Verilog,一个generate 块只能放在一个模块中。它们不能放在always 块内。如果您将always 移动到生成for 循环中,您将拥有合法的语法,但它仍然无法合成,因为address 上有多个驱动程序。
    猜你喜欢
    • 2020-09-14
    • 1970-01-01
    • 2018-01-10
    • 1970-01-01
    • 1970-01-01
    • 2014-10-03
    • 1970-01-01
    • 2022-11-04
    • 2020-10-25
    相关资源
    最近更新 更多