这一篇在干嘛?

UG1211《DR1 系列 FPSoC Libraries Guide》前半部分的精华。原语(Primitive)是 FPGA 内部最底层的硬件单元,综合器平时会”悄悄”帮你推断,但涉及到 IO 时序、高速接口、存储器精细控制时,就必须手动例化。这一篇覆盖基础逻辑、IO 串并转换和存储三大族;时钟与 DSP 族见原语库:DR1(二)

原语是什么、怎么读这一族手册

布线与基础逻辑:BUF、BUFG、SEQ_DIV、SHIFTER、SLICE

IO 串并转换:IDDR / ODDR / x2 / x2I 全家桶

IO 辅助三件套:动态延迟、三态、IOBUF

存储三兄弟:DRAM、ERAM、FIFO/RAMFIFO

可靠性外设:ECC 校验与 DNA 芯片指纹

原语是什么、怎么读这一族手册

原语就是芯片厂留给你的”裸硬件接口”。写 Verilog 时你例化一个 DR1_LOGIC_BUFG,综合器不会把它优化掉,而是直接映射到芯片里真实的一个全局时钟缓冲单元。这和写 assign o = i; 让工具自己安排是完全不同的掌控级别。

UG1211 里每个原语都按固定五段式介绍:简介 → 端口描述 → 参数描述 → 使用方式 → Verilog 例化示例。读任何原语都建议按这个顺序扫一遍:

  1. 简介:一句话说清它是什么硬件。先看这句,判断”我要不要用它”。
  2. 端口描述:Name / Direction / Width / Function 四列表格。注意 Direction 里有 inout 的(如 IOTRIBUF 的 io)。
  3. 参数描述:Attribute / Allowed Values / Default / Descriptions。默认值往往就是你该用的值。
  4. 使用方式:这张表告诉你两种路径——“原语例化”所有原语都支持;“IP Generator”只有存储、PLL、ADC 等大块头支持。像 DR1_LOGIC_SEQ_DIVDR1_LOGIC_SHIFTER 这类,图形界面里是找不到的,只能手写例化。
  5. 例化示例:直接抄,改信号名即可。

常见坑:手册里的原语名以 DR1_ 开头,这是 DR1 系列专属前缀。不同系列(PH1A 的 PH1A_ 系列、PH1 系列各自不同)原语名不通用,从别的工程抄例化代码时先确认系列,否则综合直接报错。

布线与基础逻辑:BUF、BUFG、SEQ_DIV、SHIFTER、SLICE

BUF 与 BUFG:一根线的两种走法

DR1_LOGIC_BUF 是 PL 内部的低延时布线资源,就两个端口 i/o,没参数。它对应的是普通局部缓冲,适合短距离信号。

DR1_LOGIC_BUFG 则是高扇出全局时钟缓冲器,延时和抖动小,官方明确说它用于”时钟网络和其他高扇出的网路(如复位信号、时钟使能等)“,而且可以把普通信号走到 BUFG 上。一个复位信号要扇出到全片几万个触发器时,走普通布线会到处都是长路径,插一个 BUFG 让它走全局时钟树是标准操作:

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

DR1_LOGIC_BUFG 全局时钟缓冲:只有 i/o 两个端口

什么时候需要手动插 BUFG?大多数时候综合器会把”被当成时钟用的信号”自动放上全局网络;但复位、时钟使能这类非时钟的高扇出信号,以及内部逻辑生成的时钟(比如分频时钟),工具不一定猜得到你的意图,手动例化最保险。

SEQ_DIV:软件集成的软核除法器

DR1_LOGIC_SEQ_DIV 是一个多周期时序除法器,不占 DSP 资源,靠 LUT 一拍一拍算。它的握手协议要记牢:

端口方向位宽功能
clk / rstinput1时钟;复位(rst=1 时 quotient/remain 置 0,done 置 1)
startinput1start=1 时缓存输入;start 由 1 变 0 时开始计算
numer / denominputNUMER_WIDTH / DENOM_WIDTH被除数 / 除数
quotient / remainoutput同上商 / 余数,done=1 时才有效
doneoutput1计算完成标志

参数只有两个:NUMER_WIDTHDENOM_WIDTH,默认都是 16。注意它的使用方式表里 IP Generator 是”否”——只能在代码里例化。除法在 FPGA 里是出了名的慢操作,如果你的算法里只有零星几次除法(比如求平均值后归一化),用这个软核除法器省事;如果是每拍都要除的流水线,考虑改定点数或查表。

SHIFTER:可变深度移位寄存器

DR1_LOGIC_SHIFTER 是内部移位寄存器模块,本质是”SRL(移位查找表)“的官方封装。核心参数:

