FPGA芯片型号识别:用JTAG IDCODE读取硬件身份
2026/9/24 2:54:42 网站建设 项目流程

反正每次翻到项目历史文件里那些旧板卡,最头疼的一步就是“这板子上到底是哪颗FPGA”。丝印被打磨、标签脱落、工程文件丢失,光凭眼睛根本没法判断。我在调试或者维修二手板的时候,第一件事永远是插上JTAG,把IDCODE读出来。这个操作不费任何硬件成本,也不需要对板卡通电跑逻辑,几秒钟就能确定芯片的厂家、系列和版本代次,可以说是FPGA调试里最值得熟练掌握的一个基本功。这篇文章就顺着我自己的实操流程,把JTAG连接、IDCODE寄存器原理、软件扫描方法和坑位排查完整过一遍。适合刚接触FPGA开发的入门者,也适合常年跟板卡打交道、偶尔会遇到“无标识芯片”的硬件工程师和维修人员。

1. IDCODE原理:一条JTAG指令就能读出的32位“身份ID”

1.1 JTAG边界扫描协议里被强制要求的那条指令

JTAG最初是IEEE 1149.1标准定义的边界扫描测试接口,用来做板级互连测试。后来几乎所有的FPGA、CPLD以及带调试功能的高集成度芯片,都把这个接口同时复用为编程和调试口。芯片内部有一套TAP(Test Access Port)状态机,通过TCK时钟和TMS状态选择信号,控制芯片进入不同的操作模式。在TAP状态机里,有一条指令是所有符合IEEE 1149.1标准的芯片都必须实现的,就是IDCODE。

IDCODE指令的作用很简单:让芯片把固定在硅片内部的32位标识寄存器内容,通过TDO串行移出。这32位数据在芯片出厂的时候就被硬编码在逻辑里,谁都没法通过软件修改。所以读IDCODE不只是“识别型号”,更准确的说法是“读取芯片本身的硬件身份证明”。

1.2 32位IDCODE的字段排布:版本、器件号、厂商号

IDCODE的32位布局在IEEE 1149.1标准里是固定定义的。我从高位到低位拆开说:

位段位宽含义
bit[31:28]4 bit芯片版本号(Revision / Version)
bit[27:12]16 bit器件型号编号(Part Number / Device ID)
bit[11:1]11 bitJEDEC厂商编号(Manufacturer ID)
bit[0]1 bit固定为1,用于IDCODE移位校验

最低位固定为1,这是IEEE 1149.1里规定的。JTAG扫描器靠这个“最末尾的1”来检测IDCODE数据流的边界和对齐状态,如果读到最低位不是1,说明数据流没对齐或者链路有异常。

厂商编号这个字段,按照JEDEC标准分配,每个半导体厂商在全球范围内都有一个唯一编号。Xilinx(现属AMD)的JEDEC厂商编号是0x049,在IDCODE里占位后整体表现就是IDCODE尾部常见的0x093。Altera/Intel的厂商编号是0x06E,对应的IDCODE尾部常见值就是0x0DD。不同厂商的芯片,只要看IDCODE的后12位,就能先确认是哪家的东西。

1.3 为什么IDCODE比丝印更值得信任

很多工程师习惯性依赖PCB丝印或芯片表面印字来判断型号,这在调试和维修中是高风险习惯。芯片表面的激光印字可能被磨掉,翻新片甚至可能被重新打字,丝印本身更可能因版本迭代和改板而跟实际物料不一致。

IDCODE不一样,它是芯片内部的硬逻辑,外部无法篡改。我自己处理过一个案例:一块板卡丝印清晰写着XC7K325T,但扫描IDCODE后发现器件编号段对应的其实是XC7K410T。最后查采购记录才发现是替代料,板卡文件没同步更新。这种“丝印说谎”的情况,在返修市场和BOM调整后的板卡上非常常见,只信IDCODE才能拿到真实答案。

另外,读取IDCODE不需要芯片启动用户逻辑,只要给芯片供电、TAP状态机工作正常就能读。这意味着哪怕FPGA配置失败、时钟没有起振、甚至引脚被错误约束,只要JTAG链路是通的,照样能把型号读出来。

2. 硬件连接:JTAG四根信号线、接插件布局与上电前检查

2.1 TCK、TMS、TDI、TDO四根线各司其职

JTAG通信只需要四根核心信号线,对照一下它们的角色:

信号方向(以FPGA为准)作用
TCK输入JTAG时钟,所有状态跳变和移位都跟随这个时钟
TMS输入状态机控制信号,控制TAP状态切换
TDI输入串行数据输入,用于把指令和数据移入芯片
TDO输出串行数据输出,用于把IDCODE等寄存器内容移出芯片

除了这四根线,通常还需要共地GND,以及提供给下载器参考电平的VTref。VTref非常关键,下载器通过这个引脚感知目标板卡的IO电压水平,从而调整内部驱动电平,避免用3.3V去驱动1.8V的JTAG引脚导致损坏。所以VTref必须连接到FPGA的JTAG bank电源,而不是随便接一个3.3V。

TCK和TMS在FPGA内部一般都有弱上拉。TCK空闲状态拉高,TMS拉高,这样能保证下载器还没开始驱动时序的时候,TAP状态机不会乱跑。TDO在空闲时是高阻态,多个器件挂在同一条JTAG链上时,靠这个特性实现菊花链复用。

2.2 常见的JTAG接插件:14针双排、10针、20针怎么认

实际板卡上JTAG接口的物理形态非常不统一。最常遇到的是14针双排2.54mm间距连接器,这也是网上搜索量最高的“14针双排jtag定位键”所指的形态。这类连接器通常设计有防插反的定位键,也就是塑料外壳上的一个凸起缺口,配合排线的卡扣,保证插线方向唯一。

但需要注意,即使外形都是14针,不同厂商的引脚定义也不完全一样。ARM标准的14针JTAG调试接口很常见,Xilinx的Platform Cable也出过14针版本,还有一些第三方下载器用10针或20针。直接把某一种定义套到另一块板卡上,很容易烧东西。

我这些年用得最多的引脚定义表是下面这个,属于ARM标准的14针JTAG。很多兼容下载器和第三方调试器都默认按这套定义来:

引脚信号引脚信号
1VTref2GND
3nTRST4GND
5TDI6GND
7TMS8GND
9TCK10GND
11RTCK12GND
13TDO14GND

这个定义里奇数控信号、偶数基本都是地,所以也叫“奇数信号偶数地”布局。它最大的好处是信号之间用地隔开,高频串扰小。

Xilinx官方下载线常见的20针接口,引脚顺序差异更大。第三方JTAG-HS3、Platform Cable USB II,不同批次甚至不同贴牌商的引脚排布都有区别。所以拿到一个陌生下载器,我建议优先做两件事:一是翻下载器配套的接口定义文档,二是用万用表通断档,把下载器排线上的VTref、GND、四根信号线对应到连接器引脚上,实测确认后再插板子。

2.3 上电之前先用万用表做的三个检查

很多人插上JTAG就急着开软件,扫描不到设备才回头检查硬件,浪费时间也容易误判。我习惯上电前先做三件事:

第一,量VTref引脚对GND的电压。如果板卡正常供电,这个电压应该等于FPGA JTAG bank的IO电压,常见1.8V、2.5V、3.3V。测不到电压就先检查板卡是否上电,不要直接接下载器。

第二,量TCK和TMS对地的电阻。正常情况下会看到阻值不太高的上拉,有些板卡上拉到100k甚至1k,量出来不是无穷大就行。如果TCK对地直接短路,或者悬空没有上拉,扫描时大概率会出问题。

第三,用通断档量TDI、TDO、TCK、TMS四根线到FPGA引脚的连通性。有些板卡做了JTAG信号缓冲隔离,中间加了电阻或缓冲芯片,直接通断可能不响,这时候至少能确认没有开路。

做完这三件事再上电扫描,“硬件问题”这个最大的变量就已经被排除了。

3. 实操扫描:Vivado、XSCT和OpenOCD三种读取IDCODE的办法

3.1 Vivado Hardware Manager图形化扫描

如果你的板卡用的是AMD/Xilinx芯片,Vivado自带的Hardware Manager是最省事的路径。操作步骤很简单:

打开Vivado,在下方的Flow Navigator里找到 Hardware Manager,点击 Open Target,选择 Auto Connect。Vivado会自动连接本地下载器,扫描JTAG链路,然后把识别到的器件列出来。图界面里可以直接看到器件型号,比如 xc7z010、xc7k325t 之类。这个识别结果的背后,就是软件读取IDCODE跟内部数据库比对后的输出。

