这一篇在干嘛?

UG710 第 29、2228 章收录了一批”和时钟、IO 打交道”的原语。这一篇按功能族把它们串起来:先是布线缓冲(BUF/BUFG),然后是 IO 上的串并转换家族(IDDR/ODDR 及 x2 高速版)、输入延迟微调(DYNAMIC_IDELAY),最后是时钟网络原语(LCLK/GCLK/MLCLK/SCLK/IOCLK/OSCDIV)和锁相环 PLL。存储与运算类原语见第 2 篇

原语是什么,为什么要在 RTL 里手动例化

布线缓冲:BUF 与 BUFG

IO 串并转换:IDDR 与 ODDR

高速版 1:4 与 4:1:IDDRx2 / IDDRx2l / ODDRx2 / ODDRx2l

输入延迟微调:PH1_LOGIC_DYNAMIC_IDELAY

IO 时钟分频:PH1_PHY_LCLK

全局时钟切换:PH1_PHY_GCLK

区域时钟网络:MLCLK、SCLK、IOCLK 与内部振荡器 OSCDIV

锁相环:PH1_PHY_PLL

原语是什么,为什么要在 RTL 里手动例化

“原语”(Primitive)是 FPGA厂商提供的底层硬件模块的 Verilog 名字。你平时写的 always @(posedge clk) 会被综合器自动映射到 LUT、DFF 这些资源上,但有些专用硬件——全局时钟缓冲、DDR 接口、块存储、硬核乘法器、PLL——综合器猜不出你想用它们,或者你想精确控制用法,这时就要手动例化对应原语。

UG710 里每个原语的章节结构都一样:简介 → 端口描述 → 参数描述 → 使用方式 → Verilog 例化示例。读手册时抓住三个要点就够了:

  1. 端口表:哪些信号必须接、接什么值(有些端口是”必须接固定值”的保留端口,比如某些片选要接 3'b111)。
  2. 参数表: Allowed Values 一列决定了你能不能配出想要的行为。
  3. 使用方式表:是否同时支持”原语例化”和”IP Generator”。支持 IP Generator 的(如 FIFO、ERAM、PLL)优先用图形化 IP 配置工具生成,更不容易出错;只支持原语例化的(如 BUFG、SLICE、GCLK)就必须手写例化。

常见坑:

手册中的例化示例是 OCR/排版后可能丢逗号、丢右括号的”示意代码”,直接复制进工程经常编译不过。正确姿势是:参考它的端口名和参数名,自己按 Verilog 语法重新敲一遍,端口连接不全的必须显式补齐(不用的输出接 open,不用的输入接固定值)。

布线缓冲:BUF 与 BUFG

这两个原语是最简单的”一进一出”,区别在于走的是哪种布线资源:

原语端口作用IP Generator
PH1_LOGIC_BUFi → oFPGA 内部的低延时布线资源不支持
PH1_LOGIC_BUFGi → o高扇出全局缓冲,延时和抖动小不支持

BUFG 是本篇最重要的一个”小原语”。它不只是给时钟用的——手册明确说常用于”时钟网络和其他高扇出的网路(如复位信号、时钟使能等)“,而且可以把普通信号走线到 BUFG 上。

BUFG:高扇出全局时钟缓冲器一根信号要驱动全芯片成千上万个触发器时(典型:全局复位、全局 clock enable),如果走普通布线,到达不同触发器的延时差异(skew)会大到直接吃掉你的时序裕量;上 BUFG 之后走专用全局长线,skew 极小。

例化示例:

PH1_LOGIC_BUFG u_LOGIC_BUFG (
    .o(o),
    .i(i)
);

什么时候用哪个:时钟信号 → BUFG(时钟输入管脚通常在 IO 约束里已经自动接 BUFG,内部再 fanout 的时钟分支才需要手动例化);高扇出复位/使能 → BUFG;只是想给一根普通信号”标记”低延时路径 → BUF。

IO 串并转换:IDDR 与 ODDR

DDR(Double Data Rate)接口在时钟的上升沿和下降沿都传数据,而 FPGA 内部逻辑只在单沿工作。IDDR/ODDR 就是 IO 环节上的”变速齿轮”,一对原语分别解决收和发:

IDDR:IO 上双沿采样数据转单沿数据

PH1_LOGIC_IDDR(收方向,1 位 DDR → 2 位单沿):

端口方向功能
clkinput采样时钟
dinputIO 上输入的 DDR 数据
rstinput复位,高有效
q0output上升沿数据输出
q1output下降沿数据输出

参数只有两个:ASYNCRST(“ENABLE”/“DISABLE”,复位使能,默认 ENABLE)和 PIPEMODE(“PIPED”/“NONE”,q0/q1 数据对齐模式,默认 PIPED)。

PH1_LOGIC_IDDR #(
    .ASYNCRST("ENABLE"),
    .PIPEMODE("PIPED"))
