FPGA 组合逻辑和时序逻辑

vivado在进行实现阶段的opt_design过程报错,出现多驱动问题;

DRC MDRV-1\] multiple Drive Nets:Net UNCONN_OUT\[1\] has multiple drivers: genblk1\[0\].tmp_max_1d_reg\[1\]\[1\]/Q,and genblk1\[1\].tmp_max_1d_reg\[1\]\[1\]/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 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 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 区别分析: | 特性 | 第一段代码(正常) | 第二段代码(有多驱动) | |----------|------------------------------------|---------------------------------------------| | **赋值方式** | 阻塞赋值 (`=`) | 非阻塞赋值 (`<=`) | | **变量性质** | 临时变量(组合逻辑) | 推断为寄存器(时序逻辑) | | **执行时机** | 立即计算,在同一时钟周期内完成 | 值在时钟边沿后更新,延迟生效 | | **关键影响** | 每个 `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` 块中,`<=` 用于推断寄存器,`=` 用于临时计算。 **设计原则** :**"计算用阻塞,输出用非阻塞"**。在时钟触发的块内进行复杂的组合逻辑计算时,使用阻塞赋值和局部变量;只有需要寄存到下一个时钟周期的最终结果,才使用非阻塞赋值输出。

相关推荐
Js_cold3 小时前
Xilinx FPGA温度等级及选型建议
fpga开发·fpga·vivado·xilinx
从此不归路4 小时前
FPGA 结构与 CAD 设计(第5章)上
fpga开发
洋洋Young4 小时前
【Xilinx FPGA】7 Series Clocking 设计
fpga开发·xilinx fpga
156082072195 小时前
FPGA下AD采集时钟相位的调整
fpga开发
从此不归路5 小时前
FPGA 结构与 CAD 设计(第5章)下
fpga开发
Js_cold7 小时前
Xilinx FPGA Flash启动时钟频率
单片机·嵌入式硬件·fpga开发·vivado·xilinx·flash·cclk
博览鸿蒙1 天前
FPGA的学习路径和入行指南
fpga开发
ShiMetaPi1 天前
GM-3568JHF丨ARM+FPGA异构开发板应用开发教程:01 UART读写案例
arm开发·单片机·嵌入式硬件·fpga开发·fpga·rk3568
楠了个难1 天前
AXI4接口简介——ZYNQ学习笔记24
笔记·学习·fpga开发