Bitstream structure — XC9500
On a high level, the whole bitstream is split into “areas”. Each FB of the device corresponds two areas, one of which contains the UIM wire-AND configuration, and the other (main area) contains everything else.
The main area of a FB is made of 72 “rows”. Each row is made of 15 “columns”. Each column is made of 6 or 8 bits: columns 0-8 are made of 8 bits, while columns 9-14 are made of 6 bits.
The low 6 bits of every column are used to store product term masks, and the high 2 bits of columns 0-8 are used to store everything else.
The UIM wire-AND area of a FB is, in turn, made of “subareas”, one for each FB of the device. Each subarea is in turn made of 18 rows. Each row is made of 5 columns. Column 0 is made of 8 bits, while columns 1-4 are made of 7 bits, making for 36 total bits per row.
When programmed or read via JTAG, the bitstream is transmitted as bytes, which are 6-8 bits long. Each byte of the bitstream has its address. Not all addresses are valid, and valid addresses are not contiguous. Address is 17 bits long, and is split to several fields:
bits 13-16: FB index
bit 12: area kind
0: main FB config
1: UIM wire-AND config
for main FB config area:
bits 5-11: row
bits 3-4: column / 5
bits 0-2: column % 5
for UIM wire-AND config area:
bits 8-11: subarea (source FB index)
bits 3-7: row
bits 0-2: column
The unprogrammed state of a bit on XC9500 is 1
.
The programmed state is 0
. Thus, whenever a boolean fuse is mentioned
in the documentation, the “true” value is actually represented as 0
in the bitstream. This includes the USERCODE bits.
JED format mapping
In the JED format, all fuses of the device are simply concatenated in order, skipping over invalid addresses. The bytes are not padded to 8 bits, but have their native size. Thus, converting from JED fuse index to device address involves some complex calculations:
main_row_bits = 8 * 9 + 6 * 6
uim_row_bits = 8 + 7 * 4
main_area_bits = main_row_bits * 72
uim_subarea_bits = uim_row_bits * 18
uim_area_bits = uim_subarea_bits * device.num_fbs
fb_bits = main_area_bits + uim_area_bits
total_bits = fb_bits * device.num_fbs
def jed_to_jtag(fuse):
fb = fuse // fb_bits
fuse %= fb_bits
if fuse < main_area_bits:
row = fuse // main_row_bits
fuse %= main_row_bits
if fuse < 8 * 9:
column = fuse // 8
bit = fuse % 8
else:
fuse -= 8 * 9
column = 9 + fuse // 6
bit = fuse % 6
return (
fb << 13 |
0 << 12 |
row << 5 |
(column // 5) << 3 |
(column % 5)
), bit
else:
fuse -= main_area_bits
subarea = fuse // uim_subarea_bits
fuse %= uim_subarea_bits
row = fuse // uim_row_bits
fuse %= uim_row_bits
if fuse < 8:
column = 0
bit = fuse
else:
fuse -= 8
column = 1 + fuse // 7
bit = fuse % 7
return (
fb << 13 |
1 << 12 |
subarea << 8 |
row << 3 |
column
), bit
def jtag_to_jed(addr, bit):
fb = addr >> 13 & 0xf
assert fb < device.num_fbs
if addr & (1 << 12):
row = addr >> 5 & 0x7f
assert row < 72
col_hi = addr >> 3 & 3
assert col_hi < 3
col_lo = addr & 7
assert col_lo < 5
column = col_hi * 5 + col_lo
if column < 9:
cfuse = column * 8 + bit
else:
cfuse = 8 * 8 + (column - 9) * 6 + bit
return fb * fb_bits + row * main_row_bits + cfuse
else:
subarea = addr >> 8 & 0xf
assert subarea < device.num_fbs
row = addr >> 3 & 0x1f
assert row < 18
column = addr & 7
assert column < 5
if column == 0:
cfuse = bit
else:
cfuse = 8 + (column - 1) * 7 + bit
return fb * fb_bits + main_area_bits + subarea * uim_subarea_bits + row * uim_row_bits + cfuse
Fuses — product terms
The product term masks are stored in bits 0-5 of every column and every row of the main area. The formulas are as follows:
FB[i].MC[j].PT[k].IM[l].P
is stored at:row:
l * 2 + 1
column:
k + (j % 3) * 5
bit:
j // 3
FB[i].MC[j].PT[k].IM[l].N
is stored at:row:
l * 2
column:
k + (j % 3) * 5
bit:
j // 3
Fuses — macrocells
Per-MC config fuses (that are not product term masks) are stored in bits 6-7 of columns 0-8 of rows 12-54 of the main area. The formulas are as follows:
row: corresponds to fuse function
column:
mc_idx % 9
bit:
6 + mc_idx // 9
Row | Bit |
---|---|
12 | PT[0].ALLOC[0] |
13 | PT[0].ALLOC[1] |
14 | PT[1].ALLOC[0] |
15 | PT[1].ALLOC[1] |
16 | PT[2].ALLOC[0] |
17 | PT[2].ALLOC[1] |
18 | PT[3].ALLOC[0] |
19 | PT[3].ALLOC[1] |
20 | PT[4].ALLOC[0] |
21 | PT[4].ALLOC[1] |
22 | ~INV |
23 | IMPORT_UP_ALLOC |
24 | IMPORT_DOWN_ALLOC |
25 | EXPORT_CHAIN_DIR |
26 | ~SUM_HP |
27 | IOB_OE_MUX[0] |
28 | IOB_OE_MUX[1] |
29 | OE_MUX[0] |
30 | OE_MUX[1] |
31 | OE_MUX[2] |
32 | - |
33 | - |
34 | - |
35 | OUT_MUX |
36 | CLK_MUX[0] |
37 | CLK_MUX[1] |
38 | - |
39 | - |
40 | REG_MODE |
41 | RST_MUX |
42 | SET_MUX |
43 | ~REG_INIT |
44 | UIM_OE_MUX[0] |
45 | UIM_OE_MUX[1] |
46 | ~UIM_OUT_INV |
47 | - |
48 | ~IOB_GND |
49 | IOB_SLEW |
50 | ~PT[0].HP |
51 | ~PT[1].HP |
52 | ~PT[2].HP |
53 | ~PT[3].HP |
54 | ~PT[4].HP |
PT[0].ALLOC | 13 | 12 |
---|---|---|
NONE | 1 | 1 |
SUM | 1 | 0 |
EXPORT | 0 | 1 |
SPECIAL | 0 | 0 |
PT[1].ALLOC | 15 | 14 |
---|---|---|
NONE | 1 | 1 |
SUM | 1 | 0 |
EXPORT | 0 | 1 |
SPECIAL | 0 | 0 |
PT[2].ALLOC | 17 | 16 |
---|---|---|
NONE | 1 | 1 |
SUM | 1 | 0 |
EXPORT | 0 | 1 |
SPECIAL | 0 | 0 |
PT[3].ALLOC | 19 | 18 |
---|---|---|
NONE | 1 | 1 |
SUM | 1 | 0 |
EXPORT | 0 | 1 |
SPECIAL | 0 | 0 |
PT[4].ALLOC | 21 | 20 |
---|---|---|
NONE | 1 | 1 |
SUM | 1 | 0 |
EXPORT | 0 | 1 |
SPECIAL | 0 | 0 |
INV | 22 |
---|---|
Inverted | ~[0] |
IMPORT_UP_ALLOC | 23 |
---|---|
EXPORT | 1 |
SUM | 0 |
IMPORT_DOWN_ALLOC | 24 |
---|---|
EXPORT | 1 |
SUM | 0 |
EXPORT_CHAIN_DIR | 25 |
---|---|
UP | 1 |
DOWN | 0 |
SUM_HP | 26 |
---|---|
Inverted | ~[0] |
IOB_OE_MUX | 28 | 27 |
---|---|---|
GND | 1 | 1 |
OE_MUX | 1 | 0 |
VCC | 0 | 1 |
OE_MUX | 31 | 30 | 29 |
---|---|---|---|
PT | 1 | 1 | 1 |
FOE0 | 1 | 1 | 0 |
FOE1 | 1 | 0 | 1 |
FOE2 | 1 | 0 | 0 |
FOE3 | 0 | 1 | 1 |
OUT_MUX | 35 |
---|---|
FF | 1 |
COMB | 0 |
CLK_MUX | 37 | 36 |
---|---|---|
FCLK1 | 1 | 1 |
FCLK2 | 1 | 0 |
FCLK0 | 0 | 1 |
PT | 0 | 0 |
REG_MODE | 40 |
---|---|
DFF | 1 |
TFF | 0 |
RST_MUX | 41 |
---|---|
PT | 1 |
FSR | 0 |
SET_MUX | 42 |
---|---|
PT | 1 |
FSR | 0 |
REG_INIT | 43 |
---|---|
Inverted | ~[0] |
UIM_OE_MUX | 45 | 44 |
---|---|---|
OE_MUX | 1 | 1 |
GND | 1 | 0 |
VCC | 0 | 1 |
UIM_OUT_INV | 46 |
---|---|
Inverted | ~[0] |
IOB_GND | 48 |
---|---|
Inverted | ~[0] |
IOB_SLEW | 49 |
---|---|
SLOW | 1 |
FAST | 0 |
PT[0].HP | 50 |
---|---|
Inverted | ~[0] |
PT[1].HP | 51 |
---|---|
Inverted | ~[0] |
PT[2].HP | 52 |
---|---|
Inverted | ~[0] |
PT[3].HP | 53 |
---|---|
Inverted | ~[0] |
PT[4].HP | 54 |
---|---|
Inverted | ~[0] |
Fuses — FB inputs
The FB input mux configuraton is stored in rows 55-66, columns 0-8, bits 6-7. The exact bit assignments are irregular and should be obtained from the database.
Fuses — per-FB bits and globals
Per-FB bits are stored in rows 67-68, columns 0-8, bits 6-7. The bits are (row, bit, column):
Row | Bit, column | |||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
6 | 7 | |||||||||||||||||
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | |
11 | - | - | - | X | - | - | - | - | - | - | - | - | - | - | - | - | - | - |
67 | X | X | - | - | - | - | - | - | - | - | - | - | - | - | - | - | - | - |
68 | X | - | - | X | - | - | X | - | - | - | - | - | - | - | - | - | - | - |
READ_PROT_A | [11, 6, 3] |
---|---|
Inverted | ~[0] |
ENABLE | [67, 6, 0] |
---|---|
Inverted | ~[0] |
EXPORT_ENABLE | [67, 6, 1] |
---|---|
Inverted | ~[0] |
WRITE_PROT | [68, 6, 0] |
---|---|
Inverted | ~[0] |
READ_PROT_B | [68, 6, 3] |
---|---|
Inverted | ~[0] |
PULLUP_DISABLE | [68, 6, 6] |
---|---|
Inverted | ~[0] |
Global bits are stored in rows (0, 3, 4, 6, 7), columns 0-8, bits 6-7 of FB 0. The bits are (fb, row, bit, column):
FB | Row | Bit, column | |||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
6 | 7 | ||||||||||||||||||
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | ||
0 | 0 | - | X | X | X | X | X | X | X | X | - | - | - | - | - | - | - | - | - |
0 | 3 | - | - | X | X | X | XX | XX | X | X | - | - | - | - | - | - | - | - | - |
0 | 4 | - | - | X | X | X | XX | XX | X | X | - | - | - | - | - | - | - | - | - |
0 | 6 | X | X | X | X | X | X | X | X | - | X | X | X | X | X | X | X | X | - |
0 | 7 | X | X | X | X | X | X | X | X | - | X | X | X | X | X | X | X | X | - |
FSR_INV | [0, 0, 6, 1] |
---|---|
Inverted | ~[0] |
FCLK0_INV | [0, 0, 6, 2] |
---|---|
Inverted | ~[0] |
FCLK1_INV | [0, 0, 6, 3] |
---|---|
Inverted | ~[0] |
FCLK2_INV | [0, 0, 6, 4] |
---|---|
Inverted | ~[0] |
FOE0_INV | [0, 0, 6, 5] |
---|---|
Inverted | ~[0] |
FOE1_INV | [0, 0, 6, 6] |
---|---|
Inverted | ~[0] |
FOE2_INV | [0, 0, 6, 7] |
---|---|
Inverted | ~[0] |
FOE3_INV | [0, 0, 6, 8] |
---|---|
Inverted | ~[0] |
FCLK0_MUX | [0, 4, 6, 2] | [0, 3, 6, 2] |
---|---|---|
NONE | 1 | 1 |
GCLK0 | 1 | 0 |
GCLK1 | 0 | 1 |
FCLK1_MUX | [0, 4, 6, 3] | [0, 3, 6, 3] |
---|---|---|
NONE | 1 | 1 |
GCLK1 | 1 | 0 |
GCLK2 | 0 | 1 |
FCLK2_MUX | [0, 4, 6, 4] | [0, 3, 6, 4] |
---|---|---|
NONE | 1 | 1 |
GCLK2 | 1 | 0 |
GCLK0 | 0 | 1 |
FOE0_MUX.LARGE | [0, 4, 6, 5] | [0, 3, 6, 5] |
---|---|---|
NONE | 1 | 1 |
GOE0 | 1 | 0 |
GOE1 | 0 | 1 |
FOE0_MUX.SMALL | [0, 4, 6, 5] | [0, 3, 6, 5] |
---|---|---|
NONE | 1 | 1 |
GOE0 | 1 | 0 |
GOE1 | 0 | 1 |
FOE1_MUX.LARGE | [0, 4, 6, 6] | [0, 3, 6, 6] |
---|---|---|
NONE | 1 | 1 |
GOE1 | 1 | 0 |
GOE2 | 0 | 1 |
FOE1_MUX.SMALL | [0, 4, 6, 6] | [0, 3, 6, 6] |
---|---|---|
NONE | 1 | 1 |
GOE1 | 1 | 0 |
GOE0 | 0 | 1 |
FOE2_MUX.LARGE | [0, 4, 6, 7] | [0, 3, 6, 7] |
---|---|---|
NONE | 1 | 1 |
GOE2 | 1 | 0 |
GOE3 | 0 | 1 |
FOE3_MUX.LARGE | [0, 4, 6, 8] | [0, 3, 6, 8] |
---|---|---|
NONE | 1 | 1 |
GOE3 | 1 | 0 |
GOE0 | 0 | 1 |
USERCODE | [0, 6, 7, 0] | [0, 6, 6, 0] | [0, 6, 7, 1] | [0, 6, 6, 1] | [0, 6, 7, 2] | [0, 6, 6, 2] | [0, 6, 7, 3] | [0, 6, 6, 3] | [0, 6, 7, 4] | [0, 6, 6, 4] | [0, 6, 7, 5] | [0, 6, 6, 5] | [0, 6, 7, 6] | [0, 6, 6, 6] | [0, 6, 7, 7] | [0, 6, 6, 7] | [0, 7, 7, 0] | [0, 7, 6, 0] | [0, 7, 7, 1] | [0, 7, 6, 1] | [0, 7, 7, 2] | [0, 7, 6, 2] | [0, 7, 7, 3] | [0, 7, 6, 3] | [0, 7, 7, 4] | [0, 7, 6, 4] | [0, 7, 7, 5] | [0, 7, 6, 5] | [0, 7, 7, 6] | [0, 7, 6, 6] | [0, 7, 7, 7] | [0, 7, 6, 7] |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Inverted | ~[31] | ~[30] | ~[29] | ~[28] | ~[27] | ~[26] | ~[25] | ~[24] | ~[23] | ~[22] | ~[21] | ~[20] | ~[19] | ~[18] | ~[17] | ~[16] | ~[15] | ~[14] | ~[13] | ~[12] | ~[11] | ~[10] | ~[9] | ~[8] | ~[7] | ~[6] | ~[5] | ~[4] | ~[3] | ~[2] | ~[1] | ~[0] |
Fuses — input buffer enable
On XC95288, the IBUF_UIM_ENABLE
fuses are stored in rows (1, 2, 5, 8, 9),
columns 0-8, bits 6-7 of FBs (0, 1, 14, 15) in an irregular manner. Each
fuse is duplicated twice: once in FBs (0, 1) and once in FBs (14, 15).
The purpose of this duplication is unknown. Consult the database for exact
bit assignments.
Fuses — UIM wire-AND
The FB[i].IM[j].UIM.FB[k].MC[l]
fuse is stored at:
subarea:
k
row:
l
column:
j % 5
bit:
j // 5