参数可选值默认说明
DATA_WIDTH>016数据位宽
DEPTH_WIDTH>12深度控制字位宽
SHIFT_TYPE”FIXED” / “VARIABLE""FIXED”固定深度 / 动态深度
DATA_DEPTH32FIXED 模式下的实际深度
INIT_FILE路径或 “NONE""NONE”预加载初始值文件

DR1_LOGIC_SHIFTER:datain 经 en 与 depth 控制移位后从 dataout 输出

两种模式要分清:

  • FIXED 模式:深度在编译期由 DATA_DEPTH 定死,depth 端口是无效信号(例化时接 {0{1'b0}})。
  • VARIABLE 模式:移位深度为 2**DEPTH_WIDTH 量级,depth 端口是运行时的真实深度控制字。手册的属性表给了换算公式:16 位宽时 shift_depth = depth[4:0] + 2(深度 233),8 位宽时 shift_depth = depth[5:0] + 2(深度 265)。

典型用途:视频行缓冲、延迟线匹配、串行协议里的对齐延迟。用 depth 动态可调这一点,写一个”可编程延迟线”就不用自己手搓寄存器链了。

SLICE:最底层的逻辑单元

DR1_LOGIC_SLICE 是内部 SLICE 模块的端口级封装:两个非独立的双 LUT5 + 两个独立 DFF,还带进位链(fci/fco)。除非你在做极度的手动面积/时序优化,一般不需要例化它——综合器对你写的组合/时序逻辑会自动映射到 SLICE。但它值得看,因为参数表就是一本”SLICE 能做什么”的说明书:LUTMODE 可选 “LUT6”/“DLUT5”(一个 SLICE 可以拼成 6 输入 LUT 或两个 5 输入 LUT)、LATCHMODE 可选 “DFF”/“LATCH”、进位链支持 ADDERMUX 配置,甚至 INIT_LUT5A/B 可以直接指定 LUT 的 32 位真值表。看到这里你就明白为什么”两个 LUT5 非独立”——某些输入是共享复用的(LUT5A_SD0 等参数就在选输入来源)。

IO 串并转换:IDDR / ODDR / x2 / x2I 全家桶

这一族解决同一个问题:芯片引脚上是 DDR(双沿)数据,内部逻辑只跑单沿时钟,中间必须有个转换器。FPGA 的 IO 单元里专门为此放了硬件。

IDDR / ODDR:1:2 与 2:1

DR1_LOGIC_IDDR:d 输入双沿采样,q0/q1 分别输出上升沿/下降沿数据

DR1_LOGIC_IDDR 把 IO 上的双沿采样数据变成两路单沿数据:d 在时钟上升沿的值走 q0,下降沿的值走 q1。参数两个:

  • ASYNCRST:“ENABLE”/“DISABLE”,控制 rst 是异步复位还是被忽略;
  • PIPEMODE:“PIPED”/“NONE”,q0/q1 的数据对齐模式,默认 “PIPED”(打一拍对齐后再出,时序更好)。

DR1_LOGIC_ODDR 反过来,把内部两路单沿数据 d0(上升沿)、d1(下降沿)合成一路 DDR 输出 q,只有 ASYNCRST 一个参数。输出 DDR 源同步接口(比如往 Camera 输出带时钟的数据)必用。

DR1_LOGIC_ODDR #(
    .ASYNCRST("ENABLE")
) u_LOGIC_ODDR (
    .q(q), .d1(d1), .d0(d0), .clk(clk), .rst(rst)
);

x2 / x2I:速度不够,串并来凑

DR1_LOGIC_IDDRx21:4 串转并单元:串行输入 d 被 sclk/pclk 两相时钟拆成 q0q3 四路并行输出。DR1_LOGIC_ODDRx2 则是 4:1 并转串:d0d3 四路并行按先低 bit 后高 bit 的顺序串行输出到 q。它们与 IDDR/ODDR 功能同源,但支持更高的 IO 速度——原因也很直觉:IO 触发器只跑半速率的 sclk,靠两相时钟交替采样,内部时序压力小一半。

DR1_LOGIC_IDDRx2:pclk/sclk 双时钟域把串行 d 拆成 q0~q3

时钟接法要特别注意端口表里的约定:pclk 频率为 sclk 的 1/2,sclk 为 1/2 数据率。也就是说 800 Mbps 的数据率对应 sclk=200MHz、pclk=100MHz,两个时钟必须严格同源同相,通常都从同一个 PLL 的不同输出通道拿。

x2I 是省时钟的变体DR1_LOGIC_IDDRx2I / DR1_LOGIC_ODDRx2I 与 x2 功能相同,但”直接使用内部 sclk 的 2 分频作为 pclk,节省 1 个 clk”——少占一个全局时钟资源,代价是少一个 pclk 端口(因此也少一次外部对齐的机会)。时钟资源紧张的高速设计优先考虑 x2I 版本。

常见坑:x2/x2I 的 rst 是 高有效复位,而很多同学的习惯是低有效 rst_n。直接把 rst_n 接上去会导致芯片一上电"永远处于复位",现象是 IO 数据全为初始值且不来数据。接反之前先看一眼端口表 Function 列。

IO 辅助三件套:动态延迟、三态、IOBUF

  • DR1_LOGIC_DYNAMIC_IDELAY:IO 输入端口上的动态延迟调节模块。端口 in_dly[4:0] 可设 0~31 级延迟,indly_en 拉高使能动态调节。源同步接口(如 LVDS 接收)里采样时钟和数据skew不匹配时,靠它微调数据眼图位置,比改 PCB 走线便宜得多。手册例化示例就是一行 .in_dly(5'd28)——28 级延迟。
  • DR1_LOGIC_IOTRIBUF三态 IO 控制模块t=0 时 io 输出 i,t=1 时 io 呈高阻(变输入,o 可以读回)。任何双向总线(如外挂 SRAM/并口 ADC 的数据线)都靠它。注意 1.1 版手册特别更新了三态控制信号的说明——t 的语义是”1 为高阻”,和某些厂家的 OE(输出使能)正好相反。
  • DR1_LOGIC_IOBUF输入输出控制模块,就 i/o 两个端口,是最简单的 IO 路径封装,通常在需要明确约束 IO 时序路径或手工控制 IO 单元行为时使用。

这三个原语都只支持原语例化,IP Generator 里没有。

存储三兄弟:DRAM、ERAM、FIFO/RAMFIFO

DRAM:分布式 RAM

DR1_LOGIC_DRAM内部的分布式 RAM 模块(用 LUT 资源实现),可配置为单口 RAM。它天生”写一口、读一口”分离(waddr/wclk/we 写口,raddr/rclk/rce/rdo 读口),小容量、深度浅的存储(系数表、小缓冲)用它最省 BRAM 资源。关键参数:

参数默认说明
DATA_WIDTH_W / ADDR_WIDTH_W8 / 6写侧位宽 / 地址位宽
DATA_WIDTH_R / ADDR_WIDTH_R8 / 6读侧位宽 / 地址位宽
INIT_FILE”NONE”预加载初始值文件(.mi)
FILL_ALL”NONE”未初始化空间填充(二进制串如 “0101”)
READREG”DISABLE”读寄存器使能(使能后 rdoq 多一拍)
RESETMODE”SYNC”读侧复位同步/异步

注意它有 rdo(组合读)和 rdoq(带寄存器读)两个输出口:READREG=“DISABLE” 时用 rdo,地址一给数据就出,适合”真单口”行为;ENABLE 时数据打一拍从 rdoq 出,时序更容易收敛。

ERAM:20K 大块头

DR1_LOGIC_ERAM 是内部 ERAM20K 资源,DR1 片上块 RAM 的正式名字。端口是完整的双口结构(A 口、B 口各自有 dia/addra/cea/ocea/clka/wea/rsta/bea 与 doa),参数表非常长,核心是这几个:

参数可选值说明
MODE”DP”/“SP”/“PDPW”/“FIFO”真双口 / 单口 / 简单双口(一写一读)/ FIFO 模式
DATA_WIDTH_A/B>0(默认 20)两口数据位宽,支持不对称位宽
WRITEMODE_A/B”NORMAL”/“READBEFOREWRITE”/“WRITETHROUGH”写操作时读口的行为
REGMODE_A/B”NOREG”/“OUTREG”输出寄存器模式
RESETMODE_A/B”SYNC”/“ASYNC”(默认 ASYNC)复位模式
ECC_ENCODE/DECODE”DISABLE”/“ENABLE”ECC 编解码
BYTE_ENABLE0, 8, 10字节使能位宽
IMPLEMENT”20K”实现物理单元选择

DR1_LOGIC_ERAM:A/B 双端口完整的地址、数据、使能与 ECC 信号

手册的时序图一节给了四种代表性时序:单口 Write-Before-Read、单口 Read-Before-Write、简单双口、真双口。WRITEMODE 决定”同一地址又读又写时读口看到什么”:NORMAL(读旧值不变)、READBEFOREWRITE(新旧穿透)、WRITETHROUGH(写数据立即穿透到读口)。做交换矩阵、深度缓冲时这是必须想清楚的行为差异。

常见坑:手册注 1 写明—— 当 ERAM 输出不带寄存器(NOREG)时,RESETMODE 只能选异步(ASYNC),不能选同步。选错了综合可能报错或行为不符。反之输出带寄存器(OUTREG)时同步/异步都可以。另记住:输出加寄存器后数据延迟一个时钟周期,和上游逻辑对拍时序时要算进去。

ECC 相关端口(ecc_sbiterr/ecc_dbiterr 输出标志,ecc_sbiterrinj/ecc_dbiterrinj 注错输入)平时不用接死值即可;使能双 bit 注错时两个注错信号要同时拉高

FIFO 与 RAMFIFO:硬件队列的两种做法

DR1_LOGIC_FIFO 是 FPGA 内部硬 FIFO 单元(吃 ERAM 资源),特征是大而快:DATA_WIDTH 1320 位、ADDR_WIDTH 914(深度 512~16K),带 empty/aempty/full/afull 四个标志(AE/AF 参数可设”几乎空/几乎满”阈值,默认 96),还输出读写指针 fifo_wrpointer/fifo_rdpointer。注意 csw/csr 两个 3 位片选必须接 3’b111——这是手册端口表里明说的硬性要求,忘了接 FIFO 就不工作。

DR1_LOGIC_RAMFIFO 则是软件集成的软核 FIFO 控制器,特征是功能灵活:支持实时深度指示(rdusedw/wrusedw 直接告诉你队列里有几个数)与 Showahead 模式(SHOWAHEAD=1 时数据先摆到 dout 上、re 只是确认消费,省一拍读延迟)。跨时钟域场景它的 CLKMODE(“SYNC”/“ASYNC”)配合读写双时钟使用。

选择原则:大吞吐、只关心空满标志 → 硬 FIFO;需要知道”队列里还剩多少数据”来做流量控制、或想要 Showahead 的零延迟读 → RAMFIFO。

可靠性外设:ECC 校验与 DNA 芯片指纹

DR1_LOGIC_ECC:给配置存储器做体检

DR1_LOGIC_ECC 是 DR1 系列 PL 侧的 ECC 单元,专门校验 Configuration Memory(配置帧)有没有被单粒子翻转打坏。它的使用模型是一套小握手:

  • 用户拉低 ecc_enable_n_i 并保持 → ECC 开始扫配置帧;
  • ecc_clk_o 是它自己的主时钟(内部晶振分频而来,DR1 上 2~11 MHz,由 ECC_FREQ 参数配置);
  • ecc_stop_o 默认高(停止态);主动停止后必须等 ecc_stop_o 变高才能重新发起
  • 校验到最后一个配置帧进入 global crc check 时 ecc_done_o 拉高;
  • ecc_info_o[37:0] 打包了出错现场:[37:15] 配置帧地址、[14:8] syndrome 对应帧内 81 个 DWORD、[7:3] 对应 DWORD 内 32 个 bit、[2] 单 bit 错、[1] 双 bit 错、[0] gcrc 错。

最有用的参数是 SEC_OPTION,四个模式决定发现单 bit 错误后怎么办:

SEC_OPTION行为
”CONTINUE”不处理,继续校验(gcrc 出错也不报)
“HOLD”停下来等人来
”CORRECT_AND_CONTINUE”修复该 bit 并回写 Configuration Memory,继续扫
”CORRECT_AND_HOLD”修复回写后停下,等重启

高可靠应用(长期上电不停机)选 CORRECT_AND_CONTINUE 定期扫描即可;ECCERR_REPORT_EN="ENABLE" 还能把 ECC 错误映射到 INITN 管脚电平上,外部 MCU 看一眼引脚就知道芯片健康状况。

DR1_LOGIC_DNA:读出 64 位芯片唯一 ID

DR1_LOGIC_DNA 是芯片唯一 DNA 模块,接口是个极简移位寄存器:dna_shift_n_i 低有效使能移位、dna_din_i 移入、dna_do_odna_clk_i 驱动下逐位移出 64 位 DNA。典型用法:做加密狗/授权校验,把 DNA 与板上 MCU 里存的密钥做哈希比对,防止 bit 文件被拷到别的板子上跑。手册还有配套时序图,注意 shift_n 拉低期间才移位。

通关标准:

  • 能不看手册例化 BUFG、IDDR、ODDR,并说出 PIPEMODE/ASYNCRST 各自控制什么。
  • 能根据容量和接口需求在 DRAM / ERAM / RAMFIFO 之间做出正确选型,并解释 WRITEMODE 三种行为的差别。
  • 看到 IO 数据”不来”能想起三件事:rst 是不是高有效、csw/csr 是否接了 3’b111、x2 系列的 pclk/sclk 频率关系对不对。