#!/usr/bin/env python3 from argparse import ArgumentParser from io import StringIO from enum import Enum, auto import os.path import sys import re class Cell: def __init__(self, name, keep=False, port_attrs={}): self.name = name self.keep = keep self.port_attrs = port_attrs CELLS = [ # Design element types listed in: # - UG607 (Spartan 3) # - UG613 (Spartan 3A) # - UG617 (Spartan 3E) # - UG615 (Spartan 6) # - UG619 (Virtex 4) # - UG621 (Virtex 5) # - UG623 (Virtex 6) # - UG953 (Series 7) # - UG974 (Ultrascale) # CLB -- RAM/ROM. # Cell('RAM16X1S', port_attrs={'WCLK': ['clkbuf_sink']}), # Cell('RAM16X1S_1', port_attrs={'WCLK': ['clkbuf_sink']}), # Cell('RAM32X1S', port_attrs={'WCLK': ['clkbuf_sink']}), # Cell('RAM32X1S_1', port_attrs={'WCLK': ['clkbuf_sink']}), # Cell('RAM64X1S', port_attrs={'WCLK': ['clkbuf_sink']}), # Cell('RAM64X1S_1', port_attrs={'WCLK': ['clkbuf_sink']}), # Cell('RAM128X1S', port_attrs={'WCLK': ['clkbuf_sink']}), # Cell('RAM128X1S_1', port_attrs={'WCLK': ['clkbuf_sink']}), # Cell('RAM256X1S', port_attrs={'WCLK': ['clkbuf_sink']}), # Cell('RAM512X1S', port_attrs={'WCLK': ['clkbuf_sink']}), # Cell('RAM16X2S', port_attrs={'WCLK': ['clkbuf_sink']}), # Cell('RAM32X2S', port_attrs={'WCLK': ['clkbuf_sink']}), # Cell('RAM64X2S', port_attrs={'WCLK': ['clkbuf_sink']}), # Cell('RAM16X4S', port_attrs={'WCLK': ['clkbuf_sink']}), # Cell('RAM32X4S', port_attrs={'WCLK': ['clkbuf_sink']}), # Cell('RAM16X8S', port_attrs={'WCLK': ['clkbuf_sink']}), # Cell('RAM32X8S', port_attrs={'WCLK': ['clkbuf_sink']}), # Cell('RAM16X1D', port_attrs={'WCLK': ['clkbuf_sink']}), # Cell('RAM16X1D_1', port_attrs={'WCLK': ['clkbuf_sink']}), # Cell('RAM32X1D', port_attrs={'WCLK': ['clkbuf_sink']}), # Cell('RAM32X1D_1', port_attrs={'WCLK': ['clkbuf_sink']}), # Cell('RAM64X1D', port_attrs={'WCLK': ['clkbuf_sink']}), # Cell('RAM64X1D_1', port_attrs={'WCLK': ['clkbuf_sink']}), # Cell('RAM128X1D', port_attrs={'WCLK': ['clkbuf_sink']}), # Cell('RAM256X1D', port_attrs={'WCLK': ['clkbuf_sink']}), # Cell('RAM32M', port_attrs={'WCLK': ['clkbuf_sink']}), # Cell('RAM32M16', port_attrs={'WCLK': ['clkbuf_sink']}), # Cell('RAM64M', port_attrs={'WCLK': ['clkbuf_sink']}), # Cell('RAM64M8', port_attrs={'WCLK': ['clkbuf_sink']}), # Cell('RAM32X16DR8', port_attrs={'WCLK': ['clkbuf_sink']}), # Cell('RAM64X8SW', port_attrs={'WCLK': ['clkbuf_sink']}), # Cell('ROM16X1'), # Cell('ROM32X1'), # Cell('ROM64X1'), # Cell('ROM128X1'), # Cell('ROM256X1'), # CLB -- registers/latches. # Virtex 1/2/4/5, Spartan 3. # Cell('FDCPE', port_attrs={'C': ['clkbuf_sink']}), # Cell('FDRSE', port_attrs={'C': ['clkbuf_sink']}), # Cell('LDCPE', port_attrs={'C': ['clkbuf_sink']}), # Virtex 6, Spartan 6, Series 7, Ultrascale. # Cell('FDCE'), # Cell('FDPE'), # Cell('FDRE'), # Cell('FDSE'), # Cell('LDCE'), # Cell('LDPE'), # Cell('AND2B1L'), # Cell('OR2L'), # CLB -- other. # Cell('LUT1'), # Cell('LUT2'), # Cell('LUT3'), # Cell('LUT4'), # Cell('LUT5'), # Cell('LUT6'), # Cell('LUT6_2'), # Cell('MUXF5'), # Cell('MUXF6'), # Cell('MUXF7'), # Cell('MUXF8'), # Cell('MUXF9'), # Cell('CARRY4'), # Cell('CARRY8'), # Cell('MUXCY'), # Cell('XORCY'), # Cell('ORCY'), # Cell('MULT_AND'), # Cell('SRL16', port_attrs={'CLK': ['clkbuf_sink']}), # Cell('SRL16E', port_attrs={'CLK': ['clkbuf_sink']}), # Cell('SRLC16', port_attrs={'CLK': ['clkbuf_sink']}), # Cell('SRLC16E', port_attrs={'CLK': ['clkbuf_sink']}), # Cell('SRLC32E', port_attrs={'CLK': ['clkbuf_sink']}), # Cell('CFGLUT5', port_attrs={'CLK': ['clkbuf_sink']}), # Block RAM. # Virtex. # TODO: RAMB4_* # Virtex 2, Spartan 3. Cell('RAMB16_S1', port_attrs={'CLK': ['clkbuf_sink']}), Cell('RAMB16_S2', port_attrs={'CLK': ['clkbuf_sink']}), Cell('RAMB16_S4', port_attrs={'CLK': ['clkbuf_sink']}), Cell('RAMB16_S9', port_attrs={'CLK': ['clkbuf_sink']}), Cell('RAMB16_S18', port_attrs={'CLK': ['clkbuf_sink']}), Cell('RAMB16_S36', port_attrs={'CLK': ['clkbuf_sink']}), Cell('RAMB16_S1_S1', port_attrs={'CLKA': ['clkbuf_sink'], 'CLKB': ['clkbuf_sink']}), Cell('RAMB16_S1_S2', port_attrs={'CLKA': ['clkbuf_sink'], 'CLKB': ['clkbuf_sink']}), Cell('RAMB16_S1_S4', port_attrs={'CLKA': ['clkbuf_sink'], 'CLKB': ['clkbuf_sink']}), Cell('RAMB16_S1_S9', port_attrs={'CLKA': ['clkbuf_sink'], 'CLKB': ['clkbuf_sink']}), Cell('RAMB16_S1_S18', port_attrs={'CLKA': ['clkbuf_sink'], 'CLKB': ['clkbuf_sink']}), Cell('RAMB16_S1_S36', port_attrs={'CLKA': ['clkbuf_sink'], 'CLKB': ['clkbuf_sink']}), Cell('RAMB16_S2_S2', port_attrs={'CLKA': ['clkbuf_sink'], 'CLKB': ['clkbuf_sink']}), Cell('RAMB16_S2_S4', port_attrs={'CLKA': ['clkbuf_sink'], 'CLKB': ['clkbuf_sink']}), Cell('RAMB16_S2_S9', port_attrs={'CLKA': ['clkbuf_sink'], 'CLKB': ['clkbuf_sink']}), Cell('RAMB16_S2_S18', port_attrs={'CLKA': ['clkbuf_sink'], 'CLKB': ['clkbuf_sink']}), Cell('RAMB16_S2_S36', port_attrs={'CLKA': ['clkbuf_sink'], 'CLKB': ['clkbuf_sink']}), Cell('RAMB16_S4_S4', port_attrs={'CLKA': ['clkbuf_sink'], 'CLKB': ['clkbuf_sink']}), Cell('RAMB16_S4_S9', port_attrs={'CLKA': ['clkbuf_sink'], 'CLKB': ['clkbuf_sink']}), Cell('RAMB16_S4_S18', port_attrs={'CLKA': ['clkbuf_sink'], 'CLKB': ['clkbuf_sink']}), Cell('RAMB16_S4_S36', port_attrs={'CLKA': ['clkbuf_sink'], 'CLKB': ['clkbuf_sink']}), Cell('RAMB16_S9_S9', port_attrs={'CLKA': ['clkbuf_sink'], 'CLKB': ['clkbuf_sink']}), Cell('RAMB16_S9_S18', port_attrs={'CLKA': ['clkbuf_sink'], 'CLKB': ['clkbuf_sink']}), Cell('RAMB16_S9_S36', port_attrs={'CLKA': ['clkbuf_sink'], 'CLKB': ['clkbuf_sink']}), Cell('RAMB16_S18_S18', port_attrs={'CLKA': ['clkbuf_sink'], 'CLKB': ['clkbuf_sink']}), Cell('RAMB16_S18_S36', port_attrs={'CLKA': ['clkbuf_sink'], 'CLKB': ['clkbuf_sink']}), Cell('RAMB16_S36_S36', port_attrs={'CLKA': ['clkbuf_sink'], 'CLKB': ['clkbuf_sink']}), # Spartan 3A (in addition to above). Cell('RAMB16BWE_S18', port_attrs={'CLK': ['clkbuf_sink']}), Cell('RAMB16BWE_S36', port_attrs={'CLK': ['clkbuf_sink']}), Cell('RAMB16BWE_S18_S9', port_attrs={'CLKA': ['clkbuf_sink'], 'CLKB': ['clkbuf_sink']}), Cell('RAMB16BWE_S18_S18', port_attrs={'CLKA': ['clkbuf_sink'], 'CLKB': ['clkbuf_sink']}), Cell('RAMB16BWE_S36_S9', port_attrs={'CLKA': ['clkbuf_sink'], 'CLKB': ['clkbuf_sink']}), Cell('RAMB16BWE_S36_S18', port_attrs={'CLKA': ['clkbuf_sink'], 'CLKB': ['clkbuf_sink']}), Cell('RAMB16BWE_S36_S36', port_attrs={'CLKA': ['clkbuf_sink'], 'CLKB': ['clkbuf_sink']}), # Spartan 3A DSP. Cell('RAMB16BWER', port_attrs={ 'CLKA': ['clkbuf_sink'], 'CLKB': ['clkbuf_sink']}), # Spartan 6 (in addition to above). Cell('RAMB8BWER', port_attrs={ 'CLKAWRCLK': ['clkbuf_sink'], 'CLKBRDCLK': ['clkbuf_sink']}), # Virtex 4. Cell('FIFO16', port_attrs={'RDCLK': ['clkbuf_sink'], 'WRCLK': ['clkbuf_sink']}), Cell('RAMB16', port_attrs={'CLKA': ['clkbuf_sink'], 'CLKB': ['clkbuf_sink']}), Cell('RAMB32_S64_ECC', port_attrs={'RDCLK': ['clkbuf_sink'], 'WRCLK': ['clkbuf_sink']}), # Virtex 5. Cell('FIFO18', port_attrs={'RDCLK': ['clkbuf_sink'], 'WRCLK': ['clkbuf_sink']}), Cell('FIFO18_36', port_attrs={'RDCLK': ['clkbuf_sink'], 'WRCLK': ['clkbuf_sink']}), Cell('FIFO36', port_attrs={'RDCLK': ['clkbuf_sink'], 'WRCLK': ['clkbuf_sink']}), Cell('FIFO36_72', port_attrs={'RDCLK': ['clkbuf_sink'], 'WRCLK': ['clkbuf_sink']}), Cell('RAMB18', port_attrs={'CLKA': ['clkbuf_sink'], 'CLKB': ['clkbuf_sink']}), Cell('RAMB36', port_attrs={'CLKA': ['clkbuf_sink'], 'CLKB': ['clkbuf_sink']}), Cell('RAMB18SDP', port_attrs={'RDCLK': ['clkbuf_sink'], 'WRCLK': ['clkbuf_sink']}), Cell('RAMB36SDP', port_attrs={'RDCLK': ['clkbuf_sink'], 'WRCLK': ['clkbuf_sink']}), # Virtex 6 / Series 7. Cell('FIFO18E1', port_attrs={'RDCLK': ['clkbuf_sink'], 'WRCLK': ['clkbuf_sink']}), Cell('FIFO36E1', port_attrs={'RDCLK': ['clkbuf_sink'], 'WRCLK': ['clkbuf_sink']}), #Cell('RAMB18E1', port_attrs={'CLKARDCLK': ['clkbuf_sink'], 'CLKBWRCLK': ['clkbuf_sink']]}), #Cell('RAMB36E1', port_attrs={'CLKARDCLK': ['clkbuf_sink'], 'CLKBWRCLK': ['clkbuf_sink']]}), # Ultrascale. Cell('FIFO18E2', port_attrs={'RDCLK': ['clkbuf_sink'], 'WRCLK': ['clkbuf_sink']}), Cell('FIFO36E2', port_attrs={'RDCLK': ['clkbuf_sink'], 'WRCLK': ['clkbuf_sink']}), Cell('RAMB18E2', port_attrs={'CLKARDCLK': ['clkbuf_sink'], 'CLKBWRCLK': ['clkbuf_sink']}), Cell('RAMB36E2', port_attrs={'CLKARDCLK': ['clkbuf_sink'], 'CLKBWRCLK': ['clkbuf_sink']}), # Ultra RAM. Cell('URAM288', port_attrs={'CLK': ['clkbuf_sink']}), Cell('URAM288_BASE', port_attrs={'CLK': ['clkbuf_sink']}), # Multipliers and DSP. # Cell('MULT18X18'), # Virtex 2, Spartan 3 # Cell('MULT18X18S', port_attrs={'C': ['clkbuf_sink']}), # Spartan 3 # Cell('MULT18X18SIO', port_attrs={'CLK': ['clkbuf_sink']}), # Spartan 3E # Cell('DSP48A', port_attrs={'CLK': ['clkbuf_sink']}), # Spartan 3A DSP # Cell('DSP48A1', port_attrs={'CLK': ['clkbuf_sink']}), # Spartan 6 # Cell('DSP48', port_attrs={'CLK': ['clkbuf_sink']}), # Virtex 4 Cell('DSP48E', port_attrs={'CLK': ['clkbuf_sink']}), # Virtex 5 #Cell('DSP48E1', port_attrs={'CLK': ['clkbuf_sink']}), # Virtex 6 / Series 7 Cell('DSP48E2', port_attrs={'CLK': ['clkbuf_sink']}), # Ultrascale # I/O logic. # Virtex 2, Spartan 3. # Note: these two are not officially listed in the HDL library guide, but # they are more fundamental than OFDDR* and are necessary to construct # differential DDR outputs (OFDDR* can only do single-ended). Cell('FDDRCPE', port_attrs={'C0': ['clkbuf_sink'], 'C1': ['clkbuf_sink']}), Cell('FDDRRSE', port_attrs={'C0': ['clkbuf_sink'], 'C1': ['clkbuf_sink']}), Cell('IFDDRCPE', port_attrs={'C0': ['clkbuf_sink'], 'C1': ['clkbuf_sink'], 'D': ['iopad_external_pin']}), Cell('IFDDRRSE', port_attrs={'C0': ['clkbuf_sink'], 'C1': ['clkbuf_sink'], 'D': ['iopad_external_pin']}), Cell('OFDDRCPE', port_attrs={'C0': ['clkbuf_sink'], 'C1': ['clkbuf_sink'], 'Q': ['iopad_external_pin']}), Cell('OFDDRRSE', port_attrs={'C0': ['clkbuf_sink'], 'C1': ['clkbuf_sink'], 'Q': ['iopad_external_pin']}), Cell('OFDDRTCPE', port_attrs={'C0': ['clkbuf_sink'], 'C1': ['clkbuf_sink'], 'O': ['iopad_external_pin']}), Cell('OFDDRTRSE', port_attrs={'C0': ['clkbuf_sink'], 'C1': ['clkbuf_sink'], 'O': ['iopad_external_pin']}), # Spartan 3E. Cell('IDDR2', port_attrs={'C0': ['clkbuf_sink'], 'C1': ['clkbuf_sink']}), Cell('ODDR2', port_attrs={'C0': ['clkbuf_sink'], 'C1': ['clkbuf_sink']}), # Virtex 4. Cell('IDDR', port_attrs={'C': ['clkbuf_sink']}), Cell('IDDR_2CLK', port_attrs={'C': ['clkbuf_sink'], 'CB': ['clkbuf_sink']}), Cell('ODDR', port_attrs={'C': ['clkbuf_sink']}), Cell('IDELAYCTRL', keep=True, port_attrs={'REFCLK': ['clkbuf_sink']}), Cell('IDELAY', port_attrs={'C': ['clkbuf_sink']}), Cell('ISERDES', port_attrs={ 'CLK': ['clkbuf_sink'], 'OCLK': ['clkbuf_sink'], 'CLKDIV': ['clkbuf_sink'], }), Cell('OSERDES', port_attrs={'CLK': ['clkbuf_sink'], 'CLKDIV': ['clkbuf_sink']}), # Virtex 5. Cell('IODELAY', port_attrs={'C': ['clkbuf_sink']}), Cell('ISERDES_NODELAY', port_attrs={ 'CLK': ['clkbuf_sink'], 'CLKB': ['clkbuf_sink'], 'OCLK': ['clkbuf_sink'], 'CLKDIV': ['clkbuf_sink'], }), # Virtex 6. Cell('IODELAYE1', port_attrs={'C': ['clkbuf_sink']}), Cell('ISERDESE1', port_attrs={ 'CLK': ['clkbuf_sink'], 'CLKB': ['clkbuf_sink'], 'OCLK': ['clkbuf_sink'], 'CLKDIV': ['clkbuf_sink'], }), Cell('OSERDESE1', port_attrs={'CLK': ['clkbuf_sink'], 'CLKDIV': ['clkbuf_sink']}), # Series 7. Cell('IDELAYE2', port_attrs={'C': ['clkbuf_sink']}), Cell('ODELAYE2', port_attrs={'C': ['clkbuf_sink']}), Cell('ISERDESE2', port_attrs={ 'CLK': ['clkbuf_sink'], 'CLKB': ['clkbuf_sink'], 'OCLK': ['clkbuf_sink'], 'OCLKB': ['clkbuf_sink'], 'CLKDIV': ['clkbuf_sink'], 'CLKDIVP': ['clkbuf_sink'], }), Cell('OSERDESE2', port_attrs={'CLK': ['clkbuf_sink'], 'CLKDIV': ['clkbuf_sink']}), Cell('PHASER_IN', keep=True), Cell('PHASER_IN_PHY', keep=True), Cell('PHASER_OUT', keep=True), Cell('PHASER_OUT_PHY', keep=True), Cell('PHASER_REF', keep=True), Cell('PHY_CONTROL', keep=True), # Ultrascale. Cell('IDDRE1', port_attrs={'C': ['clkbuf_sink'], 'CB': ['clkbuf_sink']}), Cell('ODDRE1', port_attrs={'C': ['clkbuf_sink']}), Cell('IDELAYE3', port_attrs={'CLK': ['clkbuf_sink']}), Cell('ODELAYE3', port_attrs={'CLK': ['clkbuf_sink']}), Cell('ISERDESE3', port_attrs={ 'CLK': ['clkbuf_sink'], 'CLK_B': ['clkbuf_sink'], 'FIFO_RD_CLK': ['clkbuf_sink'], 'CLKDIV': ['clkbuf_sink'], }), Cell('OSERDESE3', port_attrs={'CLK': ['clkbuf_sink'], 'CLKDIV': ['clkbuf_sink']}), Cell('BITSLICE_CONTROL', keep=True), Cell('RIU_OR', keep=True), Cell('RX_BITSLICE'), Cell('RXTX_BITSLICE'), Cell('TX_BITSLICE'), Cell('TX_BITSLICE_TRI'), # Spartan 6. Cell('IODELAY2', port_attrs={'IOCLK0': ['clkbuf_sink'], 'IOCLK1': ['clkbuf_sink'], 'CLK': ['clkbuf_sink']}), Cell('IODRP2', port_attrs={'IOCLK0': ['clkbuf_sink'], 'IOCLK1': ['clkbuf_sink'], 'CLK': ['clkbuf_sink']}), Cell('IODRP2_MCB', port_attrs={'IOCLK0': ['clkbuf_sink'], 'IOCLK1': ['clkbuf_sink'], 'CLK': ['clkbuf_sink']}), Cell('ISERDES2', port_attrs={ 'CLK0': ['clkbuf_sink'], 'CLK1': ['clkbuf_sink'], 'CLKDIV': ['clkbuf_sink'], }), Cell('OSERDES2', port_attrs={ 'CLK0': ['clkbuf_sink'], 'CLK1': ['clkbuf_sink'], 'CLKDIV': ['clkbuf_sink'], }), # I/O buffers. # Input. # Cell('IBUF', port_attrs={'I': ['iopad_external_pin']}), Cell('IBUF_DLY_ADJ', port_attrs={'I': ['iopad_external_pin']}), Cell('IBUF_IBUFDISABLE', port_attrs={'I': ['iopad_external_pin']}), Cell('IBUF_INTERMDISABLE', port_attrs={'I': ['iopad_external_pin']}), Cell('IBUF_ANALOG', port_attrs={'I': ['iopad_external_pin']}), Cell('IBUFE3', port_attrs={'I': ['iopad_external_pin']}), Cell('IBUFDS', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), Cell('IBUFDS_DLY_ADJ', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), Cell('IBUFDS_IBUFDISABLE', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), Cell('IBUFDS_INTERMDISABLE', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), Cell('IBUFDS_DIFF_OUT', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), Cell('IBUFDS_DIFF_OUT_IBUFDISABLE', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), Cell('IBUFDS_DIFF_OUT_INTERMDISABLE', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), Cell('IBUFDSE3', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), Cell('IBUFDS_DPHY', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), # Cell('IBUFG', port_attrs={'I': ['iopad_external_pin']}), Cell('IBUFGDS', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), Cell('IBUFGDS_DIFF_OUT', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), # I/O. # Cell('IOBUF', port_attrs={'IO': ['iopad_external_pin']}), Cell('IOBUF_DCIEN', port_attrs={'IO': ['iopad_external_pin']}), Cell('IOBUF_INTERMDISABLE', port_attrs={'IO': ['iopad_external_pin']}), Cell('IOBUFE3', port_attrs={'IO': ['iopad_external_pin']}), Cell('IOBUFDS', port_attrs={'IO': ['iopad_external_pin'], 'IOB': ['iopad_external_pin']}), Cell('IOBUFDS_DCIEN', port_attrs={'IO': ['iopad_external_pin'], 'IOB': ['iopad_external_pin']}), Cell('IOBUFDS_INTERMDISABLE', port_attrs={'IO': ['iopad_external_pin'], 'IOB': ['iopad_external_pin']}), Cell('IOBUFDS_DIFF_OUT', port_attrs={'IO': ['iopad_external_pin'], 'IOB': ['iopad_external_pin']}), Cell('IOBUFDS_DIFF_OUT_DCIEN', port_attrs={'IO': ['iopad_external_pin'], 'IOB': ['iopad_external_pin']}), Cell('IOBUFDS_DIFF_OUT_INTERMDISABLE', port_attrs={'IO': ['iopad_external_pin'], 'IOB': ['iopad_external_pin']}), Cell('IOBUFDSE3', port_attrs={'IO': ['iopad_external_pin'], 'IOB': ['iopad_external_pin']}), # Output. # Cell('OBUF', port_attrs={'O': ['iopad_external_pin']}), Cell('OBUFDS', port_attrs={'O': ['iopad_external_pin'], 'OB': ['iopad_external_pin']}), Cell('OBUFDS_DPHY', port_attrs={'O': ['iopad_external_pin'], 'OB': ['iopad_external_pin']}), # Output + tristate. # Cell('OBUFT', port_attrs={'O': ['iopad_external_pin']}), Cell('OBUFTDS', port_attrs={'O': ['iopad_external_pin'], 'OB': ['iopad_external_pin']}), # Pulls. Cell('KEEPER'), Cell('PULLDOWN'), Cell('PULLUP'), # Misc. Cell('DCIRESET', keep=True), Cell('HPIO_VREF', keep=True), # Ultrascale # Clock buffers (global). # Cell('BUFG', port_attrs={'O': ['clkbuf_driver']}), Cell('BUFGCE', port_attrs={'O': ['clkbuf_driver']}), Cell('BUFGCE_1', port_attrs={'O': ['clkbuf_driver']}), Cell('BUFGMUX', port_attrs={'O': ['clkbuf_driver']}), Cell('BUFGMUX_1', port_attrs={'O': ['clkbuf_driver']}), #Cell('BUFGCTRL', port_attrs={'O': ['clkbuf_driver']}), Cell('BUFGMUX_CTRL', port_attrs={'O': ['clkbuf_driver']}), Cell('BUFGMUX_VIRTEX4', port_attrs={'O': ['clkbuf_driver']}), Cell('BUFG_GT', port_attrs={'O': ['clkbuf_driver']}), Cell('BUFG_GT_SYNC'), Cell('BUFG_PS', port_attrs={'O': ['clkbuf_driver']}), Cell('BUFGCE_DIV', port_attrs={'O': ['clkbuf_driver']}), Cell('BUFH', port_attrs={'O': ['clkbuf_driver']}), #Cell('BUFHCE', port_attrs={'O': ['clkbuf_driver']}), # Clock buffers (IO) -- Spartan 6. Cell('BUFIO2', port_attrs={'IOCLK': ['clkbuf_driver'], 'DIVCLK': ['clkbuf_driver']}), Cell('BUFIO2_2CLK', port_attrs={'IOCLK': ['clkbuf_driver'], 'DIVCLK': ['clkbuf_driver']}), Cell('BUFIO2FB', port_attrs={'O': ['clkbuf_driver']}), Cell('BUFPLL', port_attrs={'IOCLK': ['clkbuf_driver']}), Cell('BUFPLL_MCB', port_attrs={'IOCLK0': ['clkbuf_driver'], 'IOCLK1': ['clkbuf_driver']}), # Clock buffers (IO and regional) -- Virtex. Cell('BUFIO', port_attrs={'O': ['clkbuf_driver']}), Cell('BUFIODQS', port_attrs={'O': ['clkbuf_driver']}), Cell('BUFR', port_attrs={'O': ['clkbuf_driver']}), Cell('BUFMR', port_attrs={'O': ['clkbuf_driver']}), Cell('BUFMRCE', port_attrs={'O': ['clkbuf_driver']}), # Clock components. # VIrtex. # TODO: CLKDLL # TODO: CLKDLLE # TODO: CLKDLLHF # Virtex 2, Spartan 3. Cell('DCM'), # Spartan 3E. Cell('DCM_SP'), # Spartan 6 (also uses DCM_SP and PLL_BASE). Cell('DCM_CLKGEN'), # Virtex 4/5. Cell('DCM_ADV'), Cell('DCM_BASE'), Cell('DCM_PS'), # Virtex 4. Cell('PMCD'), # Virtex 5. Cell('PLL_ADV'), Cell('PLL_BASE'), # Virtex 6. Cell('MMCM_ADV'), Cell('MMCM_BASE'), # Series 7. Cell('MMCME2_ADV'), Cell('MMCME2_BASE'), Cell('PLLE2_ADV'), Cell('PLLE2_BASE'), # Ultrascale. Cell('MMCME3_ADV'), Cell('MMCME3_BASE'), Cell('PLLE3_ADV'), Cell('PLLE3_BASE'), # Ultrascale+. Cell('MMCME4_ADV'), Cell('MMCME4_BASE'), Cell('PLLE4_ADV'), Cell('PLLE4_BASE'), # Misc stuff. Cell('BUFT'), # Series 7 I/O FIFOs. Cell('IN_FIFO', port_attrs={'RDCLK': ['clkbuf_sink'], 'WRCLK': ['clkbuf_sink']}), Cell('OUT_FIFO', port_attrs={'RDCLK': ['clkbuf_sink'], 'WRCLK': ['clkbuf_sink']}), # Ultrascale special synchronizer register. Cell('HARD_SYNC', port_attrs={'CLK': ['clkbuf_sink']}), # Singletons. # Startup. # TODO: STARTUP_VIRTEX # TODO: STARTUP_VIRTEX2 Cell('STARTUP_SPARTAN3', keep=True), Cell('STARTUP_SPARTAN3E', keep=True), Cell('STARTUP_SPARTAN3A', keep=True), Cell('STARTUP_SPARTAN6', keep=True), Cell('STARTUP_VIRTEX4', keep=True), Cell('STARTUP_VIRTEX5', keep=True), Cell('STARTUP_VIRTEX6', keep=True), Cell('STARTUPE2', keep=True), # Series 7 Cell('STARTUPE3', keep=True), # Ultrascale # Capture trigger. # TODO: CAPTURE_VIRTEX # TODO: CAPTURE_VIRTEX2 Cell('CAPTURE_SPARTAN3', keep=True), Cell('CAPTURE_SPARTAN3A', keep=True), Cell('CAPTURE_VIRTEX4', keep=True), Cell('CAPTURE_VIRTEX5', keep=True), Cell('CAPTURE_VIRTEX6', keep=True), Cell('CAPTUREE2', keep=True), # Series 7 # Internal Configuration Access Port. # TODO: ICAP_VIRTEX2 Cell('ICAP_SPARTAN3A', keep=True), Cell('ICAP_SPARTAN6', keep=True), Cell('ICAP_VIRTEX4', keep=True), Cell('ICAP_VIRTEX5', keep=True), Cell('ICAP_VIRTEX6', keep=True), Cell('ICAPE2', keep=True), # Series 7 Cell('ICAPE3', keep=True), # Ultrascale # JTAG. # TODO: BSCAN_VIRTEX # TODO: BSCAN_VIRTEX2 Cell('BSCAN_SPARTAN3', keep=True), Cell('BSCAN_SPARTAN3A', keep=True), Cell('BSCAN_SPARTAN6', keep=True), Cell('BSCAN_VIRTEX4', keep=True), Cell('BSCAN_VIRTEX5', keep=True), Cell('BSCAN_VIRTEX6', keep=True), Cell('BSCANE2', keep=True), # Series 7, Ultrascale # DNA port. Cell('DNA_PORT'), # Virtex 5/6, Series 7, Spartan 3A/6 Cell('DNA_PORTE2'), # Ultrascale # Frame ECC. Cell('FRAME_ECC_VIRTEX4'), Cell('FRAME_ECC_VIRTEX5'), Cell('FRAME_ECC_VIRTEX6'), Cell('FRAME_ECCE2'), # Series 7 Cell('FRAME_ECCE3'), # Ultrascale Cell('FRAME_ECCE4'), # Ultrascale+ # AXSS command access. Cell('USR_ACCESS_VIRTEX4'), Cell('USR_ACCESS_VIRTEX5'), Cell('USR_ACCESS_VIRTEX6'), Cell('USR_ACCESSE2'), # Series 7, Ultrascale # Misc. Cell('POST_CRC_INTERNAL'), # Spartan 6 Cell('SUSPEND_SYNC', keep=True), # Spartan 6 Cell('KEY_CLEAR', keep=True), # Virtex 5 Cell('MASTER_JTAG', keep=True), # Ultrascale Cell('SPI_ACCESS', keep=True), # Spartan 3AN Cell('EFUSE_USR'), # ADC. Cell('SYSMON', keep=True), # Virtex 5/6 Cell('XADC', keep=True), # Series 7 Cell('SYSMONE1', keep=True), # Ultrascale Cell('SYSMONE4', keep=True), # Ultrascale+ # Gigabit transceivers. # Spartan 6. Cell('GTPA1_DUAL'), # Virtex 2 Pro. # TODO: GT_* # TODO: GT10_* # Virtex 4. Cell('GT11_CUSTOM'), Cell('GT11_DUAL'), Cell('GT11CLK'), Cell('GT11CLK_MGT'), # Virtex 5. Cell('GTP_DUAL'), Cell('GTX_DUAL'), Cell('CRC32', port_attrs={'CRCCLK': ['clkbuf_sink']}), Cell('CRC64', port_attrs={'CRCCLK': ['clkbuf_sink']}), # Virtex 6. Cell('GTHE1_QUAD'), Cell('GTXE1'), Cell('IBUFDS_GTXE1', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), Cell('IBUFDS_GTHE1', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), # Series 7. Cell('GTHE2_CHANNEL'), Cell('GTHE2_COMMON'), Cell('GTPE2_CHANNEL'), Cell('GTPE2_COMMON'), Cell('GTXE2_CHANNEL'), Cell('GTXE2_COMMON'), Cell('IBUFDS_GTE2', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), # Ultrascale. Cell('GTHE3_CHANNEL'), Cell('GTHE3_COMMON'), Cell('GTYE3_CHANNEL'), Cell('GTYE3_COMMON'), Cell('IBUFDS_GTE3', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), Cell('OBUFDS_GTE3', port_attrs={'O': ['iopad_external_pin'], 'OB': ['iopad_external_pin']}), Cell('OBUFDS_GTE3_ADV', port_attrs={'O': ['iopad_external_pin'], 'OB': ['iopad_external_pin']}), # Ultrascale+. Cell('GTHE4_CHANNEL'), Cell('GTHE4_COMMON'), Cell('GTYE4_CHANNEL'), Cell('GTYE4_COMMON'), Cell('IBUFDS_GTE4', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), Cell('OBUFDS_GTE4', port_attrs={'O': ['iopad_external_pin'], 'OB': ['iopad_external_pin']}), Cell('OBUFDS_GTE4_ADV', port_attrs={'O': ['iopad_external_pin'], 'OB': ['iopad_external_pin']}), # Ultrascale+ GTM. Cell('GTM_DUAL'), # not in the libraries guide Cell('IBUFDS_GTM', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), Cell('OBUFDS_GTM', port_attrs={'O': ['iopad_external_pin'], 'OB': ['iopad_external_pin']}), Cell('OBUFDS_GTM_ADV', port_attrs={'O': ['iopad_external_pin'], 'OB': ['iopad_external_pin']}), # High-speed ADC/DAC. Cell('HSDAC'), # not in libraries guide Cell('HSADC'), # not in libraries guide Cell('RFDAC'), # not in libraries guide Cell('RFADC'), # not in libraries guide # PCIE IP. Cell('PCIE_A1'), # Spartan 6 Cell('PCIE_EP'), # Virtex 5 Cell('PCIE_2_0'), # Virtex 6 Cell('PCIE_2_1'), # Series 7 Cell('PCIE_3_0'), # Series 7 Cell('PCIE_3_1'), # Ultrascale Cell('PCIE40E4'), # Ultrascale+ Cell('PCIE4CE4'), # Ultrascale+ v2 (not in the libraries guide) # Ethernet IP. Cell('EMAC'), # Virtex 4 Cell('TEMAC'), # Virtex 5 Cell('TEMAC_SINGLE'), # Virtex 6 Cell('CMAC'), # Ultrascale Cell('CMACE4'), # Ultrsacale+ # Hard memory controllers. Cell('MCB'), # Spartan 6 Memory Controller Block Cell('HBM_REF_CLK', keep=True), # not in liraries guide # not sure how the following relate to the hw Cell('HBM_SNGLBLI_INTF_APB', keep=True), # not in liraries guide Cell('HBM_SNGLBLI_INTF_AXI', keep=True), # not in liraries guide Cell('HBM_ONE_STACK_INTF', keep=True), # not in liraries guide Cell('HBM_TWO_STACK_INTF', keep=True), # not in liraries guide # PowerPC. # TODO PPC405 (Virtex 2) Cell('PPC405_ADV'), # Virtex 4 Cell('PPC440'), # Virtex 5 # ARM. Cell('PS7', keep=True), # The Zynq 7000 ARM Processor System (not in libraries guide). Cell('PS8', keep=True), # The Zynq Ultrascale+ ARM Processor System (not in libraries guide). # Misc hard IP. Cell('ILKN'), # Ultrascale Interlaken Cell('ILKNE4'), # Ultrascale+ Interlaken Cell('VCU', keep=True), # Zynq MPSoC Video Codec Unit (not in libraries guide). Cell('FE'), # Zynq RFSoC Forward Error Correction (not in libraries guide). ] class State(Enum): OUTSIDE = auto() IN_MODULE = auto() IN_OTHER_MODULE = auto() IN_FUNCTION = auto() IN_TASK = auto() def xtract_cell_decl(cell, dirs, outf): for dir in dirs: for ext in ['.v', '.sv']: fname = os.path.join(dir, cell.name + ext) try: with open(fname) as f: state = State.OUTSIDE found = False # Probably the most horrible Verilog "parser" ever written. module_ports = [] invertible_ports = set() for l in f: l = l.partition('//')[0] l = l.strip() if l == 'module {}'.format(cell.name) or l.startswith('module {} '.format(cell.name)): if found: print('Multiple modules in {}.'.format(fname)) sys.exit(1) elif state != State.OUTSIDE: print('Nested modules in {}.'.format(fname)) sys.exit(1) found = True state = State.IN_MODULE if cell.keep: outf.write('(* keep *)\n') outf.write('module {} (...);\n'.format(cell.name)) elif l.startswith('module '): if state != State.OUTSIDE: print('Nested modules in {}.'.format(fname)) sys.exit(1) state = State.IN_OTHER_MODULE elif l.startswith('task '): if state == State.IN_MODULE: state = State.IN_TASK elif l.startswith('function '): if state == State.IN_MODULE: state = State.IN_FUNCTION elif l == 'endtask': if state == State.IN_TASK: state = State.IN_MODULE elif l == 'endfunction': if state == State.IN_FUNCTION: state = State.IN_MODULE elif l == 'endmodule': if state == State.IN_MODULE: for kind, rng, port in module_ports: for attr in cell.port_attrs.get(port, []): outf.write(' (* {} *)\n'.format(attr)) if port in invertible_ports: outf.write(' (* invertible_pin = "IS_{}_INVERTED" *)\n'.format(port)) if rng is None: outf.write(' {} {};\n'.format(kind, port)) else: outf.write(' {} {} {};\n'.format(kind, rng, port)) outf.write(l + '\n') outf.write('\n') elif state != State.IN_OTHER_MODULE: print('endmodule in weird place in {}.'.format(cell.name, fname)) sys.exit(1) state = State.OUTSIDE elif l.startswith(('input ', 'output ', 'inout ')) and state == State.IN_MODULE: if l.endswith((';', ',')): l = l[:-1] if ';' in l: print('Weird port line in {} [{}].'.format(fname, l)) sys.exit(1) kind, _, ports = l.partition(' ') for port in ports.split(','): port = port.strip() if port.startswith('['): rng, port = port.split() else: rng = None module_ports.append((kind, rng, port)) elif l.startswith('parameter ') and state == State.IN_MODULE: if 'UNPLACED' in l: continue if l.endswith((';', ',')): l = l[:-1] while ' ' in l: l = l.replace(' ', ' ') if ';' in l: print('Weird parameter line in {} [{}].'.format(fname, l)) sys.exit(1) outf.write(' {};\n'.format(l)) match = re.search('IS_([a-zA-Z0-9_]+)_INVERTED', l) if match: invertible_ports.add(match[1]) if state != State.OUTSIDE: print('endmodule not found in {}.'.format(fname)) sys.exit(1) if not found: print('Cannot find module {} in {}.'.format(cell.name, fname)) sys.exit(1) return except FileNotFoundError: continue print('Cannot find {}.'.format(cell.name)) sys.exit(1) if __name__ == '__main__': parser = ArgumentParser(description='Extract Xilinx blackbox cell definitions from ISE and Vivado.') parser.add_argument('vivado_dir', nargs='?', default='/opt/Xilinx/Vivado/2018.1') parser.add_argument('ise_dir', nargs='?', default='/opt/Xilinx/ISE/14.7') args = parser.parse_args() dirs = [ os.path.join(args.vivado_dir, 'data/verilog/src/xeclib'), os.path.join(args.vivado_dir, 'data/verilog/src/unisims'), os.path.join(args.vivado_dir, 'data/verilog/src/retarget'), os.path.join(args.ise_dir, 'ISE_DS/ISE/verilog/xeclib/unisims'), ] for dir in dirs: if not os.path.isdir(dir): print('{} is not a directory'.format(dir)) out = StringIO() for cell in CELLS: xtract_cell_decl(cell, dirs, out) with open('cells_xtra.v', 'w') as f: f.write('// Created by cells_xtra.py from Xilinx models\n') f.write('\n') f.write(out.getvalue())