SDL LOOP_DIRECTIVES and VARIABLE SUBSTITUTION 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
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.
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 4 main types of LOOP_DIRECTIVES
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
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.
`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 seperated 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 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,12,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_*_12 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. It will be expanded to: 1,2,3,4,12,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 |
`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 |
REPEAT LOOPS:
REPEAT_LOOPS provide an convienent 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 LOOP
SDL_STATEMENTS (some with BUSSED INC_DEC operators)
`END_REPEAT
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 ':' seperated 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 |
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 SIG_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. |
0 Comments