在Vivado的Hardware界面里,选中器件,点击右键调出 Device Properties,可以看到IDCODE原始值和具体的版本号。比较实用的一点是,这里显示的Device属性里除了IDCODE,还能看到IR长度、JTAG链位置等,这些在手动配置调试链时很有用。Vivado识别不了某些芯片的时候,也可以在Add Device里手动按器件型号添加,选中的型号会被强制匹配到JTAG链上。

3.2 XSCT和Tcl命令行方式读取

如果板卡数量多,或者需要在自动化脚本里批量读取IDCODE,图形界面效率太低。Vivado自带的XSCT(Xilinx Software Command-Line Tool)或者Vivado Tcl Shell都能完成。

用XSCT的时候,连接下载器和目标后,执行:

connect targets

targets 命令会列出当前JTAG链上的所有目标,比如:

1 Xilinx TCF Agent 2 xc7z010

接着使用:

target 2 target -get -filter {name =~ "xc7z010"}

但XSCT更常用于Zynq这类带ARM核的芯片调试。如果只想读IDCODE,Vivado Tcl命令更直接:

open_hw_manager connect_hw_server -url localhost:3121 open_hw_target set devs [get_hw_devices] foreach dev $devs { puts [get_property NAME $dev] puts [get_property IDCODE $dev] }

这段循环在检修多条板卡时非常实用。把输出的IDCODE收集起来,跟自己的数据库比对,哪个板卡用了哪个版本芯片一目了然。我自己会把这些数据追加到CSV里,包含板卡编号、IDCODE、识别型号、日期,长期积累了之后,再遇到返修板一眼就能定位物料批次。

3.3 OpenOCD扫描:不受厂商工具限制的通用方案

OpenOCD原本常被用于ARM调试,但它的JTAG底层扫描做得非常通用,完全可以用在FPGA上,尤其是当你手里的下载器是FT2232H这类通用USB转JTAG工具时,Vivado未必认,OpenOCD却很稳。

安装OpenOCD之后,最小化的扫描配置只需要指定下载器接口配置。以FT2232H核心的JTAG-HS3为例:

openocd -f interface/ftdi/jtagkey.cfg \ -c "adapter_khz 1000; transport select jtag; init; scan_chain; shutdown"

执行后会看到类似下的输出:

Info : JTAG tap: zynq.tap tap/device found: 0x0362d093 (mfg: 0x093 (Xilinx), part: 0x362d, ver: 0x0) Info : JTAG tap: xc7z010.tap tap/device found: 0x0362d093 (mfg: 0x093 (Xilinx), part: 0x362d, ver: 0x0)

这一行已经把IDCODE从原始值到厂商名、器件编号、版本号全部拆解出来了。OpenOCD还有一个好处是它不会因为未知的IDCODE直接拒绝工作,有些工具遇到没见过的IDCODE就报错退出,OpenOCD只是提示一下“tap/device found”,照样把链路和IDCODE给你列出来。这一点在识别新板卡、早期工程样品的时候,价值远大于那些“只认自家人”的工具。

4. IDCODE拆解:从十六进制数字反推芯片型号的完整方法

4.1 把0x0362d093拆开来看,三段信息就出来了

以OpenOCD扫描Zynq-7000系列时常见的0x0362d093为例,手把手过一遍拆解。

先转成二进制,按位段切分:

  • 0x0362d093 = 0000 0011 0110 0010 1101 0000 1001 0011
  • bit[31:28] = 0000 = 0x0,所以版本号为0
  • bit[27:12] = 0011 0110 0010 1101 = 0x362D,这是Xilinx内部定义的器件编号,对应Zynq-7000家族
  • bit[11:1] = 000 1001 0011,去掉最低位后得到厂商号0x049,也就是AMD/Xilinx
  • bit[0] = 1,校验位正常

所以0x0362d093代表一颗Xilinx的Zynq-7000系列器件,版本0。至于是7010还是7020、7030,则需要结合器件编号段做进一步区分,常见Zynq-7000的IDCODE是0x0362d093,对应xc7z010或xc7z020。不同型号甚至不同速度等级,IDCODE都可能变化。如果版本号字段变成0x1或者0x2,意味着芯片是更新的stepping版本。

再举一个Intel/Altera的典型值。Cyclone V系列常见的IDCODE尾部是0x0DD,厂商段对应0x06E,正是Altera/Intel的JEDEC编号。看到IDCODE尾部是0xDD,基本可以判断是Intel系的芯片。

