Skip to content

FPGA Bitstream Explained

🐪

Version History
DateDescription
Dec 20, 2019Update
Oct 24, 2019Created

Introduction

A bitstream can configure an FPGA. A bitstream includes the descriptions of the hardware logic, routing, and initial values of registers and on-chip memory. The common impression is that a bitstream has vendor-specific format and cannot be reversed. The answer is yes and no. The fact is that the bitstream file is more than the bits to configure an FPGA, it also has certain human-readable fields to describe the contents. In addition, it has a simple assembly-like instruction set to describe the FPGA configuration process. This note is trying to walk through this.

At a high-level, a bitstream file is similar to an executable program, in the sense that it describes everything of a desired functionality. Analogous to the ELF format, a bistream has its own format to describe the contents. Note that, this file format is publicly documented 1. That means you can analyze the contents of a bitstream file. The undocument part is the configuration bits: FPGA vendor does not document the format of the configuration bits, and how they may to hardware resources.

As a normal FPGA user, you mostly do not need to understand neither of these. These understandings are only required if you plan to do bitstream readback, preemption scheduling and so forth.

After reading this note, you will understand that a bitstream file is a sequence of instructions and data. The FPGA has a simple state machine to parse the bitstream and then configure the chip. Part of the bistream file format is public, the mapping between the bitstream configuration bits and the actual physical resource is undocumented.

In a normal flow, Vivado only generates a simple .bit file. When you click “Program Device”, Vivado will use this file to configure your FPGA.

In addition to generating this file, Vivado is capable of generating a bunch other files. You can find a complete coverage in this link. We give a high level summary here. Most of the files have the same content and have similar file size. For instance, the difference between a .rbt and a .bit is that the former one is in ASCII format while the latter is in binary format, but they have the same contents. As for a .bit and a .bin file, the latter does not have some ASCII headers at the beginning of the file.

.ll, the logical link file, is very interesting. It tells you the mapping between user logic and the actual bit offset in the bistream file data section. This file can be used to aid preemption scheduling. However, note that, this file only documents a very small part of the mapping. To the best of my knowledge, I think only the registers, on-chip memory are documented, but the routing information is missing. Thus, this file can help reserve engineer bitstream data section to some extend, but not full of it. Prjxray is an open source project working on cracking everything on 7-series FPGA.

Details

We use .rbt and .bit to demonstrate the file format. Note that they are essentially the same thing, except the former in human-readable ASCII format.

The target board is VCU118, the one used by many cloud vendors.

The following snippt is the first few lines of the .rpt file. The first few lines are human-readable ASCII contents describing some general information about the bitstream. Starting from line 8 is the actual bitstream file contents. Note that the .bin file starts directly from line 8, no general header info is attached. The interesting part is the 1s and 0s. Unless otherwise noted, when we refer to bitstream format, we focus on the 1s and 0s only and omit any general ASICC information headers.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
Xilinx ASCII Bitstream
Created by Bitstream 2018.3 SW Build 2405991 on Thu Dec  6 23:36:41 MST 2018
Design name:    base_mb_wrapper;UserID=0XFFFFFFFF;Version=2018.3
Architecture:   virtexuplus
Part:           xcvu9p-flga2104-2L-e
Date:           Wed Nov 20 04:13:05 2019
Bits:           641272864
11111111111111111111111111111111
11111111111111111111111111111111
11111111111111111111111111111111
...

Note that each line has 32 bits, thus 4 bytes. In Xilinx bistream format, each four bytes is a packet (analogous to CPU instruction). Each packet has certain format, it could be a special header packet, or a normal data packet. The header packet follows a simple assembly-like instruction set to dictate the configuration process. The bitstream file is a sequence of these four bytes packets.

Why it sounds so complicated, a sequence of instructions?! I think the short answer is that configuraing FPGA is not an easy task, and any wrong doings may permanently harm the chip. Natually, the designer would have a on-chip state machine to control the configuration process, not only to control the whole process but also to ensure safety.

Each Xilinx FPGA has an on-chip configuration packet processor. All configuration methods such as JTAG, SelectMAP, ICAP merge into this final narrow bridge to carry out the configuration. The configuration packet processor has many internal registers (similar to x86 RAX, CRn, MSR registers). The bitstream usually interact with one of the registers at a time to do one thing. For a more detailed explanation, check out this blog, and UG570 chapter 9.

To this end, a bitstream consits of three parts:

  • 1) Header packets to prepare the configuration process.
  • 2) The actual configuration bits in a contiguous sequence of data packets. AN write to the FDRI register marks the beginning of this section. The length of this section is described by the packet following the FDRI header packet.
  • 3) Header packets to clean up the configuration process.

The actual configuration bits are the ones determine the FPGA functionality. Note that if you are using an SSI Xilinx device like VCU118, the bitstream format is a bit more complicated. Basically, each die has the above three parts. If an chip has N dies, it will have N above triplet. I have complained about this is not well documented here and here.

I wrote a simple C program to parse the .rbt file and associate a human-reable syntax with each line. I didn’t have a complete coverage of the header packet format. The following snippt shows a parsed .rbt file with header removed. Here, 0xffffffff has no effect, like a NOP. 0x000000bb and 0x11220044 are special bus detect words. 0xaa995566 is another special work marking the synchronization status. The last few lines mark the beginning of the configuration bits section.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
Parsed from base_mb_wrapper.rbt
ffffffff 
ffffffff 
ffffffff 
ffffffff 
ffffffff 
ffffffff 
ffffffff 
ffffffff 
ffffffff 
ffffffff 
ffffffff 
ffffffff 
ffffffff 
ffffffff 
ffffffff 
ffffffff 
000000bb Bus Width Sync
11220044 Bus Width Detect
ffffffff 
ffffffff 
aa995566  SYNC
20000000 
20000000 
30022001 Write to regs 17
00000000 
30020001 Write to regs 16
00000000 
30008001 Write to CMD
00000000 
20000000 
30008001 Write to CMD
00000007 
20000000 
20000000 
30002001 Write to FAR
00000000 
30026001 Write to regs 19
00000000 
30012001 Write to regs 9
38003fe5 Write to regs 1
3001c001 Write to regs 14
00400000 
30018001 Write to IDCODE
04b31093 IDCODE=4b31093
30008001 Write to CMD
00000009 
20000000 
3000c001 Write to regs 6
00000001 
3000a001 Write to regs 5
00000101 
3000c001 Write to regs 6
00000000 
30030001 Write to regs 24
00000000 
20000000 
20000000 
20000000 
20000000 
20000000 
20000000 
20000000 
20000000 
30002001 Write to FAR
00000000 
30008001 Write to CMD
00000001 
20000000 
30004000 Write to FDRI
5065eadc            <- The length of configuration bits, follows a certain format
00000000            <- The first 4 bytes of the configuration bits!

Hope you have learned something.

References

  1. Xilinx UG570
  2. Xilinx bitstream files
  3. Another blog on Xilinx Bitstream Internals
  4. Source code to annotate bitstream

Comments