这一篇在干嘛?

第 1 篇解决了”时钟怎么走、DDR 数据怎么收发”,这一篇补齐 UG710 的另外三大功能族:存储(硬核 FIFO、软核 RAMFIFO、ERAM20K 块存储、分布式 DRAM、移位寄存器 SHIFTER)、运算(硬核乘法器 MULT 与 DSP 加法/逻辑/寄存器家族、软核除法器 SEQ_DIV),以及系统辅助(SLICE 底层积木、配置存储纠错 ECC、芯片唯一码 DNA、电压温度传感器 PVT、全局控制 GCTRL/TRSTN)。时钟与 IO 部分见第 1 篇

本篇导读:存储与运算资源怎么选

硬核 FIFO:PH1_LOGIC_FIFO

软核 FIFO:PH1_LOGIC_RAMFIFO

块存储:PH1_LOGIC_ERAM(ERAM20K)

分布式 RAM:PH1_LOGIC_DRAM

移位寄存器:PH1_LOGIC_SHIFTER

乘法器:PH1_LOGIC_MULT

DSP 家族:DSPADD、DSPLOGIC、DSPREG、DSPMREG、DSPTADD

软核除法器:PH1_LOGIC_SEQ_DIV

底层积木:PH1_LOGIC_SLICE

可靠性与身份:ECC、DNA、PVT

杂项控制信号:GCTRL 与 TRSTN

本篇导读:存储与运算资源怎么选

PH1A100 片上的存储和运算硬件不止一种,选型错了不是”性能差点”,而是根本综合不出来或资源爆掉。先给一张地图:

需求该用谁一句话理由
跨时钟域缓冲、位宽 1~320PH1_LOGIC_FIFO(硬核)双时钟域原生支持,带 ECC
跨时钟域 + 想知道”还剩多少数据”PH1_LOGIC_RAMFIFO(软核)额外支持实时深度指示与 Showahead
大容量存储(20K bit 为单位级联)PH1_LOGIC_ERAM单/伪双口/真双口/FIFO 四种模式
小容量、要很多份的存储PH1_LOGIC_DRAM用 LUT/CLB 资源实现的分布式 RAM
延迟线、行缓冲PH1_LOGIC_SHIFTER固定深度移位链
乘法PH1_LOGIC_MULT18x18→36 硬核乘法器
乘加/复杂运算流水的积木DSPADD/DSPLOGIC/DSPREG/DSPMREG/DSPTADDDSP 块内部各功能单元
除法(商+余数)PH1_LOGIC_SEQ_DIVTD 软核除法器,多拍完成

这些原语大部分同时支持原语例化和 IP Generator(FIFO/ERAM/DRAM/RAMFIFO/SHIFTER/SEQ_DIV/DSP 系列都是),只有 MULT、SLICE 等少数只支持手写例化。

硬核 FIFO:PH1_LOGIC_FIFO

PH1_LOGIC_FIFO 是片上硬 FIFO 单元,写口和读口各自独立(时钟、复位、使能、片选全套分离),天然适合跨时钟域。

FIFO:硬核先入先出单元

端口要点(完整表见 UG710 第 10.2 节):

端口方向功能
wrst / rrstinput写/读复位,高有效
clkw / clkrinput写/读时钟
di / doutinout写入 / 读出数据(DATA_WIDTH 位)
we / reinput写/读使能
csw / csrinput, 3片选,高有效,必须接 3’b111
ore / oweinput读出/写寄存器使能
empty_flag / full_flagoutput空/满标志
fifo_wrpointer / fifo_rdpointeroutput写/读指针
ecc_sbiterr / ecc_dbiterroutputECC 单/双 bit 错误标志

关键参数:

