这一篇在干嘛?
你平时写的
always块、assign语句,最终都要落到 FPGA 芯片里真实的硬件上。而芯片里有些硬件——全局时钟网络、双沿采样触发器、块存储、硬件乘法器——靠普通写法很难(或没法保证)用上,这时就需要”点名”例化芯片厂商提供的现成模块,也就是原语(Primitive)。这篇笔记把安路 EAGLE 系列原语库文档里的 23 个原语按类别梳理一遍,重点讲每个类别最常用的几个:端口、参数、例化代码和坑。
原语是什么?和普通 Verilog 什么关系
打个比方:FPGA 是一盒乐高,你平时写 Verilog 相当于”我要一个能实现与或非逻辑的东西”,具体怎么拼由综合工具决定;而原语是盒子里预装好的成品组件——时钟树、乘法器、FIFO 控制器这些专用电路,你直接说”给我用这个”,名字和引脚都对上号即可。
两者的关系可以这么理解:
- 普通 Verilog:描述”行为”,综合器帮你映射到芯片资源。大多数逻辑这样写就够了。
- 原语例化:描述”我要用哪个具体硬件单元”,例化写法和调用普通模块一模一样——
模块名 #(.参数(...)) 实例名 (.端口(...));。
那什么时候才需要手搓原语?典型场景:
- 时钟与高扇出信号:时钟要进专用全局时钟网络(BUFG),复位、时钟使能这类扇出极大的信号也建议走全局缓冲;
- DDR 类接口:引脚上数据是双沿采样的,必须用 IO 里专用的 IDDR/ODDR 单元;
- 精确延时:输入/输出管脚上的纳秒级延时调整,普通逻辑做不了;
- 硬核资源:块 RAM、硬件乘法器、除法器,想确保用上硬核而不是被综合成逻辑门,就显式例化;
- 芯片特殊功能:多重启动、读取芯片 64 位 DNA、配置时钟频率等,只有原语能碰。
原语不可移植
原语名是跟着厂商和器件系列走的。本篇所有原语都以
EG_LOGIC_/EG_PHY_开头,是安路 EAGLE 系列专属命名,搬到 Xilinx 或 Intel 的芯片上编译必报错。反过来,别人的代码里出现 Xilinx 原语(如 BUFG、IDDR 原语名不同),移植到安路器件时也要对照本系列文档改名。
能用 IP 生成器就别手敲
文档里每个原语都有”使用方式”表,标明是否支持原语例化和 IP Generator(图形界面配置生成)两种途径。像 BRAM、FIFO 这类参数一大堆的原语,用 IP Generator 点选配置更不容易出错;只有 IP Generator 不支持的原语(如 BUFGMUX、MBOOT、MULT)才必须手写例化。
全家福:23 个原语速查总表
先上总表建立全局观,后面按类别精讲。名称一律以文档为准:
| 类别 | 原语名 | 用途一句话 |
|---|---|---|
| 时钟与布线 | EG_LOGIC_BUF | 芯片内部低延时布线资源 |
| 时钟与布线 | EG_LOGIC_BUFG | 高扇出全局时钟缓冲,延时抖动小 |
| 时钟与布线 | EG_LOGIC_BUFIO | IO 组内的时钟分频器,每组两个 |
| 时钟与布线 | EG_LOGIC_BUFGMUX | 全局时钟二选一选择器 |
| IO 类 | EG_LOGIC_IDELAY | 输入管脚延时控制(0~31 挡) |
| IO 类 | EG_LOGIC_ODELAY | 输出管脚延时控制(4 挡) |
| IO 类 | EG_LOGIC_IDDR | IO 双沿采样数据 → 内部单沿数据 |
| IO 类 | EG_LOGIC_ODDR | 内部单沿数据 → IO 双沿输出 |
| IO 类 | EG_LOGIC_IDDRx2 | IO 上 1:4 串转并(更高速) |
| IO 类 | EG_LOGIC_ODDRx2 | IO 内 4:1 并转串(更高速) |
| IO 类 | EG_LOGIC_ODDRx2I | 4:1 并转串,省一个 pclk 时钟 |
| 存储类 | EG_LOGIC_FIFO | 硬核 FIFO 控制器,支持同步/异步/混合端口 |
| 存储类 | EG_LOGIC_RAMFIFO | 软核 FIFO 控制器,多深度指示与 Showahead 模式 |
| 存储类 | EG_LOGIC_DRAM | 分布式 RAM,可配单口/单双口 |
| 存储类 | EG_LOGIC_DRAM16X4 | 16×4 分布式 RAM 基本单元 |
| 存储类 | EG_LOGIC_BRAM | BRAM9K/BRAM32K 块存储资源 |
| 运算类 | EG_LOGIC_MULT | 18×18 硬件乘法器 |
| 运算类 | EG_LOGIC_CLOCKED_DIV | 内部除法器(start/done 握手) |
| 配置与特殊 | EG_LOGIC_MBOOT | 多重启动控制模块 |
| 配置与特殊 | EG_LOGIC_DNA | 64 位芯片 DNA 信息读取接口 |
| 配置与特殊 | EG_LOGIC_CCLK | 配置时钟频率控制 |
| 底层逻辑单元 | EG_PHY_LSLICE | 底层 SLICE:2 个增强 LUT5 + 2 寄存器 + 4 级进位链 |
| 底层逻辑单元 | EG_PHY_MSLICE | 底层 SLICE:2 个 LUT4 + 2 寄存器 + 2 级进位链 |
子模块别乱例化
文档特别注明:
gray2bin、gray_count、showahead_buffer是 RAMFIFO 的内部子模块,不建议用户直接例化。
时钟类:BUFG 与 BUFGMUX
BUFG:把信号送上全局时钟网络
BUFG 是高扇出的全局时钟缓冲器,延时和抖动都小。除了时钟,复位信号、时钟使能这类要”撒满全片”的高扇出网络也应该走它。端口极简:一个进 i、一个出 o,没有参数。
EG_LOGIC_BUFG BUFG_inst(
.o(o),
.i(I)
);BUFGMUX:两路时钟二选一
BUFGMUX 是全局时钟缓冲选择器:选择信号 s 为低时输出 i0,为高时输出 i1。典型的用处是”跑慢时钟省电、跑快时钟干活”的场景下切换系统时钟。

