vivado在进行实现阶段的opt_design过程报错,出现多驱动问题;
DRC MDRV-1 multiple Drive Nets:Net UNCONN_OUT1 has multiple drivers: genblk10.tmp_max_1d_reg11/Q,and genblk11.tmp_max_1d_reg11/Q;
问题代码1:
'd1: begin // 实现每2个数累加求和,320个数,一共输出160个
group_size = 2;
group_num = 320 / group_size; // 160组
group_idx = m; // 每组输出一个累加和
if(group_idx < group_num) begin
start_idx <= group_idx * group_size;
temp_sum <= 'd0;
// 计算组内累加和
for(i=0; i<group_size; i=i+1) begin
temp_sum <= temp_sum + din[start_idx + i];
end
// 只取低8位输出(如果累加和超过8位)
dout[m] <= temp_sum;
end
else begin
dout[m] <= 'd0;
end
end
问题代码2:
'd6: begin // 实现每160个数比较,输出一个最大值和最小值,320个数,一共输出4个
group_idx = m / 2;
start_idx = group_idx * 160;
if(group_idx < 2) begin // 共2组,每组160个数
// 找到当前组的最大值和最小值
max_val = din[start_idx];
min_val = din[start_idx];
for(i=1; i<160; i=i+1) begin
if(din[start_idx+i] > max_val) begin
max_val <= din[start_idx+i];
end
if(din[start_idx+i] < min_val) begin
min_val <= din[start_idx+i];
end
end
// 分配输出
if(m % 2 == 0) begin // 偶数位置输出最大值
dout[m] <= max_val;
end
else begin // 奇数位置输出最小值
dout[m] <= min_val;
end
end
else begin
dout[m] <= 'd0;
end
end
分析原因,对于赋值,尽管这些逻辑是在一个always 块里面实现的,但是在for 循环中进行循环计算再赋值,不应该用非阻塞赋值,而是要用阻塞赋值;
正确代码1:
'd1: begin // 实现每2个数累加求和,320个数,一共输出160个
group_size = 2;
group_num = 320 / group_size; // 160组
group_idx = m; // 每组输出一个累加和
if(group_idx < group_num) begin
start_idx <= group_idx * group_size;
temp_sum <= 'd0;
// 计算组内累加和
for(i=0; i<group_size; i=i+1) begin
temp_sum = temp_sum + din[start_idx + i];
end
// 只取低8位输出(如果累加和超过8位)
dout[m] <= temp_sum;
end
else begin
dout[m] <= 'd0;
end
end
正确代码2:
'd6: begin // 实现每160个数比较,输出一个最大值和最小值,320个数,一共输出4个
group_idx = m / 2;
start_idx = group_idx * 160;
if(group_idx < 2) begin // 共2组,每组160个数
// 找到当前组的最大值和最小值
max_val = dinstart_idx;
min_val = dinstart_idx;
for(i=1; i<160; i=i+1) begin
if(dinstart_idx+i > max_val) begin
max_val = dinstart_idx+i;
end
if(dinstart_idx+i < min_val) begin
min_val = dinstart_idx+i;
end
end
// 分配输出
if(m % 2 == 0) begin // 偶数位置输出最大值
doutm <= max_val;
end
else begin // 奇数位置输出最小值
doutm <= min_val;
end
end
else begin
doutm <= 'd0;
end
end
区别分析:
| 特性 | 第一段代码(正常) | 第二段代码(有多驱动) |
|---|---|---|
| 赋值方式 | 阻塞赋值 (=) |
非阻塞赋值 (<=) |
| 变量性质 | 临时变量(组合逻辑) | 推断为寄存器(时序逻辑) |
| 执行时机 | 立即计算,在同一时钟周期内完成 | 值在时钟边沿后更新,延迟生效 |
| 关键影响 | 每个 m 实例独立计算自己的 max_val/min_val |
所有 m 实例共享并竞争同一个 max_val/min_val 寄存器 |
1. 非阻塞赋值 (<=) 的硬件含义
在 always @(posedge i_clk) 块中使用 <= 赋值,综合工具会推断出寄存器。这意味着:
-
max_val和min_val不再是临时计算变量,而是会在时钟沿之间保持状态的物理寄存器。 -
循环中的
max_val <= din[start_idx+i];不是立即更新,而是安排一个"计划",在时钟周期结束时更新。因此,for循环中后续的比较使用的max_val值始终是该寄存器在上一个时钟周期的旧值,这完全打破了查找最大值的逻辑。
2. 多驱动冲突的产生
这是最关键的一点:在 generate 循环中,每个展开的 m 实例都包含自己的 always 块,但所有这些块都试图驱动名为 max_val 和 min_val 的同一个(全局)寄存器。
-
当
group_idx < 2时(即m = 0, 1, 2, 3),4个并行的硬件实例会在每个时钟沿同时执行。 -
每个实例都试图根据自己的
start_idx和循环逻辑,向max_val和min_val写入数据。 -
这就造成了4个驱动源同时驱动同一根线,即
multiple driver错误。
第一段代码之所以正确 ,是因为它使用了阻塞赋值 (=),且没有将 max_val/min_val 声明为 reg (它们很可能是 integer 或隐式的临时变量)。这样,每个 m 实例的 always 块中的 max_val 和 min_val 都是该实例本地、独立的组合逻辑变量,彼此互不干扰。
在时序逻辑的 always 块中,<= 用于推断寄存器,= 用于临时计算。
设计原则 :"计算用阻塞,输出用非阻塞"。在时钟触发的块内进行复杂的组合逻辑计算时,使用阻塞赋值和局部变量;只有需要寄存到下一个时钟周期的最终结果,才使用非阻塞赋值输出。