参数范围默认说明
DATA_WIDTH1~3209数据宽度
ADDR_WIDTH9~1410地址位宽(决定深度)
REGMODE_W / REGMODE_R”NOREG”/“OUTREG""NOREG”写/读寄存器
AE / AF0~2^1496快空/快满标志深度
CLKMODE”SYNC”/“ASYNC""SYNC”时钟模式
FIRSTWRITE_RDENABLE/DISABLEDISABLERead Ahead 使能
ECC_ENCODE / ECC_DECODEENABLE/DISABLEDISABLEECC 编解码
ASYNC_RESET_RELEASE”SYNC”/“ASYNC""SYNC”异步复位是否同步释放
GSRENABLE/DISABLEDISABLE全局复位使能
PH1_LOGIC_FIFO #(
    .DATA_WIDTH_W(9),
    .ADDR_WIDTH(10),
    .REGMODE_W("NOREG"),
    .REGMODE_R("NOREG"),
    .GSR("DISABLE"),
    .FIRSTWRITE_RD("DISABLE"),
    .AE(96),
    .AF(96),
    .ECC_DECODE("DISABLE"),
    .ECC_ENCODE("DISABLE"),
    .ASYNC_RESET_RELEASE("SYNC")
) u_LOGIC_FIFO (
    .rrst(rrst), .di(di), .clkw(clkw), .we(we), .csw(csw),
    .dout(dout), .clkr(clkr), .re(re), .csr(csr),
    .ore(ore), .owe(owe),
    .ecc_sbiterr(ecc_sbiterr), .ecc_dbiterr(ecc_dbiterr),
    .empty_flag(empty_flag), .full_flag(full_flag),
    .fifo_wrpointer(fifo_wrpointer), .fifo_rdpointer(fifo_rdpointer)
);

常见坑:

csw/csr 两个片选不是普通使能,手册写明必须接 3’b111,悬空或接别的值 FIFO 不工作。② 深度是 2^ADDR_WIDTH 而不是 ADDR_WIDTH 本身,ADDR_WIDTH=10 就是 1024 深。③ 跨时钟域用的时候 CLKMODE 必须配 “ASYNC”,默认值是 “SYNC”,用默认值跨时钟域指针比较会出错。

软核 FIFO:PH1_LOGIC_RAMFIFO

PH1_LOGIC_RAMFIFO 是 TD 集成的软核 FIFO 控制器(基于 ERAM20K 实现,IMPLEMENT 参数固定 “20K”)。与硬核 FIFO 相比,它额外支持两个好用的特性:实时深度指示(rdusedw/wrusedw 直接告诉你可读/已写数据个数)和 Showahead 模式(SHOWAHEAD=1 时数据先摆在 dout 上,读使能来了即”确认拿走”,省一拍读延迟)。

端口方向功能
rstinput异步复位,高有效
di / doutinout数据输入 / 输出(DATA_WIDTH 位)
clkinput时钟(注意:单时钟,读写共用)
we / reinput写/读使能
empty_flag / full_flagoutput空/满指示
rdusedw / wrusedwoutput可读数据个数 / 已写数据个数

参数只有 4 个:DATA_WIDTH(默认 8)、ADDR_WIDTH(默认 8)、SHOWAHEAD(0/1,默认 0)、IMPLEMENT(固定 “20K”)。

PH1_LOGIC_RAMFIFO #(
    .DATA_WIDTH(8),
    .ADDR_WIDTH(8),
    .SHOWAHEAD(1)
) u_logic_ramfifo (
    .rst(rst), .di(di), .we(we), .dout(dout),
    .clk(clk), .re(re),
    .empty_flag(empty_flag), .full_flag(full_flag),
    .rdusedw(rdusedw), .wrusedw(wrusedw)
);

和硬核 FIFO 的选择依据:要跨时钟域选硬核 PH1_LOGIC_FIFO(双时钟口);单时钟域但需要流量监控(按 rdusedw 做反压/整形)或 Showahead 快速读,选软核 RAMFIFO。

块存储:PH1_LOGIC_ERAM(ERAM20K)

PH1_LOGIC_ERAM 对应片上 ERAM20K 资源,是容量最大的存储原语。通过 MODE 参数支持四种工作模式:“DP”(真双口)、“SP”(单口)、“PDPW”(简单双口,一口写一口读)、“FIFO”。A/B 两个口各有独立的时钟、使能、字节使能、复位和输出寄存器配置。

ERAM:20K 块存储,双口结构

端口骨架(每口一组):dia/addra/cea/ocea/clka/wea/rsta/bea/doa(A 口),dib/addrb/.../dob(B 口),另有 ecc_sbiterr/ecc_dbiterr。参数重点:

参数说明
DATA_WIDTH_A/B、ADDR_WIDTH_A/B各口数据/地址位宽,深度 = 2^ADDR_WIDTH
MODE”DP”/“SP”/“PDPW”/“FIFO”,默认 “DP”
REGMODE_A/B”NOREG”/“OUTREG” 输出寄存器
WRITEMODE_A/B”NORMAL”/“READBEFOREWRITE”/“WRITETHROUGH” 写模式
RESETMODE_A/B”SYNC”/“ASYNC”,默认 ASYNC
BYTE_ENABLE0/8/10,字节使能粒度
ECC_ENCODE / ECC_DECODEECC 编解码使能
CLK_MODE”ASYNC”/“SYNC”,默认 ASYNC
INIT_FILE / FILL_ALL初始值文件 / 未初始化空间填充

一个简单双口(PDPW)的例化骨架:

PH1_LOGIC_ERAM #(
    .DATA_WIDTH_A(16),  .DATA_WIDTH_B(16),
    .ADDR_WIDTH_A(11),  .ADDR_WIDTH_B(11),
    .DATA_DEPTH_A(2048), .DATA_DEPTH_B(2048),
    .MODE("PDPW"),
    .REGMODE_A("NOREG"), .REGMODE_B("NOREG"),
    .WRITEMODE_A("NORMAL"), .WRITEMODE_B("NORMAL"),
    .ECC_ENCODE("DISABLE"), .ECC_DECODE("DISABLE"),
    .CLKMODE("ASYNC"),
    .RESETMODE_A("ASYNC"), .RESETMODE_B("ASYNC"),
    .ASYNC_RESET_RELEASE_A("SYNC"), .ASYNC_RESET_RELEASE_B("SYNC"),
    .INIT_FILE("NONE"), .FILL_ALL("NONE")
) inst (
    .dia(dia), .addra(addra), .cea(cea), .clka(clka), .wea(wea),
    .dib({16{1'b0}}), .addrb(addrb), .ceb(ceb), .clkb(clkb), .web(1'b0),
    .ocea(1'b0), .oceb(1'b0),
    .bea(1'b0), .beb(1'b0), .rsta(1'b0), .rstb(1'b0),
    .ecc_sbiterr(open), .ecc_dbiterr(open),
    .doa(), .dob(dob)
);

常见坑:

手册注释第 14.3 节写得很明确:输出不带寄存器时,RESETMODE 只能选 “ASYNC”,不能选同步;带输出寄存器(OUTREG)时才可以二选一。另外输出加寄存器后数据会延迟一个时钟周期,算读延迟时别漏了这一拍。

分布式 RAM:PH1_LOGIC_DRAM

PH1_LOGIC_DRAM 是分布式 RAM,用逻辑资源实现,可配置为单口或简单双口 RAM。和 ERAM 相比容量小、但数量多、分布广,适合小而多的存储需求(寄存器堆、小查找表、状态缓冲)。

DRAM:分布式 RAM 模块

端口:写侧 di/waddr/wclk/we,读侧 raddr/rclk/rce/rrst,输出两套:rdo(不带寄存器)和 rdoq(带寄存器)。参数:

参数默认说明
DATA_WIDTH_W / ADDR_WIDTH_W8 / 6写侧位宽/地址位宽
DATA_WIDTH_R / ADDR_WIDTH_R8 / 6读侧位宽/地址位宽
DATA_DEPTH_W/R2^ADDR_WIDTH深度自动跟随地址位宽
READREG”DISABLE”读寄存器使能
RESETMODE”SYNC”复位模式
INIT_FILE / FILL_ALL”NONE”初始值文件 / 未初始化填充
PH1_LOGIC_DRAM #(
    .DATA_WIDTH_W(9),  .ADDR_WIDTH_W(10),
    .DATA_WIDTH_R(9),  .ADDR_WIDTH_R(10)
) u_LOGIC_DRAM (
    .di(di), .waddr(waddr), .we(we), .wclk(wclk),
    .raddr(raddr), .rdo(rdo)
);

注意 RESETMODE 默认是 “SYNC”,和 ERAM(默认 ASYNC)方向相反,两个都手写例化时容易记混。

移位寄存器:PH1_LOGIC_SHIFTER

PH1_LOGIC_SHIFTER 是片内移位寄存器模块,典型用途是数据延迟线、图像行缓冲。datain 默认上升沿锁存,en 控制是否移位,深度由参数和端口共同决定——这是它最容易踩坑的地方。

SHIFTER:移位寄存器模块

参数与深度规则:

参数默认说明
DATA_WIDTH16数据位宽
DEPTH_WIDTH2地址位宽
SHIFT_TYPE”FIXED""FIXED”/“VARIABLE” 转换类型
DATA_DEPTH32数据深度
INIT_FILE”NONE”预加载初始值文件

规则拆开讲:SHIFT_TYPE="FIXED" 时 depth 端口是无用信号,深度就是 DATA_DEPTH;SHIFT_TYPE="VARIABLE" 时深度为 2^DEPTH_WIDTH,depth 端口是真实的运行时深度控制信号。但注意手册注释:PH1A100 器件不支持 “VARIABLE” 模式,只支持 “FIXED”,所以在这颗芯片上 depth 端口实际不用管。深度还有一条属性表公式:16 位宽时 shift_depth = depth[4:0] + 2(0x00→2,0x1F→33,最大 33);8 位宽时 shift_depth = depth[5:0] + 2(最大 65)。

PH1_LOGIC_SHIFTER #(
    .DATA_WIDTH(16),
    .DEPTH_WIDTH(2),
    .SHIFT_TYPE("FIXED")
) u1_LOGIC_SHIFTER (
    .clk(clk), .en(en),
    .datain(datain),
    .depth(depth),
    .dataout(dataout)
);