它有三个参数:INIT_OUT 设置输出初始化值(默认 “0”);PRESELECT_I0 / PRESELECT_I1 设置上电后预先选择哪一路(默认选 i0)。
EG_LOGIC_BUFGMUX #(
.INIT_OUT ("0"),
.PRESELECT_I0 ("TRUE"),
.PRESELECT_I1 ("FALSE"))
BUFGMUX_inst(
.o(o),
.i0(i0),
.i1(i1),
.s(s)
);BUFIO:IO 组里的分频器
BUFIO 是 IO 上的时钟分频器,每个 I/O 组有两个。注意它的三路输出性质不同:clko 输出与输入同频,但只能供 IO 使用;clkdiv1 和 clkdivx(x=1,2,4 分频)才能供全局时钟网使用。参数有 DIV(分频系数 2 或 4)、GSR(全局复位,默认 DISABLE)、STOPCLK(时钟关闭,默认 DISABLE)。
BUFIO 的输出别接错
clko只能在 IO 局部用,想把它接进全局时钟网络是行不通的;要进全局网就接clkdiv1/clkdivx。
IO 类:DDR 采样与管脚延时
先搞懂 DDR 单元在干嘛
引脚上的高速接口(比如摄像头、高速 ADC)常用双沿采样:一个时钟的上升沿和下降沿各传一位数据。而 FPGA 内部逻辑几乎都是单沿工作,所以需要专门的硬件做”翻译”——进芯片用 IDDR(1 位双沿 → 2 位单沿 q0/q1),出芯片用 ODDR(2 位单沿 d0/d1 → 1 位双沿输出)。
IDDR 的参数:ASYNCRST(默认 “ENABLE”,异步复位使能)和 PIPEMODE(“PIPED”/“NONE”,控制 q0、q1 的数据对齐模式,默认 “PIPED”)。
EG_LOGIC_IDDR #(
.ASYNCRST("ENABLE"),
.PIPEMODE("PIPED"))
IDDR_inst(
.q1(q1),
.q0(q0),
.clk(clk),
.d(d),
.rst(rst)
);ODDR 同样只有一个 ASYNCRST 参数(默认 “ENABLE”):
EG_LOGIC_ODDR #(
.ASYNCRST("ENABLE"))
ODDR_inst(
.q(q),
.d1(d1),
.d0(d0),
.clk(clk),
.rst(rst)
);IDDRx2 / ODDRx2:更高速的 1:4 与 4:1
EG_LOGIC_IDDRx2 是 IO 上的 1:4 串转并单元,功能与 IDDR 相同但支持更高的 IO 速度:串行输入 d 变成 4 位并行输出 q0~q3。它需要两个时钟:sclk 是 1/2 数据率的时钟,pclk 是 sclk 的 1/2(即 1/4 数据率)。
反方向,EG_LOGIC_ODDRx2 是 4:1 并转串:4 位并行数据 d0~d3 压成 1 位串行输出 q,同样用 pclk(1/2 sclk)和 sclk(1/2 数据率)双时钟。
EG_LOGIC_ODDRx2 #(
.ASYNCRST("ENABLE"))
ODDRx2_inst(
.q(q),
.pclk(pclk),
.sclk(sclk),
.d3(d3),
.d2(d2),
.d1(d1),
.d0(d0),
.rst(rst)
);EG_LOGIC_ODDRx2I 是 ODDRx2 的省时钟版本:直接用内部 sclk 的 2 分频充当 pclk,省掉一个时钟输入;代价是数据输出比 ODDRx2 模式晚一个 sclk 时钟周期。
时钟关系别配错
用 x2 系列原语时记牢:
sclk= 1/2 数据率,pclk= 1/2 sclk。pclk 接成了 sclk 同频,输出数据就会错位。用 ODDRx2I 时则根本没有 pclk 端口,别照着 ODDRx2 的模板连。
IDELAY / ODELAY:纳秒级延时微调
IDELAY 是输入延时控制单元,参数 INDEL 取 0~31,初始化延时 0.2ns,最大延时 3.8ns;ODELAY 是输出延时单元,参数 OUTDEL 只有 4 挡可调。两者端口都只有 i 进 o 出。
新版软件可以不例化
使用 4.2.266 及以后版本的软件,IDELAY/ODELAY 都不用再手动调用,直接在 IO CONSTRAINT 图形界面里设置延时长度即可,更省事。
存储类:FIFO 与 RAM
硬核 FIFO:EG_LOGIC_FIFO
这是 EAGLE 的 FIFO 控制器模块,支持同步/异步以及混合端口(读写位宽不同)的工作模式。核心端口:写侧 clkw/we/di/csw,读侧 clkr/re/do/csr/ore,外加四个状态标志——empty_flag(读空,与 clkr 同步)、aempty_flag(几乎空,可设阈值)、full_flag(写满,与 clkw 同步)、afull_flag(几乎满,可设阈值)。

