Core
For the case of the EP4CE6E22C8 model, it's a 34x24 matrix (details here). The routing sections found are 1728 which is close to the double of the number of tiles (34x24 = 816).
Everything I know at the moment is that they are mostly 210 bytes length including the CRC-16.
High level struct¶
Based on the analysis of repettive patterns, the bitstream seems to be structured by columns, in a positional struct. This means that its made of "structs" of configuration stacked. In particular, these patterns occurs on the following positions:
[0, 37, 72, 107, 142, 177, 212, 247, 282, 317, 352, 387, 422, 457, 492, 820, 855, 894, 929, 989, 1024, 1059, 1094, 1129, 1164, 1492, 1527, 1562, 1597, 1632, 1667, 1706, 1727]
So from here, some position will be expressed as cc.ss.bb, which c means the column number, s the section number inside it and b the byte inside it (0-208).
Column routing (work in progress)¶
The smallest step possible is to route a pin to another but carefully choosing both of them. Using Chip Planner Quartus tool, its possible to see how internally routed a desing. Which routing arbitrary pins generate "non-intuitive" routing, some other desings provide a much simpler routing, for example by routing two pins that are in the same column of the fabric.
This allows to identify very specific routing paths.
I've been using pins 68,69 and 110,111 because it just uses a col. Not exactly a col but a C16 interconnect. Let's see it.
Cyclone IV MultiTrack technology is divided in 3 layers of routing:
- Block interconect
- Adjacent blocks (C5): 5 columns length
- Long routing (C16): 16 columns length
As can be appreciated by the name, each layers is used to route signals from closer tiles to far tiles.
In particular, 110 to 68 pins uses 2 C16, which then means the bitstream enables has to:
- Enable pin 110 input net
- Route pin 110 to C16
- Connect to C16 to other C16
- Enable pin 68 as output
- Routing a C16 to the output pin
This is the result of some desings:
/home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed1_1_2.rbf | /home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/single_110_68.rbf
col #0 len=37 differs
(9, [(165, '0x0', '0x1')])
col #27 len=35 differs
(24, [(145, '0x0', '0x8')])
(26, [(139, '0x0', '0x8')])
(29, [(12, '0x0', '0x80')])
col #28 len=35 differs
(1, [(186, '0x0', '0x1')])
(7, [(19, '0x0', '0x80')])
(10, [(2, '0x80', '0x0')])
(15, [(207, '0x0', '0x1')])
(18, [(207, '0x0', '0x1')])
/home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed1_1_2.rbf | /home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/single_110_69.rbf
col #0 len=37 differs
(9, [(165, '0x0', '0x1')])
col #27 len=35 differs
(24, [(145, '0x0', '0x8')])
(26, [(139, '0x0', '0x8')])
(29, [(12, '0x0', '0x80')])
col #28 len=35 differs
(1, [(186, '0x0', '0x1')])
(14, [(7, '0x0', '0x80')])
(15, [(207, '0x0', '0x1')])
(18, [(207, '0x0', '0x1')])
(24, [(2, '0x80', '0x0')])
/home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed1_1_2.rbf | /home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/single_111_68.rbf
col #0 len=37 differs
(9, [(165, '0x0', '0x1')])
col #27 len=35 differs
(1, [(207, '0x0', '0x1')])
(4, [(207, '0x0', '0x1')])
(20, [(201, '0x0', '0x1')])
(24, [(102, '0x0', '0x4')])
(26, [(72, '0x0', '0x4')])
(29, [(14, '0x0', '0x80')])
col #28 len=35 differs
(7, [(19, '0x0', '0x80')])
(10, [(2, '0x80', '0x0'), (19, '0x0', '0x80')])
/home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed1_1_2.rbf | /home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/single_111_69.rbf
col #0 len=37 differs
(9, [(165, '0x0', '0x1')])
col #27 len=35 differs
(1, [(207, '0x0', '0x1')])
(4, [(207, '0x0', '0x1')])
(20, [(201, '0x0', '0x1')])
(24, [(102, '0x0', '0x4')])
(26, [(72, '0x0', '0x4')])
(29, [(14, '0x0', '0x80')])
col #28 len=35 differs
(11, [(7, '0x0', '0x80')])
(14, [(7, '0x0', '0x80')])
(24, [(2, '0x80', '0x0')])
So is believed that pin 110 Input configurations lives on:
col #27
(24, [(145, '0x0', '0x8')])
(26, [(139, '0x0', '0x8')])
(29, [(12, '0x0', '0x80')])
col #28
(1, [(186, '0x0', '0x1')])
(15, [(207, '0x0', '0x1')])
(18, [(207, '0x0', '0x1')])
and pin 111 on:
col #27
(1, [(207, '0x0', '0x1')])
(4, [(207, '0x0', '0x1')])
(20, [(201, '0x0', '0x1')])
(24, [(102, '0x0', '0x4')])
(26, [(72, '0x0', '0x4')])
(29, [(14, '0x0', '0x80')])
Based of experiments with the board, 28.1.186 enables pin 110 as input and 71.20.201 enables pin 111 as input. All the values on sections 24 to 29 are related with C16 routing.
The values as positions meaning are still unknown, fuzzing the values on sections 24 and 29 disables the routing, however setting section 26 full to ones doesnt affect.
Also, 28.11.7 configures pin routing to/from col for pin 68 and 28.10.19 for pin 69.
I/O Routing¶
I've started with the I/O because if the most simple to test and see. Using this verilog module I have collected this changes in the sections:
In order to recognize a pattern, I'm comparing the sections but also the bytes inside the section. For example, this line corresponds to compare 2 different RBF files.
There is a section in first and the last cols that changes every time. Don't forget that middle columns only have few I/O at most, while the side columns contains many of them, this is reflected into the bitstream.
But in general the pattern is identical for all the columns in the middle, sections 10 and 24 at position 2 and 207 contains the bit that enables the corresponding bit.
For the case of assign out = 'b0 there is a extra bit, which is supposed that it inverts the signal for the output pin.
/home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed1_1_2.rbf | /home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed1_1_3.rbf
col #0 len=37 differs
(9, [(147, '0x1', '0x0'), (165, '0x0', '0x1')])
/home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed1_1_2.rbf | /home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed1_1_7.rbf
col #0 len=37 differs
(9, [(25, '0x1', '0x0'), (165, '0x0', '0x1')])
/home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed1_1_2.rbf | /home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed1_1_10.rbf
col #0 len=37 differs
(9, [(4, '0x2', '0x0'), (165, '0x0', '0x1')])
/home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed1_1_2.rbf | /home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed1_1_11.rbf
col #0 len=37 differs
(9, [(165, '0x0', '0x1'), (194, '0x4', '0x0')])
/home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed1_1_2.rbf | /home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed1_1_28.rbf
col #0 len=37 differs
(9, [(13, '0x10', '0x0'), (165, '0x0', '0x1')])
/home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed1_1_2.rbf | /home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed1_1_30.rbf
col #0 len=37 differs
(9, [(132, '0x20', '0x0'), (165, '0x0', '0x1')])
/home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed1_1_2.rbf | /home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed1_1_31.rbf
col #0 len=37 differs
(9, [(97, '0x20', '0x0'), (165, '0x0', '0x1')])
/home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed1_1_2.rbf | /home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed1_1_32.rbf
col #0 len=37 differs
(9, [(165, '0x0', '0x1'), (199, '0x40', '0x0')])
/home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed1_1_2.rbf | /home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed1_1_33.rbf
col #0 len=37 differs
(9, [(165, '0x0', '0x1'), (182, '0x41', '0x1')])
/home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed1_1_2.rbf | /home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed1_1_34.rbf
col #0 len=37 differs
(9, [(129, '0x40', '0x0'), (165, '0x0', '0x1')])
/home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed1_1_2.rbf | /home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed1_1_38.rbf
col #0 len=37 differs
(9, [(165, '0x0', '0x1')])
col #1 len=35 differs
(10, [(2, '0x80', '0x0')])
/home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed1_1_2.rbf | /home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed1_1_39.rbf
col #0 len=37 differs
(9, [(165, '0x0', '0x1')])
col #1 len=35 differs
(24, [(2, '0x80', '0x0')])
/home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed1_1_2.rbf | /home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed1_1_42.rbf
col #0 len=37 differs
(9, [(165, '0x0', '0x1')])
col #4 len=35 differs
(24, [(2, '0x80', '0x0')])
/home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed1_1_2.rbf | /home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed1_1_43.rbf
col #0 len=37 differs
(9, [(165, '0x0', '0x1')])
col #5 len=35 differs
(10, [(2, '0x80', '0x0')])
/home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed1_1_2.rbf | /home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed1_1_44.rbf
col #0 len=37 differs
(9, [(165, '0x0', '0x1')])
col #5 len=35 differs
(24, [(2, '0x80', '0x0')])
/home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed1_1_2.rbf | /home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed1_1_46.rbf
col #0 len=37 differs
(9, [(165, '0x0', '0x1')])
col #8 len=35 differs
(24, [(2, '0x80', '0x0')])
/home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed1_1_2.rbf | /home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed1_1_49.rbf
col #0 len=37 differs
(9, [(165, '0x0', '0x1')])
col #13 len=35 differs
(24, [(2, '0x80', '0x0')])
/home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed0_1_3.rbf | /home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed0_1_7.rbf
col #0 len=37 differs
(8, [(25, '0x0', '0x1'), (147, '0x1', '0x0')])
(9, [(25, '0x1', '0x0'), (147, '0x0', '0x1')])
/home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed0_1_3.rbf | /home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed0_1_10.rbf
col #0 len=37 differs
(8, [(4, '0x0', '0x2'), (147, '0x1', '0x0')])
(9, [(4, '0x2', '0x0'), (147, '0x0', '0x1')])
/home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed0_1_3.rbf | /home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed0_1_11.rbf
col #0 len=37 differs
(8, [(147, '0x1', '0x0'), (194, '0x0', '0x4')])
(9, [(147, '0x0', '0x1'), (194, '0x4', '0x0')])
/home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed0_1_3.rbf | /home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed0_1_28.rbf
col #0 len=37 differs
(8, [(13, '0x0', '0x10'), (147, '0x1', '0x0')])
(9, [(13, '0x10', '0x0'), (147, '0x0', '0x1')])
/home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed0_1_3.rbf | /home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed0_1_30.rbf
col #0 len=37 differs
(8, [(132, '0x0', '0x20'), (147, '0x1', '0x0')])
(9, [(132, '0x20', '0x0'), (147, '0x0', '0x1')])
/home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed0_1_3.rbf | /home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed0_1_31.rbf
col #0 len=37 differs
(8, [(97, '0x0', '0x20'), (147, '0x1', '0x0')])
(9, [(97, '0x20', '0x0'), (147, '0x0', '0x1')])
/home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed0_1_3.rbf | /home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed0_1_32.rbf
col #0 len=37 differs
(8, [(147, '0x1', '0x0'), (199, '0x0', '0x40')])
(9, [(147, '0x0', '0x1'), (199, '0x40', '0x0')])
/home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed0_1_3.rbf | /home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed0_1_33.rbf
col #0 len=37 differs
(8, [(147, '0x1', '0x0'), (182, '0x0', '0x40')])
(9, [(147, '0x0', '0x1'), (182, '0x41', '0x1')])
/home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed0_1_3.rbf | /home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed0_1_34.rbf
col #0 len=37 differs
(8, [(129, '0x0', '0x40'), (147, '0x1', '0x0')])
(9, [(129, '0x40', '0x0'), (147, '0x0', '0x1')])
/home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed0_1_3.rbf | /home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed0_1_38.rbf
col #0 len=37 differs
(8, [(147, '0x1', '0x0')])
(9, [(147, '0x0', '0x1')])
col #1 len=35 differs
(9, [(2, '0x0', '0x80')])
(10, [(2, '0x80', '0x0')])
/home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed0_1_3.rbf | /home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed0_1_39.rbf
col #0 len=37 differs
(8, [(147, '0x1', '0x0')])
(9, [(147, '0x0', '0x1')])
col #1 len=35 differs
(23, [(2, '0x0', '0x80')])
(24, [(2, '0x80', '0x0')])
/home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed0_1_3.rbf | /home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed0_1_42.rbf
col #0 len=37 differs
(8, [(147, '0x1', '0x0')])
(9, [(147, '0x0', '0x1')])
col #4 len=35 differs
(23, [(2, '0x0', '0x80')])
(24, [(2, '0x80', '0x0')])
/home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed0_1_3.rbf | /home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed0_1_43.rbf
col #0 len=37 differs
(8, [(147, '0x1', '0x0')])
(9, [(147, '0x0', '0x1')])
col #5 len=35 differs
(9, [(2, '0x0', '0x80')])
(10, [(2, '0x80', '0x0')])
/home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed0_1_3.rbf | /home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed0_1_44.rbf
col #0 len=37 differs
(8, [(147, '0x1', '0x0')])
(9, [(147, '0x0', '0x1')])
col #5 len=35 differs
(23, [(2, '0x0', '0x80')])
(24, [(2, '0x80', '0x0')])
/home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed0_1_3.rbf | /home/jovyan/work/trasteo/RZ-easyFPGA-A2.2/simple/fixed0_1_46.rbf
col #0 len=37 differs
(8, [(147, '0x1', '0x0')])
(9, [(147, '0x0', '0x1')])
col #8 len=35 differs
(23, [(2, '0x0', '0x80')])
(24, [(2, '0x80', '0x0')])