乘法器:PH1_LOGIC_MULT

PH1_LOGIC_MULT 是硬核乘法器,默认 18x18 → 36 位,A/B/输出三级都有可选寄存器(PIPE),适合做滤波器、FFT 这类流水化乘法。

MULT:硬核乘法器

端口方向功能
a / binput乘数(INPUT_WIDTH_A/B 位)
poutput乘积(OUTPUT_WIDTH 位)
cea / ceb / cepdinputA/B/输出片选,高有效
rstan / rstbn / rstpdninputA/B/输出复位,低有效
clkinput同步时钟

参数要点:

参数默认说明
INPUT_WIDTH_A/B / OUTPUT_WIDTH18/18/36位宽
INPUTFORMAT”SIGNED""SIGNED”/“UNSIGNED”
INPUTREGA/INPUTREGB/OUTPUTREG”ENABLE”三级寄存器使能
SRMODE”ASYNC”复位置位模式 SYNC/ASYNC
IMPLEMENT”AUTO""AUTO”/“DSP”/“GATE”,实现方式
PH1_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)
);

时序规则一句话:任何一级寄存器使能都会让输出延迟一个时钟周期,全开时 a/b 进来后 3 拍才出现在 p 上。它只支持原语例化(IP Generator 为”否”),所以流水级数要自己心里有数。

DSP 家族:DSPADD、DSPLOGIC、DSPREG、DSPMREG、DSPTADD

MULT 之外的五个 DSP 原语是 DSP 块内部各功能单元的独立入口,用来搭更复杂的运算流水线:

  • PH1_PHY_DSPADD:27 位加/减法模块。opctrl[0] 使能,opctrl[1] 选 sum=a+b 或 a-b。
  • PH1_PHY_DSPLOGIC:54 位逻辑运算模块,opctrl[3:0] 选择 xor/xnor/and/and-not/or/nor/nand 等十种运算,另有 54 位输入的宽位异或输出 wxor[1:0]
  • PH1_PHY_DSPREG:DSP 寄存器模块,WIDTH 可配 1~54,参数 RSTMUX/CEMUX/CLKMUX 与 RSTMODE(SYNC/ASYNC,默认 ASYNC)。
  • PH1_PHY_DSPMREG:带动态级数选择的寄存器模块。opctrl=0 时 dynamic_q 是 d 的 2 级寄存输出;opctrl=1 时级数由 DYNAMIC_DATA 参数决定(“D” 为 0 级直通,“Q” 为 1 级)。可在运行中切换流水深度。
  • PH1_PHY_DSPTADD:动态选择切换的三输入加法器。x0/y0/z0 与 x1_special/y1_special/z1_special 可运行时动态切换,opctrl[3:0] 决定 sum 表达式(x+y+z+ci 及各路取负组合),opctrl[8:4] 控制各输入的切换与 overflow/underflow 输出;参数 X1_EXTEND(符号扩展)、Y1_ROUND(换成内置常数 RND_CONST)、Z1_SHIFT(右移 17 位)、CI_INVERT(进位取反)用于特殊运算(如四舍五入、移位对齐)。
