FPGA内部架构:从LUT到IO,这些基本单元你都得懂
做FPGA逆向,说白了就是跟芯片内部的「积木块」打交道。你得先知道这些积木长什么样,才能看懂别人是怎么搭电路的。今天我就带你把这些基础单元过一遍,都是我在项目里反复摸爬滚打总结出来的。
LUT(查找表)——FPGA的灵魂
LUT是FPGA最核心的东西。你可以把它理解成一个「万能逻辑门」。一个4输入LUT,内部其实是一个16×1的SRAM。你给它什么输入,它就输出什么结果。
关键点:LUT本质上就是一张真值表。逆向时,我们读到的LUT配置值,就是这张表的输出列。
举个例子,一个2输入LUT,配置值为0x8(二进制1000),那它的逻辑就是AND门。为什么?因为只有两个输入都是1时,输出才是1。我在逆向一个老款Xilinx芯片时,就靠读LUT配置值反推出了一个加密算法的S盒——那感觉,就像在拼图里找到了关键一块。
我的习惯:拿到LUT配置值,先转成二进制,然后按地址顺序排列。这样一眼就能看出逻辑功能。
FF(触发器)——时序的基石
触发器负责存储状态。FPGA里的FF通常是D触发器,带有时钟使能和复位。逆向时,FF的连接关系直接决定了状态机的结构。
我记得有一次,客户给了一个加密芯片的网表。我花了三天时间,把几百个FF的连接关系画出来,才发现那是一个32位的线性反馈移位寄存器(LFSR)。嗯,那一刻我明白了——FF的级联方式,就是算法的骨架。
注意:有些FF的复位信号是异步的,有些是同步的。逆向时一定要区分清楚,否则时序分析会全错。
BRAM(块RAM)——数据的仓库
BRAM是FPGA里的专用存储单元。一个BRAM通常是36Kb,可以配置成不同的位宽和深度。逆向时,BRAM的内容往往藏着关键数据——比如查找表、系数、甚至微代码。
我曾经逆向过一个图像处理芯片,BRAM里存着一组256字节的伽马校正表。读出来之后,整个图像处理流程就清晰了。说白了,BRAM就是芯片的「记忆体」,它的初始化值就是算法的参数。
| BRAM配置 | 深度 | 位宽 | 典型用途 |
|---|---|---|---|
| 单端口 | 1024 | 36 | 数据缓存 |
| 双端口 | 512 | 72 | FIFO |
| 简单双端口 | 2048 | 18 | 查找表 |
DSP(数字信号处理单元)——算力的核心
DSP单元是专门做乘加运算的。一个DSP48E1可以完成25×18的乘法,然后累加。逆向时,DSP的连接方式往往揭示了算法的计算结构。
你想想看,如果网表里有一排DSP级联,那大概率是FIR滤波器。如果DSP的输入来自BRAM,那可能是矩阵乘法。我在分析一个音频编解码器时,就是靠DSP的配置模式,反推出了它的滤波器系数。
实战技巧:DSP的配置寄存器里,藏着运算模式(乘加、乘减、累加等)。逆向时一定要读出来。
IO(输入输出)——芯片的边界
IO单元负责芯片和外界通信。每个IO都可以配置成输入、输出或双向。逆向时,IO的配置决定了信号的方向和电平标准。
我记得有一次,芯片的IO配置里有个奇怪的延迟链。后来才发现,那是为了对齐DDR数据的时钟。嗯,IO的细节往往藏着接口协议的秘密。
网表文件格式:EDIF、Verilog网表、XDL
网表文件就是芯片的「设计蓝图」。逆向工程师拿到网表,就像侦探拿到案件卷宗。常见的格式有三种,我一个个说。
EDIF(电子设计交换格式)
EDIF是一种标准化的网表格式,用括号嵌套描述电路。它很古老,但兼容性极好。逆向时,EDIF文件里全是cell和net的定义。
(cell AND2 (cellType GENERIC)
(view netlist (viewType NETLIST)
(interface
(port A (direction INPUT))
(port B (direction INPUT))
(port O (direction OUTPUT))
)
(implementation
(net net1 (joined
(portRef A)
(instanceRef U1 (portRef A1))
))
)
)
)
说实话,EDIF读起来很累。我一般会先转成Verilog网表再分析。但有些老芯片只有EDIF,那就得硬着头皮看。
Verilog网表
Verilog网表是现在最常用的格式。它用module实例化来描述电路。逆向时,Verilog网表可读性最好。
module top (
input clk,
input rst,
input [7:0] data_in,
output [7:0] data_out
);
wire [7:0] w1;
wire [7:0] w2;
LUT4 #(.INIT(16'h8F8F)) u_lut (
.I0(data_in[0]),
.I1(data_in[1]),
.I2(w1[0]),
.I3(w1[1]),
.O(w2[0])
);
FDRE #(.INIT(1'b0)) u_ff (
.C(clk),
.R(rst),
.CE(1'b1),
.D(w2[0]),
.Q(data_out[0])
);
endmodule
我的建议:拿到Verilog网表,先看顶层模块的端口。端口往往暗示了芯片的功能——比如有HDMI接口,那肯定是视频芯片。
XDL(Xilinx Design Language)
XDL是Xilinx的专用格式,可以直接描述FPGA内部的物理资源。它比EDIF和Verilog更底层,包含了LUT、FF、BRAM的具体位置和配置。
inst "u_lut" "SLICEL", placed CLBLL_L_X10Y100 SLICE_X0Y100:
cfg " LUT::#LUT:O6=LUT
#FF::INIT=0
CLKINV::1
IS_CLK_INVERTED::1
LUT_OR::0
LUT_INIT[0:63]=64'h0000000000000008 " ;
XDL文件里,每个实例都有精确的坐标和配置。逆向时,XDL能帮你定位到具体的LUT和FF。我曾在XDL里发现一个隐藏的测试电路——那家伙藏在芯片角落里,要不是看XDL,根本发现不了。
网表的层次化结构
网表不是一坨乱麻,它有清晰的层次。理解层次化结构,是逆向的关键。
顶层模块
顶层模块是芯片的「大门」。它定义了所有外部端口。逆向时,先看顶层,再往下钻。
子模块
子模块是功能单元。比如一个加法器、一个状态机、一个FIFO。子模块之间通过信号线连接。
基本单元
最底层是LUT、FF、BRAM、DSP这些基本单元。它们构成了芯片的「原子」。
逆向策略:从顶层往下,一层层拆解。先搞清楚大模块的功能,再分析内部细节。千万别一上来就扎进LUT里,你会迷路的。
我习惯用思维导图来整理层次结构。顶层画一个框,子模块画小框,连线标清楚。这样整个芯片的架构就一目了然了。
这张图展示了网表的层次化结构。顶层模块下面挂子模块,子模块下面挂基本单元。逆向时,你就像剥洋葱,一层层剥开,直到看到最底层的LUT和FF。
避坑指南:我曾经遇到一个网表,子模块嵌套了十几层。我一开始逐层分析,结果越看越乱。后来我改用「黑盒法」——先不管内部细节,只关注模块的输入输出关系。等搞清楚整体架构后,再深入内部。效率高了很多。
好了,FPGA的基础架构和网表结构就讲到这里。这些知识是逆向的「内功心法」,你得练扎实了。下一节我们会讲网表解析工具的使用,到时候我会分享一些实战脚本。
公众号:蓝海资料掘金营,微信deep3321