u_LOGIC_IDDR (
    .q1(q1), .q0(q0),
    .clk(clk), .d(d), .rst(rst)
);

ODDR:内部单沿数据转双沿输出到 IO

PH1_LOGIC_ODDR(发方向,2 位单沿 → 1 位 DDR):

端口方向功能
clkinput同步时钟
rstinput复位,高有效
d0input上升沿输入数据
d1input下降沿输入数据
qoutputDDR 双沿输出数据

参数只有 ASYNCRST。例化时注意端口顺序按手册写全,别漏 rst

为什么不用普通 Verilog 写双沿逻辑?因为 always @(posedge clk or negedge clk) 这种写法综合器不支持/不建议,双沿采样必须靠 IO 单元里专门的 DFF 硬件(IDDR/ODDR)实现,这就是原语存在的意义。

高速版 1:4 与 4:1:IDDRx2 / IDDRx2l / ODDRx2 / ODDRx2l

IDDR/ODDR 一次只处理 1 位 DDR 数据;当接口速率更高时,用 x2 系列一次转换 4 bit:

  • PH1_LOGIC_IDDRx2:IO 上的 1:4 串转并单元。串行输入 d,输出 q0~q3;时钟两个:sclk(1/2 数据率)和 pclk(1/2 sclk)。
  • PH1_LOGIC_IDDRx2l:功能同 IDDRx2,但内部直接用 sclk 的 2 分频当 pclk,省掉一个时钟;代价是数据输出比 IDDRx2 晚一个 sclk 周期。
  • PH1_LOGIC_ODDRx2:4:1 并转串。并行输入 d0~d3,串行输出 q,同样要 sclk + pclk 两个时钟。
  • PH1_LOGIC_ODDRx2l:同 ODDRx2,内部自分频省一个 clk,输出晚一拍。

IDDRx2:1:4 串转并单元

ODDRx2:4:1 并转串单元

以 IDDRx2 为例的例化:

PH1_LOGIC_IDDRx2 #(
    .ASYNCRST("ENABLE"))
u_LOGIC_IDDRx2 (
    .q3(q3), .q2(q2), .q1(q1), .q0(q0),
    .pclk(pclk), .sclk(sclk),
    .d(d), .rst(rst)
);

选型逻辑一句话:速率不够 IDDR 用 x2;布线紧张、想省一个 pclk 时钟网络用 x2l(接受晚一拍)。四个原语的参数都只有 ASYNCRST,且都同时支持原语例化和 IP Generator。

输入延迟微调:PH1_LOGIC_DYNAMIC_IDELAY

源同步接口(数据与时钟一起从外部芯片送来)布线后各数据线到达时间不一致,需要逐位微调采样点。PH1_LOGIC_DYNAMIC_IDELAY 是 IO 输入端口上的动态延迟调节模块

