diff --git a/.buildinfo b/.buildinfo new file mode 100644 index 00000000..2e68ce94 --- /dev/null +++ b/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: 117c0c5490c7a38a33b72ed05e1d75dd +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/.doctrees/environment.pickle b/.doctrees/environment.pickle new file mode 100644 index 00000000..b13b0673 Binary files /dev/null and b/.doctrees/environment.pickle differ diff --git a/.doctrees/index.doctree b/.doctrees/index.doctree new file mode 100644 index 00000000..b38d1fc1 Binary files /dev/null and b/.doctrees/index.doctree differ diff --git a/.doctrees/xc9500/bitstream-xc9500.doctree b/.doctrees/xc9500/bitstream-xc9500.doctree new file mode 100644 index 00000000..1a0aefd7 Binary files /dev/null and b/.doctrees/xc9500/bitstream-xc9500.doctree differ diff --git a/.doctrees/xc9500/bitstream-xc9500xl.doctree b/.doctrees/xc9500/bitstream-xc9500xl.doctree new file mode 100644 index 00000000..0b639d5c Binary files /dev/null and b/.doctrees/xc9500/bitstream-xc9500xl.doctree differ diff --git a/.doctrees/xc9500/index.doctree b/.doctrees/xc9500/index.doctree new file mode 100644 index 00000000..e912e814 Binary files /dev/null and b/.doctrees/xc9500/index.doctree differ diff --git a/.doctrees/xc9500/intro.doctree b/.doctrees/xc9500/intro.doctree new file mode 100644 index 00000000..a06020dd Binary files /dev/null and b/.doctrees/xc9500/intro.doctree differ diff --git a/.doctrees/xc9500/jtag.doctree b/.doctrees/xc9500/jtag.doctree new file mode 100644 index 00000000..75fb0240 Binary files /dev/null and b/.doctrees/xc9500/jtag.doctree differ diff --git a/.doctrees/xc9500/structure.doctree b/.doctrees/xc9500/structure.doctree new file mode 100644 index 00000000..8063ded9 Binary files /dev/null and b/.doctrees/xc9500/structure.doctree differ diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 00000000..e69de29b diff --git a/_sources/index.rst.txt b/_sources/index.rst.txt new file mode 100644 index 00000000..ebca11ba --- /dev/null +++ b/_sources/index.rst.txt @@ -0,0 +1,17 @@ +Project Combine +############### + +.. toctree:: + :maxdepth: 1 + :caption: Contents: + + xc9500/index + + + +.. Indices and tables +.. ================== + +.. * :ref:`genindex` +.. * :ref:`modindex` +.. * :ref:`search` diff --git a/_sources/xc9500/bitstream-xc9500.rst.txt b/_sources/xc9500/bitstream-xc9500.rst.txt new file mode 100644 index 00000000..7f71b1cb --- /dev/null +++ b/_sources/xc9500/bitstream-xc9500.rst.txt @@ -0,0 +1,415 @@ +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: + +1. ``FB[i].MC[j].PT[k].IM[l].P`` is stored at: + + - row: ``l * 2`` + - column: ``k + (j % 3) * 5`` + - bit: ``j // 3`` + +2. ``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`` + +The row is: + +- 12: ``PT[0].ALLOC`` bit 0 +- 13: ``PT[0].ALLOC`` bit 1 +- 14: ``PT[1].ALLOC`` bit 0 +- 15: ``PT[1].ALLOC`` bit 1 +- 16: ``PT[2].ALLOC`` bit 0 +- 17: ``PT[2].ALLOC`` bit 1 +- 18: ``PT[3].ALLOC`` bit 0 +- 19: ``PT[3].ALLOC`` bit 1 +- 20: ``PT[4].ALLOC`` bit 0 +- 21: ``PT[5].ALLOC`` bit 1 +- 22: ``INV`` +- 23: ``IMPORT_UP_ALLOC`` +- 24: ``IMPORT_DOWN_ALLOC`` +- 25: ``EXPORT_DIR`` +- 26: ``SUM_HP`` +- 27: ``IOB_OE_MUX`` bit 0 +- 28: ``IOB_OE_MUX`` bit 1 +- 29: ``OE_MUX`` bit 0 +- 30: ``OE_MUX`` bit 1 +- 31: ``OE_MUX`` bit 2 +- 32-34: unused? +- 35: ``OUT_MUX`` +- 36: ``CLK_MUX`` bit 0 +- 37: ``CLK_MUX`` bit 1 +- 38-39: unused +- 40: ``REG_MODE`` +- 41: ``RST_MUX`` +- 42: ``SET_MUX`` +- 43: ``INIT`` +- 44: ``UIM_OE_MUX`` bit 0 +- 45: ``UIM_OE_MUX`` bit 1 +- 46: ``UIM_OUT_INV`` +- 47: unused +- 48: ``GND`` +- 49: ``SLEW`` +- 50: ``PT[0].HP`` +- 51: ``PT[1].HP`` +- 52: ``PT[2].HP`` +- 53: ``PT[3].HP`` +- 54: ``PT[4].HP`` + +The fuse combination assignments are: + +- ``PT[*].ALLOC``: + + - ``11``: ``NONE`` + - ``10``: ``OR_MAIN`` + - ``01``: ``OR_EXPORT`` + - ``00``: ``SPECIAL`` + +- ``IMPORT_*_ALLOC``: + + - ``1``: ``OR_EXPORT`` + - ``0``: ``OR_MAIN`` + +- ``EXPORT_DIR``: + + - ``1``: ``UP`` + - ``0``: ``DOWN`` + +- ``IOB_OE_MUX``: + + - ``11``: ``GND`` + - ``10``: ``OE_MUX`` + - ``01``: ``VCC`` + +- ``OUT_MUX``: + + - ``1``: ``COMB`` + - ``0``: ``FF`` + +- ``OE_MUX``: + + - ``111``: ``PT`` + - ``110``: ``FOE0`` + - ``101``: ``FOE1`` + - ``100``: ``FOE2`` + - ``011``: ``FOE3`` + +- ``CLK_MUX``: + + - ``11``: ``FCLK1`` + - ``10``: ``FCLK2`` + - ``01``: ``FCLK0`` + - ``00``: ``PT`` + +- ``REG_MODE``: + + - ``1``: ``DFF`` + - ``0``: ``TFF`` + +- ``RST_MUX``, ``SET_MUX``: + + - ``1``: ``PT`` + - ``0``: ``FSR`` + +- ``UIM_OE_MUX``: + + - ``11``: ``OE_MUX`` + - ``10``: ``GND`` + - ``01``: ``VCC`` + +- ``SLEW``: + + - ``1``: ``SLOW`` + - ``0``: ``FAST`` + +- everything else: + + - ``1``: false + - ``0``: true + + +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, column, bit): + +- (67, 0, 6): ``ENABLE`` +- (67, 1, 6): ``EXPORT_ENABLE`` +- (68, 6, 6): ``PULLUP_DISABLE`` + +Global bits are stored in rows (0, 3, 4, 6, 7), columns 0-8, bits 6-7 of FB 0. The bits are (row, column, bit): + +- (0, 1, 6): ``FSR_INV`` +- (0, 2, 6): ``FCLK[0].INV`` +- (0, 3, 6): ``FCLK[1].INV`` +- (0, 4, 6): ``FCLK[2].INV`` +- (0, 5, 6): ``FOE[0].INV`` +- (0, 6, 6): ``FOE[1].INV`` +- (0, 7, 6): ``FOE[2].INV`` +- (0, 8, 6): ``FOE[3].INV`` +- (3, 2, 6): ``FCLK[0].MUX`` bit 0 +- (3, 3, 6): ``FCLK[1].MUX`` bit 0 +- (3, 4, 6): ``FCLK[2].MUX`` bit 0 +- (3, 5, 6): ``FOE[0].MUX`` bit 0 +- (3, 6, 6): ``FOE[1].MUX`` bit 0 +- (3, 7, 6): ``FOE[2].MUX`` bit 0 +- (3, 8, 6): ``FOE[3].MUX`` bit 0 +- (4, 2, 6): ``FCLK[0].MUX`` bit 1 +- (4, 3, 6): ``FCLK[1].MUX`` bit 1 +- (4, 4, 6): ``FCLK[2].MUX`` bit 1 +- (4, 5, 6): ``FOE[0].MUX`` bit 1 +- (4, 6, 6): ``FOE[1].MUX`` bit 1 +- (4, 7, 6): ``FOE[2].MUX`` bit 1 +- (4, 8, 6): ``FOE[3].MUX`` bit 1 +- (6, i, j) for i < 8, j in (6, 7): ``USERCODE`` bit ``16 + (7 - i) * 2 + (j - 6)`` +- (7, i, j) for i < 8, j in (6, 7): ``USERCODE`` bit ``(7 - i) * 2 + (j - 6)`` + +The fuse combination assignments are: + +- ``FCLK[0].MUX``: + + - ``11``: ``NONE`` + - ``10``: ``GCLK[1]`` + - ``01``: ``GCLK[0]`` + +- ``FCLK[1].MUX``: + + - ``11``: ``NONE`` + - ``10``: ``GCLK[2]`` + - ``01``: ``GCLK[1]`` + +- ``FCLK[2].MUX``: + + - ``11``: ``NONE`` + - ``10``: ``GCLK[0]`` + - ``01``: ``GCLK[2]`` + +- ``FOE[0].MUX`` (small device): + + - ``11``: ``NONE`` + - ``10``: ``GOE[1]`` + - ``01``: ``GOE[0]`` + +- ``FOE[1].MUX`` (small device): + + - ``11``: ``NONE`` + - ``10``: ``GOE[0]`` + - ``01``: ``GOE[1]`` + +- ``FOE[0].MUX`` (large device): + + - ``11``: ``NONE`` + - ``10``: ``GOE[1]`` + - ``01``: ``GOE[0]`` + +- ``FOE[1].MUX`` (large device): + + - ``11``: ``NONE`` + - ``10``: ``GOE[2]`` + - ``01``: ``GOE[1]`` + +- ``FOE[2].MUX`` (large device): + + - ``11``: ``NONE`` + - ``10``: ``GOE[3]`` + - ``01``: ``GOE[2]`` + +- ``FOE[3].MUX`` (large device): + + - ``11``: ``NONE`` + - ``10``: ``GOE[0]`` + - ``01``: ``GOE[3]`` + +- ``USERCODE``: each bit stored inverted + +- everything else: + + - ``1``: false + - ``0``: true + + +Fuses — input buffer enable +=========================== + +On XC95288, the ``IBUF_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 — protection bits +======================= + +The protection bits are stored as follows (row, column, bit) in every FB: + +- (11, 3, 6): ``READ_PROT_A`` +- (68, 3, 6): ``READ_PROT_B`` +- (68, 0, 6): ``WRITE_PROT`` + + +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`` diff --git a/_sources/xc9500/bitstream-xc9500xl.rst.txt b/_sources/xc9500/bitstream-xc9500xl.rst.txt new file mode 100644 index 00000000..fb8d18d4 --- /dev/null +++ b/_sources/xc9500/bitstream-xc9500xl.rst.txt @@ -0,0 +1,272 @@ +Bitstream structure — XC9500XL/XV +################################# + +The main differences from XC9500 are: + +1. The UIM wire-AND area is completely gone, only the main areas exist. +2. The main area has 108 rows per FB instead of 72. +3. Unprogrammed fuse state is ``0``, programmed fuse state is ``1``. + Thus, the sense of every bitstream bit is inverted from the XC9500 version. +4. While in XC9500 all areas are loaded sequentially, in XC9500XL/XV the areas + are loaded in parallel. Thus, the JTAG unit is not a byte, but a word of + size ``8 * num_fbs``. Likewise, the bytes for each FB are interleaved + in the JED format. + +On a high level, the whole bitstream is split into "areas". Each FB +of the device corresponds to one area. + +Each area is made of 108 "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. + +When programmed or read via JTAG, the bitstream is transmitted as words. +Each word is 8 bits per FB. Each word of the bitstream has its address. +Not all addresses are valid, and valid addresses are not contiguous. +Address is 12 bits long, and is split to several fields: + +- bits 5-11: row +- bits 3-4: column / 5 +- bits 0-2: column % 5 + +The unprogrammed state of a bit on XC9500XL/XV is ``0``. +The programmed state is ``1``. Thus, whenever a boolean fuse is mentioned +in the documentation, the "true" value is actually represented as ``1`` +in the bitstream. + + +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:: + + row_bits = (8 * 9 + 6 * 6) * device.num_fbs + total_bits = row_bits * 108 + + def jed_to_jtag(fuse): + row = fuse // row_bits + fuse %= row_bits + if fuse < 8 * 9 * device.num_fbs: + column = fuse // (8 * device.num_fbs) + fuse %= (8 * device.num_fbs) + fb = fuse // 8 + bit = fuse % 8 + else: + fuse -= 8 * 9 * device.num_fbs + column = 9 + fuse // (6 * device.num_fbs) + fuse %= (6 * device.num_fbs) + fb = fuse // 6 + bit = fuse % 6 + return ( + row << 5 | + (column // 5) << 3 | + (column % 5) + ), (fb * 8 + bit) + + def jtag_to_jed(addr, bit): + fb = bit // 8 + bit %= 8 + row = addr >> 5 & 0x7f + assert row < 108 + 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 * device.num_fbs + fb * 8 + bit + else: + cfuse = 8 * 8 + (column - 9) * 6 * device.num_fbs + fb * 6 + bit + return row * 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 (unchanged from XC9500, but now with more rows): + +1. ``FB[i].MC[j].PT[k].IM[l].P`` is stored at: + + - row: ``l * 2`` + - column: ``k + (j % 3) * 5`` + - bit: ``j // 3`` + +2. ``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-49 of the main area. The formulas are as follows: + +- row: corresponds to fuse function +- column: ``mc_idx % 9`` +- bit: ``6 + mc_idx // 9`` + +The row is: + +- 12: ``PT[0].ALLOC`` bit 0 +- 13: ``PT[0].ALLOC`` bit 1 +- 14: ``PT[1].ALLOC`` bit 0 +- 15: ``PT[1].ALLOC`` bit 1 +- 16: ``PT[2].ALLOC`` bit 0 +- 17: ``PT[2].ALLOC`` bit 1 +- 18: ``PT[3].ALLOC`` bit 0 +- 19: ``PT[3].ALLOC`` bit 1 +- 20: ``PT[4].ALLOC`` bit 0 +- 21: ``PT[5].ALLOC`` bit 1 +- 22: ``INV`` +- 23: ``IMPORT_UP_ALLOC`` +- 24: ``IMPORT_DOWN_ALLOC`` +- 25: ``EXPORT_DIR`` +- 26: ``SUM_HP`` +- 27: ``OE_MUX`` bit 0 +- 28: ``OE_MUX`` bit 1 +- 29: ``OE_MUX`` bit 2 +- 30: ``OE_INV`` +- 31: unused +- 32: ``OUT_MUX`` +- 33: ``CLK_MUX`` bit 0 +- 34: ``CLK_MUX`` bit 1 +- 35: ``CLK_INV`` +- 36: ``CE_MUX`` bit 0 +- 37: ``CE_MUX`` bit 1 +- 38: unused +- 39: ``REG_MODE`` +- 40: ``RST_MUX`` +- 41: ``SET_MUX`` +- 42: ``INIT`` +- 43: ``GND`` +- 44: ``SLEW`` +- 45: ``PT[0].HP`` +- 46: ``PT[1].HP`` +- 47: ``PT[2].HP`` +- 48: ``PT[3].HP`` +- 49: ``PT[4].HP`` + +The fuse combination assignments are: + +- ``PT[*].ALLOC``: + + - ``00``: ``NONE`` + - ``01``: ``OR_MAIN`` + - ``10``: ``OR_EXPORT`` + - ``11``: ``SPECIAL`` + +- ``IMPORT_*_ALLOC``: + + - ``0``: ``OR_EXPORT`` + - ``1``: ``OR_MAIN`` + +- ``EXPORT_DIR``: + + - ``0``: ``UP`` + - ``1``: ``DOWN`` + +- ``OUT_MUX``: + + - ``0``: ``COMB`` + - ``1``: ``FF`` + +- ``CLK_MUX``: + + - ``00``: ``FCLK1`` + - ``01``: ``FCLK0`` + - ``10``: ``FCLK2`` + - ``11``: ``PT`` + +- ``CE_MUX``: + + - ``00``: ``NONE`` + - ``01``: ``PT2`` + - ``10``: ``PT3`` + +- ``REG_MODE``: + + - ``0``: ``DFF`` + - ``1``: ``TFF`` + +- ``RST_MUX``, ``SET_MUX``: + + - ``0``: ``PT`` + - ``1``: ``FSR`` + +- ``SLEW``: + + - ``0``: ``SLOW`` + - ``1``: ``FAST`` + +- everything else: + + - ``0``: false + - ``1``: true + + +Fuses — FB inputs +================= + +The FB input mux configuraton is stored in rows 50-76, columns 0-8, bits 6-7. +``FB[i].IM[j].MUX`` has 9 bits and is stored at the following coordinates: + +- row: ``50 + j % 27`` +- column: mux fuse index (0-8) +- bit: 6 if ``j < 27``, 7 otherwise + +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 row 78, columns 0-8, bits 6-7. The bits are (row, column, bit): + +- (78, 0, 6): ``ENABLE`` +- (78, 1, 6): ``EXPORT_ENABLE`` +- (78, 6, 6): ``PULLUP_DISABLE`` + +Global bits are stored in rows (2, 6, 7), columns 0-8, bits 6-7 of FB 0. The bits are (row, column, bit): + +- (2, 0, 6): ``FSR_INV`` +- (2, 1, 6): ``FCLK[0].EN`` +- (2, 2, 6): ``FCLK[1].EN`` +- (2, 3, 6): ``FCLK[2].EN`` +- (2, 4, 6): ``FOE[0].EN`` +- (2, 5, 6): ``FOE[1].EN`` +- (2, 6, 6): ``FOE[2].EN`` +- (2, 7, 6): ``FOE[3].EN`` +- (2, 8, 6): ``KEEPER`` +- (6, i, j) for i < 8, j in (6, 7): ``USERCODE`` bit ``16 + (7 - i) * 2 + (j - 6)`` +- (7, i, j) for i < 8, j in (6, 7): ``USERCODE`` bit ``(7 - i) * 2 + (j - 6)`` + +The fuse combination assignments are: + +- ``USERCODE``: each bit stored directly + +- everything else: + + - ``0``: false + - ``1``: true + + +Fuses — protection bits, DONE +============================= + +The protection bits are stored as follows (row, column, bit) in every FB: + +- (11, 0, 6): ``WRITE_PROT`` +- (11, 3, 6): ``READ_PROT`` + +The ``DONE`` bit is stored only once, in FB 0: + +- (11, 6, 6): ``DONE`` diff --git a/_sources/xc9500/index.rst.txt b/_sources/xc9500/index.rst.txt new file mode 100644 index 00000000..87f80ec7 --- /dev/null +++ b/_sources/xc9500/index.rst.txt @@ -0,0 +1,12 @@ +XC9500, XC9500XL, XC9500XV +########################## + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + + intro + structure + bitstream-xc9500 + bitstream-xc9500xl + jtag \ No newline at end of file diff --git a/_sources/xc9500/intro.rst.txt b/_sources/xc9500/intro.rst.txt new file mode 100644 index 00000000..b48d096c --- /dev/null +++ b/_sources/xc9500/intro.rst.txt @@ -0,0 +1,126 @@ +Introduction +############ + +XC9500 is a family of flash-based CPLDs manufactured by Xilinx. It is a derivative of the earlier XC7200 and XC7300 +EPLD families. It comes in three variants: + +1. XC9500: 5V core logic, 3.3V or 5V I/O, original version. +2. XC9500XL: 3.3V core logic, 2.5V or 3.3V I/O (5V tolerant), with some functional changes from XC9500: + + - UIM no longer has wired-AND functionality + - FFs have clock enable function + - 54 (instead of 36) UIM inputs per function block + - FF has configurable clock polarity + - FOE/FCLK multiplexers and inversion have been removed + - optional weak bus keeper can be configured for all pins + +3. XC9500XV: 2.5V core logic, 1.8V, 2.5V, or 3.3V I/O, with minor functional changes from XC9500XL: + + - larger devices have two I/O banks with separate VCCIO + - the bitstream now contains a ``DONE`` bit tied to ``ISC_DONE``, preventing problems with partially configured devices + + +Devices +======= + +The following devices exist: + +========= ======== =============== +Device Variant Function Blocks +========= ======== =============== +XC9536 XC9500 2 +XC9572 XC9500 4 +XC95108 XC9500 6 +XC95144 XC9500 8 +XC95216 XC9500 12 +XC95288 XC9500 16 +XC9536XL XC9500XL 2 +XC9572XL XC9500XL 4 +XC95144XL XC9500XL 8 +XC95288XL XC9500XL 16 +XA9536XL XC9500XL 2 +XA9572XL XC9500XL 4 +XA95144XL XC9500XL 8 +XC9536XV XC9500XV 2 +XC9572XV XC9500XV 4 +XC95144XV XC9500XV 8 +XC95288XV XC9500XV 16 +========= ======== =============== + +The parts starting with XA are automotive versions. They are functionally completely identical to corresponding XC versions. + + +Packages +======== + +The devices come in the following packages: + +- PLCC: + + - PC44 (JEDEC MO-047) + - PC84 (JEDEC MO-047) + +- QFP: + + - very thin QFP (1mm thickness): + + - VQ44 (0.8mm pitch; JEDEC MS-026-ACB) + - VQ64 (0.5mm pitch; JEDEC MS-026-ACD) + + - thin QFP (1.4mm thickness): + + - TQ100 (0.5mm pitch; JEDEC MS-026-BED) + - TQ144 (0.5mm pitch; JEDEC MS-026-BFB) + + - plastic QFP: + + - PQ100 (2.7mm thickness, non-square, 30×20 pins, 0.65mm pitch; JEDEC MS-022-GC1) + - PQ160 (3.4mm thickness, 0.65mm pitch; JEDEC MS-022-DD1) + - PQ208 (3.4mm thickness, 0.5mm pitch; JEDEC MS-029-FA-1) + + - platic QFP with heat sink: + + - HQ208 (same footprint as PQ208) + +- BGA: + + - standard BGA (1.27mm pitch): + + - BG256 (JEDEC MS-034-BAL-2) + - BG352 + + - fine-pitch BGA (1mm pitch): + + - FG256 + + - chip-scale BGA (0.8mm pitch): + + - CS48 + - CS144 (JEDEC MO-216-BAG-2) + - CS280 (JEDEC MO-216-BAL-1) + + +========= ==== ==== ==== ==== ===== ===== ===== ===== ===== ===== ===== ===== ===== ==== ===== ===== +Device PC44 PC84 VQ44 VQ64 TQ100 TQ144 PQ100 PQ160 PQ208 HQ208 BG256 BG352 FG256 CS48 CS144 CS280 +========= ==== ==== ==== ==== ===== ===== ===== ===== ===== ===== ===== ===== ===== ==== ===== ===== +XC9536 X X X +XC9572 X X X X +XC95108 X X X X +XC95144 X X X +XC95216 X X X +XC95288 X X +XC9536XL X X X X +XC9572XL X X X X X +XC95144XL X X X +XC95288XL X X X X X +XA9536XL X +XA9572XL X X X +XA95144XL X +XC9536XV X X X +XC9572XV X X X X +XC95144XV X X X +XC95288XV X X X X +========= ==== ==== ==== ==== ===== ===== ===== ===== ===== ===== ===== ===== ===== ==== ===== ===== + +Pin compatibility is maintained across all 3 variants of the XC9500 family within a single package. +Additionally, devices in PQ208 and HQ208 packages are pin compatible with each other. \ No newline at end of file diff --git a/_sources/xc9500/jtag.rst.txt b/_sources/xc9500/jtag.rst.txt new file mode 100644 index 00000000..f925a078 --- /dev/null +++ b/_sources/xc9500/jtag.rst.txt @@ -0,0 +1,171 @@ +JTAG interface +############## + +IR +== + +The IR is 8 bits long. The following instructions exist: + +============ ============ ==================== ======= +IR Instruction Register Notes +============ ============ ==================== ======= +``00000000`` ``EXTEST`` ``BOUNDARY`` +``00000001`` ``SAMPLE`` ``BOUNDARY`` +``00000010`` ``INTEST`` ``BOUNDARY`` +``11100101`` ``FBLANK`` ``ISPADDRESS`` XC9500XL/XV only +``11101000`` ``ISPEN`` ``ISPENABLE`` +``11101001`` ``ISPENC`` ``ISPENABLE`` XC9500XL/XV only +``11101010`` ``FPGM`` ``ISPCONFIGURATION`` +``11101011`` ``FPGMI`` ``ISPDATA`` +``11101100`` ``FERASE`` ``ISPCONFIGURATION`` XC9500 only +``11101100`` ``FERASE`` ``ISPADDRESS`` XC9500XL/XV only +``11101101`` ``FBULK`` ``ISPCONFIGURATION`` XC9500 only +``11101101`` ``FBULK`` ``ISPADDRESS`` XC9500XL/XV only +``11101110`` ``FVFY`` ``ISPCONFIGURATION`` +``11101111`` ``FVFYI`` ``ISPDATA`` +``11110000`` ``ISPEX`` ``BYPASS`` +``11111010`` ``CLAMP`` ``BYPASS`` XC9500XL/XV only +``11111100`` ``HIGHZ`` ``BYPASS`` +``11111101`` ``USERCODE`` ``USERCODE`` +``11111110`` ``IDCODE`` ``IDCODE`` +``11111111`` ``BYPASS`` ``BYPASS`` +============ ============ ==================== ======= + +The IR status is: + +- bit 0: const 1 +- bit 1: const 0 +- bit 2: ``WRITE_PROT`` status +- bit 3: ``READ_PROT`` status +- bit 4: ISP mode enabled +- bit 5: ``DONE`` status (XC9500XV only, const 0 on other devices) +- bits 6-7: const 0 + +.. todo:: verify + + +Boundary scan register +====================== + +The boundary scan register is ``3 * 18 * num_fbs`` bits long, and consists of 3 bits for every MC +in the device: input, output, and output enable. Such bits are included even for MCs that do not +have a corresponding IOB. + +The boundary register bit indices for ``FB[i].MC[j]`` are: + +- input: ``(num_fbs - 1 - i) * 18 * 3 + (17 - j) * 3 + 2`` +- output: ``(num_fbs - 1 - i) * 18 * 3 + (17 - j) * 3 + 1`` +- output enable: ``(num_fbs - 1 - i) * 18 * 3 + (17 - j) * 3 + 0`` + +All bits of the register are ``BC_1`` type cells. + +.. todo:: details on the cell connection, EXTEST, INTEST semantics + + +ISP instructions +================ + +ISP DR registers — XC9500 +------------------------- + +The following DR registers exist on XC9500: + +1. ``ISPENABLE`` (16 bits): function and contents unclear +2. ``ISPCONFIGURATION`` (27 bits): used to load and store bitstream bytes + + - bit 0: valid bit + - bit 1: strobe bit + - bits 2-9: data byte + - bits 10-26: address + +3. ``ISPDATA`` (10 bits): a subset of ``ISPCONFIGURATION`` used by instructions with autoincrementing address + + - bit 0: valid bit + - bit 1: strobe bit + - bits 2-9: data byte + +.. todo:: ISPENABLE, describe valid & strobe + + +ISP DR registers — XC9500XL/XV +------------------------------ + +The following DR registers exist on XC9500XL/XV: + +1. ``ISPENABLE`` (6 bits): function and contents unclear +2. ``ISPCONFIGURATION`` (``18 + num_fbs * 8`` bits): used to load and store bitstream words + + - bit 0: valid bit + - bit 1: strobe bit + - bits 2-``(num_sbs * 8 + 1)``: data word + - bits ``(num_fbs * 8 + 2)``-``(num_fbs * 8 + 17)``: address + +3. ``ISPDATA`` (``2 + num_fbs * 8`` bits): a subset of ``ISPCONFIGURATION`` used by instructions with autoincrementing address + + - bit 0: valid bit + - bit 1: strobe bit + - bits 2-``(num_sbs * 8 + 1)``: data word + +4. ``ISPADDRESS`` (18 bits): a subset of ``ISPCONFIGURATION`` used by some instructions: + + - bit 0: valid bit + - bit 1: strobe bit + - bits 2-17: address + + +Entering and exiting ISP mode +----------------------------- + +Before any programming or readout can be done, the device needs to be put into ISP mode. +For that purpose, the ``ISPEN`` or ``ISPENC`` (XC9500XL/XV only) instructions can be used. +Both instructions use the ``ISPENABLE`` register, which is 16 bits on XC9500 +and 6 bits on XC9500XL/XV. Its meaning, if any, is unknown. + +To enter ISP mode: + +- shift ``ISPEN`` or ``ISPENC`` into IR +- shift 0s into DR +- go to Run-Test/Idle state for at least 1 clock + +If the ``ISPEN`` instruction is used, all outputs will be put in high-Z with weak pull-ups while ISP mode is active. +If the ``ISPENC`` ("clamp" mode) instruction is used, all output and output enable signals will be snapshotted +and outputs will continue driving the last value while ISP mode is active. + +To exit ISP mode: + +- shift ``ISPEX`` into IR +- go to Run-Test/Idle state for at least 1 clock + +When ISP mode is exitted, the device will initialize itself and start normal operation. + +.. todo:: verify, see if anything can be figured out about the DR + + +Erasing fuses +------------- + +.. todo:: write me + + +Programming fuses +----------------- + +.. todo:: write me + + +Reading fuses +------------- + +.. todo:: write me + + +Blank check +----------- + +.. todo:: write me + + +Programming sequence +==================== + +.. todo:: write me \ No newline at end of file diff --git a/_sources/xc9500/structure.rst.txt b/_sources/xc9500/structure.rst.txt new file mode 100644 index 00000000..133e2bb3 --- /dev/null +++ b/_sources/xc9500/structure.rst.txt @@ -0,0 +1,622 @@ +Device structure +################ + +Overview +======== + +An XC9500 family device is made of: + +- the UIM (universal interconnect matrix), which routes MC and IOB outputs to FB inputs +- 2-16 FBs (function blocks), each of which has: + + - 36 (XC9500) or 54 (XC9500XL/XV) routable inputs from UIM + - 18 MCs (macrocells), each of which has: + + - configurable low power / high performance mode + - 5 PTs (product terms) + - PT router, which can route PTs to: + + - the sum term for this MC + - the sum term for export into neighbouring MCs + - a special function (OE, RST, SET, CLK, CE, XOR depending on the PT) + + - PT export/import logic for borrowing PTs between neighbouring MCs + - a sum term + - a dedicated XOR gate + - optional inverter + - a flip-flop, with: + + - configurable DFF or TFF function + - configurable initial value + - clock (freely invertible on XC9500XL/XV), routable from FCLK or PT + - async reset, routable from FSR or PT + - async set, routable from FSR or PT + - (XC9500XL/XV only) clock enable, routable from PT + + - a single output (selectable from combinatorial or FF output), routed to IOB and UIM + - (XC9500 only) UIM output enable and inversion + - IOB (input/output buffer) (on larger devices, not all macrocells have an IOB), with: + + - input buffer (routed to UIM) + - output enable (freely invertible on XC9500XL/XV), routable from FOE or PT + - configurable slew rate (fast or slow) + - programmable ground + +- global signals + + - 3 FCLK (fast clock) signals + + - (XC9500) freely invertible and routable from GCLK pins + - (XC9500XL/XV) hardwired 1-1 to GCLK pins + + - 1 FSR (fast set/reset) signal + + - freely invertible + - always routed from GSR pin + + - 2-4 FOE (fast output enable) signals + + - (XC9500) freely invertible and routable from GOE pins + - (XC9500XL/XV) hardwired 1-1 to GOE pins + +- global pull-up enable (only meant to be used in unconfigured devices) +- (XC9500XL/XV) global bus keeper enable +- special global configuration bits + + - 32-bit standard JTAG USERCODE + - read protection enable + - write protection enable + - (XC9500XV only) DONE bit + + +UIM and FB inputs — XC9500 +========================== + +The core interconnect structure in XC9500 devices is the UIM, Universal Interconnect Matrix. +The name is quite appropriate, at least for internal signals: any FB input can be routed +to any MC output. More than that, any FB input can be routed to a *wire-AND* of an arbitrary +subset of MC outputs from the entire device. Together with the UIM OE functionality within +the MC, this can be used for emulated internal tri-state buses. + +The name is, however, less appropriate when it comes to external signals: a given FB input +can only be routed to some subset of input signals from IOBs. The set of routable IOBs +depends on the FB input index and the device. + +Additionally, on devices other than XC9536, some FB inputs can be routed to "fast feedback" +paths, which come straight from MC outputs within the same FB. This is functionally redundant +with the wire-AND path, but much faster. + +Each FB has 36 inputs, which we call ``FB[i].IM[j]``. Each FB input is controlled by two sets of fuses: + +- mux fuses (``FB[i].IM[j].MUX``) select what is routed to the input. The combinations include: + + - ``EMPTY``: the input is a constant ??? (for unused inputs) + - ``UIM``: the input is a wire-AND of MC outputs (and the second set of fuses is relevant) + - ``FBK_MC{k}``: the input is routed through fast feedback path from ``FB[i].MC[k].OUT`` + - ``PAD_FB{k}_MC{l}``: the input is routed from an input buffer ``FB[k].MC[l].IOB.I`` + + The allowable combinations differ between inputs within a single FB, but don't differ across + FBs within a single device. In other words, the set of allowed values for these fuses + depends only on the ``j`` coordinate, but not on ``i``. + +- wire-AND fuses (``FB[i].IM[j].UIM.FB[k].MC[l]``) select which MC outputs participate in the + wire-AND. If a given fuse is programmed, it means that ``FB[k].MC[l].OUT_UIM`` is included + in the product. These fuses are only relevant when the mux fuse set is set to ``UIM``. + +.. todo:: check ``EMPTY`` semantics + +.. todo:: verify ``FBK`` doesn't go through OE and inversion + + +UIM and FB inputs — XC9500XL/XV +=============================== + +The core interconnect structure in XC9500XL/XV devices is the UIM 2. This version of the UIM +is not really universal, and is much more of a classic CPLD design. + +Each FB has 54 inputs, which we call ``FB[i].IM[j]``. Each FB input is controlled by a set of fuses: + +- mux fuses (``FB[i].IM[j].MUX``) select what is routed to the input. The combinations include: + + - ``EMPTY``: the input is a constant ??? (for unused inputs) + - ``FB{k}_MC{l}``: the input is routed from the macrocell output ``FB[k].MC[l].OUT`` + - ``PAD_FB{k}_MC{l}``: the input is routed from the input buffer ``FB[k].MC[l].IOB.I`` + + The allowable combinations differ between inputs within a single FB, but don't differ across + FBs within a single device. In other words, the set of allowed values for these fuses + depends only on the ``j`` coordinate, but not on ``i``. + +.. todo:: check ``EMPTY`` semantics + + +FB global fuses +=============== + +Each function block has two fuses controlling the entire FB: + +- ``FB[i].ENABLE``: function block enable; needs to be programmed to use this function block +- ``FB[i].EXPORT_ENABLE``: function block PT export enable; needs to be programmed to use PT + import/export within this function block + +.. todo:: determine what these do exactly + + +Product terms +============= + +Each function block has 90 product terms, 5 per macrocell. We call them ``FB[i].MC[j].PT[k]``. +Each of the 5 PTs has a dedicated function, as follows: + +- ``*.PT[0]``: clock +- ``*.PT[1]``: output enable +- ``*.PT[2]``: async reset (or clock enable on XC9500XL/XV) +- ``*.PT[3]``: async set (or clock enable on XC9500XL/XV) +- ``*.PT[4]``: second XOR input + +The inputs to all product terms within a FB are the same, and consist of all FB inputs, in both +true and inverted forms. + +Each product term can be individually configured as low power or high performance. This affects propagation time. + +Each product term can be routed to at most one of three destinations: + +- ``OR_MAIN``: input to the MC's sum term +- ``OR_EXPORT``: input to the export OR gate +- ``SPECIAL``: used for the dedicated function + +The fuses controlling a product term are: + +- ``FB[i].MC[j].PT[k].IM[l].P``: if programmed, ``FB[i].IM[l]`` is included in the product term (true polarity) +- ``FB[i].MC[j].PT[k].IM[l].N``: if programmed, ``~FB[i].IM[l]`` is included in the product term (inverted polarity) +- ``FB[i].MC[j].PT[k].HP``: if programmed, the product term is in high performance mode; otherwise, it is in low power mode +- ``FB[i].MC[j].PT[k].ALLOC``: has one of four values: + + - ``EMPTY``: product term is unused + - ``OR_MAIN``: product term is used for MC's sum term; dedicated function wired to 0 + - ``OR_EXPORT`` product term is used for export sum term; dedicated function wired to 0 + - ``SPECIAL``: product term is used for the dedicated function + +The product term's corresponding dedicated function is called ``FB[i].MC[j].PT[k].SPECIAL``. +It is equal to ``FB[i].MC[j].PT[k]`` if the dedicated function is enabled in ``ALLOC``, 0 otherwise. + +PT import/export +---------------- + +Product terms can be borrowed between neighbouring MCs within a FB. To this end, each MC has two outputs, +``FB[i].MC[j].EXPORT_{UP|DOWN}``, and two inputs, ``FB[i].MC[j].IMPORT_{UP|DOWN}``. The "down" direction +corresponds to exporting PTs toward lower-numbered MCs (with a wraparound from 0 to 17), and the "up" +direction corresponds to exporting PTs towards higher-numbered MCs (with a wraparound from 17 to 0). +Accordingly, we have:: + + FB[i].MC[j].IMPORT_DOWN = FB[i].MC[(j + 1) % 18].EXPORT_DOWN; + FB[i].MC[j].IMPORT_UP = FB[i].MC[(j - 1) % 18].EXPORT_UP; + +A MC can only export product terms in one direction (up or down). +Product terms can be imported from both directions at once. +Imported terms from a given direction can be used for either the main sum term, or for further export, but not both at once. + +PT import/export is controlled by the following per-MC fuses: + +- ``FB[i].MC[j].EXPORT_DIR``: one of: + + - ``DOWN``: exports PTs downwards + - ``UP``: exports PTs upwards + +- ``FB[i].MC[j].IMPORT_UP_ALLOC``: one of: + + - ``OR_MAIN``: includes PTs imported upwards in the main sum term + - ``OR_EXPORT``: includes PTs imported upwards in the export sum term + +- ``FB[i].MC[j].IMPORT_DOWN_ALLOC``: one of: + + - ``OR_MAIN``: includes PTs imported downwards in the main sum term + - ``OR_EXPORT``: includes PTs imported downwards in the export sum term + +Additionally, the per-FB ``FB[i].EXPORT_ENABLE`` fuse needs to be set if any term within a FB is exported or imported. + +Export works as follows:: + + FB[i].MC[j].EXPORT = + (FB[i].MC[j].IMPORT_UP_ALLOC == OR_EXPORT ? FB[i].MC[j].IMPORT_UP : 0) | + (FB[i].MC[j].IMPORT_DOWN_ALLOC == OR_EXPORT ? FB[i].MC[j].IMPORT_DOWN : 0) | + (FB[i].MC[j].PT[0].ALLOC == OR_EXPORT ? FB[i].MC[j].PT[0] : 0) | + (FB[i].MC[j].PT[1].ALLOC == OR_EXPORT ? FB[i].MC[j].PT[1] : 0) | + (FB[i].MC[j].PT[2].ALLOC == OR_EXPORT ? FB[i].MC[j].PT[2] : 0) | + (FB[i].MC[j].PT[3].ALLOC == OR_EXPORT ? FB[i].MC[j].PT[3] : 0) | + (FB[i].MC[j].PT[4].ALLOC == OR_EXPORT ? FB[i].MC[j].PT[4] : 0); + + FB[i].MC[j].EXPORT_UP = (FB[i].MC[j].EXPORT_DIR == UP ? FB[i].MC[j].EXPORT : 0); + FB[i].MC[j].EXPORT_DOWN = (FB[i].MC[j].EXPORT_DIR == DOWN ? FB[i].MC[j].EXPORT : 0); + +.. todo:: verify all of the above + + +Sum term, XOR gate +================== + +Each macrocell has a main sum term, which includes all product terms and imports routed towards it:: + + FB[i].MC[j].SUM = + (FB[i].MC[j].IMPORT_UP_ALLOC == OR_MAIN ? FB[i].MC[j].IMPORT_UP : 0) | + (FB[i].MC[j].IMPORT_DOWN_ALLOC == OR_MAIN ? FB[i].MC[j].IMPORT_DOWN : 0) | + (FB[i].MC[j].PT[0].ALLOC == OR_MAIN ? FB[i].MC[j].PT[0] : 0) | + (FB[i].MC[j].PT[1].ALLOC == OR_MAIN ? FB[i].MC[j].PT[1] : 0) | + (FB[i].MC[j].PT[2].ALLOC == OR_MAIN ? FB[i].MC[j].PT[2] : 0) | + (FB[i].MC[j].PT[3].ALLOC == OR_MAIN ? FB[i].MC[j].PT[3] : 0) | + (FB[i].MC[j].PT[4].ALLOC == OR_MAIN ? FB[i].MC[j].PT[4] : 0); + +The sum term then goes through a XOR gate (whose other input is either 0 or a dedicated PT) and a programmable inverter:: + + FB[i].MC[j].XOR = FB[i].MC[j].SUM ^ FB[i].MC[j].PT[4].SPECIAL ^ FB[i].MC[j].INV; + +The fuses involved are: + +- ``FB[i].MC[j].SUM_HP``: if programmed, the sum term is in high performance mode; otherwise, it's in low power mode +- ``FB[i].MC[j].INV``: if programmed, the output of the XOR gate is further inverted + +Flip-flop +========= + +Each macrocell includes a flip-flop. It has: + +- configurable DFF or TFF function +- D or T input connected to the (potentially inverted) XOR gate output +- configurable initial value +- clock (freely invertible on XC9500XL/XV), routable from FCLK or ``PT[0]`` +- async reset, routable from FSR or ``PT[2]`` +- async set, routable from FSR or ``PT[3]`` +- (XC9500XL/XV only) clock enable, routable from ``PT[2]`` or ``PT[3]`` + +The fuses involved are: + +- ``FB[i].MC[j].CLK_MUX``: selects CLK input + + - ``PT``: product term 0 dedicated function + - ``FCLK[0-2]``: global ``FCLK[0-2]`` network + +- ``FB[i].MC[j].CLK_INV``: if programmed, the CLK input is inverted (ie. clock is negedge) (XC9500XL/XV only) + +- ``FB[i].MC[j].RST_MUX``: selects RST input + + - ``PT``: product term 2 dedicated function or 0; if PT 2 is used for clock enable, it will not be routed to RST (0 will be substituted) + - ``FSR``: global ``FSR`` network + +- ``FB[i].MC[j].SET_MUX``: selects SET input + + - ``PT``: product term 3 dedicated function or 0; if PT 3 is used for clock enable, it will not be routed to SET (0 will be substituted) + - ``FSR``: global ``FSR`` network + +- ``FB[i].MC[j].CE_MUX``: selects CE input (XC9500XL/XV only) + + - ``NONE``: const 1 + - ``PT2``: product term 2 dedicated function + - ``PT3``: product term 3 dedicated function + +- ``FB[i].MC[j].INIT``: if programmed, the initial value of the FF is 1; otherwise, it is 0 + +- ``FB[i].MC[j].REG_MODE``: selects FF mode + + - ``DFF`` + - ``TFF`` + +On XC9500, the FF works as follows:: + + case(FB[i].MC[j].CLK_MUX) + PT: FB[i].MC[j].CLK = FB[i].MC[j].PT[0].SPECIAL; + FCLK0: FB[i].MC[j].CLK = FCLK[0]; + FCLK1: FB[i].MC[j].CLK = FCLK[1]; + FCLK2: FB[i].MC[j].CLK = FCLK[2]; + endcase + + case(FB[i].MC[j].RST_MUX) + PT: FB[i].MC[j].RST = FB[i].MC[j].PT[2].SPECIAL; + FSR: FB[i].MC[j].RST = FSR; + endcase + + case(FB[i].MC[j].SET_MUX) + PT: FB[i].MC[j].SET = FB[i].MC[j].PT[3].SPECIAL; + FSR: FB[i].MC[j].SET = FSR; + endcase + + initial FB[i].MC[j].FF = FB[i].MC[j].INIT; + + // Pretend the usual synth/sim mismatch doesn't happen. + always @(posedge FB[i].MC[j].CLK, posedge FB[i].MC[j].RST_MUX, posedge FB[i].MC[j].SET_MUX) + if (FB[i].MC[j].RST_MUX) + FB[i].MC[j].FF = 0; + else if (FB[i].MC[j].SET_MUX) + FB[i].MC[j].FF = 1; + else + FB[i].MC[j].FF = FB[i].MC[j].XOR; + +On XC9500XL/XV, the FF works as follows:: + + case(FB[i].MC[j].CLK_MUX) + PT: FB[i].MC[j].CLK = FB[i].MC[j].PT[0].SPECIAL ^ FB[i].MC[j].CLK_INV; + FCLK0: FB[i].MC[j].CLK = FCLK[0] ^ FB[i].MC[j].CLK_INV; + FCLK1: FB[i].MC[j].CLK = FCLK[1] ^ FB[i].MC[j].CLK_INV; + FCLK2: FB[i].MC[j].CLK = FCLK[2] ^ FB[i].MC[j].CLK_INV; + endcase + + case(FB[i].MC[j].RST_MUX) + PT: FB[i].MC[j].RST = (FB[i].MC[j].CE_MUX == PT2 ? 0 : FB[i].MC[j].PT[2].SPECIAL); + FSR: FB[i].MC[j].RST = FSR; + endcase + + case(FB[i].MC[j].SET_MUX) + PT: FB[i].MC[j].SET = (FB[i].MC[j].CE_MUX == PT3 ? 0 : FB[i].MC[j].PT[3].SPECIAL); + FSR: FB[i].MC[j].SET = FSR; + endcase + + case(FB[i].MC[j].CE_MUX) + PT2: FB[i].MC[j].CE = FB[i].MC[j].PT[2].SPECIAL; + PT3: FB[i].MC[j].CE = FB[i].MC[j].PT[3].SPECIAL; + NONE: FB[i].MC[j].CE = 1; + endcase + + initial FB[i].MC[j].FF = FB[i].MC[j].INIT; + + // Pretend the usual synth/sim mismatch doesn't happen. + always @(posedge FB[i].MC[j].CLK, posedge FB[i].MC[j].RST_MUX, posedge FB[i].MC[j].SET_MUX) + if (FB[i].MC[j].RST_MUX) + FB[i].MC[j].FF = 0; + else if (FB[i].MC[j].SET_MUX) + FB[i].MC[j].FF = 1; + else if (FB[i].MC[j].CE) + FB[i].MC[j].FF = FB[i].MC[j].XOR; + +.. todo:: verify (in particular, CE vs RST/SET shenanigans) + + +Macrocell output — XC9500 +========================= + +The output of the macrocell can be selected from combinatorial (XOR gate output) or registered (FF output):: + + FB[i].MC[j].OUT = (FB[i].MC[j].OUT_MUX == COMB ? FB[i].MC[j].XOR : FB[i].MC[j].FF); + +The macrocell also has an output enable, which can be from a product term, or a global network. +It can be used for the IOB output buffer, for UIM output, or both:: + + case(FB[i].MC[j].OE_MUX) + PT: FB[i].MC[j].OE = FB[i].MC[j].PT[1].SPECIAL; + FOE0: FB[i].MC[j].OE = FOE[0]; + FOE1: FB[i].MC[j].OE = FOE[1]; + FOE2: FB[i].MC[j].OE = FOE[2]; + FOE3: FB[i].MC[j].OE = FOE[3]; + endcase + + case(FB[i].MC[j].UIM_OE_MUX) + GND: FB[i].MC[j].UIM_OE = 0; + VCC: FB[i].MC[j].UIM_OE = 1; + OE_MUX: FB[i].MC[j].UIM_OE = FB[i].MC[j].OE; + endcase + + case(FB[i].MC[j].IOB_OE_MUX) + GND: FB[i].MC[j].IOB_OE = 0; + VCC: FB[i].MC[j].IOB_OE = 1; + OE_MUX: FB[i].MC[j].IOB_OE = FB[i].MC[j].OE; + endcase + +The output is routed to up to three places: + +- this MC's IOB (``FB[i].MC[j].OUT``) +- this FB's inputs via the feedback path (``FB[i].MC[j].OUT``) +- the UIM (``FB[i].MC[j].OUT_UIM``) + +The output to UIM additionally goes through (emulated) output enable logic, which can be used +to implement emulated on-chip tristate buses in conjunction with the UIM wire-AND logic:: + + FB[i].MC[j].OUT_UIM = FB[i].MC[j].UIM_OE ? FB[i].MC[j].OUT ^ FB[i].MC[j].UIM_OUT_INV : 1; + +The fuses involved are: + +- ``FB[i].MC[j].OUT_MUX``: selects output mode + + - ``COMB``: combinatorial, the output is connected to XOR gate output + - ``FF``: registered, the output is connected to FF output + +- ``FB[i].MC[j].OE_MUX``: selects output enable source + + - ``PT``: product term 1 dedicated function or 0 + - ``FOE[0-3]``: global ``FOE[0-3]`` network + +- ``FB[i].MC[j].UIM_OE_MUX``: selects output enable for UIM output + + - ``GND``: const 0 + - ``VCC``: const 1 + - ``OE_MUX``: the input selected by the ``OE_MUX`` fuses + +- ``FB[i].MC[j].IOB_OE_MUX``: selects output enable for IOB output + + - ``GND``: const 0 + - ``VCC``: const 1 + - ``OE_MUX``: the input selected by the ``OE_MUX`` fuses + +- ``FB[i].MC[j].UIM_OUT_INV``: if programmed, the output to UIM is inverted + + +.. todo:: verify all of the above (in particular, feedback path vs OE and UIM out) + + +Macrocell output — XC9500XL/XV +============================== + +The output of the macrocell can be selected from combinatorial (XOR gate output) or registered (FF output):: + + FB[i].MC[j].OUT = (FB[i].MC[j].OUT_MUX == COMB ? FB[i].MC[j].XOR : FB[i].MC[j].FF); + +The output is routed to the UIM and this MC's IOB. + +The macrocell also has an output enable, which can be from a product term, or a global network, and can +be freely inverted. It is used for the IOB output buffer:: + + case(FB[i].MC[j].OE_MUX) + PT: FB[i].MC[j].IOB_OE = FB[i].MC[j].PT[1].SPECIAL ^ FB[i].MC[j].OE_INV; + FOE0: FB[i].MC[j].IOB_OE = FOE[0] ^ FB[i].MC[j].OE_INV; + FOE1: FB[i].MC[j].IOB_OE = FOE[1] ^ FB[i].MC[j].OE_INV; + FOE2: FB[i].MC[j].IOB_OE = FOE[2] ^ FB[i].MC[j].OE_INV; + FOE3: FB[i].MC[j].IOB_OE = FOE[3] ^ FB[i].MC[j].OE_INV; + endcase + +The fuses involved are: + +- ``FB[i].MC[j].OUT_MUX``: selects output mode + + - ``COMB``: combinatorial, the output is connected to XOR gate output + - ``FF``: registered, the output is connected to FF output + +- ``FB[i].MC[j].OE_MUX``: selects output enable source + + - ``PT``: product term 1 dedicated function or 0 + - ``FOE[0-3]``: global ``FOE[0-3]`` network + +- ``FB[i].MC[j].OE_INV``: if programmed, the output enable is inverted + + +Input/output buffer +=================== + +All I/O buffers (except dedicated JTAG pins) are associated with a macrocell. Not all MCs +have associated IOBs. + +The output buffer is controlled by the ``FB[i].MC[j].OUT`` and ``FB[i].MC[j].IOB_OE`` signals of the macrocell. +If the pad is supposed to be input only, the OE signal should be programmed to be always 0: + +- on XC9500, ``IOB_OE_MUX`` should be set to ``GND`` +- on XC9500XL/XV, ``OE_MUX`` should be set to ``PT``, ``OE_INV`` should be unset, and ``PT[1]`` should not be allocated to its dedicated function + +Likewise, if the pad is supposed to be always-on output, the OE signal should be programmed to be always 1: + +- on XC9500, ``IOB_OE_MUX`` should be set to ``VCC`` +- on XC9500XL/XV, ``OE_MUX`` should be set to ``PT``, ``OE_INV`` should be set, and ``PT[1]`` should not be allocated to its dedicated function + +The output slew rate is programmable between two settings, "fast" and "slow". + +Instead of being connected to MC output, an IOB can also be a "programmed ground", ie be set to always output a const 0 +regardless of the ``IOB_OE`` and ``OUT`` signals. In this case, ``IOB_OE`` should be 0. + +The input buffer is connected to the ``FB[i].MC[j].IOB.I`` network. On all devices other than XC95288 (non-XL/XV), +it is directly connected to the UIM. On XC95288, there are additional enable fuses for this connection. + +Each I/O buffer has the following fuses: + +- ``FB[i].MC[j].GND``: if programmed, this pin is "programmed ground" and will always output a const 0 +- ``FB[i].MC[j].SLEW``: selects slew rate, one of: + + - ``SLOW`` + - ``FAST`` + +- ``FB[i].MC[j].IBUF_ENABLE`` (XC95288 only): when programmed, the input buffer is active and connected to UIM + +.. todo:: figure out the IBUF_ENABLE thing + + +Configuration pull-ups +====================== + +Before the device is configured, all IOBs are configured with a very weak pull-up +resistor (XC9500) or a bus keeper (XC9500XL/XV). To disable this pull-up, a per-FB fuse +is used which is set in the bitstream: + +- ``FB[i].PULLUP_DISABLE``: if programmed, disables the pre-configuration pull-ups / bus keepers for all IOBs in this FB + + +XC9500XL/XV bus keeper +====================== + +The XC9500XL/XV have a weak bus keeper in each IOB. The keeper functionality can only be enabled +globally for all pads on the device, or not at all, via a global fuse: + +- ``KEEPER``: if programmed, the bus keeper is enabled on all IOBs + + +Global networks — XC9500 +======================== + +The device has several global networks for fast control signals. The networks are always driven by special pads +on the device (which can also be used as normal I/O). The networks are: + +- ``FCLK[0-2]``: clock +- ``FSR``: async set or reset +- ``FOE[0-1]`` (XC9536, XC9572, XC95108) or ``FOE[0-3]`` (XC95144, XC95216, XC95288): output enable + +The special pads are: + +- ``GCLK[0-2]``: clock +- ``GSR``: async set or reset +- ``GOE[0-1]`` (XC9536, XC9572, XC95108) or ``GOE[0-3]`` (XC95144, XC95216, XC95288): output enable + +The mapping of ``G*`` special pads to MCs depends on the device and, in at least one case, the package (!). + +The allowed mappings are: + +- ``FCLK0``: ``GCLK0``, ``GCLK1`` +- ``FCLK1``: ``GCLK1``, ``GCLK2`` +- ``FCLK2``: ``GCLK2``, ``GCLK0`` +- ``FSR``: ``GSR`` +- ``FOE0`` (XC9536, XC9572, XC95108): ``GOE0``, ``GOE1`` +- ``FOE1`` (XC9536, XC9572, XC95108): ``GOE0``, ``GOE1`` +- ``FOE0`` (XC95144, XC95216, XC95288): ``GOE0``, ``GOE1`` +- ``FOE1`` (XC95144, XC95216, XC95288): ``GOE1``, ``GOE2`` +- ``FOE2`` (XC95144, XC95216, XC95288): ``GOE2``, ``GOE3`` +- ``FOE3`` (XC95144, XC95216, XC95288): ``GOE3``, ``GOE0`` + +Additionally, all networks can be inverted from their source pins. + +The fuses involved are: + +- ``FCLK[i].MUX``: selects the input routed to ``FCLK[i]`` + + - ``NONE``: const ??? + - ``GCLK[i]``: the corresponding ``GCLK`` pad + +- ``FOE[i].MUX``: selects the input routed to ``FOE[i]`` + + - ``NONE``: const ??? + - ``FOE[i]``: the corresponding ``FOE`` pad + +- ``FCLK[i].INV``: if programmed, the ``GCLK`` pad is inverted before driving ``FCLK[i]`` network +- ``FSR.INV``: if programmed, the ``GSR`` pad is inverted before driving ``FSR`` network +- ``FOE[i].INV``: if programmed, the ``GOE`` pad is inverted before driving ``FOE[i]`` network + +.. todo:: consts + +.. todo:: no, really, what is it with the XC9572 GOE mapping varying between packages + + +Global networks — XC9500XL/XV +============================= + +Global networks on XC9500XL/XV work similarly, except there are no muxes and no inversion (except for ``FSR``). +Thus the ``GCLK[i]`` and ``GOE[i]`` pads are mapped 1-1 directly to ``FCLK[i]`` and ``FOE[i]`` networks, with only +an enable fuse. + +The fuses involved are: + +- ``FCLK[i].EN``: if programmed, the given ``FCLK`` network is active and connected to the ``GCLK[i]`` pad +- ``FOE[i].EN``: if programmed, the given ``FOE`` network is active and connected to the ``GOE[i]`` pad +- ``FSR.INV``: if programmed, the ``GSR`` pad is inverted before driving ``FSR`` network + +The ``FSR`` network is always enabled. + +.. todo:: what does disabled network do + + +Misc configuration +================== + +The devices also include the following misc fuses: + +- ``USERCODE``: 32-bit fuse set, readable via the JTAG USERCODE instruction + +- ``FB[i].READ_PROT_{A|B}`` (XC9500): if programmed, the device is read protected +- ``FB[i].READ_PROT`` (XC9500XL/XV): if programmed, the device is read protected +- ``FB[i].WRITE_PROT``: if programmed, the device is write protected (needs a special JTAG instruction sequence + to program/erase) +- ``DONE`` (XC9500XV only): used to mark a fully programmed device; if programmed, the device will complete its + boot sequence and activate I/O buffers; otherwise, all output buffers will be disabled + +Due to their special semantics, the protection fuses and the ``DONE`` fuse should be programmed last, after all other fuses in the bitstream. + +.. todo:: exact semantics of protection fuses \ No newline at end of file diff --git a/_static/alabaster.css b/_static/alabaster.css new file mode 100644 index 00000000..517d0b29 --- /dev/null +++ b/_static/alabaster.css @@ -0,0 +1,703 @@ +@import url("basic.css"); + +/* -- page layout ----------------------------------------------------------- */ + +body { + font-family: Georgia, serif; + font-size: 17px; + background-color: #fff; + color: #000; + margin: 0; + padding: 0; +} + + +div.document { + width: 940px; + margin: 30px auto 0 auto; +} + +div.documentwrapper { + float: left; + width: 100%; +} + +div.bodywrapper { + margin: 0 0 0 220px; +} + +div.sphinxsidebar { + width: 220px; + font-size: 14px; + line-height: 1.5; +} + +hr { + border: 1px solid #B1B4B6; +} + +div.body { + background-color: #fff; + color: #3E4349; + padding: 0 30px 0 30px; +} + +div.body > .section { + text-align: left; +} + +div.footer { + width: 940px; + margin: 20px auto 30px auto; + font-size: 14px; + color: #888; + text-align: right; +} + +div.footer a { + color: #888; +} + +p.caption { + font-family: inherit; + font-size: inherit; +} + + +div.relations { + display: none; +} + + +div.sphinxsidebar a { + color: #444; + text-decoration: none; + border-bottom: 1px dotted #999; +} + +div.sphinxsidebar a:hover { + border-bottom: 1px solid #999; +} + +div.sphinxsidebarwrapper { + padding: 18px 10px; +} + +div.sphinxsidebarwrapper p.logo { + padding: 0; + margin: -10px 0 0 0px; + text-align: center; +} + +div.sphinxsidebarwrapper h1.logo { + margin-top: -10px; + text-align: center; + margin-bottom: 5px; + text-align: left; +} + +div.sphinxsidebarwrapper h1.logo-name { + margin-top: 0px; +} + +div.sphinxsidebarwrapper p.blurb { + margin-top: 0; + font-style: normal; +} + +div.sphinxsidebar h3, +div.sphinxsidebar h4 { + font-family: Georgia, serif; + color: #444; + font-size: 24px; + font-weight: normal; + margin: 0 0 5px 0; + padding: 0; +} + +div.sphinxsidebar h4 { + font-size: 20px; +} + +div.sphinxsidebar h3 a { + color: #444; +} + +div.sphinxsidebar p.logo a, +div.sphinxsidebar h3 a, +div.sphinxsidebar p.logo a:hover, +div.sphinxsidebar h3 a:hover { + border: none; +} + +div.sphinxsidebar p { + color: #555; + margin: 10px 0; +} + +div.sphinxsidebar ul { + margin: 10px 0; + padding: 0; + color: #000; +} + +div.sphinxsidebar ul li.toctree-l1 > a { + font-size: 120%; +} + +div.sphinxsidebar ul li.toctree-l2 > a { + font-size: 110%; +} + +div.sphinxsidebar input { + border: 1px solid #CCC; + font-family: Georgia, serif; + font-size: 1em; +} + +div.sphinxsidebar hr { + border: none; + height: 1px; + color: #AAA; + background: #AAA; + + text-align: left; + margin-left: 0; + width: 50%; +} + +div.sphinxsidebar .badge { + border-bottom: none; +} + +div.sphinxsidebar .badge:hover { + border-bottom: none; +} + +/* To address an issue with donation coming after search */ +div.sphinxsidebar h3.donation { + margin-top: 10px; +} + +/* -- body styles ----------------------------------------------------------- */ + +a { + color: #004B6B; + text-decoration: underline; +} + +a:hover { + color: #6D4100; + text-decoration: underline; +} + +div.body h1, +div.body h2, +div.body h3, +div.body h4, +div.body h5, +div.body h6 { + font-family: Georgia, serif; + font-weight: normal; + margin: 30px 0px 10px 0px; + padding: 0; +} + +div.body h1 { margin-top: 0; padding-top: 0; font-size: 240%; } +div.body h2 { font-size: 180%; } +div.body h3 { font-size: 150%; } +div.body h4 { font-size: 130%; } +div.body h5 { font-size: 100%; } +div.body h6 { font-size: 100%; } + +a.headerlink { + color: #DDD; + padding: 0 4px; + text-decoration: none; +} + +a.headerlink:hover { + color: #444; + background: #EAEAEA; +} + +div.body p, div.body dd, div.body li { + line-height: 1.4em; +} + +div.admonition { + margin: 20px 0px; + padding: 10px 30px; + background-color: #EEE; + border: 1px solid #CCC; +} + +div.admonition tt.xref, div.admonition code.xref, div.admonition a tt { + background-color: #FBFBFB; + border-bottom: 1px solid #fafafa; +} + +div.admonition p.admonition-title { + font-family: Georgia, serif; + font-weight: normal; + font-size: 24px; + margin: 0 0 10px 0; + padding: 0; + line-height: 1; +} + +div.admonition p.last { + margin-bottom: 0; +} + +div.highlight { + background-color: #fff; +} + +dt:target, .highlight { + background: #FAF3E8; +} + +div.warning { + background-color: #FCC; + border: 1px solid #FAA; +} + +div.danger { + background-color: #FCC; + border: 1px solid #FAA; + -moz-box-shadow: 2px 2px 4px #D52C2C; + -webkit-box-shadow: 2px 2px 4px #D52C2C; + box-shadow: 2px 2px 4px #D52C2C; +} + +div.error { + background-color: #FCC; + border: 1px solid #FAA; + -moz-box-shadow: 2px 2px 4px #D52C2C; + -webkit-box-shadow: 2px 2px 4px #D52C2C; + box-shadow: 2px 2px 4px #D52C2C; +} + +div.caution { + background-color: #FCC; + border: 1px solid #FAA; +} + +div.attention { + background-color: #FCC; + border: 1px solid #FAA; +} + +div.important { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.note { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.tip { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.hint { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.seealso { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.topic { + background-color: #EEE; +} + +p.admonition-title { + display: inline; +} + +p.admonition-title:after { + content: ":"; +} + +pre, tt, code { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; + font-size: 0.9em; +} + +.hll { + background-color: #FFC; + margin: 0 -12px; + padding: 0 12px; + display: block; +} + +img.screenshot { +} + +tt.descname, tt.descclassname, code.descname, code.descclassname { + font-size: 0.95em; +} + +tt.descname, code.descname { + padding-right: 0.08em; +} + +img.screenshot { + -moz-box-shadow: 2px 2px 4px #EEE; + -webkit-box-shadow: 2px 2px 4px #EEE; + box-shadow: 2px 2px 4px #EEE; +} + +table.docutils { + border: 1px solid #888; + -moz-box-shadow: 2px 2px 4px #EEE; + -webkit-box-shadow: 2px 2px 4px #EEE; + box-shadow: 2px 2px 4px #EEE; +} + +table.docutils td, table.docutils th { + border: 1px solid #888; + padding: 0.25em 0.7em; +} + +table.field-list, table.footnote { + border: none; + -moz-box-shadow: none; + -webkit-box-shadow: none; + box-shadow: none; +} + +table.footnote { + margin: 15px 0; + width: 100%; + border: 1px solid #EEE; + background: #FDFDFD; + font-size: 0.9em; +} + +table.footnote + table.footnote { + margin-top: -15px; + border-top: none; +} + +table.field-list th { + padding: 0 0.8em 0 0; +} + +table.field-list td { + padding: 0; +} + +table.field-list p { + margin-bottom: 0.8em; +} + +/* Cloned from + * https://github.com/sphinx-doc/sphinx/commit/ef60dbfce09286b20b7385333d63a60321784e68 + */ +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +table.footnote td.label { + width: .1px; + padding: 0.3em 0 0.3em 0.5em; +} + +table.footnote td { + padding: 0.3em 0.5em; +} + +dl { + margin-left: 0; + margin-right: 0; + margin-top: 0; + padding: 0; +} + +dl dd { + margin-left: 30px; +} + +blockquote { + margin: 0 0 0 30px; + padding: 0; +} + +ul, ol { + /* Matches the 30px from the narrow-screen "li > ul" selector below */ + margin: 10px 0 10px 30px; + padding: 0; +} + +pre { + background: #EEE; + padding: 7px 30px; + margin: 15px 0px; + line-height: 1.3em; +} + +div.viewcode-block:target { + background: #ffd; +} + +dl pre, blockquote pre, li pre { + margin-left: 0; + padding-left: 30px; +} + +tt, code { + background-color: #ecf0f3; + color: #222; + /* padding: 1px 2px; */ +} + +tt.xref, code.xref, a tt { + background-color: #FBFBFB; + border-bottom: 1px solid #fff; +} + +a.reference { + text-decoration: none; + border-bottom: 1px dotted #004B6B; +} + +/* Don't put an underline on images */ +a.image-reference, a.image-reference:hover { + border-bottom: none; +} + +a.reference:hover { + border-bottom: 1px solid #6D4100; +} + +a.footnote-reference { + text-decoration: none; + font-size: 0.7em; + vertical-align: top; + border-bottom: 1px dotted #004B6B; +} + +a.footnote-reference:hover { + border-bottom: 1px solid #6D4100; +} + +a:hover tt, a:hover code { + background: #EEE; +} + + +@media screen and (max-width: 870px) { + + div.sphinxsidebar { + display: none; + } + + div.document { + width: 100%; + + } + + div.documentwrapper { + margin-left: 0; + margin-top: 0; + margin-right: 0; + margin-bottom: 0; + } + + div.bodywrapper { + margin-top: 0; + margin-right: 0; + margin-bottom: 0; + margin-left: 0; + } + + ul { + margin-left: 0; + } + + li > ul { + /* Matches the 30px from the "ul, ol" selector above */ + margin-left: 30px; + } + + .document { + width: auto; + } + + .footer { + width: auto; + } + + .bodywrapper { + margin: 0; + } + + .footer { + width: auto; + } + + .github { + display: none; + } + + + +} + + + +@media screen and (max-width: 875px) { + + body { + margin: 0; + padding: 20px 30px; + } + + div.documentwrapper { + float: none; + background: #fff; + } + + div.sphinxsidebar { + display: block; + float: none; + width: 102.5%; + margin: 50px -30px -20px -30px; + padding: 10px 20px; + background: #333; + color: #FFF; + } + + div.sphinxsidebar h3, div.sphinxsidebar h4, div.sphinxsidebar p, + div.sphinxsidebar h3 a { + color: #fff; + } + + div.sphinxsidebar a { + color: #AAA; + } + + div.sphinxsidebar p.logo { + display: none; + } + + div.document { + width: 100%; + margin: 0; + } + + div.footer { + display: none; + } + + div.bodywrapper { + margin: 0; + } + + div.body { + min-height: 0; + padding: 0; + } + + .rtd_doc_footer { + display: none; + } + + .document { + width: auto; + } + + .footer { + width: auto; + } + + .footer { + width: auto; + } + + .github { + display: none; + } +} + + +/* misc. */ + +.revsys-inline { + display: none!important; +} + +/* Make nested-list/multi-paragraph items look better in Releases changelog + * pages. Without this, docutils' magical list fuckery causes inconsistent + * formatting between different release sub-lists. + */ +div#changelog > div.section > ul > li > p:only-child { + margin-bottom: 0; +} + +/* Hide fugly table cell borders in ..bibliography:: directive output */ +table.docutils.citation, table.docutils.citation td, table.docutils.citation th { + border: none; + /* Below needed in some edge cases; if not applied, bottom shadows appear */ + -moz-box-shadow: none; + -webkit-box-shadow: none; + box-shadow: none; +} + + +/* relbar */ + +.related { + line-height: 30px; + width: 100%; + font-size: 0.9rem; +} + +.related.top { + border-bottom: 1px solid #EEE; + margin-bottom: 20px; +} + +.related.bottom { + border-top: 1px solid #EEE; +} + +.related ul { + padding: 0; + margin: 0; + list-style: none; +} + +.related li { + display: inline; +} + +nav#rellinks { + float: right; +} + +nav#rellinks li+li:before { + content: "|"; +} + +nav#breadcrumbs li+li:before { + content: "\00BB"; +} + +/* Hide certain items when printing */ +@media print { + div.related { + display: none; + } +} \ No newline at end of file diff --git a/_static/basic.css b/_static/basic.css new file mode 100644 index 00000000..30fee9d0 --- /dev/null +++ b/_static/basic.css @@ -0,0 +1,925 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +div.section::after { + display: block; + content: ''; + clear: left; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li p.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 360px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +a:visited { + color: #551A8B; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, figure.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, figure.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, figure.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +img.align-default, figure.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-default { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar, +aside.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px; + background-color: #ffe; + width: 40%; + float: right; + clear: right; + overflow-x: auto; +} + +p.sidebar-title { + font-weight: bold; +} + +nav.contents, +aside.topic, +div.admonition, div.topic, blockquote { + clear: left; +} + +/* -- topics ---------------------------------------------------------------- */ + +nav.contents, +aside.topic, +div.topic { + border: 1px solid #ccc; + padding: 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +aside.sidebar > :last-child, +nav.contents > :last-child, +aside.topic > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +nav.contents::after, +aside.topic::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + margin-top: 10px; + margin-bottom: 10px; + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table.align-default { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +th > :first-child, +td > :first-child { + margin-top: 0px; +} + +th > :last-child, +td > :last-child { + margin-bottom: 0px; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure, figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption, figcaption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number, +figcaption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text, +figcaption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist { + margin: 1em 0; +} + +table.hlist td { + vertical-align: top; +} + +/* -- object description styles --------------------------------------------- */ + +.sig { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + +/* C++ specific styling */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, .sig.c .kt, +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.c .m, +.sig.cpp .m { + color: #1750EB; +} + +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { + color: #067D17; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +:not(li) > ol > li:first-child > :first-child, +:not(li) > ul > li:first-child > :first-child { + margin-top: 0px; +} + +:not(li) > ol > li:last-child > :last-child, +:not(li) > ul > li:last-child > :last-child { + margin-bottom: 0px; +} + +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; +} + +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; +} + +ol.simple p, +ul.simple p { + margin-bottom: 0; +} + +aside.footnote > span, +div.citation > span { + float: left; +} +aside.footnote > span:last-of-type, +div.citation > span:last-of-type { + padding-right: 0.5em; +} +aside.footnote > p { + margin-left: 2em; +} +div.citation > p { + margin-left: 4em; +} +aside.footnote > p:last-of-type, +div.citation > p:last-of-type { + margin-bottom: 0em; +} +aside.footnote > p:last-of-type:after, +div.citation > p:last-of-type:after { + content: ""; + clear: both; +} + +dl.field-list { + display: grid; + grid-template-columns: fit-content(30%) auto; +} + +dl.field-list > dt { + font-weight: bold; + word-break: break-word; + padding-left: 0.5em; + padding-right: 5px; +} + +dl.field-list > dd { + padding-left: 0.5em; + margin-top: 0em; + margin-left: 0em; + margin-bottom: 0em; +} + +dl { + margin-bottom: 15px; +} + +dd > :first-child { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +.sig dd { + margin-top: 0px; + margin-bottom: 0px; +} + +.sig dl { + margin-top: 0px; + margin-bottom: 0px; +} + +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +.classifier:before { + font-style: normal; + margin: 0 0.5em; + content: ":"; + display: inline-block; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +.translated { + background-color: rgba(207, 255, 207, 0.2) +} + +.untranslated { + background-color: rgba(255, 207, 207, 0.2) +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +pre, div[class*="highlight-"] { + clear: both; +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; + white-space: nowrap; +} + +div[class*="highlight-"] { + margin: 1em 0; +} + +td.linenos pre { + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + display: block; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; +} + +table.highlighttable td { + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding-right: 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div { + margin-top: 0; +} + +div.code-block-caption { + margin-top: 1em; + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +table.highlighttable td.linenos, +span.linenos, +div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + margin: 1em 0; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: absolute; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/_static/custom.css b/_static/custom.css new file mode 100644 index 00000000..2a924f1d --- /dev/null +++ b/_static/custom.css @@ -0,0 +1 @@ +/* This file intentionally left blank. */ diff --git a/_static/doctools.js b/_static/doctools.js new file mode 100644 index 00000000..d06a71d7 --- /dev/null +++ b/_static/doctools.js @@ -0,0 +1,156 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Base JavaScript utilities for all Sphinx HTML documentation. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([ + "TEXTAREA", + "INPUT", + "SELECT", + "BUTTON", +]); + +const _ready = (callback) => { + if (document.readyState !== "loading") { + callback(); + } else { + document.addEventListener("DOMContentLoaded", callback); + } +}; + +/** + * Small JavaScript module for the documentation. + */ +const Documentation = { + init: () => { + Documentation.initDomainIndexTable(); + Documentation.initOnKeyListeners(); + }, + + /** + * i18n support + */ + TRANSLATIONS: {}, + PLURAL_EXPR: (n) => (n === 1 ? 0 : 1), + LOCALE: "unknown", + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext: (string) => { + const translated = Documentation.TRANSLATIONS[string]; + switch (typeof translated) { + case "undefined": + return string; // no translation + case "string": + return translated; // translation exists + default: + return translated[0]; // (singular, plural) translation tuple exists + } + }, + + ngettext: (singular, plural, n) => { + const translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated !== "undefined") + return translated[Documentation.PLURAL_EXPR(n)]; + return n === 1 ? singular : plural; + }, + + addTranslations: (catalog) => { + Object.assign(Documentation.TRANSLATIONS, catalog.messages); + Documentation.PLURAL_EXPR = new Function( + "n", + `return (${catalog.plural_expr})` + ); + Documentation.LOCALE = catalog.locale; + }, + + /** + * helper function to focus on search bar + */ + focusSearchBar: () => { + document.querySelectorAll("input[name=q]")[0]?.focus(); + }, + + /** + * Initialise the domain index toggle buttons + */ + initDomainIndexTable: () => { + const toggler = (el) => { + const idNumber = el.id.substr(7); + const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`); + if (el.src.substr(-9) === "minus.png") { + el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`; + toggledRows.forEach((el) => (el.style.display = "none")); + } else { + el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`; + toggledRows.forEach((el) => (el.style.display = "")); + } + }; + + const togglerElements = document.querySelectorAll("img.toggler"); + togglerElements.forEach((el) => + el.addEventListener("click", (event) => toggler(event.currentTarget)) + ); + togglerElements.forEach((el) => (el.style.display = "")); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); + }, + + initOnKeyListeners: () => { + // only install a listener if it is really needed + if ( + !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && + !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS + ) + return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.altKey || event.ctrlKey || event.metaKey) return; + + if (!event.shiftKey) { + switch (event.key) { + case "ArrowLeft": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const prevLink = document.querySelector('link[rel="prev"]'); + if (prevLink && prevLink.href) { + window.location.href = prevLink.href; + event.preventDefault(); + } + break; + case "ArrowRight": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const nextLink = document.querySelector('link[rel="next"]'); + if (nextLink && nextLink.href) { + window.location.href = nextLink.href; + event.preventDefault(); + } + break; + } + } + + // some keyboard layouts may need Shift to get / + switch (event.key) { + case "/": + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; + Documentation.focusSearchBar(); + event.preventDefault(); + } + }); + }, +}; + +// quick alias for translations +const _ = Documentation.gettext; + +_ready(Documentation.init); diff --git a/_static/documentation_options.js b/_static/documentation_options.js new file mode 100644 index 00000000..7e4c114f --- /dev/null +++ b/_static/documentation_options.js @@ -0,0 +1,13 @@ +const DOCUMENTATION_OPTIONS = { + VERSION: '', + LANGUAGE: 'en', + COLLAPSE_INDEX: false, + BUILDER: 'html', + FILE_SUFFIX: '.html', + LINK_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: false, + SHOW_SEARCH_SUMMARY: true, + ENABLE_SEARCH_SHORTCUTS: true, +}; \ No newline at end of file diff --git a/_static/file.png b/_static/file.png new file mode 100644 index 00000000..a858a410 Binary files /dev/null and b/_static/file.png differ diff --git a/_static/language_data.js b/_static/language_data.js new file mode 100644 index 00000000..250f5665 --- /dev/null +++ b/_static/language_data.js @@ -0,0 +1,199 @@ +/* + * language_data.js + * ~~~~~~~~~~~~~~~~ + * + * This script contains the language-specific data used by searchtools.js, + * namely the list of stopwords, stemmer, scorer and splitter. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +var stopwords = ["a", "and", "are", "as", "at", "be", "but", "by", "for", "if", "in", "into", "is", "it", "near", "no", "not", "of", "on", "or", "such", "that", "the", "their", "then", "there", "these", "they", "this", "to", "was", "will", "with"]; + + +/* Non-minified version is copied as a separate JS file, is available */ + +/** + * Porter Stemmer + */ +var Stemmer = function() { + + var step2list = { + ational: 'ate', + tional: 'tion', + enci: 'ence', + anci: 'ance', + izer: 'ize', + bli: 'ble', + alli: 'al', + entli: 'ent', + eli: 'e', + ousli: 'ous', + ization: 'ize', + ation: 'ate', + ator: 'ate', + alism: 'al', + iveness: 'ive', + fulness: 'ful', + ousness: 'ous', + aliti: 'al', + iviti: 'ive', + biliti: 'ble', + logi: 'log' + }; + + var step3list = { + icate: 'ic', + ative: '', + alize: 'al', + iciti: 'ic', + ical: 'ic', + ful: '', + ness: '' + }; + + var c = "[^aeiou]"; // consonant + var v = "[aeiouy]"; // vowel + var C = c + "[^aeiouy]*"; // consonant sequence + var V = v + "[aeiou]*"; // vowel sequence + + var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0 + var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 + var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 + var s_v = "^(" + C + ")?" + v; // vowel in stem + + this.stemWord = function (w) { + var stem; + var suffix; + var firstch; + var origword = w; + + if (w.length < 3) + return w; + + var re; + var re2; + var re3; + var re4; + + firstch = w.substr(0,1); + if (firstch == "y") + w = firstch.toUpperCase() + w.substr(1); + + // Step 1a + re = /^(.+?)(ss|i)es$/; + re2 = /^(.+?)([^s])s$/; + + if (re.test(w)) + w = w.replace(re,"$1$2"); + else if (re2.test(w)) + w = w.replace(re2,"$1$2"); + + // Step 1b + re = /^(.+?)eed$/; + re2 = /^(.+?)(ed|ing)$/; + if (re.test(w)) { + var fp = re.exec(w); + re = new RegExp(mgr0); + if (re.test(fp[1])) { + re = /.$/; + w = w.replace(re,""); + } + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1]; + re2 = new RegExp(s_v); + if (re2.test(stem)) { + w = stem; + re2 = /(at|bl|iz)$/; + re3 = new RegExp("([^aeiouylsz])\\1$"); + re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re2.test(w)) + w = w + "e"; + else if (re3.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + else if (re4.test(w)) + w = w + "e"; + } + } + + // Step 1c + re = /^(.+?)y$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(s_v); + if (re.test(stem)) + w = stem + "i"; + } + + // Step 2 + re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step2list[suffix]; + } + + // Step 3 + re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step3list[suffix]; + } + + // Step 4 + re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; + re2 = /^(.+?)(s|t)(ion)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + if (re.test(stem)) + w = stem; + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1] + fp[2]; + re2 = new RegExp(mgr1); + if (re2.test(stem)) + w = stem; + } + + // Step 5 + re = /^(.+?)e$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + re2 = new RegExp(meq1); + re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) + w = stem; + } + re = /ll$/; + re2 = new RegExp(mgr1); + if (re.test(w) && re2.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + + // and turn initial Y back to y + if (firstch == "y") + w = firstch.toLowerCase() + w.substr(1); + return w; + } +} + diff --git a/_static/minus.png b/_static/minus.png new file mode 100644 index 00000000..d96755fd Binary files /dev/null and b/_static/minus.png differ diff --git a/_static/plus.png b/_static/plus.png new file mode 100644 index 00000000..7107cec9 Binary files /dev/null and b/_static/plus.png differ diff --git a/_static/pygments.css b/_static/pygments.css new file mode 100644 index 00000000..57c7df37 --- /dev/null +++ b/_static/pygments.css @@ -0,0 +1,84 @@ +pre { line-height: 125%; } +td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +.highlight .hll { background-color: #ffffcc } +.highlight { background: #f8f8f8; } +.highlight .c { color: #8f5902; font-style: italic } /* Comment */ +.highlight .err { color: #a40000; border: 1px solid #ef2929 } /* Error */ +.highlight .g { color: #000000 } /* Generic */ +.highlight .k { color: #004461; font-weight: bold } /* Keyword */ +.highlight .l { color: #000000 } /* Literal */ +.highlight .n { color: #000000 } /* Name */ +.highlight .o { color: #582800 } /* Operator */ +.highlight .x { color: #000000 } /* Other */ +.highlight .p { color: #000000; font-weight: bold } /* Punctuation */ +.highlight .ch { color: #8f5902; font-style: italic } /* Comment.Hashbang */ +.highlight .cm { color: #8f5902; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #8f5902 } /* Comment.Preproc */ +.highlight .cpf { color: #8f5902; font-style: italic } /* Comment.PreprocFile */ +.highlight .c1 { color: #8f5902; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #8f5902; font-style: italic } /* Comment.Special */ +.highlight .gd { color: #a40000 } /* Generic.Deleted */ +.highlight .ge { color: #000000; font-style: italic } /* Generic.Emph */ +.highlight .ges { color: #000000 } /* Generic.EmphStrong */ +.highlight .gr { color: #ef2929 } /* Generic.Error */ +.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.highlight .gi { color: #00A000 } /* Generic.Inserted */ +.highlight .go { color: #888888 } /* Generic.Output */ +.highlight .gp { color: #745334 } /* Generic.Prompt */ +.highlight .gs { color: #000000; font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.highlight .gt { color: #a40000; font-weight: bold } /* Generic.Traceback */ +.highlight .kc { color: #004461; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #004461; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #004461; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #004461; font-weight: bold } /* Keyword.Pseudo */ +.highlight .kr { color: #004461; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #004461; font-weight: bold } /* Keyword.Type */ +.highlight .ld { color: #000000 } /* Literal.Date */ +.highlight .m { color: #990000 } /* Literal.Number */ +.highlight .s { color: #4e9a06 } /* Literal.String */ +.highlight .na { color: #c4a000 } /* Name.Attribute */ +.highlight .nb { color: #004461 } /* Name.Builtin */ +.highlight .nc { color: #000000 } /* Name.Class */ +.highlight .no { color: #000000 } /* Name.Constant */ +.highlight .nd { color: #888888 } /* Name.Decorator */ +.highlight .ni { color: #ce5c00 } /* Name.Entity */ +.highlight .ne { color: #cc0000; font-weight: bold } /* Name.Exception */ +.highlight .nf { color: #000000 } /* Name.Function */ +.highlight .nl { color: #f57900 } /* Name.Label */ +.highlight .nn { color: #000000 } /* Name.Namespace */ +.highlight .nx { color: #000000 } /* Name.Other */ +.highlight .py { color: #000000 } /* Name.Property */ +.highlight .nt { color: #004461; font-weight: bold } /* Name.Tag */ +.highlight .nv { color: #000000 } /* Name.Variable */ +.highlight .ow { color: #004461; font-weight: bold } /* Operator.Word */ +.highlight .pm { color: #000000; font-weight: bold } /* Punctuation.Marker */ +.highlight .w { color: #f8f8f8; text-decoration: underline } /* Text.Whitespace */ +.highlight .mb { color: #990000 } /* Literal.Number.Bin */ +.highlight .mf { color: #990000 } /* Literal.Number.Float */ +.highlight .mh { color: #990000 } /* Literal.Number.Hex */ +.highlight .mi { color: #990000 } /* Literal.Number.Integer */ +.highlight .mo { color: #990000 } /* Literal.Number.Oct */ +.highlight .sa { color: #4e9a06 } /* Literal.String.Affix */ +.highlight .sb { color: #4e9a06 } /* Literal.String.Backtick */ +.highlight .sc { color: #4e9a06 } /* Literal.String.Char */ +.highlight .dl { color: #4e9a06 } /* Literal.String.Delimiter */ +.highlight .sd { color: #8f5902; font-style: italic } /* Literal.String.Doc */ +.highlight .s2 { color: #4e9a06 } /* Literal.String.Double */ +.highlight .se { color: #4e9a06 } /* Literal.String.Escape */ +.highlight .sh { color: #4e9a06 } /* Literal.String.Heredoc */ +.highlight .si { color: #4e9a06 } /* Literal.String.Interpol */ +.highlight .sx { color: #4e9a06 } /* Literal.String.Other */ +.highlight .sr { color: #4e9a06 } /* Literal.String.Regex */ +.highlight .s1 { color: #4e9a06 } /* Literal.String.Single */ +.highlight .ss { color: #4e9a06 } /* Literal.String.Symbol */ +.highlight .bp { color: #3465a4 } /* Name.Builtin.Pseudo */ +.highlight .fm { color: #000000 } /* Name.Function.Magic */ +.highlight .vc { color: #000000 } /* Name.Variable.Class */ +.highlight .vg { color: #000000 } /* Name.Variable.Global */ +.highlight .vi { color: #000000 } /* Name.Variable.Instance */ +.highlight .vm { color: #000000 } /* Name.Variable.Magic */ +.highlight .il { color: #990000 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/_static/searchtools.js b/_static/searchtools.js new file mode 100644 index 00000000..7918c3fa --- /dev/null +++ b/_static/searchtools.js @@ -0,0 +1,574 @@ +/* + * searchtools.js + * ~~~~~~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for the full-text search. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +/** + * Simple result scoring code. + */ +if (typeof Scorer === "undefined") { + var Scorer = { + // Implement the following function to further tweak the score for each result + // The function takes a result array [docname, title, anchor, descr, score, filename] + // and returns the new score. + /* + score: result => { + const [docname, title, anchor, descr, score, filename] = result + return score + }, + */ + + // query matches the full name of an object + objNameMatch: 11, + // or matches in the last dotted part of the object name + objPartialMatch: 6, + // Additive scores depending on the priority of the object + objPrio: { + 0: 15, // used to be importantResults + 1: 5, // used to be objectResults + 2: -5, // used to be unimportantResults + }, + // Used when the priority is not in the mapping. + objPrioDefault: 0, + + // query found in title + title: 15, + partialTitle: 7, + // query found in terms + term: 5, + partialTerm: 2, + }; +} + +const _removeChildren = (element) => { + while (element && element.lastChild) element.removeChild(element.lastChild); +}; + +/** + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping + */ +const _escapeRegExp = (string) => + string.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string + +const _displayItem = (item, searchTerms, highlightTerms) => { + const docBuilder = DOCUMENTATION_OPTIONS.BUILDER; + const docFileSuffix = DOCUMENTATION_OPTIONS.FILE_SUFFIX; + const docLinkSuffix = DOCUMENTATION_OPTIONS.LINK_SUFFIX; + const showSearchSummary = DOCUMENTATION_OPTIONS.SHOW_SEARCH_SUMMARY; + const contentRoot = document.documentElement.dataset.content_root; + + const [docName, title, anchor, descr, score, _filename] = item; + + let listItem = document.createElement("li"); + let requestUrl; + let linkUrl; + if (docBuilder === "dirhtml") { + // dirhtml builder + let dirname = docName + "/"; + if (dirname.match(/\/index\/$/)) + dirname = dirname.substring(0, dirname.length - 6); + else if (dirname === "index/") dirname = ""; + requestUrl = contentRoot + dirname; + linkUrl = requestUrl; + } else { + // normal html builders + requestUrl = contentRoot + docName + docFileSuffix; + linkUrl = docName + docLinkSuffix; + } + let linkEl = listItem.appendChild(document.createElement("a")); + linkEl.href = linkUrl + anchor; + linkEl.dataset.score = score; + linkEl.innerHTML = title; + if (descr) { + listItem.appendChild(document.createElement("span")).innerHTML = + " (" + descr + ")"; + // highlight search terms in the description + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + } + else if (showSearchSummary) + fetch(requestUrl) + .then((responseData) => responseData.text()) + .then((data) => { + if (data) + listItem.appendChild( + Search.makeSearchSummary(data, searchTerms) + ); + // highlight search terms in the summary + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + }); + Search.output.appendChild(listItem); +}; +const _finishSearch = (resultCount) => { + Search.stopPulse(); + Search.title.innerText = _("Search Results"); + if (!resultCount) + Search.status.innerText = Documentation.gettext( + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories." + ); + else + Search.status.innerText = _( + `Search finished, found ${resultCount} page(s) matching the search query.` + ); +}; +const _displayNextItem = ( + results, + resultCount, + searchTerms, + highlightTerms, +) => { + // results left, load the summary and display it + // this is intended to be dynamic (don't sub resultsCount) + if (results.length) { + _displayItem(results.pop(), searchTerms, highlightTerms); + setTimeout( + () => _displayNextItem(results, resultCount, searchTerms, highlightTerms), + 5 + ); + } + // search finished, update title and status message + else _finishSearch(resultCount); +}; + +/** + * Default splitQuery function. Can be overridden in ``sphinx.search`` with a + * custom function per language. + * + * The regular expression works by splitting the string on consecutive characters + * that are not Unicode letters, numbers, underscores, or emoji characters. + * This is the same as ``\W+`` in Python, preserving the surrogate pair area. + */ +if (typeof splitQuery === "undefined") { + var splitQuery = (query) => query + .split(/[^\p{Letter}\p{Number}_\p{Emoji_Presentation}]+/gu) + .filter(term => term) // remove remaining empty strings +} + +/** + * Search Module + */ +const Search = { + _index: null, + _queued_query: null, + _pulse_status: -1, + + htmlToText: (htmlString) => { + const htmlElement = new DOMParser().parseFromString(htmlString, 'text/html'); + htmlElement.querySelectorAll(".headerlink").forEach((el) => { el.remove() }); + const docContent = htmlElement.querySelector('[role="main"]'); + if (docContent !== undefined) return docContent.textContent; + console.warn( + "Content block not found. Sphinx search tries to obtain it via '[role=main]'. Could you check your theme or template." + ); + return ""; + }, + + init: () => { + const query = new URLSearchParams(window.location.search).get("q"); + document + .querySelectorAll('input[name="q"]') + .forEach((el) => (el.value = query)); + if (query) Search.performSearch(query); + }, + + loadIndex: (url) => + (document.body.appendChild(document.createElement("script")).src = url), + + setIndex: (index) => { + Search._index = index; + if (Search._queued_query !== null) { + const query = Search._queued_query; + Search._queued_query = null; + Search.query(query); + } + }, + + hasIndex: () => Search._index !== null, + + deferQuery: (query) => (Search._queued_query = query), + + stopPulse: () => (Search._pulse_status = -1), + + startPulse: () => { + if (Search._pulse_status >= 0) return; + + const pulse = () => { + Search._pulse_status = (Search._pulse_status + 1) % 4; + Search.dots.innerText = ".".repeat(Search._pulse_status); + if (Search._pulse_status >= 0) window.setTimeout(pulse, 500); + }; + pulse(); + }, + + /** + * perform a search for something (or wait until index is loaded) + */ + performSearch: (query) => { + // create the required interface elements + const searchText = document.createElement("h2"); + searchText.textContent = _("Searching"); + const searchSummary = document.createElement("p"); + searchSummary.classList.add("search-summary"); + searchSummary.innerText = ""; + const searchList = document.createElement("ul"); + searchList.classList.add("search"); + + const out = document.getElementById("search-results"); + Search.title = out.appendChild(searchText); + Search.dots = Search.title.appendChild(document.createElement("span")); + Search.status = out.appendChild(searchSummary); + Search.output = out.appendChild(searchList); + + const searchProgress = document.getElementById("search-progress"); + // Some themes don't use the search progress node + if (searchProgress) { + searchProgress.innerText = _("Preparing search..."); + } + Search.startPulse(); + + // index already loaded, the browser was quick! + if (Search.hasIndex()) Search.query(query); + else Search.deferQuery(query); + }, + + /** + * execute search (requires search index to be loaded) + */ + query: (query) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + const allTitles = Search._index.alltitles; + const indexEntries = Search._index.indexentries; + + // stem the search terms and add them to the correct list + const stemmer = new Stemmer(); + const searchTerms = new Set(); + const excludedTerms = new Set(); + const highlightTerms = new Set(); + const objectTerms = new Set(splitQuery(query.toLowerCase().trim())); + splitQuery(query.trim()).forEach((queryTerm) => { + const queryTermLower = queryTerm.toLowerCase(); + + // maybe skip this "word" + // stopwords array is from language_data.js + if ( + stopwords.indexOf(queryTermLower) !== -1 || + queryTerm.match(/^\d+$/) + ) + return; + + // stem the word + let word = stemmer.stemWord(queryTermLower); + // select the correct list + if (word[0] === "-") excludedTerms.add(word.substr(1)); + else { + searchTerms.add(word); + highlightTerms.add(queryTermLower); + } + }); + + if (SPHINX_HIGHLIGHT_ENABLED) { // set in sphinx_highlight.js + localStorage.setItem("sphinx_highlight_terms", [...highlightTerms].join(" ")) + } + + // console.debug("SEARCH: searching for:"); + // console.info("required: ", [...searchTerms]); + // console.info("excluded: ", [...excludedTerms]); + + // array of [docname, title, anchor, descr, score, filename] + let results = []; + _removeChildren(document.getElementById("search-progress")); + + const queryLower = query.toLowerCase(); + for (const [title, foundTitles] of Object.entries(allTitles)) { + if (title.toLowerCase().includes(queryLower) && (queryLower.length >= title.length/2)) { + for (const [file, id] of foundTitles) { + let score = Math.round(100 * queryLower.length / title.length) + results.push([ + docNames[file], + titles[file] !== title ? `${titles[file]} > ${title}` : title, + id !== null ? "#" + id : "", + null, + score, + filenames[file], + ]); + } + } + } + + // search for explicit entries in index directives + for (const [entry, foundEntries] of Object.entries(indexEntries)) { + if (entry.includes(queryLower) && (queryLower.length >= entry.length/2)) { + for (const [file, id] of foundEntries) { + let score = Math.round(100 * queryLower.length / entry.length) + results.push([ + docNames[file], + titles[file], + id ? "#" + id : "", + null, + score, + filenames[file], + ]); + } + } + } + + // lookup as object + objectTerms.forEach((term) => + results.push(...Search.performObjectSearch(term, objectTerms)) + ); + + // lookup as search terms in fulltext + results.push(...Search.performTermsSearch(searchTerms, excludedTerms)); + + // let the scorer override scores with a custom scoring function + if (Scorer.score) results.forEach((item) => (item[4] = Scorer.score(item))); + + // now sort the results by score (in opposite order of appearance, since the + // display function below uses pop() to retrieve items) and then + // alphabetically + results.sort((a, b) => { + const leftScore = a[4]; + const rightScore = b[4]; + if (leftScore === rightScore) { + // same score: sort alphabetically + const leftTitle = a[1].toLowerCase(); + const rightTitle = b[1].toLowerCase(); + if (leftTitle === rightTitle) return 0; + return leftTitle > rightTitle ? -1 : 1; // inverted is intentional + } + return leftScore > rightScore ? 1 : -1; + }); + + // remove duplicate search results + // note the reversing of results, so that in the case of duplicates, the highest-scoring entry is kept + let seen = new Set(); + results = results.reverse().reduce((acc, result) => { + let resultStr = result.slice(0, 4).concat([result[5]]).map(v => String(v)).join(','); + if (!seen.has(resultStr)) { + acc.push(result); + seen.add(resultStr); + } + return acc; + }, []); + + results = results.reverse(); + + // for debugging + //Search.lastresults = results.slice(); // a copy + // console.info("search results:", Search.lastresults); + + // print the results + _displayNextItem(results, results.length, searchTerms, highlightTerms); + }, + + /** + * search for object names + */ + performObjectSearch: (object, objectTerms) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const objects = Search._index.objects; + const objNames = Search._index.objnames; + const titles = Search._index.titles; + + const results = []; + + const objectSearchCallback = (prefix, match) => { + const name = match[4] + const fullname = (prefix ? prefix + "." : "") + name; + const fullnameLower = fullname.toLowerCase(); + if (fullnameLower.indexOf(object) < 0) return; + + let score = 0; + const parts = fullnameLower.split("."); + + // check for different match types: exact matches of full name or + // "last name" (i.e. last dotted part) + if (fullnameLower === object || parts.slice(-1)[0] === object) + score += Scorer.objNameMatch; + else if (parts.slice(-1)[0].indexOf(object) > -1) + score += Scorer.objPartialMatch; // matches in last name + + const objName = objNames[match[1]][2]; + const title = titles[match[0]]; + + // If more than one term searched for, we require other words to be + // found in the name/title/description + const otherTerms = new Set(objectTerms); + otherTerms.delete(object); + if (otherTerms.size > 0) { + const haystack = `${prefix} ${name} ${objName} ${title}`.toLowerCase(); + if ( + [...otherTerms].some((otherTerm) => haystack.indexOf(otherTerm) < 0) + ) + return; + } + + let anchor = match[3]; + if (anchor === "") anchor = fullname; + else if (anchor === "-") anchor = objNames[match[1]][1] + "-" + fullname; + + const descr = objName + _(", in ") + title; + + // add custom score for some objects according to scorer + if (Scorer.objPrio.hasOwnProperty(match[2])) + score += Scorer.objPrio[match[2]]; + else score += Scorer.objPrioDefault; + + results.push([ + docNames[match[0]], + fullname, + "#" + anchor, + descr, + score, + filenames[match[0]], + ]); + }; + Object.keys(objects).forEach((prefix) => + objects[prefix].forEach((array) => + objectSearchCallback(prefix, array) + ) + ); + return results; + }, + + /** + * search for full-text terms in the index + */ + performTermsSearch: (searchTerms, excludedTerms) => { + // prepare search + const terms = Search._index.terms; + const titleTerms = Search._index.titleterms; + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + + const scoreMap = new Map(); + const fileMap = new Map(); + + // perform the search on the required terms + searchTerms.forEach((word) => { + const files = []; + const arr = [ + { files: terms[word], score: Scorer.term }, + { files: titleTerms[word], score: Scorer.title }, + ]; + // add support for partial matches + if (word.length > 2) { + const escapedWord = _escapeRegExp(word); + Object.keys(terms).forEach((term) => { + if (term.match(escapedWord) && !terms[word]) + arr.push({ files: terms[term], score: Scorer.partialTerm }); + }); + Object.keys(titleTerms).forEach((term) => { + if (term.match(escapedWord) && !titleTerms[word]) + arr.push({ files: titleTerms[word], score: Scorer.partialTitle }); + }); + } + + // no match but word was a required one + if (arr.every((record) => record.files === undefined)) return; + + // found search word in contents + arr.forEach((record) => { + if (record.files === undefined) return; + + let recordFiles = record.files; + if (recordFiles.length === undefined) recordFiles = [recordFiles]; + files.push(...recordFiles); + + // set score for the word in each file + recordFiles.forEach((file) => { + if (!scoreMap.has(file)) scoreMap.set(file, {}); + scoreMap.get(file)[word] = record.score; + }); + }); + + // create the mapping + files.forEach((file) => { + if (fileMap.has(file) && fileMap.get(file).indexOf(word) === -1) + fileMap.get(file).push(word); + else fileMap.set(file, [word]); + }); + }); + + // now check if the files don't contain excluded terms + const results = []; + for (const [file, wordList] of fileMap) { + // check if all requirements are matched + + // as search terms with length < 3 are discarded + const filteredTermCount = [...searchTerms].filter( + (term) => term.length > 2 + ).length; + if ( + wordList.length !== searchTerms.size && + wordList.length !== filteredTermCount + ) + continue; + + // ensure that none of the excluded terms is in the search result + if ( + [...excludedTerms].some( + (term) => + terms[term] === file || + titleTerms[term] === file || + (terms[term] || []).includes(file) || + (titleTerms[term] || []).includes(file) + ) + ) + break; + + // select one (max) score for the file. + const score = Math.max(...wordList.map((w) => scoreMap.get(file)[w])); + // add result to the result list + results.push([ + docNames[file], + titles[file], + "", + null, + score, + filenames[file], + ]); + } + return results; + }, + + /** + * helper function to return a node containing the + * search summary for a given text. keywords is a list + * of stemmed words. + */ + makeSearchSummary: (htmlText, keywords) => { + const text = Search.htmlToText(htmlText); + if (text === "") return null; + + const textLower = text.toLowerCase(); + const actualStartPosition = [...keywords] + .map((k) => textLower.indexOf(k.toLowerCase())) + .filter((i) => i > -1) + .slice(-1)[0]; + const startWithContext = Math.max(actualStartPosition - 120, 0); + + const top = startWithContext === 0 ? "" : "..."; + const tail = startWithContext + 240 < text.length ? "..." : ""; + + let summary = document.createElement("p"); + summary.classList.add("context"); + summary.textContent = top + text.substr(startWithContext, 240).trim() + tail; + + return summary; + }, +}; + +_ready(Search.init); diff --git a/_static/sphinx_highlight.js b/_static/sphinx_highlight.js new file mode 100644 index 00000000..8a96c69a --- /dev/null +++ b/_static/sphinx_highlight.js @@ -0,0 +1,154 @@ +/* Highlighting utilities for Sphinx HTML documentation. */ +"use strict"; + +const SPHINX_HIGHLIGHT_ENABLED = true + +/** + * highlight a given string on a node by wrapping it in + * span elements with the given class name. + */ +const _highlight = (node, addItems, text, className) => { + if (node.nodeType === Node.TEXT_NODE) { + const val = node.nodeValue; + const parent = node.parentNode; + const pos = val.toLowerCase().indexOf(text); + if ( + pos >= 0 && + !parent.classList.contains(className) && + !parent.classList.contains("nohighlight") + ) { + let span; + + const closestNode = parent.closest("body, svg, foreignObject"); + const isInSVG = closestNode && closestNode.matches("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.classList.add(className); + } + + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + const rest = document.createTextNode(val.substr(pos + text.length)); + parent.insertBefore( + span, + parent.insertBefore( + rest, + node.nextSibling + ) + ); + node.nodeValue = val.substr(0, pos); + /* There may be more occurrences of search term in this node. So call this + * function recursively on the remaining fragment. + */ + _highlight(rest, addItems, text, className); + + if (isInSVG) { + const rect = document.createElementNS( + "http://www.w3.org/2000/svg", + "rect" + ); + const bbox = parent.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute("class", className); + addItems.push({ parent: parent, target: rect }); + } + } + } else if (node.matches && !node.matches("button, select, textarea")) { + node.childNodes.forEach((el) => _highlight(el, addItems, text, className)); + } +}; +const _highlightText = (thisNode, text, className) => { + let addItems = []; + _highlight(thisNode, addItems, text, className); + addItems.forEach((obj) => + obj.parent.insertAdjacentElement("beforebegin", obj.target) + ); +}; + +/** + * Small JavaScript module for the documentation. + */ +const SphinxHighlight = { + + /** + * highlight the search words provided in localstorage in the text + */ + highlightSearchWords: () => { + if (!SPHINX_HIGHLIGHT_ENABLED) return; // bail if no highlight + + // get and clear terms from localstorage + const url = new URL(window.location); + const highlight = + localStorage.getItem("sphinx_highlight_terms") + || url.searchParams.get("highlight") + || ""; + localStorage.removeItem("sphinx_highlight_terms") + url.searchParams.delete("highlight"); + window.history.replaceState({}, "", url); + + // get individual terms from highlight string + const terms = highlight.toLowerCase().split(/\s+/).filter(x => x); + if (terms.length === 0) return; // nothing to do + + // There should never be more than one element matching "div.body" + const divBody = document.querySelectorAll("div.body"); + const body = divBody.length ? divBody[0] : document.querySelector("body"); + window.setTimeout(() => { + terms.forEach((term) => _highlightText(body, term, "highlighted")); + }, 10); + + const searchBox = document.getElementById("searchbox"); + if (searchBox === null) return; + searchBox.appendChild( + document + .createRange() + .createContextualFragment( + '" + ) + ); + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords: () => { + document + .querySelectorAll("#searchbox .highlight-link") + .forEach((el) => el.remove()); + document + .querySelectorAll("span.highlighted") + .forEach((el) => el.classList.remove("highlighted")); + localStorage.removeItem("sphinx_highlight_terms") + }, + + initEscapeListener: () => { + // only install a listener if it is really needed + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) return; + if (DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS && (event.key === "Escape")) { + SphinxHighlight.hideSearchWords(); + event.preventDefault(); + } + }); + }, +}; + +_ready(() => { + /* Do not call highlightSearchWords() when we are on the search page. + * It will highlight words from the *previous* search query. + */ + if (typeof Search === "undefined") SphinxHighlight.highlightSearchWords(); + SphinxHighlight.initEscapeListener(); +}); diff --git a/genindex.html b/genindex.html new file mode 100644 index 00000000..c9c857f9 --- /dev/null +++ b/genindex.html @@ -0,0 +1,102 @@ + + + + + + + Index — Project Combine documentation + + + + + + + + + + + + + + + + +
+
+
+ + +
+ + +

