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
问题分析与解决
核心原因
- 位选择表达式不满足常量要求:iverilog对静态循环的识别有严格限制,你手动计算位宽的写法
i_wbm_addr[m * 32 + 32 - 1:m * 32 + (32 - MASK_SIZE)]被工具判定为运行时可变的表达式,而非编译期可确定的常量,因此无法被静态展开。 - 笔误导致语法错误:
i_wbc_mask[c * MASK_SIZE + MASK_SIZE - 1:i_wbc_mask * MASK_SIZE]中,位选择的起始索引错误地写成了i_wbc_mask * MASK_SIZE,应该是c * MASK_SIZE。 - 端口位宽定义错误:比如
[$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
相关产品推荐
相关产品推荐