// DSPADD 示例
PH1_PHY_DSPADD DSPADD_inst (
    .a(a), .b(b), .opctrl(opctrl), .sum(sum)
);
// DSPMREG 示例
PH1_PHY_DSPMREG DSPMREG_inst (
    .clk(clk), .rst(rst), .ce(ce),
    .d(d), .opctrl(opctrl), .dynamic_q(dynamic_q)
);

DSP 家族成员都同时支持原语例化和 IP Generator。竞赛项目里如果只做普通乘加,用 MULT 甚至让综合器推断 * 就够了;DSPTADD/DSPMREG 这类动态切换单元用在需要运行时改数据通路的高阶场景。

软核除法器:PH1_LOGIC_SEQ_DIV

PH1_LOGIC_SEQ_DIV 是 TD 集成的软核除法器,多周期完成一次除法,输出商和余数。握手时序是关键:

端口方向功能
clk / rstinput时钟 / 复位(rst=1 时 quotient、remain 置 0,done 置 1)
startinput置 1 缓存输入数据;由 1 变 0 时开始计算
numer / denominput被除数(NUMER_WIDTH)/ 除数(DENOM_WIDTH)
quotient / remainoutput商 / 余数,done=1 时才有效
doneoutput计算完成标志

参数只有两个:NUMER_WIDTHDENOM_WIDTH,默认都是 16。

PH1_LOGIC_SEQ_DIV #(
    .NUMER_WIDTH(16),
    .DENOM_WIDTH(16)
) u_LOGIC_SEQ_DIV (
    .clk(clk), .rst(rst), .start(start),
    .numer(numer), .denom(denom),
    .quotient(quotient), .remain(remain), .done(done)
);

常见坑:

手册特别提示:start=0 之后改变 numer/denom 不影响本次计算,但”为了防止波形显示时产生误解”,应该在 done=1 之后才提供下一组输入——即标准的”请求-等待-取数-再请求”握手,别在计算中途换数。

底层积木:PH1_LOGIC_SLICE

PH1_LOGIC_SLICE 是 FPGA 最底层逻辑单元 SLICE 的原语入口。一个 SLICE 内含两个非独立的双 LUT5、两个独立的 DFF,还有进位链(fci/fco)。平时写 Verilog 从不需要碰它,但看懂它能明白综合器在底层怎么摆放逻辑,也能在特殊场合手工榨性能。

SLICE:LUT5 对 + DFF 对 + 进位链