Index

+ +
+ +
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 00000000..9181bb4d --- /dev/null +++ b/index.html @@ -0,0 +1,111 @@ + + + + + + + + Project Combine — Project Combine documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

Project Combine

+
+

Contents:

+ +
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/objects.inv b/objects.inv new file mode 100644 index 00000000..5a8d9128 Binary files /dev/null and b/objects.inv differ diff --git a/search.html b/search.html new file mode 100644 index 00000000..a3d2fedc --- /dev/null +++ b/search.html @@ -0,0 +1,121 @@ + + + + + + + Search — Project Combine documentation + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Search

+ + + + +

+ Searching for multiple words only shows matches that contain + all words. +

+ + +
+ + + +
+ + + +
+ +
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/searchindex.js b/searchindex.js new file mode 100644 index 00000000..5ff7f26e --- /dev/null +++ b/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({"docnames": ["index", "xc9500/bitstream-xc9500", "xc9500/bitstream-xc9500xl", "xc9500/index", "xc9500/intro", "xc9500/jtag", "xc9500/structure"], "filenames": ["index.rst", "xc9500/bitstream-xc9500.rst", "xc9500/bitstream-xc9500xl.rst", "xc9500/index.rst", "xc9500/intro.rst", "xc9500/jtag.rst", "xc9500/structure.rst"], "titles": ["Project Combine", "Bitstream structure - XC9500", "Bitstream structure \u2014 XC9500XL/XV", "XC9500, XC9500XL, XC9500XV", "Introduction", "JTAG interface", "Device structure"], "terms": {"xc9500": [0, 2, 4], "xc9500xl": [0, 4], "xc9500xv": [0, 4, 5, 6], "On": [1, 2, 6], "high": [1, 2, 5, 6], "level": [1, 2], "whole": [1, 2], "i": [1, 2, 4, 5, 6], "split": [1, 2], "area": [1, 2], "each": [1, 2, 4, 6], "devic": [1, 2, 3, 5], "correspond": [1, 2, 4, 5, 6], "two": [1, 4, 6], "one": [1, 2, 6], "which": [1, 5, 6], "contain": [1, 4], "configur": [1, 3, 4], "other": [1, 4, 5, 6], "main": [1, 2, 6], "everyth": [1, 2], "els": [1, 2, 6], "The": [1, 2, 4, 5, 6], "made": [1, 2, 6], "72": [1, 2], "row": [1, 2], "15": [1, 2], "column": [1, 2], "6": [1, 2, 4, 5], "8": [1, 2, 4, 5], "0": [1, 2, 4, 5, 6], "ar": [1, 2, 4, 5, 6], "while": [1, 2, 5], "9": [1, 2, 5], "14": [1, 2], "low": [1, 2, 6], "everi": [1, 2, 5], "us": [1, 2, 5, 6], "store": [1, 2, 5], "mask": [1, 2], "2": [1, 2, 4, 5, 6], "turn": 1, "subarea": 1, "18": [1, 2, 5, 6], "5": [1, 2, 5, 6], "1": [1, 2, 4, 5, 6], "4": [1, 2, 4, 5, 6], "7": [1, 2, 5], "make": 1, "36": [1, 2, 4, 6], "total": 1, "when": [1, 2, 5, 6], "program": [1, 2, 3, 6], "read": [1, 2, 6], "via": [1, 2, 6], "jtag": [1, 2, 3, 6], "transmit": [1, 2], "byte": [1, 2, 5], "long": [1, 2, 5], "ha": [1, 2, 4, 6], "its": [1, 2, 6], "address": [1, 2, 5], "Not": [1, 2, 6], "all": [1, 2, 4, 5, 6], "valid": [1, 2, 5], "contigu": [1, 2], "17": [1, 2, 5, 6], "sever": [1, 2, 6], "field": [1, 2], "13": [1, 2], "16": [1, 2, 4, 5, 6], "index": [1, 2, 6], "12": [1, 2, 4], "kind": 1, "config": [1, 2], "11": [1, 2], "3": [1, 2, 4, 5, 6], "sourc": [1, 6], "unprogram": [1, 2], "state": [1, 2, 5, 6], "thu": [1, 2, 6], "whenev": [1, 2], "boolean": [1, 2], "mention": [1, 2], "document": [1, 2], "true": [1, 2, 6], "valu": [1, 2, 5, 6], "actual": [1, 2], "repres": [1, 2], "thi": [1, 6], "includ": [1, 5, 6], "usercod": [1, 2, 5, 6], "In": [1, 2, 6], "simpli": [1, 2], "concaten": [1, 2], "order": [1, 2], "skip": [1, 2], "over": [1, 2], "invalid": [1, 2], "pad": [1, 2, 6], "have": [1, 2, 4, 5, 6], "nativ": [1, 2], "size": [1, 2], "convert": [1, 2], "from": [1, 2, 4, 6], "involv": [1, 2, 6], "some": [1, 2, 4, 5, 6], "complex": [1, 2], "calcul": [1, 2], "main_row_bit": 1, "uim_row_bit": 1, "main_area_bit": 1, "uim_subarea_bit": 1, "uim_area_bit": 1, "num_fb": [1, 2, 5], "fb_bit": 1, "total_bit": [1, 2], "def": [1, 2], "jed_to_jtag": [1, 2], "return": [1, 2], "jtag_to_j": [1, 2], "addr": [1, 2], "0xf": 1, "assert": [1, 2], "0x7f": [1, 2], "col_hi": [1, 2], "col_lo": [1, 2], "cfuse": [1, 2], "0x1f": 1, "formula": [1, 2], "follow": [1, 2, 4, 5, 6], "mc": [1, 2, 5, 6], "j": [1, 2, 5, 6], "pt": [1, 2], "k": [1, 2, 6], "im": [1, 2, 6], "l": [1, 2, 6], "p": [1, 2, 6], "n": [1, 2, 6], "54": [1, 4, 6], "function": [1, 2, 4, 5, 6], "mc_idx": [1, 2], "alloc": [1, 2, 6], "19": [1, 2], "20": [1, 2, 4], "21": [1, 2], "22": [1, 2], "inv": [1, 2, 6], "23": [1, 2], "import_up_alloc": [1, 2, 6], "24": [1, 2], "import_down_alloc": [1, 2, 6], "25": [1, 2], "export_dir": [1, 2, 6], "26": [1, 2, 5], "sum_hp": [1, 2, 6], "27": [1, 2, 5], "iob_oe_mux": [1, 6], "28": [1, 2], "29": [1, 2], "oe_mux": [1, 2, 6], "30": [1, 2, 4], "31": [1, 2], "32": [1, 2, 6], "34": [1, 2], "unus": [1, 2, 6], "35": [1, 2], "out_mux": [1, 2, 6], "clk_mux": [1, 2, 6], "37": [1, 2], "38": [1, 2], "39": [1, 2], "40": [1, 2], "reg_mod": [1, 2, 6], "41": [1, 2], "rst_mux": [1, 2, 6], "42": [1, 2], "set_mux": [1, 2, 6], "43": [1, 2], "init": [1, 2, 6], "44": [1, 2], "uim_oe_mux": [1, 6], "45": [1, 2], "46": [1, 2], "uim_out_inv": [1, 6], "47": [1, 2], "48": [1, 2], "gnd": [1, 2, 6], "49": [1, 2], "slew": [1, 2, 6], "50": [1, 2], "hp": [1, 2, 6], "51": 1, "52": 1, "53": 1, "combin": [1, 2, 6], "assign": [1, 2], "none": [1, 2, 6], "10": [1, 2, 5], "or_main": [1, 2, 6], "01": [1, 2], "or_export": [1, 2, 6], "00": [1, 2], "special": [1, 2, 6], "import_": [1, 2, 6], "_alloc": [1, 2], "up": [1, 2, 3, 5], "down": [1, 2, 6], "vcc": [1, 6], "comb": [1, 2, 6], "ff": [1, 2, 4, 6], "111": 1, "110": 1, "foe0": [1, 6], "101": 1, "foe1": [1, 6], "100": 1, "foe2": [1, 6], "011": 1, "foe3": [1, 6], "fclk1": [1, 2, 6], "fclk2": [1, 2, 6], "fclk0": [1, 2, 6], "dff": [1, 2, 6], "tff": [1, 2, 6], "fsr": [1, 2, 6], "slow": [1, 2, 6], "fast": [1, 2, 6], "fals": [1, 2], "mux": [1, 2, 6], "configuraton": [1, 2], "55": 1, "66": 1, "exact": [1, 2, 6], "irregular": [1, 2], "should": [1, 2, 6], "obtain": [1, 2], "databas": [1, 2], "67": 1, "68": 1, "export_en": [1, 2, 6], "pullup_dis": [1, 2, 6], "fsr_inv": [1, 2], "fclk": [1, 2, 4, 6], "foe": [1, 2, 4, 6], "gclk": [1, 6], "small": 1, "goe": [1, 6], "larg": 1, "invert": [1, 2, 6], "xc95288": [1, 4, 6], "ibuf_en": [1, 6], "an": [1, 6], "manner": 1, "duplic": 1, "twice": 1, "onc": [1, 2, 6], "purpos": [1, 5], "unknown": [1, 5], "consult": 1, "read_prot_a": 1, "read_prot_b": 1, "write_prot": [1, 2, 5, 6], "differ": [2, 6], "uim": [2, 3, 4], "wire": [2, 3, 4, 6], "AND": [2, 3, 4, 6], "complet": [2, 4, 6], "gone": 2, "onli": [2, 5, 6], "exist": [2, 4, 5], "108": 2, "instead": [2, 4, 6], "sens": 2, "version": [2, 4, 6], "load": [2, 5], "sequenti": 2, "parallel": 2, "unit": 2, "word": [2, 5, 6], "likewis": [2, 6], "interleav": 2, "row_bit": 2, "unchang": 2, "now": [2, 4], "more": [2, 6], "oe_inv": [2, 6], "33": 2, "clk_inv": [2, 6], "ce_mux": [2, 6], "pt2": [2, 6], "pt3": [2, 6], "76": 2, "coordin": [2, 6], "otherwis": [2, 6], "78": 2, "enabl": [2, 3, 4, 5, 6], "en": [2, 6], "keeper": [2, 3, 4], "directli": [2, 6], "read_prot": [2, 5, 6], "introduct": 3, "packag": [3, 6], "structur": 3, "overview": 3, "fb": [3, 5], "input": [3, 4, 5], "xv": 3, "global": 3, "fuse": 3, "product": 3, "term": 3, "sum": 3, "xor": 3, "gate": 3, "flip": 3, "flop": 3, "macrocel": 3, "output": [3, 5], "buffer": 3, "pull": [3, 5], "bu": [3, 4], "network": 3, "misc": 3, "bitstream": [3, 4, 5, 6], "jed": 3, "format": 3, "map": [3, 6], "per": [3, 4, 6], "bit": [3, 4, 5, 6], "protect": [3, 6], "done": [3, 4, 5, 6], "interfac": 3, "ir": 3, "boundari": 3, "scan": 3, "regist": [3, 6], "isp": 3, "instruct": [3, 6], "sequenc": [3, 6], "famili": [4, 6], "flash": 4, "base": 4, "cpld": [4, 6], "manufactur": 4, "xilinx": 4, "It": [4, 6], "deriv": 4, "earlier": 4, "xc7200": 4, "xc7300": 4, "epld": 4, "come": [4, 6], "three": [4, 6], "variant": 4, "5v": 4, "core": [4, 6], "logic": [4, 6], "3v": 4, "o": [4, 6], "origin": 4, "toler": 4, "chang": 4, "longer": 4, "clock": [4, 5, 6], "block": [4, 6], "polar": [4, 6], "multiplex": 4, "invers": [4, 6], "been": 4, "remov": 4, "option": [4, 6], "weak": [4, 5, 6], "can": [4, 5, 6], "pin": [4, 6], "8v": 4, "minor": 4, "larger": [4, 6], "bank": 4, "separ": 4, "vccio": 4, "ti": 4, "isc_don": 4, "prevent": 4, "problem": 4, "partial": 4, "xc9536": [4, 6], "xc9572": [4, 6], "xc95108": [4, 6], "xc95144": [4, 6], "xc95216": [4, 6], "xc9536xl": 4, "xc9572xl": 4, "xc95144xl": 4, "xc95288xl": 4, "xa9536xl": 4, "xa9572xl": 4, "xa95144xl": 4, "xc9536xv": 4, "xc9572xv": 4, "xc95144xv": 4, "xc95288xv": 4, "part": 4, "start": [4, 5], "xa": 4, "automot": 4, "thei": 4, "ident": 4, "xc": 4, "plcc": 4, "pc44": 4, "jedec": 4, "mo": 4, "047": 4, "pc84": 4, "qfp": 4, "veri": [4, 6], "thin": 4, "1mm": 4, "thick": 4, "vq44": 4, "8mm": 4, "pitch": 4, "m": 4, "026": 4, "acb": 4, "vq64": 4, "5mm": 4, "acd": 4, "4mm": 4, "tq100": 4, "bed": 4, "tq144": 4, "bfb": 4, "plastic": 4, "pq100": 4, "7mm": 4, "non": [4, 6], "squar": 4, "65mm": 4, "022": 4, "gc1": 4, "pq160": 4, "dd1": 4, "pq208": 4, "029": 4, "fa": 4, "platic": 4, "heat": 4, "sink": 4, "hq208": 4, "same": [4, 6], "footprint": 4, "bga": 4, "standard": [4, 6], "27mm": 4, "bg256": 4, "034": 4, "bal": 4, "bg352": 4, "fine": 4, "fg256": 4, "chip": [4, 6], "scale": 4, "cs48": 4, "cs144": 4, "216": 4, "bag": 4, "cs280": 4, "x": 4, "compat": 4, "maintain": 4, "across": [4, 6], "within": [4, 6], "singl": [4, 6], "addition": [4, 6], "note": 5, "00000000": 5, "extest": 5, "00000001": 5, "sampl": 5, "00000010": 5, "intest": 5, "11100101": 5, "fblank": 5, "ispaddress": 5, "11101000": 5, "ispen": 5, "11101001": 5, "ispenc": 5, "11101010": 5, "fpgm": 5, "ispconfigur": 5, "11101011": 5, "fpgmi": 5, "ispdata": 5, "11101100": 5, "feras": 5, "11101101": 5, "fbulk": 5, "11101110": 5, "fvfy": 5, "11101111": 5, "fvfyi": 5, "11110000": 5, "ispex": 5, "bypass": 5, "11111010": 5, "clamp": 5, "11111100": 5, "highz": 5, "11111101": 5, "11111110": 5, "idcod": 5, "11111111": 5, "statu": 5, "const": [5, 6], "verifi": [5, 6], "consist": [5, 6], "Such": 5, "even": 5, "do": [5, 6], "iob": [5, 6], "indic": 5, "bc_1": 5, "type": 5, "cell": 5, "detail": 5, "connect": [5, 6], "semant": [5, 6], "content": 5, "unclear": 5, "strobe": 5, "data": 5, "subset": [5, 6], "autoincr": 5, "describ": 5, "num_sb": 5, "befor": [5, 6], "ani": [5, 6], "readout": 5, "need": [5, 6], "put": 5, "For": 5, "both": [5, 6], "Its": 5, "mean": [5, 6], "To": [5, 6], "shift": 5, "go": [5, 6], "run": 5, "test": 5, "idl": 5, "least": [5, 6], "If": [5, 6], "z": 5, "activ": [5, 6], "signal": [5, 6], "snapshot": 5, "continu": 5, "drive": [5, 6], "last": [5, 6], "initi": [5, 6], "itself": 5, "normal": [5, 6], "oper": 5, "see": 5, "anyth": 5, "figur": [5, 6], "out": [5, 6], "about": 5, "write": [5, 6], "me": 5, "univers": 6, "interconnect": 6, "matrix": 6, "rout": 6, "routabl": 6, "power": 6, "perform": 6, "mode": 6, "router": 6, "neighbour": 6, "oe": 6, "rst": 6, "set": 6, "clk": 6, "ce": 6, "depend": 6, "borrow": 6, "between": 6, "dedic": 6, "freeli": 6, "async": 6, "reset": 6, "select": 6, "combinatori": 6, "rate": 6, "programm": 6, "ground": 6, "hardwir": 6, "alwai": 6, "gsr": 6, "meant": 6, "unconfigur": 6, "name": 6, "quit": 6, "appropri": 6, "intern": 6, "than": 6, "arbitrari": 6, "entir": 6, "togeth": 6, "emul": 6, "tri": 6, "buse": 6, "howev": 6, "less": 6, "extern": 6, "given": 6, "feedback": 6, "path": 6, "straight": 6, "redund": 6, "much": 6, "faster": 6, "we": 6, "call": 6, "control": 6, "what": 6, "empti": 6, "constant": 6, "second": 6, "relev": 6, "fbk_mc": 6, "through": 6, "pad_fb": 6, "_mc": 6, "allow": 6, "don": 6, "t": 6, "particip": 6, "out_uim": 6, "These": 6, "check": 6, "fbk": 6, "doesn": 6, "realli": 6, "classic": 6, "design": 6, "determin": 6, "exactli": 6, "90": 6, "them": 6, "form": 6, "individu": 6, "affect": 6, "propag": 6, "time": 6, "most": 6, "destin": 6, "": 6, "OR": 6, "four": 6, "equal": 6, "end": 6, "export_": 6, "direct": 6, "toward": 6, "lower": 6, "number": 6, "wraparound": 6, "higher": 6, "accordingli": 6, "import_down": 6, "export_down": 6, "import_up": 6, "export_up": 6, "A": 6, "either": 6, "further": 6, "downward": 6, "upward": 6, "work": 6, "abov": 6, "whose": 6, "d": 6, "potenti": 6, "ie": 6, "negedg": 6, "substitut": 6, "case": 6, "endcas": 6, "pretend": 6, "usual": 6, "synth": 6, "sim": 6, "mismatch": 6, "happen": 6, "posedg": 6, "particular": 6, "v": 6, "shenanigan": 6, "also": 6, "uim_o": 6, "iob_o": 6, "place": 6, "implement": 6, "tristat": 6, "conjunct": 6, "except": 6, "associ": 6, "suppos": 6, "unset": 6, "being": 6, "regardless": 6, "xl": 6, "addit": 6, "thing": 6, "resistor": 6, "disabl": 6, "pre": 6, "driven": 6, "g": 6, "gclk0": 6, "gclk1": 6, "gclk2": 6, "goe0": 6, "goe1": 6, "goe2": 6, "goe3": 6, "vari": 6, "similarli": 6, "doe": 6, "readabl": 6, "read_prot_": 6, "b": 6, "eras": 6, "mark": 6, "fulli": 6, "boot": 6, "due": 6, "after": 6}, "objects": {}, "objtypes": {}, "objnames": {}, "titleterms": {"project": 0, "combin": 0, "content": [0, 3], "bitstream": [1, 2], "structur": [1, 2, 6], "xc9500": [1, 3, 5, 6], "jed": [1, 2], "format": [1, 2], "map": [1, 2], "fuse": [1, 2, 5, 6], "product": [1, 2, 6], "term": [1, 2, 6], "macrocel": [1, 2, 6], "fb": [1, 2, 6], "input": [1, 2, 6], "per": [1, 2], "bit": [1, 2], "global": [1, 2, 6], "buffer": [1, 6], "enabl": 1, "protect": [1, 2], "uim": [1, 6], "wire": 1, "AND": 1, "xc9500xl": [2, 3, 5, 6], "xv": [2, 5, 6], "done": 2, "xc9500xv": 3, "introduct": 4, "devic": [4, 6], "packag": 4, "jtag": 5, "interfac": 5, "ir": 5, "todo": [5, 6], "boundari": 5, "scan": 5, "regist": 5, "isp": 5, "instruct": 5, "dr": 5, "enter": 5, "exit": 5, "mode": 5, "eras": 5, "program": 5, "read": 5, "blank": 5, "check": 5, "sequenc": 5, "overview": 6, "pt": 6, "import": 6, "export": 6, "sum": 6, "xor": 6, "gate": 6, "flip": 6, "flop": 6, "output": 6, "configur": 6, "pull": 6, "up": 6, "bu": 6, "keeper": 6, "network": 6, "misc": 6}, "envversion": {"sphinx.domains.c": 3, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 9, "sphinx.domains.index": 1, "sphinx.domains.javascript": 3, "sphinx.domains.math": 2, "sphinx.domains.python": 4, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx.ext.todo": 2, "sphinx": 60}, "alltitles": {"Project Combine": [[0, "project-combine"]], "Contents:": [[0, null], [3, null]], "Bitstream structure - XC9500": [[1, "bitstream-structure-xc9500"]], "JED format mapping": [[1, "jed-format-mapping"], [2, "jed-format-mapping"]], "Fuses \u2014 product terms": [[1, "fuses-product-terms"], [2, "fuses-product-terms"]], "Fuses \u2014 macrocells": [[1, "fuses-macrocells"], [2, "fuses-macrocells"]], "Fuses \u2014 FB inputs": [[1, "fuses-fb-inputs"], [2, "fuses-fb-inputs"]], "Fuses \u2014 per-FB bits and globals": [[1, "fuses-per-fb-bits-and-globals"], [2, "fuses-per-fb-bits-and-globals"]], "Fuses \u2014 input buffer enable": [[1, "fuses-input-buffer-enable"]], "Fuses \u2014 protection bits": [[1, "fuses-protection-bits"]], "Fuses \u2014 UIM wire-AND": [[1, "fuses-uim-wire-and"]], "Bitstream structure \u2014 XC9500XL/XV": [[2, "bitstream-structure-xc9500xl-xv"]], "Fuses \u2014 protection bits, DONE": [[2, "fuses-protection-bits-done"]], "XC9500, XC9500XL, XC9500XV": [[3, "xc9500-xc9500xl-xc9500xv"]], "Introduction": [[4, "introduction"]], "Devices": [[4, "devices"]], "Packages": [[4, "packages"]], "JTAG interface": [[5, "jtag-interface"]], "IR": [[5, "ir"]], "Todo": [[5, "id1"], [5, "id2"], [5, "id3"], [5, "id4"], [5, "id5"], [5, "id6"], [5, "id7"], [5, "id8"], [5, "id9"], [6, "id1"], [6, "id2"], [6, "id3"], [6, "id4"], [6, "id5"], [6, "id6"], [6, "id7"], [6, "id8"], [6, "id9"], [6, "id10"], [6, "id11"], [6, "id12"]], "Boundary scan register": [[5, "boundary-scan-register"]], "ISP instructions": [[5, "isp-instructions"]], "ISP DR registers \u2014 XC9500": [[5, "isp-dr-registers-xc9500"]], "ISP DR registers \u2014 XC9500XL/XV": [[5, "isp-dr-registers-xc9500xl-xv"]], "Entering and exiting ISP mode": [[5, "entering-and-exiting-isp-mode"]], "Erasing fuses": [[5, "erasing-fuses"]], "Programming fuses": [[5, "programming-fuses"]], "Reading fuses": [[5, "reading-fuses"]], "Blank check": [[5, "blank-check"]], "Programming sequence": [[5, "programming-sequence"]], "Device structure": [[6, "device-structure"]], "Overview": [[6, "overview"]], "UIM and FB inputs \u2014 XC9500": [[6, "uim-and-fb-inputs-xc9500"]], "UIM and FB inputs \u2014 XC9500XL/XV": [[6, "uim-and-fb-inputs-xc9500xl-xv"]], "FB global fuses": [[6, "fb-global-fuses"]], "Product terms": [[6, "product-terms"]], "PT import/export": [[6, "pt-import-export"]], "Sum term, XOR gate": [[6, "sum-term-xor-gate"]], "Flip-flop": [[6, "flip-flop"]], "Macrocell output \u2014 XC9500": [[6, "macrocell-output-xc9500"]], "Macrocell output \u2014 XC9500XL/XV": [[6, "macrocell-output-xc9500xl-xv"]], "Input/output buffer": [[6, "input-output-buffer"]], "Configuration pull-ups": [[6, "configuration-pull-ups"]], "XC9500XL/XV bus keeper": [[6, "xc9500xl-xv-bus-keeper"]], "Global networks \u2014 XC9500": [[6, "global-networks-xc9500"]], "Global networks \u2014 XC9500XL/XV": [[6, "global-networks-xc9500xl-xv"]], "Misc configuration": [[6, "misc-configuration"]]}, "indexentries": {}}) \ No newline at end of file diff --git a/xc9500/bitstream-xc9500.html b/xc9500/bitstream-xc9500.html new file mode 100644 index 00000000..c84650cf --- /dev/null +++ b/xc9500/bitstream-xc9500.html @@ -0,0 +1,543 @@ + + + + + + + + Bitstream structure - XC9500 — Project Combine documentation + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

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:

+
    +
  1. FB[i].MC[j].PT[k].IM[l].P is stored at:

    +
      +
    • row: l * 2

    • +
    • column: k + (j % 3) * 5

    • +
    • bit: j // 3

    • +
    +
  2. +
  3. FB[i].MC[j].PT[k].IM[l].N is stored at:

    +
      +
    • row: l * 2

    • +
    • column: k + (j % 3) * 5

    • +
    • bit: j // 3

    • +
    +
  4. +
+
+
+

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

  • +
+

The row is:

+
    +
  • 12: PT[0].ALLOC bit 0

  • +
  • 13: PT[0].ALLOC bit 1

  • +
  • 14: PT[1].ALLOC bit 0

  • +
  • 15: PT[1].ALLOC bit 1

  • +
  • 16: PT[2].ALLOC bit 0

  • +
  • 17: PT[2].ALLOC bit 1

  • +
  • 18: PT[3].ALLOC bit 0

  • +
  • 19: PT[3].ALLOC bit 1

  • +
  • 20: PT[4].ALLOC bit 0

  • +
  • 21: PT[5].ALLOC bit 1

  • +
  • 22: INV

  • +
  • 23: IMPORT_UP_ALLOC

  • +
  • 24: IMPORT_DOWN_ALLOC

  • +
  • 25: EXPORT_DIR

  • +
  • 26: SUM_HP

  • +
  • 27: IOB_OE_MUX bit 0

  • +
  • 28: IOB_OE_MUX bit 1

  • +
  • 29: OE_MUX bit 0

  • +
  • 30: OE_MUX bit 1

  • +
  • 31: OE_MUX bit 2

  • +
  • 32-34: unused?

  • +
  • 35: OUT_MUX

  • +
  • 36: CLK_MUX bit 0

  • +
  • 37: CLK_MUX bit 1

  • +
  • 38-39: unused

  • +
  • 40: REG_MODE

  • +
  • 41: RST_MUX

  • +
  • 42: SET_MUX

  • +
  • 43: INIT

  • +
  • 44: UIM_OE_MUX bit 0

  • +
  • 45: UIM_OE_MUX bit 1

  • +
  • 46: UIM_OUT_INV

  • +
  • 47: unused

  • +
  • 48: GND

  • +
  • 49: SLEW

  • +
  • 50: PT[0].HP

  • +
  • 51: PT[1].HP

  • +
  • 52: PT[2].HP

  • +
  • 53: PT[3].HP

  • +
  • 54: PT[4].HP

  • +
+

The fuse combination assignments are:

+
    +
  • PT[*].ALLOC:

    +
      +
    • 11: NONE

    • +
    • 10: OR_MAIN

    • +
    • 01: OR_EXPORT

    • +
    • 00: SPECIAL

    • +
    +
  • +
  • IMPORT_*_ALLOC:

    +
      +
    • 1: OR_EXPORT

    • +
    • 0: OR_MAIN

    • +
    +
  • +
  • EXPORT_DIR:

    +
      +
    • 1: UP

    • +
    • 0: DOWN

    • +
    +
  • +
  • IOB_OE_MUX:

    +
      +
    • 11: GND

    • +
    • 10: OE_MUX

    • +
    • 01: VCC

    • +
    +
  • +
  • OUT_MUX:

    +
    +
      +
    • 1: COMB

    • +
    • 0: FF

    • +
    +
    +
  • +
  • OE_MUX:

    +
    +
      +
    • 111: PT

    • +
    • 110: FOE0

    • +
    • 101: FOE1

    • +
    • 100: FOE2

    • +
    • 011: FOE3

    • +
    +
    +
  • +
  • CLK_MUX:

    +
      +
    • 11: FCLK1

    • +
    • 10: FCLK2

    • +
    • 01: FCLK0

    • +
    • 00: PT

    • +
    +
  • +
  • REG_MODE:

    +
      +
    • 1: DFF

    • +
    • 0: TFF

    • +
    +
  • +
  • RST_MUX, SET_MUX:

    +
      +
    • 1: PT

    • +
    • 0: FSR

    • +
    +
  • +
  • UIM_OE_MUX:

    +
      +
    • 11: OE_MUX

    • +
    • 10: GND

    • +
    • 01: VCC

    • +
    +
  • +
  • SLEW:

    +
      +
    • 1: SLOW

    • +
    • 0: FAST

    • +
    +
  • +
  • everything else:

    +
      +
    • 1: false

    • +
    • 0: true

    • +
    +
  • +
+
+
+

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, column, bit):

+
    +
  • (67, 0, 6): ENABLE

  • +
  • (67, 1, 6): EXPORT_ENABLE

  • +
  • (68, 6, 6): PULLUP_DISABLE

  • +
+

Global bits are stored in rows (0, 3, 4, 6, 7), columns 0-8, bits 6-7 of FB 0. The bits are (row, column, bit):

+
    +
  • (0, 1, 6): FSR_INV

  • +
  • (0, 2, 6): FCLK[0].INV

  • +
  • (0, 3, 6): FCLK[1].INV

  • +
  • (0, 4, 6): FCLK[2].INV

  • +
  • (0, 5, 6): FOE[0].INV

  • +
  • (0, 6, 6): FOE[1].INV

  • +
  • (0, 7, 6): FOE[2].INV

  • +
  • (0, 8, 6): FOE[3].INV

  • +
  • (3, 2, 6): FCLK[0].MUX bit 0

  • +
  • (3, 3, 6): FCLK[1].MUX bit 0

  • +
  • (3, 4, 6): FCLK[2].MUX bit 0

  • +
  • (3, 5, 6): FOE[0].MUX bit 0

  • +
  • (3, 6, 6): FOE[1].MUX bit 0

  • +
  • (3, 7, 6): FOE[2].MUX bit 0

  • +
  • (3, 8, 6): FOE[3].MUX bit 0

  • +
  • (4, 2, 6): FCLK[0].MUX bit 1

  • +
  • (4, 3, 6): FCLK[1].MUX bit 1

  • +
  • (4, 4, 6): FCLK[2].MUX bit 1

  • +
  • (4, 5, 6): FOE[0].MUX bit 1

  • +
  • (4, 6, 6): FOE[1].MUX bit 1

  • +
  • (4, 7, 6): FOE[2].MUX bit 1

  • +
  • (4, 8, 6): FOE[3].MUX bit 1

  • +
  • (6, i, j) for i < 8, j in (6, 7): USERCODE bit 16 + (7 - i) * 2 + (j - 6)

  • +
  • (7, i, j) for i < 8, j in (6, 7): USERCODE bit (7 - i) * 2 + (j - 6)

  • +
+

The fuse combination assignments are:

+
    +
  • FCLK[0].MUX:

    +
      +
    • 11: NONE

    • +
    • 10: GCLK[1]

    • +
    • 01: GCLK[0]

    • +
    +
  • +
  • FCLK[1].MUX:

    +
      +
    • 11: NONE

    • +
    • 10: GCLK[2]

    • +
    • 01: GCLK[1]

    • +
    +
  • +
  • FCLK[2].MUX:

    +
      +
    • 11: NONE

    • +
    • 10: GCLK[0]

    • +
    • 01: GCLK[2]

    • +
    +
  • +
  • FOE[0].MUX (small device):

    +
      +
    • 11: NONE

    • +
    • 10: GOE[1]

    • +
    • 01: GOE[0]

    • +
    +
  • +
  • FOE[1].MUX (small device):

    +
      +
    • 11: NONE

    • +
    • 10: GOE[0]

    • +
    • 01: GOE[1]

    • +
    +
  • +
  • FOE[0].MUX (large device):

    +
      +
    • 11: NONE

    • +
    • 10: GOE[1]

    • +
    • 01: GOE[0]

    • +
    +
  • +
  • FOE[1].MUX (large device):

    +
      +
    • 11: NONE

    • +
    • 10: GOE[2]

    • +
    • 01: GOE[1]

    • +
    +
  • +
  • FOE[2].MUX (large device):

    +
      +
    • 11: NONE

    • +
    • 10: GOE[3]

    • +
    • 01: GOE[2]

    • +
    +
  • +
  • FOE[3].MUX (large device):

    +
      +
    • 11: NONE

    • +
    • 10: GOE[0]

    • +
    • 01: GOE[3]

    • +
    +
  • +
  • USERCODE: each bit stored inverted

  • +
  • everything else:

    +
      +
    • 1: false

    • +
    • 0: true

    • +
    +
  • +
+
+
+

Fuses — input buffer enable

+

On XC95288, the IBUF_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 — protection bits

+

The protection bits are stored as follows (row, column, bit) in every FB:

+
    +
  • (11, 3, 6): READ_PROT_A

  • +
  • (68, 3, 6): READ_PROT_B

  • +
  • (68, 0, 6): WRITE_PROT

  • +
+
+
+

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

  • +
+
+
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/xc9500/bitstream-xc9500xl.html b/xc9500/bitstream-xc9500xl.html new file mode 100644 index 00000000..33391a09 --- /dev/null +++ b/xc9500/bitstream-xc9500xl.html @@ -0,0 +1,385 @@ + + + + + + + + Bitstream structure — XC9500XL/XV — Project Combine documentation + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

Bitstream structure — XC9500XL/XV

+

The main differences from XC9500 are:

+
    +
  1. The UIM wire-AND area is completely gone, only the main areas exist.

  2. +
  3. The main area has 108 rows per FB instead of 72.

  4. +
  5. Unprogrammed fuse state is 0, programmed fuse state is 1. +Thus, the sense of every bitstream bit is inverted from the XC9500 version.

  6. +
  7. While in XC9500 all areas are loaded sequentially, in XC9500XL/XV the areas +are loaded in parallel. Thus, the JTAG unit is not a byte, but a word of +size 8 * num_fbs. Likewise, the bytes for each FB are interleaved +in the JED format.

  8. +
+

On a high level, the whole bitstream is split into “areas”. Each FB +of the device corresponds to one area.

+

Each area is made of 108 “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.

+

When programmed or read via JTAG, the bitstream is transmitted as words. +Each word is 8 bits per FB. Each word of the bitstream has its address. +Not all addresses are valid, and valid addresses are not contiguous. +Address is 12 bits long, and is split to several fields:

+
    +
  • bits 5-11: row

  • +
  • bits 3-4: column / 5

  • +
  • bits 0-2: column % 5

  • +
+

The unprogrammed state of a bit on XC9500XL/XV is 0. +The programmed state is 1. Thus, whenever a boolean fuse is mentioned +in the documentation, the “true” value is actually represented as 1 +in the bitstream.

+
+

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:

+
row_bits = (8 * 9 + 6 * 6) * device.num_fbs
+total_bits = row_bits * 108
+
+def jed_to_jtag(fuse):
+    row = fuse // row_bits
+    fuse %= row_bits
+    if fuse < 8 * 9 * device.num_fbs:
+        column = fuse // (8 * device.num_fbs)
+        fuse %= (8 * device.num_fbs)
+        fb = fuse // 8
+        bit = fuse % 8
+    else:
+        fuse -= 8 * 9 * device.num_fbs
+        column = 9 + fuse // (6 * device.num_fbs)
+        fuse %= (6 * device.num_fbs)
+        fb = fuse // 6
+        bit = fuse % 6
+    return (
+        row << 5 |
+        (column // 5) << 3 |
+        (column % 5)
+    ), (fb * 8 + bit)
+
+def jtag_to_jed(addr, bit):
+    fb = bit // 8
+    bit %= 8
+    row = addr >> 5 & 0x7f
+    assert row < 108
+    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 * device.num_fbs + fb * 8 + bit
+    else:
+        cfuse = 8 * 8 + (column - 9) * 6 * device.num_fbs + fb * 6 + bit
+    return row * 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 (unchanged from XC9500, but now with more rows):

+
    +
  1. FB[i].MC[j].PT[k].IM[l].P is stored at:

    +
      +
    • row: l * 2

    • +
    • column: k + (j % 3) * 5

    • +
    • bit: j // 3

    • +
    +
  2. +
  3. FB[i].MC[j].PT[k].IM[l].N is stored at:

    +
      +
    • row: l * 2

    • +
    • column: k + (j % 3) * 5

    • +
    • bit: j // 3

    • +
    +
  4. +
+
+
+

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-49 of the main area. The formulas are as follows:

+
    +
  • row: corresponds to fuse function

  • +
  • column: mc_idx % 9

  • +
  • bit: 6 + mc_idx // 9

  • +
+

The row is:

+
    +
  • 12: PT[0].ALLOC bit 0

  • +
  • 13: PT[0].ALLOC bit 1

  • +
  • 14: PT[1].ALLOC bit 0

  • +
  • 15: PT[1].ALLOC bit 1

  • +
  • 16: PT[2].ALLOC bit 0

  • +
  • 17: PT[2].ALLOC bit 1

  • +
  • 18: PT[3].ALLOC bit 0

  • +
  • 19: PT[3].ALLOC bit 1

  • +
  • 20: PT[4].ALLOC bit 0

  • +
  • 21: PT[5].ALLOC bit 1

  • +
  • 22: INV

  • +
  • 23: IMPORT_UP_ALLOC

  • +
  • 24: IMPORT_DOWN_ALLOC

  • +
  • 25: EXPORT_DIR

  • +
  • 26: SUM_HP

  • +
  • 27: OE_MUX bit 0

  • +
  • 28: OE_MUX bit 1

  • +
  • 29: OE_MUX bit 2

  • +
  • 30: OE_INV

  • +
  • 31: unused

  • +
  • 32: OUT_MUX

  • +
  • 33: CLK_MUX bit 0

  • +
  • 34: CLK_MUX bit 1

  • +
  • 35: CLK_INV

  • +
  • 36: CE_MUX bit 0

  • +
  • 37: CE_MUX bit 1

  • +
  • 38: unused

  • +
  • 39: REG_MODE

  • +
  • 40: RST_MUX

  • +
  • 41: SET_MUX

  • +
  • 42: INIT

  • +
  • 43: GND

  • +
  • 44: SLEW

  • +
  • 45: PT[0].HP

  • +
  • 46: PT[1].HP

  • +
  • 47: PT[2].HP

  • +
  • 48: PT[3].HP

  • +
  • 49: PT[4].HP

  • +
+

The fuse combination assignments are:

+
    +
  • PT[*].ALLOC:

    +
      +
    • 00: NONE

    • +
    • 01: OR_MAIN

    • +
    • 10: OR_EXPORT

    • +
    • 11: SPECIAL

    • +
    +
  • +
  • IMPORT_*_ALLOC:

    +
      +
    • 0: OR_EXPORT

    • +
    • 1: OR_MAIN

    • +
    +
  • +
  • EXPORT_DIR:

    +
      +
    • 0: UP

    • +
    • 1: DOWN

    • +
    +
  • +
  • OUT_MUX:

    +
    +
      +
    • 0: COMB

    • +
    • 1: FF

    • +
    +
    +
  • +
  • CLK_MUX:

    +
      +
    • 00: FCLK1

    • +
    • 01: FCLK0

    • +
    • 10: FCLK2

    • +
    • 11: PT

    • +
    +
  • +
  • CE_MUX:

    +
      +
    • 00: NONE

    • +
    • 01: PT2

    • +
    • 10: PT3

    • +
    +
  • +
  • REG_MODE:

    +
      +
    • 0: DFF

    • +
    • 1: TFF

    • +
    +
  • +
  • RST_MUX, SET_MUX:

    +
      +
    • 0: PT

    • +
    • 1: FSR

    • +
    +
  • +
  • SLEW:

    +
      +
    • 0: SLOW

    • +
    • 1: FAST

    • +
    +
  • +
  • everything else:

    +
      +
    • 0: false

    • +
    • 1: true

    • +
    +
  • +
+
+
+

Fuses — FB inputs

+

The FB input mux configuraton is stored in rows 50-76, columns 0-8, bits 6-7. +FB[i].IM[j].MUX has 9 bits and is stored at the following coordinates:

+
    +
  • row: 50 + j % 27

  • +
  • column: mux fuse index (0-8)

  • +
  • bit: 6 if j < 27, 7 otherwise

  • +
+

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 row 78, columns 0-8, bits 6-7. The bits are (row, column, bit):

+
    +
  • (78, 0, 6): ENABLE

  • +
  • (78, 1, 6): EXPORT_ENABLE

  • +
  • (78, 6, 6): PULLUP_DISABLE

  • +
+

Global bits are stored in rows (2, 6, 7), columns 0-8, bits 6-7 of FB 0. The bits are (row, column, bit):

+
    +
  • (2, 0, 6): FSR_INV

  • +
  • (2, 1, 6): FCLK[0].EN

  • +
  • (2, 2, 6): FCLK[1].EN

  • +
  • (2, 3, 6): FCLK[2].EN

  • +
  • (2, 4, 6): FOE[0].EN

  • +
  • (2, 5, 6): FOE[1].EN

  • +
  • (2, 6, 6): FOE[2].EN

  • +
  • (2, 7, 6): FOE[3].EN

  • +
  • (2, 8, 6): KEEPER

  • +
  • (6, i, j) for i < 8, j in (6, 7): USERCODE bit 16 + (7 - i) * 2 + (j - 6)

  • +
  • (7, i, j) for i < 8, j in (6, 7): USERCODE bit (7 - i) * 2 + (j - 6)

  • +
+

The fuse combination assignments are:

+
    +
  • USERCODE: each bit stored directly

  • +
  • everything else:

    +
      +
    • 0: false

    • +
    • 1: true

    • +
    +
  • +
+
+
+

Fuses — protection bits, DONE

+

The protection bits are stored as follows (row, column, bit) in every FB:

+
    +
  • (11, 0, 6): WRITE_PROT

  • +
  • (11, 3, 6): READ_PROT

  • +
+

The DONE bit is stored only once, in FB 0:

+
    +
  • (11, 6, 6): DONE

  • +
+
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/xc9500/index.html b/xc9500/index.html new file mode 100644 index 00000000..39cedc49 --- /dev/null +++ b/xc9500/index.html @@ -0,0 +1,162 @@ + + + + + + + + XC9500, XC9500XL, XC9500XV — Project Combine documentation + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/xc9500/intro.html b/xc9500/intro.html new file mode 100644 index 00000000..dbe6eb21 --- /dev/null +++ b/xc9500/intro.html @@ -0,0 +1,607 @@ + + + + + + + + Introduction — Project Combine documentation + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

Introduction

+

XC9500 is a family of flash-based CPLDs manufactured by Xilinx. It is a derivative of the earlier XC7200 and XC7300 +EPLD families. It comes in three variants:

+
    +
  1. XC9500: 5V core logic, 3.3V or 5V I/O, original version.

  2. +
  3. XC9500XL: 3.3V core logic, 2.5V or 3.3V I/O (5V tolerant), with some functional changes from XC9500:

    +
      +
    • UIM no longer has wired-AND functionality

    • +
    • FFs have clock enable function

    • +
    • 54 (instead of 36) UIM inputs per function block

    • +
    • FF has configurable clock polarity

    • +
    • FOE/FCLK multiplexers and inversion have been removed

    • +
    • optional weak bus keeper can be configured for all pins

    • +
    +
  4. +
  5. XC9500XV: 2.5V core logic, 1.8V, 2.5V, or 3.3V I/O, with minor functional changes from XC9500XL:

    +
      +
    • larger devices have two I/O banks with separate VCCIO

    • +
    • the bitstream now contains a DONE bit tied to ISC_DONE, preventing problems with partially configured devices

    • +
    +
  6. +
+
+

Devices

+

The following devices exist:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Device

Variant

Function Blocks

XC9536

XC9500

2

XC9572

XC9500

4

XC95108

XC9500

6

XC95144

XC9500

8

XC95216

XC9500

12

XC95288

XC9500

16

XC9536XL

XC9500XL

2

XC9572XL

XC9500XL

4

XC95144XL

XC9500XL

8

XC95288XL

XC9500XL

16

XA9536XL

XC9500XL

2

XA9572XL

XC9500XL

4

XA95144XL

XC9500XL

8

XC9536XV

XC9500XV

2

XC9572XV

XC9500XV

4

XC95144XV

XC9500XV

8

XC95288XV

XC9500XV

16

+

The parts starting with XA are automotive versions. They are functionally completely identical to corresponding XC versions.

+
+
+

Packages

+

The devices come in the following packages:

+
    +
  • PLCC:

    +
      +
    • PC44 (JEDEC MO-047)

    • +
    • PC84 (JEDEC MO-047)

    • +
    +
  • +
  • QFP:

    +
      +
    • very thin QFP (1mm thickness):

      +
        +
      • VQ44 (0.8mm pitch; JEDEC MS-026-ACB)

      • +
      • VQ64 (0.5mm pitch; JEDEC MS-026-ACD)

      • +
      +
    • +
    • thin QFP (1.4mm thickness):

      +
        +
      • TQ100 (0.5mm pitch; JEDEC MS-026-BED)

      • +
      • TQ144 (0.5mm pitch; JEDEC MS-026-BFB)

      • +
      +
    • +
    • plastic QFP:

      +
        +
      • PQ100 (2.7mm thickness, non-square, 30×20 pins, 0.65mm pitch; JEDEC MS-022-GC1)

      • +
      • PQ160 (3.4mm thickness, 0.65mm pitch; JEDEC MS-022-DD1)

      • +
      • PQ208 (3.4mm thickness, 0.5mm pitch; JEDEC MS-029-FA-1)

      • +
      +
    • +
    • platic QFP with heat sink:

      +
        +
      • HQ208 (same footprint as PQ208)

      • +
      +
    • +
    +
  • +
  • BGA:

    +
      +
    • standard BGA (1.27mm pitch):

      +
        +
      • BG256 (JEDEC MS-034-BAL-2)

      • +
      • BG352

      • +
      +
    • +
    • fine-pitch BGA (1mm pitch):

      +
        +
      • FG256

      • +
      +
    • +
    • chip-scale BGA (0.8mm pitch):

      +
        +
      • CS48

      • +
      • CS144 (JEDEC MO-216-BAG-2)

      • +
      • CS280 (JEDEC MO-216-BAL-1)

      • +
      +
    • +
    +
  • +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Device

PC44

PC84

VQ44

VQ64

TQ100

TQ144

PQ100

PQ160

PQ208

HQ208

BG256

BG352

FG256

CS48

CS144

CS280

XC9536

X

X

X

XC9572

X

X

X

X

XC95108

X

X

X

X

XC95144

X

X

X

XC95216

X

X

X

XC95288

X

X

XC9536XL

X

X

X

X

XC9572XL

X

X

X

X

X

XC95144XL

X

X

X

XC95288XL

X

X

X

X

X

XA9536XL

X

XA9572XL

X

X

X

XA95144XL

X

XC9536XV

X

X

X

XC9572XV

X

X

X

X

XC95144XV

X

X

X

XC95288XV

X

X

X

X

+

Pin compatibility is maintained across all 3 variants of the XC9500 family within a single package. +Additionally, devices in PQ208 and HQ208 packages are pin compatible with each other.

+
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/xc9500/jtag.html b/xc9500/jtag.html new file mode 100644 index 00000000..586b549c --- /dev/null +++ b/xc9500/jtag.html @@ -0,0 +1,373 @@ + + + + + + + + JTAG interface — Project Combine documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

JTAG interface

+
+

IR

+

The IR is 8 bits long. The following instructions exist:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

IR

Instruction

Register

Notes

00000000

EXTEST

BOUNDARY

00000001

SAMPLE

BOUNDARY

00000010

INTEST

BOUNDARY

11100101

FBLANK

ISPADDRESS

XC9500XL/XV only

11101000

ISPEN

ISPENABLE

11101001

ISPENC

ISPENABLE

XC9500XL/XV only

11101010

FPGM

ISPCONFIGURATION

11101011

FPGMI

ISPDATA

11101100

FERASE

ISPCONFIGURATION

XC9500 only

11101100

FERASE

ISPADDRESS

XC9500XL/XV only

11101101

FBULK

ISPCONFIGURATION

XC9500 only

11101101

FBULK

ISPADDRESS

XC9500XL/XV only

11101110

FVFY

ISPCONFIGURATION

11101111

FVFYI

ISPDATA

11110000

ISPEX

BYPASS

11111010

CLAMP

BYPASS

XC9500XL/XV only

11111100

HIGHZ

BYPASS

11111101

USERCODE

USERCODE

11111110

IDCODE

IDCODE

11111111

BYPASS

BYPASS

+

The IR status is:

+
    +
  • bit 0: const 1

  • +
  • bit 1: const 0

  • +
  • bit 2: WRITE_PROT status

  • +
  • bit 3: READ_PROT status

  • +
  • bit 4: ISP mode enabled

  • +
  • bit 5: DONE status (XC9500XV only, const 0 on other devices)

  • +
  • bits 6-7: const 0

  • +
+
+

Todo

+

verify

+
+
+
+

Boundary scan register

+

The boundary scan register is 3 * 18 * num_fbs bits long, and consists of 3 bits for every MC +in the device: input, output, and output enable. Such bits are included even for MCs that do not +have a corresponding IOB.

+

The boundary register bit indices for FB[i].MC[j] are:

+
    +
  • input: (num_fbs - 1 - i) * 18 * 3 + (17 - j) * 3 + 2

  • +
  • output: (num_fbs - 1 - i) * 18 * 3 + (17 - j) * 3 + 1

  • +
  • output enable: (num_fbs - 1 - i) * 18 * 3 + (17 - j) * 3 + 0

  • +
+

All bits of the register are BC_1 type cells.

+
+

Todo

+

details on the cell connection, EXTEST, INTEST semantics

+
+
+
+

ISP instructions

+
+

ISP DR registers — XC9500

+

The following DR registers exist on XC9500:

+
    +
  1. ISPENABLE (16 bits): function and contents unclear

  2. +
  3. ISPCONFIGURATION (27 bits): used to load and store bitstream bytes

    +
      +
    • bit 0: valid bit

    • +
    • bit 1: strobe bit

    • +
    • bits 2-9: data byte

    • +
    • bits 10-26: address

    • +
    +
  4. +
  5. ISPDATA (10 bits): a subset of ISPCONFIGURATION used by instructions with autoincrementing address

    +
      +
    • bit 0: valid bit

    • +
    • bit 1: strobe bit

    • +
    • bits 2-9: data byte

    • +
    +
  6. +
+
+

Todo

+

ISPENABLE, describe valid & strobe

+
+
+
+

ISP DR registers — XC9500XL/XV

+

The following DR registers exist on XC9500XL/XV:

+
    +
  1. ISPENABLE (6 bits): function and contents unclear

  2. +
  3. ISPCONFIGURATION (18 + num_fbs * 8 bits): used to load and store bitstream words

    +
      +
    • bit 0: valid bit

    • +
    • bit 1: strobe bit

    • +
    • bits 2-(num_sbs * 8 + 1): data word

    • +
    • bits (num_fbs * 8 + 2)-(num_fbs * 8 + 17): address

    • +
    +
  4. +
  5. ISPDATA (2 + num_fbs * 8 bits): a subset of ISPCONFIGURATION used by instructions with autoincrementing address

    +
      +
    • bit 0: valid bit

    • +
    • bit 1: strobe bit

    • +
    • bits 2-(num_sbs * 8 + 1): data word

    • +
    +
  6. +
  7. ISPADDRESS (18 bits): a subset of ISPCONFIGURATION used by some instructions:

  8. +
+
+
    +
  • bit 0: valid bit

  • +
  • bit 1: strobe bit

  • +
  • bits 2-17: address

  • +
+
+
+
+

Entering and exiting ISP mode

+

Before any programming or readout can be done, the device needs to be put into ISP mode. +For that purpose, the ISPEN or ISPENC (XC9500XL/XV only) instructions can be used. +Both instructions use the ISPENABLE register, which is 16 bits on XC9500 +and 6 bits on XC9500XL/XV. Its meaning, if any, is unknown.

+

To enter ISP mode:

+
    +
  • shift ISPEN or ISPENC into IR

  • +
  • shift 0s into DR

  • +
  • go to Run-Test/Idle state for at least 1 clock

  • +
+

If the ISPEN instruction is used, all outputs will be put in high-Z with weak pull-ups while ISP mode is active. +If the ISPENC (“clamp” mode) instruction is used, all output and output enable signals will be snapshotted +and outputs will continue driving the last value while ISP mode is active.

+

To exit ISP mode:

+
    +
  • shift ISPEX into IR

  • +
  • go to Run-Test/Idle state for at least 1 clock

  • +
+

When ISP mode is exitted, the device will initialize itself and start normal operation.

+
+

Todo

+

verify, see if anything can be figured out about the DR

+
+
+
+

Erasing fuses

+
+

Todo

+

write me

+
+
+
+

Programming fuses

+
+

Todo

+

write me

+
+
+
+

Reading fuses

+
+

Todo

+

write me

+
+
+
+

Blank check

+
+

Todo

+

write me

+
+
+
+
+

Programming sequence

+
+

Todo

+

write me

+
+
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/xc9500/structure.html b/xc9500/structure.html new file mode 100644 index 00000000..d2740f09 --- /dev/null +++ b/xc9500/structure.html @@ -0,0 +1,753 @@ + + + + + + + + Device structure — Project Combine documentation + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

Device structure

+
+

Overview

+

An XC9500 family device is made of:

+
    +
  • the UIM (universal interconnect matrix), which routes MC and IOB outputs to FB inputs

  • +
  • 2-16 FBs (function blocks), each of which has:

    +
      +
    • 36 (XC9500) or 54 (XC9500XL/XV) routable inputs from UIM

    • +
    • 18 MCs (macrocells), each of which has:

      +
        +
      • configurable low power / high performance mode

      • +
      • 5 PTs (product terms)

      • +
      • PT router, which can route PTs to:

        +
          +
        • the sum term for this MC

        • +
        • the sum term for export into neighbouring MCs

        • +
        • a special function (OE, RST, SET, CLK, CE, XOR depending on the PT)

        • +
        +
      • +
      • PT export/import logic for borrowing PTs between neighbouring MCs

      • +
      • a sum term

      • +
      • a dedicated XOR gate

      • +
      • optional inverter

      • +
      • a flip-flop, with:

        +
          +
        • configurable DFF or TFF function

        • +
        • configurable initial value

        • +
        • clock (freely invertible on XC9500XL/XV), routable from FCLK or PT

        • +
        • async reset, routable from FSR or PT

        • +
        • async set, routable from FSR or PT

        • +
        • (XC9500XL/XV only) clock enable, routable from PT

        • +
        +
      • +
      • a single output (selectable from combinatorial or FF output), routed to IOB and UIM

      • +
      • (XC9500 only) UIM output enable and inversion

      • +
      • IOB (input/output buffer) (on larger devices, not all macrocells have an IOB), with:

        +
          +
        • input buffer (routed to UIM)

        • +
        • output enable (freely invertible on XC9500XL/XV), routable from FOE or PT

        • +
        • configurable slew rate (fast or slow)

        • +
        • programmable ground

        • +
        +
      • +
      +
    • +
    +
  • +
  • global signals

    +
      +
    • 3 FCLK (fast clock) signals

      +
        +
      • (XC9500) freely invertible and routable from GCLK pins

      • +
      • (XC9500XL/XV) hardwired 1-1 to GCLK pins

      • +
      +
    • +
    • 1 FSR (fast set/reset) signal

      +
        +
      • freely invertible

      • +
      • always routed from GSR pin

      • +
      +
    • +
    • 2-4 FOE (fast output enable) signals

      +
        +
      • (XC9500) freely invertible and routable from GOE pins

      • +
      • (XC9500XL/XV) hardwired 1-1 to GOE pins

      • +
      +
    • +
    +
  • +
  • global pull-up enable (only meant to be used in unconfigured devices)

  • +
  • (XC9500XL/XV) global bus keeper enable

  • +
  • special global configuration bits

    +
      +
    • 32-bit standard JTAG USERCODE

    • +
    • read protection enable

    • +
    • write protection enable

    • +
    • (XC9500XV only) DONE bit

    • +
    +
  • +
+
+
+

UIM and FB inputs — XC9500

+

The core interconnect structure in XC9500 devices is the UIM, Universal Interconnect Matrix. +The name is quite appropriate, at least for internal signals: any FB input can be routed +to any MC output. More than that, any FB input can be routed to a wire-AND of an arbitrary +subset of MC outputs from the entire device. Together with the UIM OE functionality within +the MC, this can be used for emulated internal tri-state buses.

+

The name is, however, less appropriate when it comes to external signals: a given FB input +can only be routed to some subset of input signals from IOBs. The set of routable IOBs +depends on the FB input index and the device.

+

Additionally, on devices other than XC9536, some FB inputs can be routed to “fast feedback” +paths, which come straight from MC outputs within the same FB. This is functionally redundant +with the wire-AND path, but much faster.

+

Each FB has 36 inputs, which we call FB[i].IM[j]. Each FB input is controlled by two sets of fuses:

+
    +
  • mux fuses (FB[i].IM[j].MUX) select what is routed to the input. The combinations include:

    +
      +
    • EMPTY: the input is a constant ??? (for unused inputs)

    • +
    • UIM: the input is a wire-AND of MC outputs (and the second set of fuses is relevant)

    • +
    • FBK_MC{k}: the input is routed through fast feedback path from FB[i].MC[k].OUT

    • +
    • PAD_FB{k}_MC{l}: the input is routed from an input buffer FB[k].MC[l].IOB.I

    • +
    +

    The allowable combinations differ between inputs within a single FB, but don’t differ across +FBs within a single device. In other words, the set of allowed values for these fuses +depends only on the j coordinate, but not on i.

    +
  • +
  • wire-AND fuses (FB[i].IM[j].UIM.FB[k].MC[l]) select which MC outputs participate in the +wire-AND. If a given fuse is programmed, it means that FB[k].MC[l].OUT_UIM is included +in the product. These fuses are only relevant when the mux fuse set is set to UIM.

  • +
+
+

Todo

+

check EMPTY semantics

+
+
+

Todo

+

verify FBK doesn’t go through OE and inversion

+
+
+
+

UIM and FB inputs — XC9500XL/XV

+

The core interconnect structure in XC9500XL/XV devices is the UIM 2. This version of the UIM +is not really universal, and is much more of a classic CPLD design.

+

Each FB has 54 inputs, which we call FB[i].IM[j]. Each FB input is controlled by a set of fuses:

+
    +
  • mux fuses (FB[i].IM[j].MUX) select what is routed to the input. The combinations include:

    +
      +
    • EMPTY: the input is a constant ??? (for unused inputs)

    • +
    • FB{k}_MC{l}: the input is routed from the macrocell output FB[k].MC[l].OUT

    • +
    • PAD_FB{k}_MC{l}: the input is routed from the input buffer FB[k].MC[l].IOB.I

    • +
    +

    The allowable combinations differ between inputs within a single FB, but don’t differ across +FBs within a single device. In other words, the set of allowed values for these fuses +depends only on the j coordinate, but not on i.

    +
  • +
+
+

Todo

+

check EMPTY semantics

+
+
+
+

FB global fuses

+

Each function block has two fuses controlling the entire FB:

+
    +
  • FB[i].ENABLE: function block enable; needs to be programmed to use this function block

  • +
  • FB[i].EXPORT_ENABLE: function block PT export enable; needs to be programmed to use PT +import/export within this function block

  • +
+
+

Todo

+

determine what these do exactly

+
+
+
+

Product terms

+

Each function block has 90 product terms, 5 per macrocell. We call them FB[i].MC[j].PT[k]. +Each of the 5 PTs has a dedicated function, as follows:

+
    +
  • *.PT[0]: clock

  • +
  • *.PT[1]: output enable

  • +
  • *.PT[2]: async reset (or clock enable on XC9500XL/XV)

  • +
  • *.PT[3]: async set (or clock enable on XC9500XL/XV)

  • +
  • *.PT[4]: second XOR input

  • +
+

The inputs to all product terms within a FB are the same, and consist of all FB inputs, in both +true and inverted forms.

+

Each product term can be individually configured as low power or high performance. This affects propagation time.

+

Each product term can be routed to at most one of three destinations:

+
    +
  • OR_MAIN: input to the MC’s sum term

  • +
  • OR_EXPORT: input to the export OR gate

  • +
  • SPECIAL: used for the dedicated function

  • +
+

The fuses controlling a product term are:

+
    +
  • FB[i].MC[j].PT[k].IM[l].P: if programmed, FB[i].IM[l] is included in the product term (true polarity)

  • +
  • FB[i].MC[j].PT[k].IM[l].N: if programmed, ~FB[i].IM[l] is included in the product term (inverted polarity)

  • +
  • FB[i].MC[j].PT[k].HP: if programmed, the product term is in high performance mode; otherwise, it is in low power mode

  • +
  • FB[i].MC[j].PT[k].ALLOC: has one of four values:

    +
      +
    • EMPTY: product term is unused

    • +
    • OR_MAIN: product term is used for MC’s sum term; dedicated function wired to 0

    • +
    • OR_EXPORT product term is used for export sum term; dedicated function wired to 0

    • +
    • SPECIAL: product term is used for the dedicated function

    • +
    +
  • +
+

The product term’s corresponding dedicated function is called FB[i].MC[j].PT[k].SPECIAL. +It is equal to FB[i].MC[j].PT[k] if the dedicated function is enabled in ALLOC, 0 otherwise.

+
+

PT import/export

+

Product terms can be borrowed between neighbouring MCs within a FB. To this end, each MC has two outputs, +FB[i].MC[j].EXPORT_{UP|DOWN}, and two inputs, FB[i].MC[j].IMPORT_{UP|DOWN}. The “down” direction +corresponds to exporting PTs toward lower-numbered MCs (with a wraparound from 0 to 17), and the “up” +direction corresponds to exporting PTs towards higher-numbered MCs (with a wraparound from 17 to 0). +Accordingly, we have:

+
FB[i].MC[j].IMPORT_DOWN = FB[i].MC[(j + 1) % 18].EXPORT_DOWN;
+FB[i].MC[j].IMPORT_UP = FB[i].MC[(j - 1) % 18].EXPORT_UP;
+
+
+

A MC can only export product terms in one direction (up or down). +Product terms can be imported from both directions at once. +Imported terms from a given direction can be used for either the main sum term, or for further export, but not both at once.

+

PT import/export is controlled by the following per-MC fuses:

+
    +
  • FB[i].MC[j].EXPORT_DIR: one of:

    +
      +
    • DOWN: exports PTs downwards

    • +
    • UP: exports PTs upwards

    • +
    +
  • +
  • FB[i].MC[j].IMPORT_UP_ALLOC: one of:

    +
      +
    • OR_MAIN: includes PTs imported upwards in the main sum term

    • +
    • OR_EXPORT: includes PTs imported upwards in the export sum term

    • +
    +
  • +
  • FB[i].MC[j].IMPORT_DOWN_ALLOC: one of:

    +
      +
    • OR_MAIN: includes PTs imported downwards in the main sum term

    • +
    • OR_EXPORT: includes PTs imported downwards in the export sum term

    • +
    +
  • +
+

Additionally, the per-FB FB[i].EXPORT_ENABLE fuse needs to be set if any term within a FB is exported or imported.

+

Export works as follows:

+
FB[i].MC[j].EXPORT =
+    (FB[i].MC[j].IMPORT_UP_ALLOC == OR_EXPORT ? FB[i].MC[j].IMPORT_UP : 0) |
+    (FB[i].MC[j].IMPORT_DOWN_ALLOC == OR_EXPORT ? FB[i].MC[j].IMPORT_DOWN : 0) |
+    (FB[i].MC[j].PT[0].ALLOC == OR_EXPORT ? FB[i].MC[j].PT[0] : 0) |
+    (FB[i].MC[j].PT[1].ALLOC == OR_EXPORT ? FB[i].MC[j].PT[1] : 0) |
+    (FB[i].MC[j].PT[2].ALLOC == OR_EXPORT ? FB[i].MC[j].PT[2] : 0) |
+    (FB[i].MC[j].PT[3].ALLOC == OR_EXPORT ? FB[i].MC[j].PT[3] : 0) |
+    (FB[i].MC[j].PT[4].ALLOC == OR_EXPORT ? FB[i].MC[j].PT[4] : 0);
+
+FB[i].MC[j].EXPORT_UP = (FB[i].MC[j].EXPORT_DIR == UP ? FB[i].MC[j].EXPORT : 0);
+FB[i].MC[j].EXPORT_DOWN = (FB[i].MC[j].EXPORT_DIR == DOWN ? FB[i].MC[j].EXPORT : 0);
+
+
+
+

Todo

+

verify all of the above

+
+
+
+
+

Sum term, XOR gate

+

Each macrocell has a main sum term, which includes all product terms and imports routed towards it:

+
FB[i].MC[j].SUM =
+    (FB[i].MC[j].IMPORT_UP_ALLOC == OR_MAIN ? FB[i].MC[j].IMPORT_UP : 0) |
+    (FB[i].MC[j].IMPORT_DOWN_ALLOC == OR_MAIN ? FB[i].MC[j].IMPORT_DOWN : 0) |
+    (FB[i].MC[j].PT[0].ALLOC == OR_MAIN ? FB[i].MC[j].PT[0] : 0) |
+    (FB[i].MC[j].PT[1].ALLOC == OR_MAIN ? FB[i].MC[j].PT[1] : 0) |
+    (FB[i].MC[j].PT[2].ALLOC == OR_MAIN ? FB[i].MC[j].PT[2] : 0) |
+    (FB[i].MC[j].PT[3].ALLOC == OR_MAIN ? FB[i].MC[j].PT[3] : 0) |
+    (FB[i].MC[j].PT[4].ALLOC == OR_MAIN ? FB[i].MC[j].PT[4] : 0);
+
+
+

The sum term then goes through a XOR gate (whose other input is either 0 or a dedicated PT) and a programmable inverter:

+
FB[i].MC[j].XOR = FB[i].MC[j].SUM ^ FB[i].MC[j].PT[4].SPECIAL ^ FB[i].MC[j].INV;
+
+
+

The fuses involved are:

+
    +
  • FB[i].MC[j].SUM_HP: if programmed, the sum term is in high performance mode; otherwise, it’s in low power mode

  • +
  • FB[i].MC[j].INV: if programmed, the output of the XOR gate is further inverted

  • +
+
+
+

Flip-flop

+

Each macrocell includes a flip-flop. It has:

+
    +
  • configurable DFF or TFF function

  • +
  • D or T input connected to the (potentially inverted) XOR gate output

  • +
  • configurable initial value

  • +
  • clock (freely invertible on XC9500XL/XV), routable from FCLK or PT[0]

  • +
  • async reset, routable from FSR or PT[2]

  • +
  • async set, routable from FSR or PT[3]

  • +
  • (XC9500XL/XV only) clock enable, routable from PT[2] or PT[3]

  • +
+

The fuses involved are:

+
    +
  • FB[i].MC[j].CLK_MUX: selects CLK input

    +
      +
    • PT: product term 0 dedicated function

    • +
    • FCLK[0-2]: global FCLK[0-2] network

    • +
    +
  • +
  • FB[i].MC[j].CLK_INV: if programmed, the CLK input is inverted (ie. clock is negedge) (XC9500XL/XV only)

  • +
  • FB[i].MC[j].RST_MUX: selects RST input

    +
      +
    • PT: product term 2 dedicated function or 0; if PT 2 is used for clock enable, it will not be routed to RST (0 will be substituted)

    • +
    • FSR: global FSR network

    • +
    +
  • +
  • FB[i].MC[j].SET_MUX: selects SET input

    +
      +
    • PT: product term 3 dedicated function or 0; if PT 3 is used for clock enable, it will not be routed to SET (0 will be substituted)

    • +
    • FSR: global FSR network

    • +
    +
  • +
  • FB[i].MC[j].CE_MUX: selects CE input (XC9500XL/XV only)

    +
      +
    • NONE: const 1

    • +
    • PT2: product term 2 dedicated function

    • +
    • PT3: product term 3 dedicated function

    • +
    +
  • +
  • FB[i].MC[j].INIT: if programmed, the initial value of the FF is 1; otherwise, it is 0

  • +
  • FB[i].MC[j].REG_MODE: selects FF mode

    +
      +
    • DFF

    • +
    • TFF

    • +
    +
  • +
+

On XC9500, the FF works as follows:

+
case(FB[i].MC[j].CLK_MUX)
+PT: FB[i].MC[j].CLK = FB[i].MC[j].PT[0].SPECIAL;
+FCLK0: FB[i].MC[j].CLK = FCLK[0];
+FCLK1: FB[i].MC[j].CLK = FCLK[1];
+FCLK2: FB[i].MC[j].CLK = FCLK[2];
+endcase
+
+case(FB[i].MC[j].RST_MUX)
+PT: FB[i].MC[j].RST = FB[i].MC[j].PT[2].SPECIAL;
+FSR: FB[i].MC[j].RST = FSR;
+endcase
+
+case(FB[i].MC[j].SET_MUX)
+PT: FB[i].MC[j].SET = FB[i].MC[j].PT[3].SPECIAL;
+FSR: FB[i].MC[j].SET = FSR;
+endcase
+
+initial FB[i].MC[j].FF = FB[i].MC[j].INIT;
+
+// Pretend the usual synth/sim mismatch doesn't happen.
+always @(posedge FB[i].MC[j].CLK, posedge FB[i].MC[j].RST_MUX, posedge FB[i].MC[j].SET_MUX)
+    if (FB[i].MC[j].RST_MUX)
+        FB[i].MC[j].FF = 0;
+    else if (FB[i].MC[j].SET_MUX)
+        FB[i].MC[j].FF = 1;
+    else
+        FB[i].MC[j].FF = FB[i].MC[j].XOR;
+
+
+

On XC9500XL/XV, the FF works as follows:

+
case(FB[i].MC[j].CLK_MUX)
+PT: FB[i].MC[j].CLK = FB[i].MC[j].PT[0].SPECIAL ^ FB[i].MC[j].CLK_INV;
+FCLK0: FB[i].MC[j].CLK = FCLK[0] ^ FB[i].MC[j].CLK_INV;
+FCLK1: FB[i].MC[j].CLK = FCLK[1] ^ FB[i].MC[j].CLK_INV;
+FCLK2: FB[i].MC[j].CLK = FCLK[2] ^ FB[i].MC[j].CLK_INV;
+endcase
+
+case(FB[i].MC[j].RST_MUX)
+PT: FB[i].MC[j].RST = (FB[i].MC[j].CE_MUX == PT2 ? 0 : FB[i].MC[j].PT[2].SPECIAL);
+FSR: FB[i].MC[j].RST = FSR;
+endcase
+
+case(FB[i].MC[j].SET_MUX)
+PT: FB[i].MC[j].SET = (FB[i].MC[j].CE_MUX == PT3 ? 0 : FB[i].MC[j].PT[3].SPECIAL);
+FSR: FB[i].MC[j].SET = FSR;
+endcase
+
+case(FB[i].MC[j].CE_MUX)
+PT2: FB[i].MC[j].CE = FB[i].MC[j].PT[2].SPECIAL;
+PT3: FB[i].MC[j].CE = FB[i].MC[j].PT[3].SPECIAL;
+NONE: FB[i].MC[j].CE = 1;
+endcase
+
+initial FB[i].MC[j].FF = FB[i].MC[j].INIT;
+
+// Pretend the usual synth/sim mismatch doesn't happen.
+always @(posedge FB[i].MC[j].CLK, posedge FB[i].MC[j].RST_MUX, posedge FB[i].MC[j].SET_MUX)
+    if (FB[i].MC[j].RST_MUX)
+        FB[i].MC[j].FF = 0;
+    else if (FB[i].MC[j].SET_MUX)
+        FB[i].MC[j].FF = 1;
+    else if (FB[i].MC[j].CE)
+        FB[i].MC[j].FF = FB[i].MC[j].XOR;
+
+
+
+

Todo

+

verify (in particular, CE vs RST/SET shenanigans)

+
+
+
+

Macrocell output — XC9500

+

The output of the macrocell can be selected from combinatorial (XOR gate output) or registered (FF output):

+
FB[i].MC[j].OUT = (FB[i].MC[j].OUT_MUX == COMB ? FB[i].MC[j].XOR : FB[i].MC[j].FF);
+
+
+

The macrocell also has an output enable, which can be from a product term, or a global network. +It can be used for the IOB output buffer, for UIM output, or both:

+
case(FB[i].MC[j].OE_MUX)
+PT: FB[i].MC[j].OE = FB[i].MC[j].PT[1].SPECIAL;
+FOE0: FB[i].MC[j].OE = FOE[0];
+FOE1: FB[i].MC[j].OE = FOE[1];
+FOE2: FB[i].MC[j].OE = FOE[2];
+FOE3: FB[i].MC[j].OE = FOE[3];
+endcase
+
+case(FB[i].MC[j].UIM_OE_MUX)
+GND: FB[i].MC[j].UIM_OE = 0;
+VCC: FB[i].MC[j].UIM_OE = 1;
+OE_MUX: FB[i].MC[j].UIM_OE = FB[i].MC[j].OE;
+endcase
+
+case(FB[i].MC[j].IOB_OE_MUX)
+GND: FB[i].MC[j].IOB_OE = 0;
+VCC: FB[i].MC[j].IOB_OE = 1;
+OE_MUX: FB[i].MC[j].IOB_OE = FB[i].MC[j].OE;
+endcase
+
+
+

The output is routed to up to three places:

+
    +
  • this MC’s IOB (FB[i].MC[j].OUT)

  • +
  • this FB’s inputs via the feedback path (FB[i].MC[j].OUT)

  • +
  • the UIM (FB[i].MC[j].OUT_UIM)

  • +
+

The output to UIM additionally goes through (emulated) output enable logic, which can be used +to implement emulated on-chip tristate buses in conjunction with the UIM wire-AND logic:

+
FB[i].MC[j].OUT_UIM = FB[i].MC[j].UIM_OE ? FB[i].MC[j].OUT ^ FB[i].MC[j].UIM_OUT_INV : 1;
+
+
+

The fuses involved are:

+
    +
  • FB[i].MC[j].OUT_MUX: selects output mode

    +
      +
    • COMB: combinatorial, the output is connected to XOR gate output

    • +
    • FF: registered, the output is connected to FF output

    • +
    +
  • +
  • FB[i].MC[j].OE_MUX: selects output enable source

    +
      +
    • PT: product term 1 dedicated function or 0

    • +
    • FOE[0-3]: global FOE[0-3] network

    • +
    +
  • +
  • FB[i].MC[j].UIM_OE_MUX: selects output enable for UIM output

    +
      +
    • GND: const 0

    • +
    • VCC: const 1

    • +
    • OE_MUX: the input selected by the OE_MUX fuses

    • +
    +
  • +
  • FB[i].MC[j].IOB_OE_MUX: selects output enable for IOB output

    +
      +
    • GND: const 0

    • +
    • VCC: const 1

    • +
    • OE_MUX: the input selected by the OE_MUX fuses

    • +
    +
  • +
  • FB[i].MC[j].UIM_OUT_INV: if programmed, the output to UIM is inverted

  • +
+
+

Todo

+

verify all of the above (in particular, feedback path vs OE and UIM out)

+
+
+
+

Macrocell output — XC9500XL/XV

+

The output of the macrocell can be selected from combinatorial (XOR gate output) or registered (FF output):

+
FB[i].MC[j].OUT = (FB[i].MC[j].OUT_MUX == COMB ? FB[i].MC[j].XOR : FB[i].MC[j].FF);
+
+
+

The output is routed to the UIM and this MC’s IOB.

+

The macrocell also has an output enable, which can be from a product term, or a global network, and can +be freely inverted. It is used for the IOB output buffer:

+
case(FB[i].MC[j].OE_MUX)
+PT: FB[i].MC[j].IOB_OE = FB[i].MC[j].PT[1].SPECIAL ^ FB[i].MC[j].OE_INV;
+FOE0: FB[i].MC[j].IOB_OE = FOE[0] ^ FB[i].MC[j].OE_INV;
+FOE1: FB[i].MC[j].IOB_OE = FOE[1] ^ FB[i].MC[j].OE_INV;
+FOE2: FB[i].MC[j].IOB_OE = FOE[2] ^ FB[i].MC[j].OE_INV;
+FOE3: FB[i].MC[j].IOB_OE = FOE[3] ^ FB[i].MC[j].OE_INV;
+endcase
+
+
+

The fuses involved are:

+
    +
  • FB[i].MC[j].OUT_MUX: selects output mode

    +
      +
    • COMB: combinatorial, the output is connected to XOR gate output

    • +
    • FF: registered, the output is connected to FF output

    • +
    +
  • +
  • FB[i].MC[j].OE_MUX: selects output enable source

    +
      +
    • PT: product term 1 dedicated function or 0

    • +
    • FOE[0-3]: global FOE[0-3] network

    • +
    +
  • +
  • FB[i].MC[j].OE_INV: if programmed, the output enable is inverted

  • +
+
+
+

Input/output buffer

+

All I/O buffers (except dedicated JTAG pins) are associated with a macrocell. Not all MCs +have associated IOBs.

+

The output buffer is controlled by the FB[i].MC[j].OUT and FB[i].MC[j].IOB_OE signals of the macrocell. +If the pad is supposed to be input only, the OE signal should be programmed to be always 0:

+
    +
  • on XC9500, IOB_OE_MUX should be set to GND

  • +
  • on XC9500XL/XV, OE_MUX should be set to PT, OE_INV should be unset, and PT[1] should not be allocated to its dedicated function

  • +
+

Likewise, if the pad is supposed to be always-on output, the OE signal should be programmed to be always 1:

+
    +
  • on XC9500, IOB_OE_MUX should be set to VCC

  • +
  • on XC9500XL/XV, OE_MUX should be set to PT, OE_INV should be set, and PT[1] should not be allocated to its dedicated function

  • +
+

The output slew rate is programmable between two settings, “fast” and “slow”.

+

Instead of being connected to MC output, an IOB can also be a “programmed ground”, ie be set to always output a const 0 +regardless of the IOB_OE and OUT signals. In this case, IOB_OE should be 0.

+

The input buffer is connected to the FB[i].MC[j].IOB.I network. On all devices other than XC95288 (non-XL/XV), +it is directly connected to the UIM. On XC95288, there are additional enable fuses for this connection.

+

Each I/O buffer has the following fuses:

+
    +
  • FB[i].MC[j].GND: if programmed, this pin is “programmed ground” and will always output a const 0

  • +
  • FB[i].MC[j].SLEW: selects slew rate, one of:

    +
      +
    • SLOW

    • +
    • FAST

    • +
    +
  • +
  • FB[i].MC[j].IBUF_ENABLE (XC95288 only): when programmed, the input buffer is active and connected to UIM

  • +
+
+

Todo

+

figure out the IBUF_ENABLE thing

+
+
+
+

Configuration pull-ups

+

Before the device is configured, all IOBs are configured with a very weak pull-up +resistor (XC9500) or a bus keeper (XC9500XL/XV). To disable this pull-up, a per-FB fuse +is used which is set in the bitstream:

+
    +
  • FB[i].PULLUP_DISABLE: if programmed, disables the pre-configuration pull-ups / bus keepers for all IOBs in this FB

  • +
+
+
+

XC9500XL/XV bus keeper

+

The XC9500XL/XV have a weak bus keeper in each IOB. The keeper functionality can only be enabled +globally for all pads on the device, or not at all, via a global fuse:

+
    +
  • KEEPER: if programmed, the bus keeper is enabled on all IOBs

  • +
+
+
+

Global networks — XC9500

+

The device has several global networks for fast control signals. The networks are always driven by special pads +on the device (which can also be used as normal I/O). The networks are:

+
    +
  • FCLK[0-2]: clock

  • +
  • FSR: async set or reset

  • +
  • FOE[0-1] (XC9536, XC9572, XC95108) or FOE[0-3] (XC95144, XC95216, XC95288): output enable

  • +
+

The special pads are:

+
    +
  • GCLK[0-2]: clock

  • +
  • GSR: async set or reset

  • +
  • GOE[0-1] (XC9536, XC9572, XC95108) or GOE[0-3] (XC95144, XC95216, XC95288): output enable

  • +
+

The mapping of G* special pads to MCs depends on the device and, in at least one case, the package (!).

+

The allowed mappings are:

+
    +
  • FCLK0: GCLK0, GCLK1

  • +
  • FCLK1: GCLK1, GCLK2

  • +
  • FCLK2: GCLK2, GCLK0

  • +
  • FSR: GSR

  • +
  • FOE0 (XC9536, XC9572, XC95108): GOE0, GOE1

  • +
  • FOE1 (XC9536, XC9572, XC95108): GOE0, GOE1

  • +
  • FOE0 (XC95144, XC95216, XC95288): GOE0, GOE1

  • +
  • FOE1 (XC95144, XC95216, XC95288): GOE1, GOE2

  • +
  • FOE2 (XC95144, XC95216, XC95288): GOE2, GOE3

  • +
  • FOE3 (XC95144, XC95216, XC95288): GOE3, GOE0

  • +
+

Additionally, all networks can be inverted from their source pins.

+

The fuses involved are:

+
    +
  • FCLK[i].MUX: selects the input routed to FCLK[i]

    +
      +
    • NONE: const ???

    • +
    • GCLK[i]: the corresponding GCLK pad

    • +
    +
  • +
  • FOE[i].MUX: selects the input routed to FOE[i]

    +
      +
    • NONE: const ???

    • +
    • FOE[i]: the corresponding FOE pad

    • +
    +
  • +
  • FCLK[i].INV: if programmed, the GCLK pad is inverted before driving FCLK[i] network

  • +
  • FSR.INV: if programmed, the GSR pad is inverted before driving FSR network

  • +
  • FOE[i].INV: if programmed, the GOE pad is inverted before driving FOE[i] network

  • +
+
+

Todo

+

consts

+
+
+

Todo

+

no, really, what is it with the XC9572 GOE mapping varying between packages

+
+
+
+

Global networks — XC9500XL/XV

+

Global networks on XC9500XL/XV work similarly, except there are no muxes and no inversion (except for FSR). +Thus the GCLK[i] and GOE[i] pads are mapped 1-1 directly to FCLK[i] and FOE[i] networks, with only +an enable fuse.

+

The fuses involved are:

+
    +
  • FCLK[i].EN: if programmed, the given FCLK network is active and connected to the GCLK[i] pad

  • +
  • FOE[i].EN: if programmed, the given FOE network is active and connected to the GOE[i] pad

  • +
  • FSR.INV: if programmed, the GSR pad is inverted before driving FSR network

  • +
+

The FSR network is always enabled.

+
+

Todo

+

what does disabled network do

+
+
+
+

Misc configuration

+

The devices also include the following misc fuses:

+
    +
  • USERCODE: 32-bit fuse set, readable via the JTAG USERCODE instruction

  • +
  • FB[i].READ_PROT_{A|B} (XC9500): if programmed, the device is read protected

  • +
  • FB[i].READ_PROT (XC9500XL/XV): if programmed, the device is read protected

  • +
  • FB[i].WRITE_PROT: if programmed, the device is write protected (needs a special JTAG instruction sequence +to program/erase)

  • +
  • DONE (XC9500XV only): used to mark a fully programmed device; if programmed, the device will complete its +boot sequence and activate I/O buffers; otherwise, all output buffers will be disabled

  • +
+

Due to their special semantics, the protection fuses and the DONE fuse should be programmed last, after all other fuses in the bitstream.

+
+

Todo

+

exact semantics of protection fuses

+
+
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file