CadEnhance
Your EDA Tools... Automated

Blog

Articles about EDA trends, tips, and our tools.

Building High Pin Count Generic Xilinx Devices with CadEnhance PartBuilder

Here we examine the process used to create a high Pin Count device from Xilinx part Data using the CadEnhance Part Builder Tool.  The Part Builder tool is designed to get accurate pin information from a variety of sources,  either cut and pasted from a PDF file or spreadsheet, from a text editor or from Industry Standard File types like BSDL or IBIS files, and from Customer specific files from FPGA Vendors like Xilinx, Altera and Lattice.

The Part Builder tool supports 2 Flows for building Xilinx parts.

  1. Build a generic part with the Xilinx pin names broken down into multiple symbols (typically one symbol for one or 2 I/O Banks.)

  2. Build a custom part for each FPGA instance which uses the actual design pin names for all the used pins, and reverts to Xilinx defined pin names for unused pins and special function pins.

CadEnhance recommends the second option and another blog post will describe the benefits in more detail

QUICK LOOK AT THE PARTS WE ARE BUILDING

HERE are a handful of the multisectioned symbols that one customer used to enter the Xilinx FPGAxc7vx690ffg1761  into their schematic. The Part has 1761 pins,  In Total the customer built 32 symbols to add the part to the schematic.
There are 17 Symbols created for the 17 generic IO Banks in this Xilinx device:

There are 9 Identical Looking Symbols for  the HighSpeed Transceiver Banks:

Then there are a handful of symbols to house the special xcvr power pins, the myriad of ground pins and core power pins :

And Last but not Least, a symbol for the configuration pins and XADC pins of the device

Its clear that  the creation of all these symbols could take quite a bit of effort. That is where the CadEnhance Part Builder Tool Enters the picture.

LET PARTBUILDER GET THE PIN DATA FOR YOU

