FPGA中的原语
FPGA中的原语(Language Templates)
一、什么是原语
原语是官方将芯片中一部分电路封成类似于IP核一样的东西,用户可以直接调用原语来实现一些常见功能比如IBUFGDS(差分转普通)
原语因芯片而异,所以可移植性比较差,正因如此,IP核的创建尽量不要使用原语
原语比IP核速度还要快,因为是底层电路
下图是xilinx的vivado中关于原语的分类,可以看到在verilog中(目前先关注这个)根据芯片分了很多类,xcku060分在Kintex UltraScale中,zynq xczu4ev严格意义上不属于其中的任何一类,但是可以使用Kintex UltraScale+和Versal UltraScale+,因为其pl端是相同的。
| 类别 | 子类 | 主要内容/用途 |
|---|---|---|
| Device Macro Instantiation | Artix-7, Kintex-7, Virtex-7 | 针对 7 系 FPGA 的宏单元例化(例如 BUFG, PLL, BRAM, MMCM 等) |
| Device Primitive Instantiation | Artix-7 | 提供 7 系 Artix 设备的底层原语例化模板 |
| Kintex UltraScale | UltraScale 架构的 Kintex 设备原语(如高速收发器 GTY、BRAM、PLL) | |
| Kintex UltraScale+ | UltraScale+ 架构的 Kintex 设备原语(支持更高性能的 DSP、GTY、HBM 等) | |
| Kintex-7 | 7 系 Kintex 设备原语 | |
| Versal AI Core series | Versal AI Core 系列设备原语(支持 AI Engine、NoC 等新特性) | |
| Versal Premium series | Versal Premium 系列设备原语(更适合高带宽通信和网络) | |
| Versal Prime series | Versal Prime 系列设备原语(均衡型,适合通用 SoC 应用) | |
| Virtex UltraScale | UltraScale 架构的 Virtex 设备原语(面向高端通信/计算) | |
| Virtex UltraScale+ | UltraScale+ 架构的 Virtex 设备原语(更高带宽、更大逻辑资源) | |
| Virtex-7 | 7 系 Virtex 设备原语 | |
| IP Integrator HDL | Advanced Interfaces | 高级接口例化模板(如 AXI 总线接口信号) |
| AXI Interfaces | 专门的 AXI4/AXI4-Lite/AXI4-Stream 接口模板 | |
| Signal Interfaces | 常用信号接口模板(如握手、时钟复位等) | |
| Simulation Constructs | — | 提供仿真专用的语法模板 |
| Synthesis Constructs | — | 提供综合相关的语法模板 |
| Xilinx Parameterized Macros (XPM) | XPM, Usage Instructions | Xilinx 提供的参数化宏(例如 XPM_FIFO, XPM_MEMORY),可移植性和灵活性比直接用原语更好 |
二、原语
2.1 IBUFDS
IBUFDS 是 Vivado 提供的 差分信号输入缓冲器原语。
它的作用是:
将一对外部差分信号(如时钟信号 CLK_P / CLK_N)转换为单端信号,
供 FPGA 内部逻辑或全局时钟网络使用。
| 端口名 | 方向 | 说明 |
|---|---|---|
I |
输入 | 差分信号正端(如 CLK_P) |
IB |
输入 | 差分信号负端(如 CLK_N) |
O |
输出 | 转换后的单端时钟输出 |
1 | IBUFDS #( |
差分终端电阻:若外部没有匹配电阻,可以开启参数 .DIFF_TERM("TRUE")。
2.2 BUFG
2.2.1 差分时钟相关设计
BUFG 是 Vivado 提供的 全局时钟缓冲器(Global Clock Buffer),它的作用是:
将一个普通时钟信号(如外部晶振输入)连接到 FPGA 内部的全局时钟网络(Global Clock Tree),保证整个 FPGA 芯片内部所有时序单元可以同步工作。
那为什么需要 BUFG?
FPGA 是一个时序电路,每个触发器、状态机、计数器等都依赖统一的全局时钟。
而从外部引脚进来的时钟(例如 PL_CLK_P/PL_CLK_N)只是普通信号:
- 没有经过专用时钟树缓冲;
- 无法直接驱动大量触发器;
- 会导致严重的时钟偏斜(clock skew);
- Vivado 会报时钟相关的 Place & Route 错误或严重 timing violation;
使用BUFG的好处:
- 全局驱动:将时钟驱动到整个 FPGA 内部
- 消除时钟偏斜:所有逻辑单元同时接受一个“均衡”的时钟
- 必须走时钟树:Vivado 综合器只允许 BUFG 的输出进入
posedge clk等时序逻辑 - 布局优化:Vivado 能做出专门优化策略,满足时序需求
如果不在时钟输入里面加BUFG,可能会导致仿真OK,结果综合后跑不了,并且在Timing Report中看到非常大的clock skew。
正确设计结构需要:
1 | IBUFDS → BUFG → clk → always @(posedge clk) |
2.2.2 BUFG使用
| 端口名 | 方向 | 说明 |
|---|---|---|
I |
输入 | 输入时钟信号 |
O |
输出 | 输出全局时钟 |
1 | BUFG BUFG_inst ( |
2.3 IDELAYE3
2.3.1 IDELAYE3 是什么与为什么
IDELAYE3 是 Xilinx UltraScale / UltraScale+ 系列 FPGA 中提供的 输入延迟原语(Input Delay Element),用于对高速输入信号进行时序补偿。
它的核心作用是:
在 FPGA 内部,对输入信号引入一个可控、可调的亚纳秒级延迟,用于补偿外部走线、器件、时钟相位不一致带来的时序偏差。
在高速接口中(如 LVDS、DDR、ADC/AFE 输出数据):
- 数据(Data)
- 时钟(Dclk / Fclk)
几乎不可能在物理上做到完全对齐。
常见问题有:
- 数据与时钟相位偏移
- PCB 走线不等长
- AFE 内部通道不一致
- 建立时间 / 保持时间不满足
- ISERDES 采样点落在数据边沿附近
- 温度、电压变化导致相位漂移
- 多通道一致性要求(lane-to-lane alignment)
IDELAYE3 就是用来解决这个问题的
2.3.2 IDELAYE3 在系统中的位置
在正确的设计中,IDELAYE3 一定处在:
1 | 外部引脚 → IBUF / IBUFDS → IDELAYE3 → ISERDES / 逻辑 |
典型结构如下:
1 | 外部 LVDS 数据 |
2.3.3 使用
IDELAYE3 本质是一个 可编程输入延时线:把输入信号(来自 IO 的 IDATAIN 或逻辑的 DATAIN)延迟若干个 tap,再从 DATAOUT 输出。它的端口大体分 4 组:
A. 数据通路端口
- IDATAIN (Input):由“关联的 IOB 引脚”驱动的输入数据(最常用的输入路径)。
- DATAIN (Input):由 FPGA 内部互连逻辑驱动的输入数据(逻辑可达的延时线输入,不能直接回 IO)。
- DATAOUT (Output):延迟后的数据输出,可去 ILOGIC/ISERDESE3 或 FPGA 逻辑。
B. 延时控制端口(VARIABLE/VAR_LOAD 模式才真正用起来)
- CLK (Input):采样控制信号(LOAD/CE/INC 等)的时钟;当 IDELAYE3 配成 VARIABLE/VAR_LOAD 时必须接。
- CE (Input):控制接口使能;CE=1 时,INC 才能对延时 tap 做加/减操作。
- !!INC (Input):与 CE 配合使用;INC=1 表示“加 tap”(延迟变大),INC=0 表示“减 tap”(延迟变小)。
- RST (Input):异步复位输入;复位会把延时线回到设定的初始值(通常是 DELAY_VALUE 对应的 tap)。
- LOAD (Input):把 CNTVALUEIN 指定的 tap 值加载到延时线(VAR_LOAD 或需要动态装载时用)。
C. 延时数值端口
- CNTVALUEIN[8:0] (Input):要加载的 tap 数(动态装载用;通常建议在 LOAD 前提前 1 个 CLK 周期把 CNTVALUEIN 准备好)。这里也就是说IDELAYE3其实是支持给定的tap数,其实对于一块成型的板子,调试一次之后,其tap数就已经稳定了,那此时就可以使用固化版本的延迟,不用每次都动态计算每一路的tap。
- CNTVALUEOUT[8:0] (Output):报告当前延时 tap 数(读出当前处在多少 tap)。
D. 电压温漂补偿端口
- EN_VTC (Input):Voltage/Temperature Compensation 使能(决定是否由 IDELAYCTRL 做温漂电压补偿,让“tap 对应的真实时间延迟”更稳定)。
E. 级联相关(不做IDELAYE3的级联的话用不到)
- CASC_IN / CASC_OUT / CASC_RETURN:用于和 ODELAYE3/IDELAYE3 做级联扩展延迟范围的链路。
使用例程
1 | module idelay |
- 延迟对象选 IDATAIN(来自 IO)
.DELAY_SRC("IDATAIN")+.IDATAIN(Idata)表示: 外部进来的高速引脚信号 做精细延时,这正是 IDELAYE3 最典型用途(给 ISERDES 找采样窗口)。 - 模式选 VARIABLE + COUNT
- VARIABLE:在运行时扫描/微调 tap(自动校准就必须是可变)
- COUNT:用 tap 计数值表达延迟(对应 CNTVALUEOUT 是“第几 tap”)
控制接口用 CE/INC + CLK
因为 IDELAYE3 的控制输入(CE/INC/LOAD)是跟着CLK跑的同步信号,选择比 Dclk 慢的时钟,便于状态机稳定操作、等待数据收敛。REFCLK_FREQUENCY(300.0)
IDELAYE3 背后一定有一个 IDELAYCTRL在 UltraScale 架构中:
IDELAYE3本身不能独立工作- 每一组 IDELAYE3 必须依赖一个 IDELAYCTRL
IDELAYCTRL需要一个 稳定的参考时钟(REFCLK)
REFCLK_FREQUENCY用来告诉 IDELAYCTRL:
“参考时钟是多少 MHz,用它来标定 IDELAYE3 每一个 tap 的真实时间长度。”它 不等于 每个 tap 的时间,
而是 tap 校准和温漂补偿的基准条件。
2.4 ISERDESE3
1 | // ISERDESE3 #( |
2.4.1 WHAT
ISERDESE3(Input SERializer / DESerializer)是 Xilinx UltraScale / UltraScale+ FPGA 中的输入端串并转换原语。
它的核心功能是:
- 在高速时钟
CLK驱动下,对单比特串行输入数据D进行采样; - 通过 DDR 结构在一个时钟周期内完成多次采样;
- 将采样得到的数据重新整理,在低速时钟
CLKDIV域中以并行形式输出。
与普通逻辑级串并转换不同,ISERDESE3 工作在 IO 逻辑与高速时钟网络附近,具备明确的时序模型和物理实现路径,是高速接口设计中不可替代的基础单元。
2.4.2 WHY
在高速数据接口中,串行传输是不可避免的选择:
- IO 引脚数量有限;
- 高速并行总线的时序、串扰和功耗难以控制;
- AFE、ADC、SerDes 前端通常以串行或准串行形式输出数据。
而 FPGA 内部逻辑并不适合直接处理 GHz 级别的串行信号。
ISERDESE3 的作用正是在 IO 边界完成“高速 → 低速”的物理级转换,将高速、严格时序约束的采样问题,封装在一个确定行为的原语中,使后级逻辑只需要面对稳定、同步的并行数据。
2.4.3 WHERE
在一个典型的高速接收链路中,ISERDESE3 所处的位置通常如下:
1 | 外部高速数据 |
其中:
- IBUF / IBUFDS 负责完成 IO 电平与差分转换;
- IDELAYE3 用于补偿数据与时钟之间的相位偏差;
- ISERDESE3 是真正完成串并转换的核心节点;
- !!后级逻辑运行在稳定的
CLKDIV时钟域中。
可以认为,ISERDESE3 是 IO 物理世界与 FPGA 同步逻辑世界的分界点。
2.4.4 HOW
下面给出一个工程里常用的封装方式:输入为串行数据与高速采样时钟,输出为并行数据与有效标志。例程默认启用 FIFO,并在 CLKDIV 域内只要 FIFO 非空就持续读出,适合 ADC/AFE 这种连续数据流。
1 | module iserdes3_rx #( |
2.4.5 TIPS
- DATA_WIDTH 的选择
DATA_WIDTH 决定每个 CLKDIV 周期输出多少位数据:
- 4:适合中等速率接口;
- 8:适合更高速率、降低后级逻辑频率压力。
必须保证:
这是硬性约束,而非推荐条件。
- CLK 与 CLK_B 的使用技巧
ISERDESE3 内部基于 DDR 采样结构,理论上需要正反两相高速时钟。
工程中常见做法是:
- 物理上只接一根高速时钟;
- 通过
IS_CLK_B_INVERTED参数在原语内部完成反相。这样就不用通过PLL再生成新的反相时钟信号了。
这种方式更利于时钟树规划,也减少了额外布线与约束复杂度。
- FIFO_ENABLE 的工程意义
启用 FIFO 后,ISERDESE3 不再是“采样即输出”的结构,而是:
- 高速采样写入 FIFO;
- 低速逻辑按自身节奏读取。
这在以下场景中尤为重要:
- 高速采样域与系统逻辑域存在不可避免的相位漂移;
- 后级逻辑需要连续、稳定的数据流;
- 希望降低 CDC 风险。
一旦启用 FIFO,FIFO_EMPTY 就成为数据有效性的唯一依据。
- FIFO_RD_EN 的推荐策略
连续流式数据(如 ADC)中,最稳妥的方式是:
1 | FIFO_RD_EN = ~FIFO_EMPTY |
避免在 FIFO 为空时误读,同时保证最大吞吐。
若是突发或分帧数据,则需要额外的读控制逻辑,而不能直接使用该简化策略。