端口分组:组合输入 ia~ie/imf;复用输入 ima/imb;寄存器控制 clk/cea/ceb/ssr/asr;输出 oqa/oqb(时序)、ofa/ofb(组合);进位 fci/fco。参数非常多(LUTMODE、INIT_LUT5A/B、各路 MUX 选择……),核心逻辑是:

  • LUTMODE:“LUT6”(两片 LUT5 拼成一片 LUT6)或 “DLUT5”(两片独立 LUT5)。
  • INIT_LUT5A/INIT_LUT5B:32 位真值表直接定义 LUT 功能——这就是”LUT 是一张 32x1 查找表”的具象化。
  • *_MUX/*_SD 参数决定内部信号怎么走(寄存器输入来自 LUT 还是复用口、输出选组合还是时序等)。

手册给的示例是”SLICE 配置为 LUT6 输出:寄存器输出和不带寄存器输出”:

PH1_LOGIC_SLICE #(
    .REGB_SD("LUT6"),
    .LUTMODE("LUT6"),
    .CLKMUX("SIG"),
    .INIT_LUT5A(INIT_LUT5A),
    .INIT_LUT5B(INIT_LUT5B),
    .CEBMUX("SIG"),
    .SSRMUX("SIG"),
    .ASRMUX("SIG"),
    .OFB_SD("LUTX"),
    .OQBMUX("QB")
) lut6_inst (
    .imf(imf), .ie(ie), .id(id), .ic(ic), .ib(ib), .ia(ia),
    .ceb(1'b1), .clk(clk), .ssr(1'b0), .asr(1'b0),
    .oqb(oqb),   // reg output
    .ofb(ofb)    // lut6 output
);

只支持原语例化。初学者了解即可,别在常规逻辑里手写 SLICE。

可靠性与身份:ECC、DNA、PVT

这三个原语不参与你的数据通路,但竞赛/产品化场景经常用得上:

PH1_LOGIC_ECC——配置存储器纠错单元。FPGA 的配置存储(Configuration Memory)在太空/高辐射/老化场景可能发生单粒子翻转,ECC 单元可对配置帧做校验、修复并上报错误信息。工作流程:拉低 ecc_enable_n_i 并保持 → 等 ecc_stop_o 变低开始运行 → 校验完最后一个配置帧进入 global crc check 阶段时 ecc_done_o 拉高(至少持续 2 个 ecc_clk_o 周期)→ 38 位 ecc_info_o 携带出错配置帧地址、syndrome、单/双 bit 错误与 gcrc 错误标志。参数:ECC_PROTECT(保护模式:单 bit 错误二次校验)、SEC_OPTION(“HOLD”/“CORRECT_AND_CONTINUE”/“CORRECT_AND_HOLD” 三种纠错策略)、ECCERR_REPORT_EN(出错时拉低 INITN 管脚对外报告)、ECC_FREQ(2/3/5/11MHz)。ecc_clk_o 由内部晶振分频产生,用户只需提供使能时序。

ECC:单次执行模式时序

PH1_LOGIC_DNA——读取 64 位芯片唯一 DNA。移位寄存器式接口:dna_shift_n_i 低电平使能移位,dna_din_i 移入、dna_do_o 逐位移出。参数 EXT_DNA_CLK_I 控制时钟来源。典型用途:产品序列号、加密绑板。

PH1_LOGIC_PVT——芯片内置两个 PVT Sensor,可高精度测量电压和温度(VSAMPLE=0 测温度、1 测电压),data_out 10 位,data_valid 指示有效。参数 SENSOR_LOC 选传感器位置(“0” 芯片右上角、“1” 芯片中间),EXT_ENA 选外部使能方式。

PVT:电压/温度传感模块

常见坑:

PVT 的 ena 是异步使能,手册注释写明不能直接接常量 1,必须提供上升沿触发信号,并保持有效直到 data_valid,否则会复位 sensor;时钟推荐 1.2MHz。三个原语都只支持原语例化。

杂项控制信号:GCTRL 与 TRSTN

最后两个是芯片级控制信号的原语入口,端口极少:

  • PH1_LOGIC_GCTRL:加载标准信号输出模块,只有两个输出端口 done_o(DONE 信号)和 wakeup_o(wakeup 信号),把芯片配置完成/唤醒状态引给用户逻辑用。
  • PH1_LOGIC_TRSTN:用户 TRSTN 控制信号,输入 usrtrstn_i 和选择信号 usrtrstn_sel_n_i,参与内部复位树控制。
PH1_LOGIC_GCTRL LOGIC_GCTRL_inst (
    .done_o(done_o),
    .wakeup_o(wakeup_o)
);

两者都只支持原语例化、无参数。它们在 UG710 里篇幅最短,但在做”配置完成后才开始工作”(等 done_o)这类上电时序设计时会用到。

通关标准:

  • 能说出硬核 FIFO 与软核 RAMFIFO 的两条选择依据(跨时钟域 vs 深度指示/Showahead)。
  • 能解释 ERAM 的 RESETMODE 与输出寄存器的联动规则(无输出寄存器只能异步复位)。
  • 能独立例化 SEQ_DIV 并描述 start/done 的正确握手时序。