Xilinx builds  PartNumber.pkg files for their devices,  and their partgen Tool from the ISE suite can be used to create a package File (in this case to build the appropriate pacakge file, the user would invoke this command:
partgen -v xc7vx690tffg1761 Below is a snippet of the package file created for the Xilinx xc7vx6906ffg1761 Part. It will be used by the CadEnhance Part Builder to extract the pin-name, pin-number,io bank and pin types for the device so the user does not have to enter it by hand. Pin Delays can also be extracted and annotated to each pin for designs that require package delay compensation.
There are 1761 pins in the part, so getting accurate information quickly into the schematic symbol is critical.

Setting up Partbuilder

I like to keep a separate directory for each part I am going to create, and I can copy another directory that I used to build a part of a similar type to get a head start on creating the new one. In this case, since we are starting from scratch, we will browse to the top level directory where we keep all the parts, and create a new sub-directory to work in.
(I need a NEW BUTTON HERE so we can create a new directory based on an old ONE)

We fill in the Part Name (in this case it is XC7VX690T_FFG1761_GENERIC… This will be the name of the part that Cadence uses. It will be the top level directory containing symbol files, chips.prt files and the entity files.
We also enter the number of Pins which allows for a high level of Error checking.
Then we move below to select the PIN_REPORT_TYPE and use the GENERIC_XILINX Selection

We Place a copy of the xilinx package file in this directory as well. (xc7vx690tffg1761.pkg) and then select that file as the pinReport file using the Browse… button next to the Pin_Report_File Entry

We need to create the SymbolOrder.txt file which is the template we will use to get PartBuilder to control the placement of pins on symbols.  Use the browse button to create a new symbolOrder.txt file in the directory.

then use the Save Config selection under the config menu to save all your selections to the symGenCtl.txt file

NOW WE CONSTRUCT THE SYMBOLS

Introducing the symbolOrder.txt file.
You can create it in a text editor or a spreadsheet
For the text editor, I prefer xemacs for windows, and the spreadsheet can be excel or openoffice.Here is where the PartBuilder Tool shines! The symbolOrder.txt file has features that allow you to very quickly define the pin layout of each symbol, without worrying about what the pin numbers for each pin are, how  many symbols you need, or how many ground/power pins there are.
Once you get the hang of the symbolOrder.txt file you can almost see the part being created on the fly.Lets revisit the first symbol shown:

And the package file:

PartBuilder Reads the Package file and builds a data base for each pin, with all the information on each line.
After reading it, PartBuilder knows that:pinname IO_L1P_T0_12 is pin number AY27 and is in bank 12, and is IOB_X0Y148
pinname IO_L1N_T0_12 is pin number AY28 and is in bank 12 ….So PartBuilder does the difficult work of getting the pin numbers right, and then we use the symbolOrder.txt file to organize the way the symbols will look just by dealing withe the pinnames.Its a good thing to notice that the pkg file is built in a very regular structure, with the pins ordered in the xy locations as they appear in columns in the package. (PartBuilder is very aware of this since it reads it)It is very easy to import the package file into an excel spreadsheet using the data import function, then you can delete all the colums except the function name and you are left with the pinnames you want to sortSo to build the symbol above,

the symbolOrder.txt file would look like this                 or the spreadsheet would look like this:

IO_BANK_12=
#PLACE ALL THE VCCO_12 PINS at the top of the  left hand side
LEFT=>VCCO_12 
#now use the balance_sym_sides to offset the start of right and left hand signals to 3 after the last VCCO_12 PIN
BALANCE_SYM_SIDES+3
#now start placing pin paris, one on the left and one on the rightLEFT=> IO_L2P_T0_12 :: RIGHT=> IO_L23N_T3_12
LEFT=> IO_L2N_T0_12 :: RIGHT=> IO_L23P_T3_12
LEFT=> IO_L3P_T0_DQS_12 :: RIGHT=> IO_L22N_T3_12
LEFT=> IO_L3N_T0_DQS_12 :: RIGHT=> IO_L22P_T3_12
LEFT=> IO_L4P_T0_12 :: RIGHT=> IO_L21N_T3_DQS_12
LEFT=> IO_L4N_T0_12 :: RIGHT=> IO_L21P_T3_DQS_12
LEFT=> IO_L5P_T0_12 :: RIGHT=> IO_L20N_T3_12
LEFT=> IO_L5N_T0_12 :: RIGHT=> IO_L20P_T3_12
LEFT=> IO_L6P_T0_12 :: RIGHT=> IO_L19N_T3_VREF_12
LEFT=> IO_L6N_T0_VREF_12 :: RIGHT=> IO_L19P_T3_12
LEFT=> IO_L7P_T1_12 :: RIGHT=> IO_L18N_T2_12
LEFT=> IO_L7N_T1_12 :: RIGHT=> IO_L18P_T2_12
LEFT=> IO_L8P_T1_12 :: RIGHT=> IO_L17N_T2_12
LEFT=> IO_L8N_T1_12 :: RIGHT=> IO_L17P_T2_12
LEFT=> IO_L9P_T1_DQS_12 :: RIGHT=> IO_L16N_T2_12
LEFT=> IO_L9N_T1_DQS_12 :: RIGHT=> IO_L16P_T2_12
LEFT=> IO_L10P_T1_12 :: RIGHT=> IO_L15N_T2_DQS_12
LEFT=> IO_L10N_T1_12 :: RIGHT=> IO_L15P_T2_DQS_12
LEFT=> IO_L11P_T1_SRCC_12 :: RIGHT=> IO_L14N_T2_SRCC_12
LEFT=> IO_L11N_T1_SRCC_12 :: RIGHT=> IO_L14P_T2_SRCC_12
LEFT=> IO_L12P_T1_MRCC_12 :: RIGHT=> IO_L13N_T2_MRCC_12
LEFT=> IO_L12N_T1_MRCC_12 :: RIGHT=> IO_L13P_T2_MRCC_12
;#Note that the :: character just tells part builder there is another pin definition on the same line.
you could interleave all the signals on their own line with
so:
LEFT=>PINNAME1 ::RIGHT=>PINNAME2
LEFT=>PINNAME3::RIGHT=:PINNAME4is equivalent to
LEFT=>PINNAME1,
RIGHT=>PINNAME2,
LEFT=>PINAME3,
RIGHT=>PINNAME4and is also equivalent to:
LEFT=>PINNAME1,
LEFT=>PINNAME3,
RIGHT=>PINNAME2,
RIGHT=>PINNAME4,PartBuilder just keeps track of the order you are placing the signal on for each side

#everytime PartBuilder encounters the #NAME=Something  construct on a line,
#It starts building a new symbol
#each symbol is ended by the ‘;’ at the end of it.

#So to start the symbol for IO_BANK_13, we add #the ‘;’ at the end of the list of pins above,
#and then add the new:

IO_BANK_13=
LEFT=>VCCO_13
BALANCE_SYM_SIDES+3
LEFT=> IO_0_VRN_13 :: RIGHT=> IO_25_VRP_13
LEFT=> IO_L1P_T0_13 :: RIGHT=> IO_L24N_T3_13
LEFT=> IO_L1N_T0_13 :: RIGHT=> IO_L24P_T3_13
LEFT=> IO_L2P_T0_13 :: RIGHT=> IO_L23N_T3_13
LEFT=> IO_L2N_T0_13 :: RIGHT=> IO_L23P_T3_13
LEFT=> IO_L3P_T0_DQS_13 :: RIGHT=> IO_L22N_T3_13
LEFT=> IO_L3N_T0_DQS_13 :: RIGHT=> IO_L22P_T3_13
LEFT=> IO_L4P_T0_13 :: RIGHT=> IO_L21N_T3_DQS_13
LEFT=> IO_L4N_T0_13 :: RIGHT=> IO_L21P_T3_DQS_13
LEFT=> IO_L5P_T0_13 :: RIGHT=> IO_L20N_T3_13
LEFT=> IO_L5N_T0_13 :: RIGHT=> IO_L20P_T3_13
LEFT=> IO_L6P_T0_13 :: RIGHT=> IO_L19N_T3_VREF_13
LEFT=> IO_L6N_T0_VREF_13 :: RIGHT=> IO_L19P_T3_13
LEFT=> IO_L7P_T1_13 :: RIGHT=> IO_L18N_T2_13
LEFT=> IO_L7N_T1_13 :: RIGHT=> IO_L18P_T2_13
LEFT=> IO_L8P_T1_13 :: RIGHT=> IO_L17N_T2_13
LEFT=> IO_L8N_T1_13 :: RIGHT=> IO_L17P_T2_13
LEFT=> IO_L9P_T1_DQS_13 :: RIGHT=> IO_L16N_T2_13
LEFT=> IO_L9N_T1_DQS_13 :: RIGHT=> IO_L16P_T2_13
LEFT=> IO_L10P_T1_13 :: RIGHT=> IO_L15N_T2_DQS_13
LEFT=> IO_L10N_T1_13 :: RIGHT=> IO_L15P_T2_DQS_13
LEFT=> IO_L11P_T1_SRCC_13 :: RIGHT=> IO_L14N_T2_SRCC_13
LEFT=> IO_L11N_T1_SRCC_13 :: RIGHT=> IO_L14P_T2_SRCC_13
LEFT=> IO_L12P_T1_MRCC_13 :: RIGHT=> IO_L13N_T2_MRCC_13
LEFT=> IO_L12N_T1_MRCC_13 :: RIGHT=> IO_L13P_T2_MRCC_13
;

HERE IS BANK 13 in the spreadsheet

As  a short Aside here, The ordering the customer used for the symbol where they wrapped the signals from the top left, down to the bottom and then over to the bottom left and back up to the top is pretty difficult to do.
(Its also not so good for wiring a xilinx part in a logical fashion…., but the customer is always right)Excel makes it somewhat easier to do this: I searched the web and came up with this gem for a way to reversing a column of data from top to bottom:https://blogs.technet.com/b/hub/archive/2010/05/06/excelling-in-excel-how-to-flip-a-column-of-data.aspx

LOOPS MAKE IT EASIER!

So we could keep copying  that construct 17 times and create the 17 IO BANK SIGNALS
Or EVEN BETTER:
Since the xilinx pin numbering is so regular,We can use the looping constructs   to describe one symbol template
and have PartBuilder build all 17 IO_BANK symbols for us`foreach BANK in (12,13,14,15,16,17,18,19,31,32,33,34,35,36,37,38,39)
IO_BANK_`BANK::=
#place all the vcco_12 pins on the left hand side
LEFT=>VCCO_`BANK::
#now move down 3 from the last vcco pin on the left hand side
BALANCE_SYM_SIDES+3
#and then place the left and right pairs
LEFT=> IO_0_VRN_`BANK:: :: RIGHT=> IO_25_VRP_`BANK::
LEFT=> IO_L1P_T0_`BANK:: :: RIGHT=> IO_L24N_T3_`BANK::
LEFT=> IO_L1N_T0_`BANK:: :: RIGHT=> IO_L24P_T3_`BANK::
LEFT=> IO_L2P_T0_`BANK:: :: RIGHT=> IO_L23N_T3_`BANK::
LEFT=> IO_L2N_T0_`BANK:: :: RIGHT=> IO_L23P_T3_`BANK::
LEFT=> IO_L3P_T0_DQS_`BANK:: :: RIGHT=> IO_L22N_T3_`BANK::
LEFT=> IO_L3N_T0_DQS_`BANK:: :: RIGHT=> IO_L22P_T3_`BANK::
LEFT=> IO_L4P_T0_`BANK:: :: RIGHT=> IO_L21N_T3_DQS_`BANK::
LEFT=> IO_L4N_T0_`BANK:: :: RIGHT=> IO_L21P_T3_DQS_`BANK::
LEFT=> IO_L5P_T0_`BANK:: :: RIGHT=> IO_L20N_T3_`BANK::
LEFT=> IO_L5N_T0_`BANK:: :: RIGHT=> IO_L20P_T3_`BANK::
LEFT=> IO_L6P_T0_`BANK:: :: RIGHT=> IO_L19N_T3_VREF_`BANK::
LEFT=> IO_L6N_T0_VREF_`BANK:: :: RIGHT=> IO_L19P_T3_`BANK::
LEFT=> IO_L7P_T1_`BANK:: :: RIGHT=> IO_L18N_T2_`BANK::
LEFT=> IO_L7N_T1_`BANK:: :: RIGHT=> IO_L18P_T2_`BANK::
LEFT=> IO_L8P_T1_`BANK:: :: RIGHT=> IO_L17N_T2_`BANK::
LEFT=> IO_L8N_T1_`BANK:: :: RIGHT=> IO_L17P_T2_`BANK::
LEFT=> IO_L9P_T1_DQS_`BANK:: :: RIGHT=> IO_L16N_T2_`BANK::
LEFT=> IO_L9N_T1_DQS_`BANK:: :: RIGHT=> IO_L16P_T2_`BANK::
LEFT=> IO_L10P_T1_`BANK:: :: RIGHT=> IO_L15N_T2_DQS_`BANK::
LEFT=> IO_L10N_T1_`BANK:: :: RIGHT=> IO_L15P_T2_DQS_`BANK::
LEFT=> IO_L11P_T1_SRCC_`BANK:: :: RIGHT=> IO_L14N_T2_SRCC_`BANK::
LEFT=> IO_L11N_T1_SRCC_`BANK:: :: RIGHT=> IO_L14P_T2_SRCC_`BANK::
LEFT=> IO_L12P_T1_MRCC_`BANK:: :: RIGHT=> IO_L13N_T2_MRCC_`BANK::
LEFT=> IO_L12N_T1_MRCC_`BANK:: :: RIGHT=> IO_L13P_T2_MRCC_`BANK::
;This won’t really work since some of the banks like 14 and 15 have similar but  extended names for their IO PINS

AND PATTERN MATCHING MAKES THE LOOPS WORK

So we need to use the pattern matching ability of PartBuilder and change the symbol definition to this:

`foreach BANK in (12,13,14,15,16,17,18,19,31,32,33,34,35,36,37,38,39)
IO_BANK_`BANK::=IO_BANK_`BANK::=
LEFT=>VCCO`BANK:::
!BALANCE_SYM_SIDES+2
LEFT=> IO_0.*_`BANK:: :: RIGHT=> IO_25.*_`BANK::
LEFT=> IO_L1P.*_`BANK:: :: RIGHT=> IO_L24N.*_`BANK::
LEFT=> IO_L1N.*_`BANK:: :: RIGHT=> IO_L24P.*_`BANK::
LEFT=> IO_L2P.*_`BANK:: :: RIGHT=> IO_L23N.*_`BANK::
LEFT=> IO_L2N.*_`BANK:: :: RIGHT=> IO_L23P.*_`BANK::
LEFT=> IO_L3P.*_`BANK:: :: RIGHT=> IO_L22N.*_`BANK::
LEFT=> IO_L3N.*_`BANK:: :: RIGHT=> IO_L22P.*_`BANK::
LEFT=> IO_L4P.*_`BANK:: :: RIGHT=> IO_L21N.*_`BANK::
LEFT=> IO_L4N.*_`BANK:: :: RIGHT=> IO_L21P.*_`BANK::
LEFT=> IO_L5P.*_`BANK:: :: RIGHT=> IO_L20N.*_`BANK::
LEFT=> IO_L5N.*_`BANK:: :: RIGHT=> IO_L20P.*_`BANK::
LEFT=> IO_L6P.*_`BANK:: :: RIGHT=> IO_L19N.*_`BANK::
LEFT=> IO_L6N.*_`BANK:: :: RIGHT=> IO_L19P.*_`BANK::
LEFT=> IO_L7P.*_`BANK:: :: RIGHT=> IO_L18N.*_`BANK::
LEFT=> IO_L7N.*_`BANK:: :: RIGHT=> IO_L18P.*_`BANK::
LEFT=> IO_L8P.*_`BANK:: :: RIGHT=> IO_L17N.*_`BANK::
LEFT=> IO_L8N.*_`BANK:: :: RIGHT=> IO_L17P.*_`BANK::
LEFT=> IO_L9P.*_`BANK:: :: RIGHT=> IO_L16N.*_`BANK::
LEFT=> IO_L9N.*_`BANK:: :: RIGHT=> IO_L16P.*_`BANK::
LEFT=> IO_L10P.*_`BANK:: :: RIGHT=> IO_L15N.*_`BANK::
LEFT=> IO_L10N.*_`BANK:: :: RIGHT=> IO_L15P.*_`BANK::
LEFT=> IO_L11P.*_`BANK:: :: RIGHT=> IO_L14N.*_`BANK::
LEFT=> IO_L11N.*_`BANK:: :: RIGHT=> IO_L14P.*_`BANK::
LEFT=> IO_L12P.*_`BANK:: :: RIGHT=> IO_L13N.*_`BANK::
LEFT=> IO_L12N.*_`BANK:: :: RIGHT=> IO_L13P.*_`BANK::
;

The .* says match anything between the 0 and _`BANK
so lets look at one of the .* matching constructs (these are regular expressions to those familar with the term)
IO_L3P.*_`BANK::

Part builder will go through the loop the first time and change that to :
IO_L3P.*_12    The signal that matches in BANK12 is IO_L3P(_T0_DQS)_12

On the third pass of the loop,
it will be changed to
IO_L3P.*_14  The signal that matches in Bank 14 is  IO_L3P(_T0_DQS_PUDC_B)_14

So now the loop will properly generate all 17 symbols just the way the customer drew them

THE LAZY PERSON’S WAY TO DO IT….

If we were really looking to save time, we wouldn’t order the pins quite the way this customer did,

We would put all the pins for bank_12 on one side, and all the pins for bank 13 on the other side
let PartBuilder do the job it was meant to do.
When reads the .pkg file, it sorts and stores the pins in the order they appear in the XY pad description, so it will add the pins in the proper order without us having to do too much

#We would end up with
`let BANKA=12;
`let BANKB=13;
`for (`i=0;`i<4;`i++)
IO_BANKS_`BANKA_`BANKB=
#add the VCCO_BANKA pins on the left and the VCCO_BANKB pins on the right
LEFT=>VCCO_`BANKA::RIGHT=>VCCO_`BANKB
#add the 3 pin spacer after the VCCO PINS (IF you need more room for decoupling caps just increase the 3 to 4,5 or 6
BALANCE_SYM_SIDES+3

LEFT=>IO.*_`BANK A:: RIGHT=>IO.*_`BANKB
`let BANKA=`BANKA+2
`let BANKB=`BANKB+2
;
#and
`let BANKA=32;
`let BANKB=33;
`for (`i=0;`i<4;`i++)
IO_BANKS_`BANKA_`BANKB=
LEFT=>VCCO_`BANKA::RIGHT=>VCCO_`BANKB
BALANCE_SYM_SIDES+3
LEFT=>IO.*_`BANK A:: RIGHT=>IO.*_`BANKB
`let BANKA=`BANKA+2
`let BANKB=`BANKB+2
;

#then since IO BANK 39 is left all alone, build the same for bank39 left on its own
`let BANKA=39
IO_BANK_`BANKA
LEFT=>VCCO_`BANKA
BALANCE_SYM_SIDES+3
LEFT=>IO.*_`BANK A
;

This would reduce the symbol count (albeit with taller symbols) from 17 to 9, and all the symbols can be desribed in the 23 lines above… NOT BAD!

Bill OLearyPartBuilder