You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Verilog for循环展开未达预期,iverilog编译报错求助

问题描述

我编写了一个带参数的crossbar模块,其中使用for循环,预期该循环会被展开为重复逻辑,消除循环及索引。但使用iverilog测试模块时出现报错:

执行命令

iverilog -g2012 -o graph/crossbar.vvp -s crossbar_tb src/defines.sv test/crossbar_tb.sv src/crossbar.sv

报错信息

src/crossbar.sv:54: error: A reference to a wire or reg (`m') is not allowed in a constant expression.
src/crossbar.sv:54: error: Part select expressions must be constant.
src/crossbar.sv:54:      : This lsb expression violates the rule: ((m)*('sd32))+(('sd32)-(MASK_SIZE))

m是循环的整数索引,我认为它会在展开时被消除。模块逻辑尚未测试,但不解为何循环未按预期展开导致报错,模块代码如下:

`default_nettype none

module crossbar
#(
  parameter MASTERS = 1,
  parameter CHANNELS = 1,
  parameter MASK_SIZE = 4
)
(
  input  logic                       i_clock,
  input  logic                       i_reset_n,

  // Inputs from masters
  input  logic [$clog2(MASTERS):0]   i_wbm_we,     // Write enable
  input  logic [$clog2(MASTERS):0]   i_wbm_cyc,    // Cycle status
  input  logic [$clog2(MASTERS):0]   i_wbm_stb,    // Strobe
  input  logic [MASTERS * 32 - 1:0]  i_wbm_addr,   // Address read from master
  input  logic [MASTERS * 32 - 1:0]  i_wbm_data,   // Data read from the master

  // Outputs to masters
  output logic [$clog2(MASTERS):0]   o_wbm_err,    // Error
  output logic [$clog2(MASTERS):0]   o_wbm_ack,    // Acknowledge
  output logic [$clog2(MASTERS):0]   o_wbm_stall,  // Stall
  output logic [MASTERS * 32 - 1:0]  o_wbm_data,   // Data write from the master

  // Outputs to channels
  output logic [$clog2(CHANNELS):0]   o_wbc_we,     // Write enable
  output logic [$clog2(CHANNELS):0]   o_wbc_cyc,    // Cycle status
  output logic [$clog2(CHANNELS):0]   o_wbc_stb,    // Strobe
  output logic [CHANNELS * 32 - 1:0]  o_wbc_addr,   // Address read from master
  output logic [CHANNELS * 32 - 1:0]  o_wbc_data,   // Data read from the master

  // Inputs from channels
  input  logic [$clog2(CHANNELS):0]          i_wbc_err,    // Error
  input  logic [$clog2(CHANNELS):0]          i_wbc_ack,    // Acknowledge
  input  logic [$clog2(CHANNELS):0]          i_wbc_stall,  // Stall
  input  logic [CHANNELS * 32 - 1:0]         i_wbc_data,   // Data write from the master
  input  logic [CHANNELS * MASK_SIZE - 1:0]  i_wbc_mask    // Mask for address space
);

logic [$clog2(CHANNELS):0] channel_in_use [$clog2(MASTERS):0];

integer m; // Master loop index
integer c; // Channel loop index