常用厂商的IDCODE尾部特征我整理了一张简表,方便快速心算:

厂商JEDEC厂商号IDCODE尾12位特征
AMD/Xilinx0x0490x093
Altera/Intel0x06E0x0DD
Lattice0x03D0x07B
Gowin(高云)各系列不同以官方手册为准

Lattice和Gowin有一部分芯片的IDCODE实现并不是严格按标准裸码来的,部分国产FPGA甚至在IDCODE上做了特殊编码,所以只凭尾段判断厂商有局限。更稳的方法是用扫描工具直接读输出,OpenOCD的mfg字段已经帮忙解析好了。

4.2 同一型号为什么会读出不同的IDCODE

很多人在调试中遇到过一个疑惑:手上两颗芯片丝印都是同型号,但IDCODE不一样。这不是异常,主要有三个原因。

一是版本号字段不同。芯片厂商在量产过程中如果修复了硅片层面的bug、调整过内部电路,会更新stepping版本,IDCODE的高4位随之变化。同一器件新老批次IDCODE不同,是很正常的事。

二是速度等级和温度等级不同。部分厂商的器件编号段会编码速度等级信息,比如-1、-2、-3速度等级对应不同的器件编号或版本号。也就是说,同一型号但速度等级不同的两颗芯片,IDCODE可能不一样。

三是工程样品(ES)和量产片。ES芯片的IDCODE常跟最终的量产版本不同,甚至早期ES和后期ES也不同。在识别“无标识”芯片时,如果发现IDCODE跟官方量产版本对不上,要考虑是不是工程样品流入市场。

这个差异在实际调试里很容易踩坑。我曾经碰到过一块板子,Vivado自动识别时提示unknown device,死活连不上。手动用IDCODE反查后确认是某款量产芯片的早期工程版本,Vivado数据库不认。处理办法是在硬件管理器里手动指定同系列的量产器件,或者改用OpenOCD绕过自动匹配,最终顺利完成了后续操作。

5. 多芯片JTAG链和多Die FPGA:IDCODE的顺序和数量

5.1 菊花链结构里,IDCODE移出的顺序有讲究

一块板卡上不只有一颗FPGA的情况并不少见,比如FPGA加CPLD、FPGA加DSP,或者FPGA加带JTAG的MCU。当多个芯片的TDI和TDO首尾相接,就形成了JTAG菊花链。

链的形态是把第一颗芯片的TDI接下载器的TDI,第一颗的TDO接到第二颗的TDI,以此类推,最后一颗的TDO接回下载器的TDO。扫描时,所有芯片的IDCODE寄存器被串联成一个大移位寄存器,下载器经过足够的TCK周期,把整串IDCODE全部移出来。

这里的顺序规律:离TDI最近的芯片,它的IDCODE会最早被移出。换句话说,从读取到的IDCODE序列里,第一个值对应链上靠近TDI的那颗,最后一个值对应靠近TDO的那颗。假如实际读到的顺序跟PCB设计文件里标注的不一致,往往是链的进出方向接反了。

在Vivado的Hardware Manager里,如果JTAG链上有多个设备,通常会以一条链的形式全部显示出来,每个节点对应一颗芯片。此时也能直接查看每一颗的IDCODE。对链上某个设备做编程或调试时,Vivado会自动向链上其他设备发送BYPASS指令,让它们变成一根短接线,只与目标设备通信。

5.2 多Die大芯片、Zynq UltraScale+的IDCODE不止一个

在高端FPGA和SoC平台上,IDCODE读出来的情况会更丰富。比如Zynq UltraScale+这种带着PS(处理器系统)和PL(可编程逻辑)的大芯片,JTAG端口可能分出多条调试通路,扫描到的IDCODE数量和组合会比单纯一颗FPGA复杂。有些器件在特定模式下会暴露出多个IDCODE节点,分别对应处理器子系统、可编程逻辑子系统和相关的调试组件。

更大规模的FPGA,比如UltraScale+的VU9P、VU19P这类采用多die封装、内部通过interposer连接的器件,JTAG链上能看到多个IDCODE。这时候,IDCODE的数量和排列本身也成了一种诊断信息。如果一颗多die芯片本该显示多个IDCODE,实际却只显示了一个,或者显示顺序跟预期不一致,往往意味着某个die的链路没有正常工作,或者interposer的连接有问题。这在用多die器件做设计的场景中是个值得留意的信号,做相关约束之前,先确认扫描到的die数量和型号匹配,能省下后面一大轮排查时间。

