用过单片机的朋友都知道,单片机芯片内部都有一串序列号,比如STM32,称之为Unique device ID,是一个96Bit的只读数据。
和单片机一样,FPGA芯片内部同样也有ID,具有不可修改的属性。以常用的Xilinx和Altera为例,Altera称之为Chip ID,Xilinx FPGA称之为Device DNA。
应用场景
FPGA的DNA我们一般的使用场景是用于用户逻辑加密。
一般来说,用户在逻辑上可以通过特定的接口把这个Device DNA读取出来,经过一系列加密算法之后和预先在外部Flash存储的一串加密后的字节串做比较,这个flash存储的加密后的字节串也是由该DNA经过加密后得到,FPGA加载程序后可以先从flash读出该段字节做比较,如果相同,则让FPGA启动相应的逻辑,如不同,则代表该FPGA没有经过用户授权,用户逻辑上可以关闭FPGA的逻辑功能甚至可以通过一些手段让硬件损坏。
Xilinx的FPGA芯片,在7系列和7系列之前的产品,DNA是一个57Bit的数据,而在7系列之后,如Ultraslace等新型号,DNA是96Bit。如何获取Xilinx FPGA的Device DNA呢,下面我从JTAG和调用源语两个方法说明,并开放核心代码供大家参考。
方法1:通过JTAG读取
ISE环境,以14.7版本为例,将下载器连接到FPGA芯片之后,使用iMPACT软件,在已经连接的芯片上右键选择Read Device DNA
,可以读出芯片的DNA。
vivado环境下,使用自带的Hardware Manager,连接到芯片之后,在REGISTER->EFUSE->DNA_PORT
,可以看到读取的DNA寄存器的值。
方法2:调用原语读取
通过我们需要在程序读取出芯片的DNA,可以通过调用DNA_PORT原语的方式来读取芯片的DNA。原语的例化模板,可以在ISE或Vivado自带的代码模板中找到:ISE中的代码模板
Vivado中的代码模板
Vivado下UltraScale系列的DNA_PORT2原语模板
DNA_PORT原语的使用
关于DNA_PORT原语的介绍和使用,可以查看Xilinx官方文档,
UG470_7Series_Config
https://www.xilinx.com/content/dam/xilinx/support/documents/user_guides/ug470_7Series_Config.pdf
7系列及其之前的FPGA芯片,DNA_PORT原语:
DNA_PORT #( .SIM_DNA_VALUE(57'h000000000000000) // Specifies the Pre-programmed factory ID value )DNA_PORT_inst ( .DOUT(DOUT), // 1-bit output: DNA output data .CLK(CLK), // 1-bit input: Clock input .DIN(DIN), // 1-bit input: User data input pin .READ(READ), // 1-bit input: Active high load DNA, active low read input .SHIFT(SHIFT) // 1-bit input: Active high shift enable input );
7系列之后Ultraslace系列的FPGA,使用DNA_PORT2原语:
DNA_PORTE2 #( .SIM_DNA_VALUE(96'h000000000000000000000000) // Specifies a sample 96-bit DNA value for simulation )DNA_PORTE2_inst ( .DOUT(DOUT), // 1-bit output: DNA output data .CLK(CLK), // 1-bit input: Clock input .DIN(DIN), // 1-bit input: User data input pin .READ(READ), // 1-bit input: Active-High load DNA, active-Low read input .SHIFT(SHIFT) // 1-bit input: Active-High shift enable input );
操作说明
先拉高READ信号,加载DNA寄存器,然后给出SHIFT拉高使能信号,DOUT串口输出DNA值,57个clk之后,DNA输出完毕,SHIFT拉低取消使能。
驱动代码:
/*************************************************************** * Copyright(C), 2010-2022, YOUR CORP/INC/COMPANY/LTD/LIMITED. * ModuleName : get_dna.v * Date : 2022年5月22日 * Time : 11:06:00 * Author : wcc149 * Function : XC7A75T获取DNA芯片ID * Version : v1.0 * Version | Modify * ---------------------------------- * v1.0 ..... ***************************************************************/ module get_dna( //inputs input clk, input rst_n, //Outputs output reg [56:0] dna, output reg dna_vld ); localparam S0_IDLE = 4'd0; localparam S1_LOAD = 4'd1; localparam S2_SHIFT = 4'd2; localparam S3_FINSIH = 4'd3; reg [7:0] cnt_bit; reg [56:0] dna_buf; reg [3:0] fsm; reg load; reg shift; always @ (posedge clk) begin if(!rst_n) begin cnt_bit <= 0; fsm <= S0_IDLE; load <= 0; shift <= 0; dna <= 0; dna_vld <= 0; end else begin case (fsm) S0_IDLE: begin if(cnt_bit != 10)//上电等待10个clk cnt_bit <= cnt_bit + 1; else begin cnt_bit <= 0; fsm <= S1_LOAD; load <= 0; shift <= 0; dna <= 0; dna_vld <= 0; end end S1_LOAD:begin if(cnt_bit != 5) begin//load信号维持5个clk cnt_bit <= cnt_bit + 1; load <= 1; end else begin cnt_bit <= 0; load <= 0; fsm <= S2_SHIFT; end end S2_SHIFT: begin // if(cnt_bit != 56) begin //Spartan-6 if(cnt_bit != 57) begin //Artix-7 cnt_bit <= cnt_bit + 1; shift <= 1; end else begin shift <= 0; fsm <= S3_FINSIH; cnt_bit <= 0; dna <= dna_buf; end end S3_FINSIH: begin cnt_bit <= 0; dna <= dna; dna_vld <= 1; fsm <= S3_FINSIH; end endcase end end //dout在上升沿变化,在下降沿采样 always @ (negedge clk) begin if(!rst_n) dna_buf <= 'h0; else if(fsm == S2_SHIFT) dna_buf <= dna_buf << 1 | dout; else dna_buf <= 'h0; end DNA_PORT #( .SIM_DNA_VALUE(57'h123456789ABCDEF) // Specifies the Pre-programmed factory ID value )get_xc6slx9_dna( //Inputs .CLK(clk), // 1-bit input: Clock input .DIN(1'b0), // 1-bit input: User data input pin .READ(load), // 1-bit input: Active high load DNA, active low read input .SHIFT(shift), // 1-bit input: Active high shift enable input //Outputs .DOUT(dout) // 1-bit output: DNA output data ); endmodule
仿真波形:
实际运行时,逻辑分析仪抓的波形:
和JTAG读取出的一致:
注意
ISE 14.7环境下,使用下载器JTAG方式读取出的Spartan-6芯片的DNA,可能并不准确,我的两块Spartan-6开发板,一块XC6SLX9的开发板,使用下载器读出的是DNA全为1,但是使用原语方式读取出是正确的。
XC6SLX9使用JTAG读取的DNA
XC6SLX9使用原语方式读取的
而另一块XC6SLX16开发板,使用下载器和原语方式读取出的DNA是一致的。