SDL PreProcessor commands
SDL PreProcessor command consist of, the `Include command, the `EXIT statement LOOP_DIRECTIVES and VARIABLE SUBSTITUTION commands. They greatly increase the efficiency of creating parts that contain multiple similar interfaces like a microprocessor with 2 DRAM busses or an FPGA with multiple IO Banks with the same number and types of pins. They can also be used to quickly break up busses into nicely structured sub-busses
Helpful Videos
Name | link | length | description |
---|---|---|---|
Using BUS_SLICER | http://scast.cadenhance.com/bus-slicing-w-partbuilder | 11:44 | Different ways of working with bussed Pins using the SDL-Editor in PartBuilder |
Working with Include Files | http://scast.cadenhance.com/using_sdl_include_files | 6:07 | Intro to the tools the SDL-Editor provides to create, insert, remove, replace and edit Include files |
The Power of Replicate in SDL | http://scast.cadenhance.com/watch/cb6fIsIAc5 | 6:30 | Intro to the workings of the Replicate Loop |
Replicating FPGA Banks using SDL Editor | http://scast.cadenhance.com/replicate_fpga_banks_with_sdl_editor | 7:43 | Shows how to wrap a block of sdl statements with a REPLICATE Loop |
The Expanded SDL File
PartBuilder first scans the input SDL file to see if it contains LOOP _DIRECTIVES or Variable Substitution. If it finds any, it creates a new, expanded version of the input SDL file which it saves to the local directory and then uses for the pin to symbol assigment step. The expanded file has all the LOOP_DIRECTIVES and VARIABLE_SUB_DIRECTIVES removed. The LOOP_DIRECTIVES cause the expander to copy ranges of lines multiple times in the expanded file with the LOOP variables substituted. The expander function does not have any intelligence about the SDL statements inside the loop, it just makes copies and substitutes the variable values.
One benefit of this approach is it allows the user to clearly see how the loops were expanded, and possibly catch any unintended consequences of the loops. While the user is encouraged to examine the expanded SDL File, They should be careful not to edit it, as any changes they make to that file will be overwritten the next time PartBuilder reads and expands the input SDL file.
Include Files
Include files allow the user to create a library of common SDL functions for similar parts in a library. For instance, all of the members of the same FPGA family will usually have the same set of configuration pins, so the SDL to describe those pins can be created once, and then moved to a file called fpga_config_pins.sdl, which can then be included in the top level SDL file for all the parts in that family. The SDL Editor provides very efficient tools allowing the user to move lines of sdl into an include file, and to edit the contents of the include files. Another reason to use include files is to make the SDL for large parts much easier to read and edit, so the SDL for each symbol in a large part can be moved to its own SDL file and can be included in the top level SDL file. The SDL Editor tool is much more responsive when working with smaller SDL files so moving big sections of SDL files to include files will improve the users editing experience as well.
The Include directive is `Include incFileName
If a `INCLUDE fileName directive is found in the input SDL file, PartBuilder will perform a first pass expansion and insert the contents of the specified File into the expanded file. PartBuilder can handle multilevel inclusions (files included within include files), but there may not be too much need for that complexity. The 2 pass expansion process enables PartBuilder to handle include files which contain LOOP directives and VARIABLE substitution.
The incFileName can contain the whole path to the included file or just a fileName. If the full path is not specified, PartBuilder will first search the local working directory for the inlcuded file, if it does not find it there, it will search any directories listed in the CE_SDL_INCLUDE_DIRS config setting is a list of directories. This allows the user to create a Directory to store commonly used include files for easy reuse between parts.
Support for INCLUDE files was added in partBuilder version 18.4.2... a video demonstration of the new SDL_EDITOR support for INCLUDE files can be seen with this link: Video Demo
The `EXIT statement
The `EXIT pre-processor command can be added anywhere in the working SDL file to tell PartBuilder to stop processing any lines following that statement. This works great when the user wants to incrementally build symbols in the SDL. For instance, the SMART-Frac Feature builds a template file with all the pin-matches required to build the symbols, but it leaves a lot of pin_matches with the CHOOSE_SIDE location modifier which tells the user that they need to pick a side to place the matching pins. PartBuilder errors out if it sees any pin_matches with the CHOOSE_SIDE modifier, so putting an `EXIT command in before a list of pins that the user has not yet worked on, allows the user to incrementally build symbols. (In this case the user should also select the BUILD PARTIAL SYMBOLS checkbox so that the symbol build process will run to completion even though PartBuilder knows that the user hasn't mapped all the pins yet)
Support for the `EXIT statement was added in PartBuilder version v18.2.1
VARIABLE Value Assignment and Substitution
The user can use variables within Loops or just globally change a of a set of PIN_MATCHES in some MATCH_STATEMENTS that they cut and paste.
VARIABLES can be substituted anywhere in the SDL including in Comments, SYMBOL_NAME_DEFINITIONS and MATCH_STATEMENTS.
A Variable is assigned with the following statement:
`LET VAR_NAME=VALUE
The VAR_NAME cannot contain spaces, but it can consist of any other characters except the backtick and the equal sign.
The VALUE can be a number or a string or a mix of numbers and characters and spaces.
To have PartBuilder substitute the current Value of a variable in the SDL, the VARIABLE is prepended with a backtick and suffixed with 2 colons like:
`VAR_NAME::
Quick Example:
Input SDL with Variable | Expanded SDL File after Variable Substitution |
---|---|
`LET SYM=3 RX_SYMBOL_`SYM::= `LET A=[5:0] LEFT:dpair=>RX`A::_P RIGHT:dpair=>TX`A::_P !BSS+2 `LET A=[11:6] LEFT:dpair=>RX`A::_P RIGHT:dpair=>TX`A::_P ; | RX_SYMBOL_3= LEFT:dpair=>RX[5:0]_P RIGHT:dpair=>TX[5:0]_P !BSS+2 LEFT:dpair=>RX[11:6]_P RIGHT:dpair=>TX[11:6]_P ; |
LOOP_DIRECTIVES
There are 6 main types of LOOP_DIRECTIVES: 2 Types of LIST BASED LOOPS, REPEAT and BUS_SLICER LOOPS, REPLICATE LOOPS and ITERATIVE LOOPS
Each one must start at the beginning of a line with the backtick ` character to tell PartBuilder that this is a special line
When PartBuilder Expands the Input SDL file upon seeing a LOOP_DIRECTIVE, what it really does is create multiple copies of the lines between
the `FOR and `END_FOR while substituting in the running value of the LOOP_VARIABLE as it copies
Lets show a simple example before we look at the technical parts
Simple Example of a LIST BASED LOOP
Input SDL | expanded SDL |
---|---|
Input SDL FILE `FOR B in (1..2,15..16) IO_BANK_`B::= left:dpair=>clk`B::_i_p right:dpair=>clk`B::_o_p !BSS+2 left=>BUS`B::_RX_DQ[7:0] right=>BUS`B::_TX_DQ[7:0] ; `ENDFOR | Expanded SDL file #This File has been expanded by partBuilder from the input file:symbolOrder.txt #Do not edit it as any changes you make will be lost the next time partBuilder #runs the map_pins_to_symbols step IO_BANK_1= left:dpair=>clk1_i_p right:dpair=>clk1_o_p !BSS+2 left=>BUS1_RX_DQ[7:0] right=>BUS1_TX_DQ[7:0] ; IO_BANK_2= left:dpair=>clk2_i_p right:dpair=>clk2_o_p !BSS+2 left=>BUS2_RX_DQ[7:0] right=>BUS2_TX_DQ[7:0] ; IO_BANK_15= left:dpair=>clk15_i_p right:dpair=>clk15_o_p !BSS+2 left=>BUS15_RX_DQ[7:0] right=>BUS15_TX_DQ[7:0] ; IO_BANK_16= left:dpair=>clk16_i_p right:dpair=>clk16_o_p !BSS+2 left=>BUS16_RX_DQ[7:0] right=>BUS16_TX_DQ[7:0] ; |
PartBuilder finds the `For in the input SDL file, so it goes through the process of creating the expanded file It first prints the warning at the top of the file The Loop is started with `FOR B in (1..2,15..16) at line 1 and ends with the `ENDFOR at line 9 The IO_BANK`B::= SYMBOL_NAME_DEFINTION which starts at line 2 and ends with the semicolon at line 7 Part Builder expands the (1..2,15..16) to a list of 1,2,15,16, and goes through the loop 4 times, assigning variable B the next value in the list. for each iteration of the loop, it prints all the lines including the space after the ';' to the expanded file while substituting the current value of B for that iteration. |
LIST BASED LOOPS:
These loops assign the LOOP_VAR or LOOP_VAR_LIST with consecutive values from the provided LIST_OF_VALUES.
Single Variable List based Loop
`FOR LOOP_VAR IN (LIST_OF_VALUES)
SDL_STATEMENTS (some containing `LOOP_VAR:: for LOOP_VARIABLE substitution )
`END_FOR (or `ENDFOR)
The LOOP_VAR is used to store the individual values from the LIST_OF_VALUES. It needs to start with a letter from A-Z. There is no restriction on how long the LOOP_VAR name is
The LIST_OF_VALUES is very flexible It is built of comma separated elements which can be numbers, letters, words, or a RANGE_OPERATOR ('1..11' or '7..3')
PartBuilder reads the LIST_OF_VALUES (and expands any range_operators)
The '!UNDEF' keyword will be substituted for any Empty elements in the LIST_OF_VALUES
It then makes one copy of the enclosed SDL_STATEMENTS for each value in the expanded list of values.
Examples:
LOOP | expanded to: | notes |
---|---|---|
`FOR B IN (2,3,5,7,9) left=>DQ`B:: `END_FOR | left=>DQ2 left=>DQ3 left=>DQ5 left=>DQ7 left=>DQ9 | |
`FOR IO_BANK IN (1..4,,B1,15..17,21..19) right=>IO_*_`IO_BANK:: `END_FOR | right=>IO_*_1 right=>IO_*_2 right=>IO_*_3 right=>IO_*_4 right=>IO_*_!UNDEF right=>IO_*_B1 right=>IO_*_15 right=>IO_*_16 right=>IO_*_17 right=>IO_*_21 right=>IO_*_20 right=>IO_*_19 | The LIST_OF_VALUES contains multiple single elements mixed with several range operatators, and one missing value It will be expanded to: 1,2,3,4,!UNDEF,B1,15,16,17,21,20,19 which has 12 elements. note the last range operator 21..19 was specified in MSB..LSB order PartBuilder makes 12 copies of the MATCH_STATEMENT, substituting the value of IO_BANK each time |
MultiVariable List based Loop
`FOR LOOP_VAR_LIST IN (LIST_OF_VALUES)
SDL_STATEMENTS (including `LOOP_VAR:: for substitution )
`END_FOR (or `ENDFOR)
The LOOP_VAR_LIST is used to pull more than one value from the LIST_OF_VALUES. It is a comma separated list of LOOP_VARS
The LIST_OF_VALUES is built of comma separated elements which can be numbers, letters, words, or a RANGE OPERATOR ('1..11' or '7..3')
PartBuilder reads the LIST_OF_VALUES (and expands any RANGE_OPERATORS)
It assigns the first n elements of the LIST_OF_VALUES to the variables in the LOOP_VAR_LIST
It then makes one copy of the enclosed SDL_STATEMENTS for each n elements in the expanded list of values.
Examples:
Loop | Expanded to | Notes |
---|---|---|
|
| Part Builder pulls 2 elements at a time out of the LOOP_VAR_LIST to populate LOOP_VARS SNAME and RST_NUM |
|
| PartBuilder expands the LIST_OF_VALUES to 1,2,7,8 it assigns 1,2 to OB and EB and then copies the lines |
|
| Very similar to previous, but there is only one element left in the list for the 3rd pass of the copy You might be building a part with 5 banks, so the first 2 symbols will have an odd and even bank, but the last symbol will only have one. PartBuilder will gracefully handle this case for you in 2 steps... For the 3rd symbol, PartBuilder expansion replaces the empty EB variable with !UNDEF When PartBuilder reads the expanded SDL and sees the !UNDEF in the SYMBOL_NAME_DIRECTIVE, it removes the !UNDEF and the Trailing underscore from the symbol_name. So it ends up with a symbol named IO_BANKS_9 any MATCH_STATEMENT containing an !UNDEF will be removed from the list since it can't match anything |
`For OB,EB IN (1..2,3,!UNDEF,7..8) IO_BANKS_`OB::_`EB::= left=>IO_*_`OB:: right=>IO_*_`EB:: ; `END_FOR | IO_BANKS_1_2= IO_BANKS_3_!UNDEF= left=>IO_*_3 right=>IO_*_!UNDEF :
| Manually Adding the !UNDEF is very powerful as well In this case there is no IO_BANK_4 to pair with IO_BANK_3 so we manually insert an !UNDEF where bank 4 should have been Again PartBuilder will gracefully handle this case for you For the 2nd symbol, PartBuilder expansion uses the 3 and the !UNDEF values When PartBuilder reads the expanded SDL and sees the !UNDEF in the SYMBOL_NAME_DIRECTIVE, and in the pin_matches it removes the !UNDEF and the Trailing underscore from the symbol_name. and removes the !UNDEF matches from the list without reporting any warnings IO_BANKS 7 and 8 get grouped together properly |
List of Multiple Lists... New after v21.2.2 | ||
`For OB,EB IN (1,3,!UNDEF,5,7) (2..8:2) The next lines are equivalent, The loop expander will substitute !UNDEF for the missing value between commas `For OB,EB IN (1,3,,5,7) (2..8:2) | IO_BANKS_1_2= IO_BANKS_3_!UNDEF= left=>IO_*_3 right=>IO_*_!UNDEF :
| In the above examples, the user was responsible for interleaving the values of the lists so that the numbers would be pulled out in the proper order in this new syntax, we added support to let the user create multiple lists that will be used to assign values to each variable which is easier to do So the first list will produce 1,3,!UNDEF,5,7 and those values will be assigned to the OB variable And values from the 2nd list (2..8:2) which will produce the list 2,4,6,8 when expanded These values will be assigned to the EB variable The user must add a list for each comma separated variable in the first list `for var1,var2,var3,...varN in (List1) (List2) (List3),...(ListN) if any of the lists are missing elements of the longest list, those values will be automatically populated with !UNDEF |
`FOR side,bank_name,bank_type (left,right,right,top) (bank1,bank7,bank11,bank25) (user,user,none,admin) `side::=>`bank_type::_`bank_name `END_FOR | left=>user_bank1 right=>user_bank7 right=>none_bank11 top=>admin_bank25 | Here is a more interesting application for using a separate list for each variable Its easier to separate these elements into 3 lists instead of having to write a list like this (left,bank1,user,right,bank7,user,right,bank11,none,top,bank25,admin) |
BUS_SLICER LOOPS (Added in PartBuilder Version 20.5.1a)
BUS_SLICER LOOPS are a special case of the REPEAT LOOPS where the user does not need to modify the PIN_MATCH to split up existing bussed pins into smaller organized slices.
`BUS_SLICER n
SDL_STATEMENTS
`END_BUS_SLICER
Operation:
The BUS_SLICER Loop provides an easy way to arrange and distribute larger busses and groups of busses
Each pass through the loop automatically adds a slice of a larger bus
It calculates the size of the slice by dividing the (number of bits in the bus)/(the number of Loops).
It selects whether the indicies will be incremented or decremented by comparing the MSB and LSB of the Specified bus-range in each pinMatch
Use Case:
Smart-FRAC attempts to combine related sets of pins into busses to minimize the number of pinMatches the user has to work with to complete their symbols.In some cases, The user will want to split out the pins of those busses in a more distributed fashion.
For instance, When SMART-FRAC finds a part with 3 I2C busses having pins
I2C_SDA_0, I2C_SCL_0, I2C_ALERT_N_0, I2C_SDA_1, I2C_SCL_1, I2C_ALERT_N_1 and I2C_SDA_2, I2C_SCL_2, I2C_ALERT_N_2,
It will combine those pins into 3 separate bussed pinMatches I2C_SDA_[0:2], I2C_SCL_[0:2] and I2C_ALERT_[0:2].
If Those pinMatches are used untouched, the I2C busses for the part
The user would probably prefer to interleave the pins by the bus number 0, 1 and 2.
They can interleave these busses manually by splitting up the busses in the SDL-EDITOR (the new EXPAND_BUS operation can help)
The BUS_SLICER provides an automated way of doing this, and allows the user to easily configure the spacing between pins and change it in only one place instead of in 3 places if they want to fix it
BUS_SLICER Examples
BUS_SLICER LOOP | AFTER EXPANSION | NOTES: |
---|---|---|
I2C_BUS_PINS `BUS_SLICER 3 LEFT=>I2C_SDA[2:0] LEFT=>I2C_SCL[2:0] RIGHT=>I2C_ALERT[2:0]_N `END_BUS_SLICER | I2C_BUS_PINS= LEFT=>I2C_SDA2 LEFT=>I2C_SCL2 RIGHT=>I2C_ALERT2_N LEFT=>I2C_SDA1 LEFT=>I2C_SCL1 RIGHT=>I2C_ALERT1_N LEFT=>I2C_SDA0 LEFT=>I2C_SCL0 RIGHT=>I2C_ALERT0_N
| The BUS_SLICER count is 3, so the expansion will create 3 copies of whats between the `BUS_SLICER and `END_BUS_SLICER pre-processor statements The 3 pin-matches I2C_SDA[2:0], I2C_SCL[2:0] and I2C_ALERT[2:0]_N will be expanded in a case by case basis In all cases the Starting range digit 2, is greater than the ending range digit 0. so The expander will decrement the expanded indicies from 2 down to 0 The end result is that the 3 pins for each I2C busses are placed together, rather than placing the 3 bussed pins together Note that the BALANCE_SYMBOL_SIDES statements do not have recognizeable bus indicies so they are repeated with no modification each pass through the REPEAT LOOP |
DQ_BUS_PINS= `BUS_SLICER 4 RIGHT=>DQ[31:0] `END_BUS_SLICER ; #end DQ_BUS_PINS symbol | DQ_BUS_PINS= RIGHT=>DQ[31:24] RIGHT=>SPACERx1 RIGHT=>DQS_P3 RIGHT=>SPACERx1 RIGHT=>DQ[23:16] RIGHT=>SPACERx1 RIGHT=>DQS_P2 RIGHT=>SPACERx1 RIGHT=>DQ[15:8] RIGHT=>SPACERx1 RIGHT=>DQS_P1 RIGHT=>SPACERx1 RIGHT=>DQ[7:0] RIGHT=>SPACERx1 RIGHT=>DQS_P0 RIGHT=>SPACERx1 | #slice all lines between here and END_BUS_SLICER 4 times #PartBuilder calculates the slice_size to be 8 bits since its slicing a 32 bit bus 4 times #since there is no bus index in the RIGHT=>SPACERx1 this will be duplicated for each loop and you will get a spacer between each 4 bit DQ slice and the 1 bit DQS bus slice #slice size for the DQS_P[7:0} bus is 1 (interleaving the 8 bit bus 8 times) #It will starts at DQS_P[7] decrements 6,5,4,3,2,1,0 |
REPEAT LOOPS:
REPEAT_LOOPS provide a convenient way to split up bussed signals and their associated control signals into nicely grouped slices.
The LOOP_VAR in a repeat loop is implied in the SLICE_IDX or IDX of the BUS INC_DEC Operator
`REPEAT n
SDL_STATEMENTS (some with BUSSED INC_DEC operators)
`END_REPEAT
Version 20.5.1a added support for simpler REPEAT Indicies
Customers found it difficult to edit the bussesd pinMatches to meet the legacy syntax with the BUS_NAME[SLICE_IDX!(INC|DEC)_COUNT]
Version 20.5.1a added support for a newer simpler syntax in the PIN_MATCHES wrapped by the `REPEAT Command
BUS_NAME[DIG1:DIG2:SLICE_COUNT]
PartBuilder automatically determines if the slice operation should Increment or decrement by looking at the first 2 DIGITS DIG1 and DIG2 to see which is greater
Simple REPEAT_LOOP Example
REPEAT LOOP | AFTER EXPANSION | NOTES: |
---|---|---|
#increment on left #decrement on right DDR_DQ_PINS= LEFT=>DQ[32:63:8] RIGHT=>DQ[31:0:8] LEFT:dpair=>DQS_P[4:7:1] RIGHT:dpair=>DQS_P[3:0:1] !BALANCE_SYMBOL_SIDES+1 `END_REPEAT | DDR_DQ_PINS= LEFT=>DQ[32:39] left:dpair=>DQS_P4 !BALANCE_SYMBOL_SIDES+1 LEFT=>DQ[40:47] LEFT:dpair=>DQS_P5 !BALANCE_SYMBOL_SIDES+1 LEFT=>DQ[48:55] LEFT:dpair=>DQS_P6 !BALANCE_SYMBOL_SIDES+1 LEFT=>DQ[56:63] LEFT:dpair=>DQS_P7 !BALANCE_SYMBOL_SIDES+1
| PartBuilder processes the 4 pin-matches DQ[32:63:8], DQS_P[4:7:1], DQ[31:0:8] and DQS_P[3:0:1] pin-matches separately DQ[32:63:8] The SLICE_COUNT is 8 and tells PartBuilder to slice the DQ pin Match by 8 each pass through the REPEAT operation. 32 is less than 63, so the Digits will be incremented and the loop will create the following 8-bit slices DQ[32:39],DQ[40:47],DQ[48:55] and DQ[56:63] DQ[31:0:8] The SLICE_COUNT is:8 tells PartBuilder to slice the DQ pin Match by 8 each pass through the REPEAT operation. 31 is greater than 0, so the Digits will be decremented and the loop will create the following 8-bit slices DQ[31:24],DQ[23:16],DQ[15:8] and DQ[7:0] DQS_P[4:7:1] The SLICE_COUNT is:1 and tells PartBuilder to slice the DQS_P pin Match by 1 each pass through the REPEAT operation. 4 is less than 7, so the Digits will be incremented and the loop creates the following one bit slices: DQS_P4, DQS_P5, DQS_P6, DQS_P7 DQS_P[3:0:1] The SLICE_COUNT is:1 and tells PartBuilder to slice the DQS_P pin Match by 1 each pass through the REPEAT operation. 3 is greater than 0, so the digits will be decremented and the loop creates the following one bit slices: DQS_P3, DQS_P2, DQS_P1, DQS_P0 Note that the BALANCE_SYMBOL_SIDES statements do not have recognizeable bus indicies so they are repeated with no modification each pass through the REPEAT LOOP |
There are some limitations to the simpler syntax... the MSB:LSB:SLICE_COUNT will only be sliced in one direction... MSB->LSB or LSB->MSB
With that in mind, the results of the BUS INC_DEC Operator shown below cannot be reproduced with the newer syntax, because the SLICES below are entered MSB down to LSB but the slices increment from 7:0->15:8→23:16->31:24
LEGACY REPEAT_LOOP Example with BUS INC_DEC Operators
BUS INC_DEC Operators
BUS_NAME[SLICE_IDX!(INC|DEC)_COUNT]
The BUS_SLICE is used to create smaller slices of a larger bus. The SLICE IDX is a ':' separated range that provides the First and Last digits of the first slice you want to create
The COUNT appended to the INC|DEC operator is added to both elements to create the next slice at the end of each iteration of the REPEAT Loop
BUS_NAME[IDX:(INC|DEC)_COUNT]
The BUS_NAME is used to create one element for a signal in a control bus. The IDX is a single number and it is the starting element of the control bus you are slicing
The COUNT appended to the INC|DEC operator is added to the IDX select the next bus_element at the end of each iteration of the REPEAT Loop
REPEAT_LOOP Example with BUS INC_DEC Operators
repeat loop | after expansion | notes |
---|---|---|
DDR_DQ= | DDR_DQ= | Modern DDR DRAM interfaces typically have a differential strobe associated with 4,8 or 16 bit slices of a data bus In this example the first strobe is: DQS0 for 8 bit data slice DQ[7:0] The next strobe is DQS1 for 8 bit data slice DQ[15:8] The next strobe is DQS2 for 8 bit data slice DQ[23:16] The next strobe is DQS3 for 8 bit data slice DQ[31:24] Note that the `REPEAT loop was located inside the DDR_DQ= SYMBOL_NAME_DEFINITION |
REPLICATE LOOPS:
The REPLICATE LOOP was released in v2.9.10 of PartBuilder to make it easier to define one complete symbol and then wrap a REPLICATE directive around it to create other symbols based off the first one. It saves the user the trouble of having to create a loop variable like A and then substitute the `A:: into the pin_matches. It gives the user an easy way to replicate symbols (or any block of SDL) without having to think too much like a programmer
`REPLICATE SUBSTITUTION_DEFINITION (SEPARATOR [SUB_DEF]...SEPARATOR [SUB_DEF])
SDL_STATEMENTS with a common match
`END_REPEAT
SUBSTITUTION_DEFINITIONS
The user provides the SUBSTITUTION_DEFINITION (SUB_DEF) to tell partBuilder what to change within in the SDL wrapped by the `REPLICATE directive each time through the REPLICATE loop. Multiple SUB_DEFS can be provided in the same `REPLICATE statement... they are separated by a space, semicolon or colon. A SUB_DEF is created with a
match_string=>replace_list
The replace_list is a comma separated list of replacement strings.
The Replicate Loop will be run once for each of the strings in the replace_list
If the SUB_DEF is P0_=>P0_,P1_,P2_,P3_ the replicate Loop will be executed 4 times, once for P0_, P1_,P2_and P3_
The replace_list can also be provided using range operators so that P0=>P(0..3)_ gets expanded to P0=>P0_,P1_,P2_,P3_
If multiple SUB_DEFS are provided, each one must have the same number of items in their replace_list
`REPLICATE Expansion Example
REPLICATE loop | after expansion | Notes |
---|---|---|
`REPLICATE P0_=>P0_,P1_,P2_,P3_ P0_SYMBOL= LEFT:dpair=>P0_RXP #(2 pins) RIGHT:dpair=>P0_TXP #(2 pins) !BALANCE_SYM_SIDES+2# RIGHT=>P0_RXD[7:0] #(8 pins) LEFT=>P0_TXD[7:0] #(8 pins) !BALANCE_SYM_SIDES+1# RIGHT=>P0_COL #(1 pins) RIGHT=>P0_CRS #(1 pins) ; `END_REPLICATE | P0_SYMBOL= LEFT:dpair=>P0_RXP #(2 pins) RIGHT:dpair=>P0_TXP #(2 pins) !BALANCE_SYM_SIDES+2# RIGHT=>P0_RXD[7:0] #(8 pins) LEFT=>P0_TXD[7:0] #(8 pins) !BALANCE_SYM_SIDES+1# RIGHT=>P0_COL #(1 pins) RIGHT=>P0_CRS #(1 pins) ; P1_SYMBOL= LEFT:dpair=>P1_RXP #(2 pins) RIGHT:dpair=>P1_TXP #(2 pins) !BALANCE_SYM_SIDES+2# RIGHT=>P1_RXD[7:0] #(8 pins) LEFT=>P1_TXD[7:0] #(8 pins) !BALANCE_SYM_SIDES+1# RIGHT=>P1_COL #(1 pins) RIGHT=>P1_CRS #(1 pins) ; P2_SYMBOL= LEFT:dpair=>P2_RXP #(2 pins) RIGHT:dpair=>P2_TXP #(2 pins) !BALANCE_SYM_SIDES+2# RIGHT=>P2_RXD[7:0] #(8 pins) LEFT=>P2_TXD[7:0] #(8 pins) !BALANCE_SYM_SIDES+1# RIGHT=>P2_COL #(1 pins) RIGHT=>P2_CRS #(1 pins) ; P3_SYMBOL= LEFT:dpair=>P3_RXP #(2 pins) RIGHT:dpair=>P3_TXP #(2 pins) !BALANCE_SYM_SIDES+2# RIGHT=>P3_RXD[7:0] #(8 pins) LEFT=>P3_TXD[7:0] #(8 pins) !BALANCE_SYM_SIDES+1# RIGHT=>P3_COL #(1 pins) RIGHT=>P3_CRS #(1 pins) ; | the `REPLICATE P0_=>P0_,P1_,P2_,P3_ directive tells partBuilder to make 4 copies of the symbol. and as it makes the copies, it will substitute any occurrence of P0_ for P0_ (on the first pass, so it doesn't really change) then P1_ for P0_ P2_ for P0_ and finally P3_ for P0_ The `REPLICATE loop eliminates the need to do the variable substitution step usually required for a list_based or iterative loop. Instead, you can create the PORT_P0 symbol, tweak it until you like it, and then wrap it with the `REPLICATE/`END_REPLICATE command. PartBuilder will then create 4 identical symbols for P0_SYMBOL, P1_SYMBOL, P2_SYMBOL and P3_SYMBOL If you had an 8 port device, you would just change the SUB_DEF to P0_=>P(0..7)_ and PartBuilder will expand the indices and create the 8 identical symbols. |
`REPLICATE _A=>_A,_C,_E _B=>_B,_D,_F SYM_A_B= LEFT:dpair=>SIG_A_P RIGHT:bubble=>SIG_B ; `END_REPLICATE | SYM_A_B= LEFT:dpair=>SIG_A_P RIGHT:bubble=>SIG_B ; SYM_C_D= LEFT:dpair=>SIG_C_P RIGHT:bubble=>SIG_D ; SYM_E_F LEFT:dpair=>SIG_E_P RIGHT:bubble=>SIG_F ; | Here we have multiple SUB_DEFS with 3 items each in the replace_list _A=>_A,_C,_E and _B=>_B,_D,_F so the `REPLICATE loop will attempt to perform 2 substitutions on each line surrounded by the `REPLICATE any occurrence of _A will be replaced by _A, then _C and _E any occurrence of _B will be replaced by _B then _D and _F Notice that the on the Lines containing SYM_A_B=, both substitutions are performed, resulting in: SYM_A_B=, SYM_C_D= and SYM_E_F= |
ITERATVE_LOOPS:
These loops are very similar to iterative loops most commonly encountered in programming languages like C and Perl.
With the advent of the other loop structures, this one has become less used for building symbols, but can still be used to perform some
simple substitutions to avoid having to input many similar lines of MATCH_STATEMENTS
`FOR (LOOP_VAR=START_VAL; LOOP_VAR COMP_OPERATOR END_VAL; LOOP_VAR INC_DEC_OPERATOR)
SDL_STATEMENTS (some with `VARNAME:: for substitution )
`END_FOR (or `ENDFOR)
The LOOP_VAR name follows the same rules as the other LOOP_TYPES, It must to start with a letter from A-Z. There is no restriction on how long the LOOP_VAR name is.
The COMP_OPERATOR can be one of ==, >, <, >=, or <=
The INC_DEC_OPERATOR can be ++, --, +=n, -=n
ITERATIVE_LOOP_EXAMPLE:
Iterative Loop | Expanded | Notes |
---|---|---|
DIFF_PAIR_SYMBOL= | DIFF_PAIR_SYMBOL= | Before PartBuilder added the dpair Modifier to the PIN_MATCH_STATEMENT Iterative loops were very useful to add a bus of diff pairs to a symbol. The equivalent of this loop using a dpair modifier in the SDL (without any need for the loop) would be DIFF_PAIR_SYMBOL= right:dpair=>dp_o_sig[0:3]_p left:dpair=>dp_i_sig[0:3]_p ; The iterative loop still provides value if a part had some oddly named diff_pairs where PartBuilder cannot automatically detect the mates using its exhaustive diff_pair detection algorithm. |
DDR_DQ_ITER= | DDR_DQ_ITER= | This iterative loop along with the variable assignments, performs the same bus slicing operation shown in the REPEAT_LOOP example above. The cumbersome math was the reason PartBuilder implemented the REPEAT_LOOP to make it easier to break apart busses. |