6. 扫描失败的排查链路:从报错信息反推硬件问题

6.1 常见报错信息的第一反应对照表

JTAG扫描失败时的报错五花八门,但绝大多数可以归因到硬件连接、电平适配、链路拓扑和设备状态四大类。我整理了最常见的几种:

报错信息或现象最常见的根因
No device found / 找不到设备下载器没识别到目标板,检查VTref、GND、TCK
Could not stop Cortex-M deviceJTAG链上挂了ARM核,但调试口配置有问题
JTAG-DP STICKY ERROR链路时序问题或设备状态异常,先降TCK频率
Invalid IDCODE / 未知设备软件数据库不认该IDCODE,手动指定器件或改用OpenOCD
扫描到全0或全1TDO通路断开、上拉/下拉异常,或信号电平错误

在FPGA+ARM复合板卡上,经常会看到类似“could not stop cortex-m device”的报错。这通常不是FPGA本身的问题,而是链上有ARM内核设备,且ARM侧的调试访问端口没有正确响应。处理思路是先确认链上到底有哪些设备,逐段排除,再决定是要复位ARM内核还是暂时绕过它。

6.2 降低TCK频率,能解决一半以上的疑难杂症

很多人扫描不到设备,第一反应是换下载器、换电脑甚至换板子,其实先降TCK频率试试,能解决一半以上的扫描异常。

默认情况下,Vivado和OpenOCD的TCK频率可能设在10MHz以上。这个频率在芯片原厂评估板上没问题,但到了杜邦线连接的自制板、长排线、或连接器氧化严重的旧板卡上,信号反射和振铃会把JTAG时序弄得面目全非。把频率降到1MHz,相当于给信号一个更宽松的建立保持时间窗口,很多“时好时坏”的扫描问题立刻消失。

OpenOCD里用 adapter_khz 1000 设置1MHz。Vivado里在Hardware Server Settings里可以调整JTAG频率。如果你手上只有普通杜邦线和飞线连接JTAG,建议从一开始就选较低频率,而不是等报错后再折腾。

6.3 全0、全1、数字乱跳:三个方向定位链路问题

读出的IDCODE全是0,通常意味着TDO这条数据通路没有把有效电平传回来。可能是TDO引脚虚焊、连接器接触不良,也可能是TDO在板卡上被下拉到地。读出的IDCODE全是1,则多半是TDO悬空或上拉过强,TAP状态下没有实际数据输出。还有一种情况是IDCODE看起来能读,但数值每次都不一样,或者数值明显“错位”,比如Xilinx的芯片读出来尾部不是0x093,这时优先怀疑TDI/TDO接线顺序接反,或者链上某颗芯片没有正确进入移位状态。

排查这类问题,我建议从下载器那头逐级往目标芯片查。先确认下载器本身的TDI、TDO有没有输出,再量到连接器、到板卡、到FPGA引脚之间的连通性。如果条件允许,可以用一个环回测试:把下载器的TDI直接短接到TDO,如果扫描软件能识别到一个固定的环回IDCODE或者至少不再报链路错误,就说明下载器到电脑这一段没问题,瓶颈在目标板一侧。

遇到疑似JTAG被禁用或芯片被安全锁定导致读不到合法IDCODE的情况,不能靠无限复位解决。部分芯片支持通过安全位禁用JTAG端口,一旦被锁定,扫描链路可能完全无效或者只能读到固定的错误值。这类芯片要恢复调试口,一般需要回到原始烧录流程里解除安全设置,或者走器件手册里规定的恢复通道,不能指望换个软件硬读。

我在实际使用中还有一个习惯:每拿到一块新板卡,扫描出IDCODE后顺手把“板卡编号+IDCODE+型号+软件识别结果+备注”写进一个小数据库里。别小看这个动作,批量返修、BOM核对、工程回溯的时候,它能让你少走很多弯路。最后再分享一个实操技巧:当Vivado或者原厂工具不识别某颗芯片时,别急着放弃,先用OpenOCD这类通用工具把IDCODE硬读出来,再拿着这个值去反查器件手册。很多时候,原厂工具只是数据库版本太老,芯片本身工作完全正常,一个小小的人工匹配就能继续往下推进。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询