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配置深度位宽典型用途
单端口102436数据缓存
双端口51272FIFO
简单双端口204818查找表

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里,你会迷路的。

我习惯用思维导图来整理层次结构。顶层画一个框,子模块画小框,连线标清楚。这样整个芯片的架构就一目了然了。

顶层模块 (Top) 子模块 A (控制) 子模块 B (数据路径) 子模块 C (存储) LUT FF BRAM DSP IO 图例 顶层模块:芯片的对外接口 子模块:功能单元 基本单元:LUT/FF/BRAM/DSP/IO 逆向策略:从顶层往下,逐层拆解

这张图展示了网表的层次化结构。顶层模块下面挂子模块,子模块下面挂基本单元。逆向时,你就像剥洋葱,一层层剥开,直到看到最底层的LUT和FF。

避坑指南:我曾经遇到一个网表,子模块嵌套了十几层。我一开始逐层分析,结果越看越乱。后来我改用「黑盒法」——先不管内部细节,只关注模块的输入输出关系。等搞清楚整体架构后,再深入内部。效率高了很多。

好了,FPGA的基础架构和网表结构就讲到这里。这些知识是逆向的「内功心法」,你得练扎实了。下一节我们会讲网表解析工具的使用,到时候我会分享一些实战脚本。


公众号:蓝海资料掘金营,微信deep3321