端口方向位宽功能
iinput1信号输入
indly_eninput1动态调节使能,高有效
in_dlyinput5延迟设置,可设 0~31
ooutput1相位调节输出
PH1_LOGIC_DYNAMIC_IDELAY DYNAMIC_IDELAY_inst (
    .i(i),
    .indly_en(1'b1),
    .in_dly(5'd28),
    .o(o)
);

两个注意点:一是它只支持原语例化,没有 IP Generator;二是手册强调具体哪些 IO 引脚具备动态调节能力要查《DS700_PH1A100_Datasheet》,不是任意管脚都能用。

IO 时钟分频:PH1_PHY_LCLK

LCLK 是 IO 上的一种外部时钟分频器,每个 IO 分组有两个,分频输出 clkdivout 可以供全局时钟网使用,驱动逻辑资源和 IP 模块。

LCLK:IO 分组内的时钟分频器

端口功能
clkin / clkout输入时钟 / 输出时钟
clkdivout分频后的输出(1~8 分频)
rst / ce复位(高有效)/ 使能(高有效)

关键参数:

参数可选值说明
DIV1~8分频系数
LCLK”BYPASS”/“DIV2T08”/“DIV1”/“GND”clkout 输出模式:直通 / 输出 clkdivout / 50% 占空比同频 / 输出低电平
CEMD”SYNC”/“ASYNC”SYNC 时 ce 延迟 4 个时钟周期进入内部 DFF
CLKSEL”ORG”/“INV”输入时钟是否取反

常见坑:

手册注释明确:如果希望 clkout 与分频输出一致,DIV=1 时 LCLK 必须选 “DIV1”(BYPASS 模式只是直通原时钟,不保证 50% 占空比),DIV=2~8 时必须选 “DIV2TO8”。模式选错,输出时钟占空比或频率就和预期对不上。

全局时钟切换:PH1_PHY_GCLK

需要在两路时钟之间切换(如主时钟坏了切备时钟)时,直接用 LUT 组合逻辑 mux 会产生毛刺,毛刺进时钟网络下游全乱。GCLK 是带无毛刺切换能力的全局时钟缓冲选择器:

GCLK:两路时钟的无毛刺选择器

端口位宽功能
clkin2两路时钟输入
seln2时钟选择,低有效
cen2寄存器时钟使能,低有效
drct2无毛刺切换使能:2'b00 无毛刺;2'b11 普通模式(可能毛刺)
clkout1切换输出

真值表(核心几行):

cen[0]seln[0]cen[1]seln[1]clkout
001Xclkin[0]
1X00clkin[1]
0000保持前一状态

参数:PRESELECT(“CLK0”/“CLK1”,初始输出选择)、HOLD(“YES”/“NO”,保持时输出高/低电平)、SEL_TRIGGER(“POS”/“NEG”,采样上升/下降沿)。

常见坑:

手册注释有三条硬约束:drct=2'b00(无毛刺模式)时 clkin 若是电平信号模块无法工作;drct=2'b11 时 seln 若为 2'b00 输出未知;无毛刺模式下”保持前一状态”指的是有效输入那一路的状态。用之前先确认你的输入是真时钟而不是电平。

区域时钟网络:MLCLK、SCLK、IOCLK 与内部振荡器 OSCDIV

PH1A100 的时钟网络是分层的,四个”搬运工”原语各管一段:

  • PH1_PHY_MLCLK:多区域时钟模块。输入是本地全局时钟输入管脚或本地 PLL 输出,能把时钟送到上下相邻两个时钟区域,也能输出到 IOCLK、LCLK。
  • PH1_PHY_SCLK:全局时钟 GCLK 的分支时钟,内部逻辑资源和 IP 模块都可以由它驱动。参数 GSR(全局复位使能,默认 ENABLE)和 BYPASS(默认 DISABLE)。
  • PH1_PHY_IOCLK:每个时钟区域 2 个,驱动 IO 列内独立于全局时钟资源的时钟网络,专门支持 LVDS 接收这类高速 IO 串并转换;输入可以是本区域/相邻区域的 MLCLK、本区域 PLL 输出或区域全局时钟输入管脚。
  • PH1_PHY_OSCDIV:芯片内部自带一个 OSC 振荡器,OSCDIV 把它分频后输出,不依赖任何外部时钟就能给逻辑提供时钟,非常适合上电初始化、看门狗这类”没有外部时钟也要活”的电路。参数 DIV(1~128 分频,默认 128)、EXT_RSTN;端口 rstn(低有效)、stdby(1 暂停输出 / 0 正常输出)。
PH1_PHY_OSCDIV #(
    .DIV(128),
    .EXT_RSTN("SIG"))
u_PHY_OSCDIV (
    .rstn(rstn),
    .stdby(stdby),
    .osc_clk(osc_clk)
);

这四个原语都只支持原语例化。绝大多数情况下综合器会自动插这些缓冲,你需要手动例化的场景是:想把某路时钟精确地”导”到某个区域(MLCLK/IOCLK),或者需要在无外部时钟条件下运行逻辑(OSCDIV)。

锁相环:PH1_PHY_PLL

PLL 是整个原语库里端口和参数最多的一个(端口 30+,参数 60+),负责从参考时钟合成出频率、占空比、相位都可调的输出时钟,共 8 路输出 clkc[7:0](最高位保留)、另有反向输出 clkcb

PLL:锁相环结构与时钟输出通道

常用端口速查:

端口方向功能
refclk / refclk_rstinput参考时钟输入 / 复位
pllresetinputPLL 复位,高有效
clkcoutput, 8时钟输出(bit7 保留)
lockoutput锁定指示,高有效
clkc_eninput, 8各路输出使能
pllpdinput电源开关,高电平关断 PLL
psclk / psclksel / psstep / psdown / psdoneinout动态相位调整接口
drp_clk / drp_sel / drp_wr / drp_rd / drp_addr / drp_wdata / drp_rdata / drp_rdy / drp_errinout动态重配置(DRP)接口
ssc_eninput展频使能

参数里最常打交道的几个:

参数说明
WORK_MODE”USER”/“WAKE_UP”,启动方式
PLL_FEED_TYPE”INTERNAL”/“EXTERNAL”,内部/外部反馈
REFCLK_DIV / FBCLK_DIV / CLKCx_DIV输入分频、反馈分频、各输出分频(1~128)
CLKCx_DUTY50 / CLKCx_DUTY_INT50% 占空比使能 / 精细占空比参数
FRAC_ENABLE / SDM_FRAC小数分频使能与系数(0~4095)
CLKC0~6_ENABLE各输出通道使能
SSC_ENABLE / SSC_MODE展频使能 / 模式(UP/DOWN/CENTER)
CLKCx_CPHASE / CLKCx_FPHASE各路粗调/细调相移

手册里有一句很反直觉的注释要记住:使用 PLL 时即使切断输入时钟,VCO 也无法完全关闭,会存在一个最低振荡频率,各通道仍有输出(频率由分频系数和芯片决定)。所以”关掉 PLL”不能靠断 refclk,要用 pllpd 电源关断。

使用方式上 PLL 同时支持原语例化和 IP Generator——强烈建议走 IP Generator:频率规划、带宽参数(LPF_RES/LPF_CAP/ICP_CUR/GMC_GAIN)由工具帮你算,手写这套 60 多个参数极易出错。

通关标准:

  • 能解释 BUFG 与 BUF 的区别,并说出两种”应该上 BUFG”的非时钟信号。
  • 能独立例化 IDDR(或 ODDR)并说明 q0/q1(或 d0/d1)与采样沿的对应关系。
  • 能说出 GCLK 无毛刺切换的条件(drct=2’b00 且输入为真时钟),以及 PLL”断输入时钟关不掉”的坑。