第二章:网表基础结构:LUT、FF、BRAM、DSP、IO等基本单元识别
做FPGA逆向,说白了就是跟一堆门级网表打交道。你拿到手的,往往是一堆看不懂的实例名、端口名,密密麻麻。很多人一上来就懵了——这玩意儿怎么下手?
我的经验是:别慌。先找基本单元。就像学英语先认字母,学汉字先认偏旁。FPGA网表再复杂,底层无非就是那几样东西:LUT、FF、BRAM、DSP、IO。把这几个祖宗认熟了,后面的路就好走了。
核心观点:网表逆向的第一步,不是分析逻辑功能,而是识别基本单元的类型。类型认错了,后面全白干。
2.1 LUT(查找表)—— 最灵活的“万能逻辑”
LUT是FPGA的灵魂。说白了,它就是一个可以配置的小型ROM。输入几根地址线,输出一个逻辑值。你想想看,任何组合逻辑,只要真值表能写出来,LUT就能实现。
在网表里,LUT通常以 LUT2、LUT3、LUT4、LUT5、LUT6 这样的名字出现。数字代表输入数量。比如 LUT4 就是4输入查找表。
识别要点:
- 实例名特征: 很多工具会保留原语名称,比如
LUT4_inst、LUT6_1。但也有工具会重命名,比如u_comb_123。这时候要看端口。 - 端口特征: LUT的输入端口通常叫
I0、I1、I2... 输出端口叫O。有些厂商用A0、A1表示地址输入。 - 初始化参数: 这是关键!LUT的配置值通常以
INIT参数给出。比如INIT = 16'h8000。这个值就是真值表。我曾经在逆向一个加密算法时,就是靠解析LUT的INIT值,反推出了S盒的替换逻辑。
个人技巧: 我习惯在网表里先搜 LUT 关键字,把所有LUT实例列出来。然后看它们的 INIT 参数。如果INIT值全是0或全是1,那大概率是冗余逻辑,可以跳过。如果INIT值分布很随机,那里面往往藏着关键逻辑。
2.2 FF(触发器)—— 时序逻辑的基石
FF就是寄存器。没有它,时序逻辑就玩不转。在网表里,FF的种类很多:D触发器、JK触发器、T触发器。但最常见的是D触发器。
识别要点:
- 实例名特征: 常见的有
FD、FDRE、FDCE、FDPE。名字里的字母代表功能:R表示同步复位,C表示时钟使能,P表示异步置位。 - 端口特征: 时钟端口
C,数据输入D,数据输出Q。复位端口R或CLR,置位端口S或PRE。 - 时钟边沿: 注意看是上升沿触发还是下降沿触发。网表里通常用
posedge或negedge标注。
嗯,这里要注意:有些工具会把FF和LUT打包在一起,做成一个叫 SLICE 或 CLB 的宏单元。这时候你不能只看顶层名字,得拆开看内部结构。我记得有一次逆向Xilinx的网表,发现所有FF都被封装在 SLICEL 里,一开始没注意,结果时序分析全错了。
避坑指南: 我曾经在分析一个高速接口设计时,把所有FF都当成了普通寄存器。后来发现有些FF的复位信号是异步的,而且复位极性是低电平有效。这导致我重建的时序模型跟实际行为对不上。所以,识别FF时一定要看清楚复位/置位的极性和同步/异步属性。
2.3 BRAM(块RAM)—— 存储大户
BRAM是FPGA里的“大仓库”。它不像LUT那样只能存几个比特,而是能存几千甚至几万个比特。在网表里,BRAM通常以 RAMB18、RAMB36、RAMB_MACRO 等形式出现。
识别要点:
- 容量特征: 名字里的数字通常代表容量。比如
RAMB18是18Kb,RAMB36是36Kb。但要注意,有些厂商的命名方式不同,比如Altera的M9K是9Kb。 - 端口特征: BRAM通常有独立的读写端口。地址端口
ADDR,数据输入DI,数据输出DO。还有写使能WE、时钟CLK等。 - 模式参数: BRAM可以配置成单端口、双端口、简单双端口等模式。这些信息通常以参数形式给出,比如
RAM_MODE = "SDP"表示简单双端口。
我个人习惯是,先看BRAM的地址位宽和数据位宽。比如一个BRAM有10位地址和8位数据,那它的深度就是1024,宽度是8。这能帮你快速判断它是不是用来做FIFO、查找表还是缓存。
实战案例: 我在逆向一个图像处理芯片时,发现网表里有一堆BRAM,地址位宽都是10位,数据位宽是8位。我一开始以为是图像缓存。后来仔细看初始化文件,发现里面存的是固定的系数。这才意识到,这些BRAM其实是用来实现卷积核的。如果当时没识别出BRAM的初始化数据,整个算法分析就偏了。
2.4 DSP(数字信号处理单元)—— 算力担当
DSP单元是FPGA里的“计算器”。它专门用来做乘法、加法、乘累加这些运算。在网表里,DSP通常以 DSP48E1、DSP48E2、DSP_MAC 等形式出现。
识别要点:
- 实例名特征: 名字里通常有
DSP或MAC字样。比如DSP48E1_inst。 - 端口特征: 数据输入端口
A、B、C,输出端口P。还有时钟CLK、复位RST、使能CE等控制端口。 - 配置参数: DSP单元可以配置成不同的运算模式。比如
USE_MULT = "MULT"表示乘法模式,USE_ACCUM = "ACCUM"表示累加模式。
你想想看,如果网表里出现大量DSP单元,那这个设计八成跟数字信号处理、滤波、FFT、神经网络推理有关。我遇到过最夸张的一个项目,网表里用了200多个DSP48E2,一看就知道是在做深度学习加速器。
识别技巧: 有些工具会把DSP单元和周围的寄存器、LUT打包成一个宏。这时候你看到的可能是一个 DSP_MACRO 或 MULT_ADD 模块。别被名字骗了,拆开看内部,你会发现里面还是那几个基本单元的组合。
2.5 IO(输入输出单元)—— 芯片的“嘴巴”
IO单元是FPGA跟外界通信的接口。在网表里,IO通常以 IBUF、OBUF、IOBUF、PAD 等形式出现。
识别要点:
- 实例名特征:
IBUF是输入缓冲,OBUF是输出缓冲,IOBUF是双向缓冲。有些厂商用PAD表示物理焊盘。 - 端口特征: 输入端口
I,输出端口O,双向端口IO。还有控制端口T(三态控制)。 - 电气特性: 有些IO单元会包含上拉、下拉、施密特触发等配置。这些信息通常以参数形式给出,比如
PULLTYPE = "PULLUP"。
嗯,这里有个坑:IO单元在网表里往往跟顶层端口直接相连。如果你看到某个模块的端口直接连到了 IBUF 或 OBUF,那这个端口大概率是芯片的物理引脚。我曾经在分析一个通信芯片时,把所有连了 IBUF 的端口都标记为输入,结果发现有些端口其实是双向的,只是当时没配置成输出模式。
避坑指南: 识别IO单元时,一定要看它有没有三态控制端口 T。如果有,那这个IO可能是双向的。另外,注意看IO单元的名字里有没有 DDR 或 SDR 字样,这表示它是双倍数据率还是单倍数据率。搞错了时序,后面分析接口协议时会非常痛苦。
2.6 知识体系总览
为了让你更直观地理解这些基本单元的关系,我画了一张图。这张图展示了FPGA网表里最常见的五类基本单元,以及它们各自的核心特征和识别要点。
2.7 综合识别策略
好了,五种基本单元都讲完了。但实际网表里,这些单元往往是混在一起的。怎么快速识别?我总结了一套策略:
- 先扫全局: 用文本搜索工具,把网表里所有实例的原语类型列出来。统计一下每种类型出现的次数。如果LUT和FF数量差不多,那大概率是普通逻辑设计。如果BRAM和DSP数量很多,那可能是数据处理类设计。
- 再看连接: 找到顶层端口,看它们连到了什么单元。如果连到IBUF,那就是输入。如果连到OBUF,那就是输出。如果连到IOBUF,那就是双向。
- 最后看参数: 对于LUT,看INIT值。对于BRAM,看初始化文件和模式参数。对于DSP,看运算模式配置。这些参数里藏着设计的核心逻辑。
我的习惯: 我会先写一个脚本,自动解析网表文件,提取所有实例的类型、端口连接和参数。然后生成一个统计报告。这样一眼就能看出这个设计用了哪些资源,大概是什么类型的应用。省时省力,还不容易漏掉关键信息。
识别基本单元,是FPGA网表逆向的第一步,也是最关键的一步。这一步走稳了,后面的逻辑重建、功能分析才能顺利进行。别嫌麻烦,多练几次,你也能一眼认出这些“老朋友”。