0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

一文了解FPGA比特流的内部结构

OpenFPGA 来源:OpenFPGA 2024-07-16 18:02 次阅读

比特流是一个常用词汇,用于描述包含FPGA完整内部配置状态的文件,包括布线、逻辑资源和IO设置。大多数现代FPGA都是基于SRAM的,包括Xilinx Spartan和Virtex系列。在FPGA上电或随后的FPGA重新配置期间,比特流从外部诸如闪存这样的非易失性存储器中读取,通过FPGA配置控制器的处理,加载到内部的配置SRAM中。

在有些情况下,设计者需要很好地了解FPGA比特流的内部结构。例如,使用FPGA物理实现工具的参数不能访问自定义的低级比特流、实现复杂的配置回溯方案、通过内部配置端口(ICAP)产生用于FPGA重新配置的短命令序列、读配置状态等。遗憾的是,逆向工程和篡改比特流以非法获取专利设计信息也属于这些使用范畴。

比特流格式

Xilinx FPGA的比特流结构如图1所示。

aa209e0c-375d-11ef-a4c8-92fbcf53809c.png

比特流包括以下组成部分:填充、同步字、用于访问配置寄存器的命令、存储器帧和解同步字。

填充

填充的数据是全0或全1序列,被FPGA配置控制器忽略。填充数据用于非易失性存储器中分离比特流。一般使用全1填充较为方便,因为执行擦除后闪存的状态一般也是全1。

同步字

同步字是一个特殊值(0xAA995566),通知FPGA配置控制器处理后续的比特流数据。

解同步字

解同步字通知FPGA配置控制器比特流的末端位置。解同步字之后,所有的比特流数据被忽略,直到遇到下一个同步字。

命令

命令用于读和写FPGA配置控制器寄存器。每个比特流中出现的一些命令,有的是ID-CODE,用于标识比特流属于哪个FPGA器件。帧地址寄存器(FAR)、帧数据寄存器(FDRI)和无操作(NOOP)将被忽略。

存储器帧

存储器帧是配置Xilinx FPGA的比特流基本单元。帧的大小与具体的FPGA系列有关,系列不同,帧的大小也不同。Virtex 6器件的帧有2592位。每个Virtex 6器件具有的帧数不同,从最小7491(对于LX75T)到最大55548(对于LX550T)。帧用于多个逻辑片、IO、BRAM及其他FPGA的配置。每帧都有一个地址,对应于FPGA配置空间的位置。比特流使用FAR和FDRI命令序列来配置帧。

Virtex 6 FPGA配置用户指南包含足够的关于比特流和访问FPGA配置控制器寄存器命令的文档。然而,关于存储器帧的详细文档不仅对于Xilinx FPGA无法获得,而且对于其他供应商的FPGA也是如此。

Xilinx的BITGEN实用程序

BITGEN是Xilinx的实用程序,利用本地电路描述(NCD)格式的布局布线后文件,创建用于FPGA配置的比特流。BITGEN是一个高度可配置的工具,具有100多个命令行选项(在命令行工具用户指南中描述)。有些选项用于确定比特流输出格式、启用压缩处理减少比特流大小、提高FPGA配置速度、使用CRC来确保数据完整性、对比特流加密等。

示例

以下示例用于根据差异部分配置的短比特流, 通过脚本语言描述比特流命令。

#!/devl/perl/bin/perl

useSwitch;