always_ff @(posedge i_clock) begin
  // Loop over each master
  for (m = 0; m < MASTERS; m = m + 1) begin
    // New request from master m
    if (i_wbm_cyc[m] == 'b1 && i_wbm_stb[m] == 'b1) begin
      // Loop over each channel
      for (c = 0; c < CHANNELS; c = c + 1) begin
        // Found the requested channel, not in use
        if (i_wbc_mask[c * MASK_SIZE + MASK_SIZE - 1:i_wbc_mask * MASK_SIZE] == i_wbm_addr[m * 32 + 32 - 1:m * 32 + (32 - MASK_SIZE)] && channel_in_use[c] == 0) begin
          channel_in_use[c] <= m;
          o_wbm_stall[m] <= 'b0;
          o_wbm_err[m] <= 'b0;
        end

        // Found the requested channel, in use
        else if (i_wbc_mask[c * MASK_SIZE + MASK_SIZE - 1:i_wbc_mask * MASK_SIZE] == i_wbm_addr[m * 32 + 32 - 1:m * 32 + (32 - MASK_SIZE)] && channel_in_use[c] != 0) begin
          o_wbm_stall[m] <= 'b1;
          o_wbm_err[m] <= 'b0;
        end

        // requested channel not found
        else begin
          o_wbm_stall[m] <= 'b0;
          o_wbm_err[m] <= 'b1;
        end
      end
    end

    // No request for mater m
    else if (i_wbm_cyc[m] == 'b0) begin
      for (c = 0; c < CHANNELS; c = c + 1) begin
        if (channel_in_use[c] == m) begin
          channel_in_use[c] = 0;
        end
      end
    end
  end

  // Loop over each channel
  for (c = 0; c < CHANNELS; c = c + 1) begin
    // Channel is addigned, connect the bus
    if (channel_in_use[c] != 0) begin
      o_wbc_we[c] <= i_wbm_we[channel_in_use[c]];
      o_wbc_cyc[c] <= i_wbm_cyc[channel_in_use[c]];
      o_wbc_stb[c] <= i_wbm_stb[channel_in_use[c]];
      o_wbc_addr[c * 32 + 31:0] <= i_wbm_addr[channel_in_use[c] * 32 + 31:0];
      o_wbc_data[c * 32 + 31:0] <= i_wbm_data[channel_in_use[c] * 32 + 31:0];
      o_wbm_err[channel_in_use[c]] <= i_wbc_err[c];
      o_wbm_ack[channel_in_use[c]] <= i_wbc_ack[c];
      o_wbm_stall[channel_in_use[c]] <= i_wbc_stall[c];
      o_wbm_data[channel_in_use[c] * 32 + 31:0] <= i_wbc_data[c * 32 + 31:0];
    end else begin
      o_wbc_we[c] <= 'b0;
      o_wbc_cyc[c] <= 'b0;
      o_wbc_stb[c] <= 'b0;
      o_wbc_addr[c * 32 + 31:0] <= 32'b0;
      o_wbc_data[c * 32 + 31:0] <= 32'b0;
      o_wbm_err[channel_in_use[c]] <= 'b0;
      o_wbm_ack[channel_in_use[c]] <= 'b0;
      o_wbm_stall[channel_in_use[c]] <='b0;
      o_wbm_data[channel_in_use[c] * 32 + 31:0] <= 32'b0;
    end
  end
end

endmodule
问题分析与解决

核心原因

  1. 位选择表达式不满足常量要求:iverilog对静态循环的识别有严格限制,你手动计算位宽的写法i_wbm_addr[m * 32 + 32 - 1:m * 32 + (32 - MASK_SIZE)]被工具判定为运行时可变的表达式,而非编译期可确定的常量,因此无法被静态展开。
  2. 笔误导致语法错误:i_wbc_mask[c * MASK_SIZE + MASK_SIZE - 1:i_wbc_mask * MASK_SIZE]中,位选择的起始索引错误地写成了i_wbc_mask * MASK_SIZE,应该是c * MASK_SIZE。
  3. 端口位宽定义错误:比如[$clog2(MASTERS):0]的写法会多一位冗余位,正确的多信号位宽应该是[MASTERS-1:0]。

修正方案

1. 改用数组端口替代扁平化总线

把原来的扁平化总线定义成多维数组,直接用索引访问,避免手动计算位宽,同时让工具更容易识别为可静态展开的逻辑:

// Inputs from masters
input  logic [MASTERS-1:0]           i_wbm_we,     // Write enable
input  logic [MASTERS-1:0]           i_wbm_cyc,    // Cycle status
input  logic [MASTERS-1:0]           i_wbm_stb,    // Strobe
input  logic [MASTERS-1:0][31:0]     i_wbm_addr,   // Address read from master
input  logic [MASTERS-1:0][31:0]     i_wbm_data,   // Data read from the master

// Outputs to masters
output logic [MASTERS-1:0]           o_wbm_err,    // Error
output logic [MASTERS-1:0]           o_wbm_ack,    // Acknowledge
output logic [MASTERS-1:0]           o_wbm_stall,  // Stall
output logic [MASTERS-1:0][31:0]     o_wbm_data,   // Data write from the master

// Outputs to channels
output logic [CHANNELS-1:0]          o_wbc_we,     // Write enable
output logic [CHANNELS-1:0]          o_wbc_cyc,    // Cycle status
output logic [CHANNELS-1:0]          o_wbc_stb,    // Strobe
output logic [CHANNELS-1:0][31:0]    o_wbc_addr,   // Address read from master
output logic [CHANNELS-1:0][31:0]    o_wbc_data,   // Data read from the master

// Inputs from channels
input  logic [CHANNELS-1:0]          i_wbc_err,    // Error
input  logic [CHANNELS-1:0]          i_wbc_ack,    // Acknowledge
input  logic [CHANNELS-1:0]          i_wbc_stall,  // Stall
input  logic [CHANNELS-1:0][31:0]    i_wbc_data,   // Data write from the master
input  logic [CHANNELS-1:0][MASK_SIZE-1:0] i_wbc_mask    // Mask for address space

2. 修正循环内的位选择逻辑

用数组索引直接访问,同时修正笔误:

// Found the requested channel, not in use
if (i_wbc_mask[c] == i_wbm_addr[m][31 : 32 - MASK_SIZE] && channel_in_use[c] == 0) begin
  channel_in_use[c] <= m;
  o_wbm_stall[m] <= 'b0;
  o_wbm_err[m] <= 'b0;
end

// Found the requested channel, in use
else if (i_wbc_mask[c] == i_wbm_addr[m][31 : 32 - MASK_SIZE] && channel_in_use[c] != 0) begin
  o_wbm_stall[m] <= 'b1;
  o_wbm_err[m] <= 'b0;
end

3. 修正channel_in_use的位宽

channel_in_use用于存储master索引,位宽应匹配master的索引范围:

logic [$clog2(MASTERS)-1:0] channel_in_use [CHANNELS];

4. 修正always块内的总线赋值

同样改用数组索引简化写法,避免手动计算位宽:

// Channel is assigned, connect the bus
if (channel_in_use[c] != 0) begin
  o_wbc_we[c] <= i_wbm_we[channel_in_use[c]];
  o_wbc_cyc[c] <= i_wbm_cyc[channel_in_use[c]];
  o_wbc_stb[c] <= i_wbm_stb[channel_in_use[c]];
  o_wbc_addr[c] <= i_wbm_addr[channel_in_use[c]];
  o_wbc_data[c] <= i_wbm_data[channel_in_use[c]];
  o_wbm_err[channel_in_use[c]] <= i_wbc_err[c];
  o_wbm_ack[channel_in_use[c]] <= i_wbc_ack[c];
  o_wbm_stall[channel_in_use[c]] <= i_wbc_stall[c];
  o_wbm_data[channel_in_use[c]] <= i_wbc_data[c];
end else begin
  o_wbc_we[c] <= 'b0;
  o_wbc_cyc[c] <= 'b0;
  o_wbc_stb[c] <= 'b0;
  o_wbc_addr[c] <= 32'b0;
  o_wbc_data[c] <= 32'b0;
end

额外注意点

  • 若要更明确地指定静态循环,可将integer m/c替换为genvar,并将循环放在generate块内,但在always_ff块中使用integer作为循环变量,只要边界是参数,iverilog也能正确展开。
  • 确保所有信号的位宽定义与实际用途匹配,避免冗余或位宽不足的问题。

内容的提问来源于stack exchange,提问作者Justin808

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 15:35:01