参数不少,抓住这几组:DATA_WIDTH_W/R 与 DATA_DEPTH_W/R 定位宽和深度(深度可选 512~8192);E/AE/AF/F 四个值分别设定空、快空、快满、满标志的深度阈值;RESETMODE(“ASYNC”/“SYNC”)与 ASYNC_RESET_RELEASE 控制复位行为;ENDIAN 控制混合端口模式下大小端对齐;REGMODE_W/R 可选输出加一级寄存器(“OUTREG”)。
EG_LOGIC_FIFO #(
.DATA_WIDTH_W(9),
.DATA_DEPTH_W(1024),
.MODE("FIFO8K"),
.REGMODE_W("NOREG"),
.REGMODE_R("NOREG"),
.GSR("ENABLE"),
.RESETMODE("ASYNC"),
.ASYNC_RESET_RELEASE("SYNC"))
FIFO_inst(
.rst(rst),
.di(di),
.clkw(clkw),
.we(we),
.csw(csw),
.do(do),
.clkr(clkr),
.re(re),
.csr(csr),
.ore(ore),
.empty_flag(empty_flag),
.aempty_flag(aempty_flag),
.full_flag(full_flag),
.afull_flag(afull_flag)
);软核版 EG_LOGIC_RAMFIFO 是 TD 软件集成的 FIFO 控制器,比硬核版多了实时深度指示(rdusedw 可读个数 / wrusedw 已写个数)和 Showahead 模式(SHOWAHEAD 置 1 时数据先摆到输出口、读使能来了就算读完,省一拍)。参数 DATA_WIDTH 范围 1432,15。ADDR_WIDTH 范围 2
DRAM 与 BRAM:小存储用分布式,大存储用块
EG_LOGIC_DRAM:分布式 RAM 例化模块,可配置为单口、单双口 RAM。参数含读写各自的位宽/地址宽度/深度,以及INIT_FILE初始化文件。EG_LOGIC_DRAM16X4:分布式 RAM 的基本单元(16 深 × 4 位宽),支持INIT_D0~D3四组初始化数据。要自己拼大容量时以它为砖头。
EG_LOGIC_DRAM16X4 #(
.INIT_D0(16'h0000),
.INIT_D1(16'h0000),
.INIT_D2(16'h0000),
.INIT_D3(16'h0000))
DRAM16X4_inst(
.di(di),
.waddr(waddr),
.we(we),
.wclk(wclk),
.raddr(raddr),
.do(do)
);EG_LOGIC_BRAM:由 BRAM9K 或 BRAM32K 搭建的块存储,是三种里面容量最大的。关键参数MODE决定工作形态:DP(真双口)、SP(单口)、PDPW(伪双口)、FIFO。其他常用参数:WRITEMODE_A/B(“NORMAL”/“READBEFOREWRITE”/“WRITETHROUGH”,写数据时读出口的行为)、REGMODE_A/B(输出是否加寄存器)、INIT_FILE(初始化文件路径)、IMPLEMENT(选 “9K”、“9K(FAST)” 或 “32K” 物理单元)。

BRAM 的 A/B 两口端口完全对称:dia/addra/cea/ocea/clka/wea/rsta/bea 对应 A 口写数据、写地址、片选、输出使能、时钟、写使能、复位、字节使能,B 口 dib~dob 同理;doa/dob 是各自口的读出数据。端口太多,例化建议直接走 IP Generator。
存储选型经验
几十字节到几百 bit 的小缓冲用 DRAM(省块存储);跨时钟域的数据缓存用 FIFO;帧缓存、大表项用 BRAM。别拿 BRAM 存几个数——块存储是稀缺资源。
运算类:硬件乘法器与除法器
MULT:18×18 硬件乘法器
EG_LOGIC_MULT 是芯片里的 18×18 硬件乘法器,输出 36 位。它自带三级流水寄存器:INPUTREGA、INPUTREGB(A/B 口输入寄存器)和 OUTPUTREG(乘积输出寄存器),默认都是 “ENABLE”,相当于帮你免费打了两拍,时序好跑得多。

注意它的复位是低有效且 A/B/输出三路独立:rstan、rstbn、rstpdn;片选 cea/ceb/cepd 也是三路独立、高有效。两个关键参数:INPUTFORMAT 选 “SIGNED”(默认)或 “UNSIGNED”;IMPLEMENT 选 “AUTO”/“DSP”/“GATE”——想强制走 DSP 硬核就填 “DSP”,“GATE” 则是用逻辑门搭(一般不选)。
EG_LOGIC_MULT #(
.INPUT_WIDTH_A(18),
.INPUT_WIDTH_B(18),
.OUTPUT_WIDTH(36),
.INPUTFORMAT("SIGNED"),
.INPUTREGA("ENABLE"),
.INPUTREGB("ENABLE"),
.OUTPUTREG("ENABLE"),
.SRMODE("ASYNC"),
.IMPLEMENT("AUTO"))
MULT_inst(
.p(p),
.a(a),
.b(b),
.cea(cea),
.ceb(ceb),
.cepd(cepd),
.clk(clk),
.rstan(rstan),
.rstbn(rstbn),
.rstpdn(rstpdn)
);乘法器复位是低有效
rstan/rstbn/rstpdn 三个复位都是低有效(名字里的 n 就是取反的意思),和高有效的 cea/ceb/cepd 片选极性正好相反,接反了乘法器会一直处于复位状态输出不动。
CLOCKED_DIV:要握手的除法器
EG_LOGIC_CLOCKED_DIV 是内部除法器,与乘法器最大的不同是它多周期计算:拉高 start 启动,等 done 拉高才能取结果 quotient(商)和 remain(余数)。参数 NUMER_WIDTH、DENOM_WIDTH 默认都是 16。

EG_LOGIC_CLOCKED_DIV #(
.NUMER_WIDTH(16),
.DENOM_WIDTH(16))
CLOCKED_DIV_inst(
.clk(clk),
.rst(rst),
.start(start),
.numer(numer),
.denom(denom),
.quotient(quotient),
.remain(remain),
.done(done)
);除法别写在 always 里
直接在组合逻辑里写
/运算符,综合出来又大又慢;用这个原语配合 start/done 握手状态机,才是除法的正确打开方式。使用时注意文档端口表中 numer 为除数、denom 为被除数,与日常”被除数在前”的习惯相反,接反了商和余数就全错了。
配置与底层:MBOOT、DNA、CCLK 和 SLICE
MBOOT:多重启动
EG_LOGIC_MBOOT 是多重启动控制模块,让 FPGA 固件损坏后能从备用镜像启动。启动地址有两种来源:参数 ADDR_SOURCE_SEL 选 “STATIC”(用参数 STATIC_ADDR 指定的静态地址,默认 8’b0)或 “DYNAMIC”(用端口 dynamic_addr 输入的 8 位地址)。这 8 位地址是 SPI Flash 地址的高 8 位。重启靠端口 rebootn(低有效)。
EG_LOGIC_MBOOT #(
.ADDR_SOURCE_SEL("STATIC"),
.STATIC_ADDR(8'b00000000))
MBOOT_inst (
.rebootn(reboot_n),
.dynamic_addr(addr)
);DNA:芯片的身份证
EG_LOGIC_DNA 用于读取芯片唯一的 64 位 DNA 信息(可做防抄板、设备序列号)。移位读取式接口:拉高 shift_en,在 clk 节拍下从 dout 一位移出,LSB 优先;din 是用户数据输入。
CCLK:配置时钟
EG_LOGIC_CCLK 控制配置时钟频率,参数 FREQ 只能填 “4.5”、“6.5”、“10.0”、“30.0” 四个字符串(单位 MHz,默认 “4.5”),端口只有使能 en 和输出 cclk。
LSLICE / MSLICE:看得见但平时别碰
EG_PHY_LSLICE(2 个增强 LUT5 + 2 寄存器 + 4 级进位链)和 EG_PHY_MSLICE(2 个 LUT4 + 2 寄存器 + 2 级进位链)是芯片最底层的逻辑单元,参数多到眼花(LUT 初始化值、各种 MUX 选择、DFFMODE 等),文档里给了配置成 LUT5/LUT6/LUT4 的例化示例。日常写逻辑时这些全由综合器自动管理,竞赛和一般开发中不需要手动例化,知道它们的存在即可。
最佳实践清单
- 时钟和全局信号上 BUFG,双沿接口用 IDDR/ODDR,x2 系列记得核对 pclk 与 sclk 的分频关系
- 参数繁多的原语(BRAM、FIFO)优先用 IP Generator 生成,再对照文档检查端口
- 复位极性逐个确认:MULT 是低有效,FIFO/IDDR/ODDR 的 rst 是高有效,MBOOT 的 rebootn 是低有效
- 例化后跑一遍综合,对照文档端口表核对每个端口位宽,别信编译器帮你猜
自测
- BUFGMUX 的选择信号 s 为高电平时,输出的是哪一路时钟?(答案:s 为高选 i1,为低选 i0;上电默认输出哪路由 PRESELECT_I0/I1 参数决定。)
- 需要把引脚上 4 倍数据率的串行数据收进来变成 4 位并行数据,应该用哪个原语?它需要哪两个时钟、频率各是多少?(答案:EG_LOGIC_IDDRx2;sclk 为 1/2 数据率,pclk 为 sclk 的 1/2 即 1/4 数据率。)