#-----------------------------------------------------------------------------
#Copyright(C)2011OutputLogic.com
#Thissourcefilemaybeusedanddistributedwithoutrestriction
#providedthatthiscopyrightstatementisnotremovedfromthefile
#andthatanyderivativeworkcontainstheoriginalcopyrightnotice
#andtheassociateddisclaimer.
#
#THISSOURCEFILEISPROVIDED"ASIS"ANDWITHOUTANYEXPRESS
#ORIMPLIEDWARRANTIES,INCLUDING,WITHOUTLIMITATION,THEIMPLIED
#WARRANTIESOFMERCHANTIBILITYANDFITNESSFORAPARTICULARPURPOSE.
#-----------------------------------------------------------------------------
#
#AscripttoparseXilinxFPGAbitstreamin.RBTformat
#
if($#ARGV< 0)
{
    die "Usage: xilinx_bitstream_parser 
";
}

$verbose=2;

open(RBT_FILE,"<$ARGV[0]")          || die "Error: can't open $ARGV[0] for input
";

# Bus OP codes
$opcode{"00"} = "no op";
$opcode{"01"} = "read";
$opcode{"10"} = "write";
$opcode{"11"} = "decrypt";

# Regster Addresses
$reg{"00000"} = "CRC ";
$reg{"00001"} = "FAR ";
$reg{"00010"} = "FDRI";
$reg{"00011"} = "FDRO";
$reg{"00100"} = "CMD ";
$reg{"00101"} = "CTL ";
$reg{"00110"} = "MASK";
$reg{"00111"} = "STAT";
$reg{"01000"} = "LOUT";
$reg{"01001"} = "COR ";
$reg{"01010"} = "MFWR";
$reg{"01011"} = "CBC ";
$reg{"01100"} = "ID  ";
$reg{"01101"} = "AXSS";
$reg{"01110"} = "COR1";
$reg{"01111"} = "CSOB";
$reg{"10000"} = "WBSTAR";
$reg{"10001"} = "TIMER";
$reg{"10010"} = "RBCRC0";
$reg{"10011"} = "RBCRC1";
$reg{"10100"} = "RBCRC2";
$reg{"10101"} = "EFAR";
$reg{"10110"} = "BOOTSTS";
$reg{"10111"} = "TESTMODE";
$reg{"11000"} = "CTL1";


# Configuration Commands
$command{"00000"} = "NULL";
$command{"00001"} = "WCFG";
$command{"00010"} = "MFW";
$command{"00011"} = "LFRM";
$command{"00100"} = "RCFG";
$command{"00101"} = "START";
$command{"00110"} = "RCAP";
$command{"00111"} = "RCRC";
$command{"01000"} = "AGHIGH";
$command{"01001"} = "SWITCH";
$command{"01010"} = "GRESTORE";
$command{"01011"} = "SHUTDOWN";
$command{"01100"} = "GCAPTURE";
$command{"01101"} = "DESYNCH";
$command{"01110"} = "DRTEST";
$command{"01111"} = "IPROG";
$command{"10000"} = "CRCC";

$fa = -1;
$last_fa = -1;
$in_LOUT = 0;
@LOUT_wordcnt = ();

while ()
{
$type="";
$op="";
$reg="";
chop;
nextif(!/^[01]/);

if(/^10101010100110010101010101100110/){
$type="Syncword";
}
elsif(/^11111111111111111111111111111111/){
$type="Dummyword";
}
elsif(/^00000000000000000000000010111011/){
$type="BusWidthword";
}
elsif(/^00010001001000100000000001000100/){
$type="8/16/32BusWidth";
}
elsif(/^001/){
$type="Type1";
}
elsif(/^010/){
$type="Type2";
}
elsif(/^00000000000000000000000000000000/){
$type="NOOP";
$wordcnt=0;
}
else{
if(($registereq"FDRI")||($registereq"FDRO")||($last_commandeq"LFRM")){
$type="PartialCRCword";
}else{
$type="TypeUnknown";
}
}

if($typeeq"Type1"||$typeeq"Type2"){
$s=substr($_,3,2);
if($opcode{$s}ne"")
{
$op=$opcode{$s};
}
else
{
$op="Unknown";
}
}

if($typeeq"Type1"){
$s=substr($_,14,5);
if($reg{$s}ne""){
$register=$reg{$s};
}
else{
$register="Unknown";
}
$wordcnt=&bin2dec(substr($_,21,11));
}

if($typeeq"Type2"){
$wordcnt=&bin2dec(substr($_,5,27));
}

$text="$type";
if($opeq"read")
{
$text.="$op"."$wordcntwordsfrom"."$register";
}
elsif(($opeq"write")||($opeq"decrypt"))
{
$text.="$op"."$wordcntwordsto"."$register";
}
elsif($opeq"noop")
{
$text.="NOOP";
}
printf("%10s%s
",&bin2hex($_),$text);


#Alittlehacksowecanseethenextstreamalso
if(($registereq"LOUT")&&($wordcnt>1))
{
$in_LOUT++;
push@LOUT_wordcnt,$wordcnt;
$wordcnt=0;
}


#startprintingouteverything
for($i=0;$i<$wordcnt && (($op eq "write") || ($op eq "decrypt") || ($op eq "read")) && ($_ = );$i++)
{
chop;

if(($opeq"write")&&($registereq"FAR"))
{
$fa=$_;
}

if(($registereq"FDRI")||($registereq"FDRO"))
{
#printf("%s%10s
","dataword".$i,$_);

#don'tprintallframewords

if($i==0)
{
printf("%s%d...%d
","datawords",$i,$wordcnt-1);
}
}
elsif($registereq"LOUT")
{
$this_fa=&bin2dec($_);
$BlkType=&bin2dec(substr($_,8,3));
$TopBot=(&bin2dec(substr($_,11,1))==0)?"Top":"Bot";
$MajRow=&bin2dec(substr($_,12,5));
$MajCol=&bin2dec(substr($_,17,8));
$MinCol=&bin2dec(substr($_,25,7));

printf("%10s%s[Block%d%sRow%dCol%dMinor%d]
",&bin2hex($_),"FrameAddress",$BlkType,$TopBot,$MajRow,$MajCol,$MinCol);


if($this_fa< $last_fa) {
             printf ("ERROR: Frame Address going down (%d < %d)?
", $this_fa, $last_fa);
          }
          $last_fa = $this_fa;
       }
        elsif ($register eq "FAR ") 
        {
            $BlkType = &bin2dec(substr($_,8,3));
            $TopBot  = (&bin2dec(substr($_,11,1)) == 0) ? "Top" : "Bot";
            $MajRow  = &bin2dec(substr($_,12,5));
            $MajCol  = &bin2dec(substr($_,17,8));
            $MinCol  = &bin2dec(substr($_,25,7));
           
            printf ("%10s %s [Block %d %s Row %d Col %d Minor %d] 
", &bin2hex($_) , $register . " data word " . $i, $BlkType, $TopBot, $MajRow, $MajCol, $MinCol);            
            
        }
        elsif ($register ne "CMD ") 
        {
            printf ("%10s %s
", &bin2hex($_) , $register . " data word " . $i);
            
        } 
        else 
        {
            $s = substr($_,27,5);
         
            if ($command{$s} ne "") 
            {
                $last_command = $command{$s};
             printf ("%10s %s
", &bin2hex($_), $command{$s} . " command",  );
         }
            else
            {
             printf ("%10s %s
", &bin2hex($_), "Unknown command" );
         }
        }
    }
} # while


close(RBT_FILE);


sub bin2dec
{
    local($num) = @_;
    $retval = 0;
    while ($num ne "")
    {
        $retval = $retval * 2;
        if (substr($num,0, 1) eq "1") 
        {
            $retval++;
     }
        $num = substr($num,1);
    }
    return $retval;
}


# convert 32-digit bin number to hex
sub bin2hex
{
    local($num) = @_;

    my $str_hex = "";
    
    for ($i=0; $i<8; $i++) 
    {
        # left to right
        my $chunk = substr($num, 4 * $i ,4); 

        my $retval = "0";

        switch ($chunk) 
        {
         case "0000" { $retval = "0" }
         case "0001" { $retval = "1" }        
         case "0010" { $retval = "2" }
         case "0011" { $retval = "3" }        
         case "0100" { $retval = "4" }
         case "0101" { $retval = "5" }        
         case "0110" { $retval = "6" }
         case "0111" { $retval = "7" }        
         case "1000" { $retval = "8" }
         case "1001" { $retval = "9" }        
         case "1010" { $retval = "A" }
         case "1011" { $retval = "B" }        
         case "1100" { $retval = "C" }
         case "1101" { $retval = "D" }        
         case "1110" { $retval = "E" }
         case "1111" { $retval = "F" }        
        }

      #  print $chunk. " : " . $retval . "
";

        $str_hex .= $retval;
    }
    
  #  print $str_hex;    
    return $str_hex;
}

关于脚本的使用,可以查看《Verilog数字系统基础设计-CRC》。

仔细观察比特流,能区分出同步和解同步命令、属于Virtex-6 LX240T FPGA的IDCODE,以及两个405个和243个字的帧。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • FPGA
    +关注

    关注

    1620

    文章

    21493

    浏览量

    598366
  • 控制器
    +关注

    关注

    112

    文章

    15837

    浏览量

    174874
  • 比特流
    +关注

    关注

    0

    文章

    10

    浏览量

    8062
  • Vivado
    +关注

    关注

    19

    文章

    792

    浏览量

    65744

原文标题:【Vivado那些事】简谈FPGA比特流结构

文章出处:【微信号:Open_FPGA,微信公众号:OpenFPGA】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    了解FPGA比特流结构

    比特流个常用词汇,用于描述包含FPGA完整内部配置状态的文件,包括布线、逻辑资源和IO设置。大多数现代FPGA都是基于SRAM的,包括X
    发表于 11-30 10:59 959次阅读

    fpga内部主要结构及其功能分析(Kintex-7FPGA内部结构

    Kintex-7 FPGA内部结构相比传统FPGA内部结构嵌入了DSP48E1,PCIE,GTX,XADC,高速IO口等单元,大大提升了FPGA
    发表于 08-24 09:26 1816次阅读
    <b class='flag-5'>fpga</b><b class='flag-5'>内部</b>主要<b class='flag-5'>结构</b>及其功能分析(Kintex-7<b class='flag-5'>FPGA</b><b class='flag-5'>内部结构</b>)

    无法生成比特流

    你好,我使用Vivado 2017.4;当我运行Synthesis和Implementation时,切似乎都可以。但是,当我想生成比特流文件时,没有任何错误消息发生。.runs / impl_l
    发表于 11-09 11:37

    如何使用IMPACT在FPGA xilinx中下载比特流

    你好,请有人解释我如何使用IMPACT在FPGA xilinx中下载比特流先谢谢你以上来自于谷歌翻译以下为原文hello,please can someone explain me how
    发表于 01-15 10:08

    中途向ICAP中止写入部分比特流

    嗨,我正在尝试部分自我重新配置。想法是通过介质将部分比特流发送到FPGAFPGA接收它(在多个块中)并将比特流写入ICAP。当连接发生时,我的FP
    发表于 02-14 09:40

    怎么在我的比特流中攻击BRAM

    嗨,我有个应用程序,我希望在下载到FPGA之前使用类似于data2mem的工具来在FPGA比特流中破解块内存内容。FPGA可以是Virte
    发表于 03-19 12:44

    比特流是什么

    `请问比特流是什么?`
    发表于 08-23 16:24

    怎么为FPGA生成了比特流

    XPS中设计了您的硬件平台,最终为FPGA生成了比特流。”这是真实的,我就是这样。现在它说,“......你将硬件平台描述导出到软件开发套件(SDK)。”手册说要遵循以下步骤:1.在PlanAhead
    发表于 03-23 09:19

    如何使用Vivado生成特定的部分比特流

    Mul7.穆添加8. Mul Sub9. Mul Mul现在我希望为上述任何种组合提供完整的比特流(比如Add Add)。并且我希望部分比特流用于所选择的组合,即添加用于部分区域1和1。 2,Sub
    发表于 05-05 09:42

    如何使用GZip的比特流完成重新配置?

    FPGA将始终首先引导未压缩的黄金比特流,这将决定下个引导哪个比特流。理想情况下,黄金比特流中的MicroBlaze可以从闪存读取压缩
    发表于 05-29 17:12

    请问如何在没有静态路由的情况下生成部分比特流

    reconfig。模块加载在可重新配置的插槽内,个带有移位 - 右侧模块加载在可重新配置的插槽内)。部分设计正常工作,我能够通过PCAP接口加载FPGA中的部分比特流。此外,我解码了左移部分
    发表于 06-04 08:52

    是否需要在flash上​​切换黄金比特流和多重比特流的位置?

    嗨专家, 我正在使用spartan-6 FPGA进行多重启动实验。我发现位文件位于ug380上,如下图所示。黄金比特流位于闪存的下部块上,多重引导比特流位于闪存的较高块上。 因此,如果我想使用保护区
    发表于 06-09 17:43

    匹配位置对比特流随机性的影响研究

    本文阐述了IP 报文标识字段比特流随机性的评价标准,通过对大量实测报文进行统计分析证明了比特流的匹配位置对随机测度值有定影响。结果表明,标识字段比特流随机测度值
    发表于 08-04 08:20 19次下载

    Zynq开发板FPGA比特流文件下载方式

    Zynq开发板FPGA比特流文件可以通过三种途径下载: 1. 利用SDK生成的FSBL.elf文件自动加载FPGA比特流配置文件,将比特流
    发表于 02-08 15:20 1058次阅读

    使用加密保护7系列FPGA比特流

    电子发烧友网站提供《使用加密保护7系列FPGA比特流.pdf》资料免费下载
    发表于 09-13 15:31 0次下载
    使用加密保护7系列<b class='flag-5'>FPGA</b><b class='flag-5'>比特流</b>