Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 2 Next »

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 VariableExpanded 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 SDLexpanded 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:

LOOPexpanded 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:

LoopExpanded toNotes

`For SNAME,RST_NUM IN (A,2,B,4)
SYM_`SNAME::=
right:bubble=>reset`RST_NUM::_n
;
`END_FOR

`For SNAME,RST_NUM IN (A,2,B,4)

SYM_A=
right:bubble=>reset2_n
;
SYM_B=
right:bubble=>reset4_n
;


Part Builder pulls 2 elements at a time out of the LOOP_VAR_LIST to populate

LOOP_VARS SNAME and RST_NUM

`For OB,EB IN (1..2,7..8)
IO_BANKS_`OB::_`EB::=
left=>IO_*_`OB::
right=>IO_*_`EB::
;
`END_FOR

IO_BANKS_1_2=
left=>IO_*_1
right=>IO_*_2
;
IO_BANKS_7_8=
left=>IO_*_7
right=>IO_*_8
;

PartBuilder expands the LIST_OF_VALUES to 1,2,7,8

it assigns 1,2 to OB and EB and then copies the lines

`For OB,EB IN (1..2,7..8,9)
IO_BANKS_`OB::_`EB::=
left=>IO_*_`OB::
right=>IO_*_`EB::
;
`END_FOR

IO_BANKS_1_2=
left=>IO_*_1
right=>IO_*_2
;
IO_BANKS_7_8=
left=>IO_*_7
right=>IO_*_8
;
IO_BANKS_9_!UNDEF=
left=>IO_*_9
right=>IO_*_!UNDEF
;

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 loopafter expansionnotes

DDR_DQ=
`REPEAT 4
right=>DQ[7:0!INC_8]
right=>spacer
right:dpair=>DQS_P[0!INC_1]
`END_REPEAT
;

DDR_DQ=
right=>DQ[7:0]
right=>spacer
right:dpair=>DQS_P0
right=>DQ[15:8]
right=>spacer
right:dpair=>DQS_P1
right=>DQ[23:16]
right=>spacer
right:dpair=>DQS_P2
right=>DQ[31:24]
right=>spacer
right:dpair=>DQS_P3
;

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 LoopExpandedNotes

DIFF_PAIR_SYMBOL=
`FOR (i=0;i<=3;i++)
right=>dp_o_sig_p`i::
right=>dp_o_sig_n`i::
left=>dp_i_sig_p`i::
left=>dp_i_sig_n`i::
!BSS+1
`END_FOR
;

DIFF_PAIR_SYMBOL=
right=>dp_o_sig_p0
right=>dp_o_sig_n0
left=>dp_i_sig_p0
left=>dp_i_sig_n0
!BSS+1
right=>dp_o_sig_p1
right=>dp_o_sig_n1
left=>dp_i_sig_p1
left=>dp_i_sig_n1
!BSS+1
right=>dp_o_sig_p2
right=>dp_o_sig_n2
left=>dp_i_sig_p2
left=>dp_i_sig_n2
!BSS+1
right=>dp_o_sig_p3
right=>dp_o_sig_n3
left=>dp_i_sig_p3
left=>dp_i_sig_n3
!BSS+1
;

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=
`FOR (i=0;i<=3;i++)
`LET j=`i::*8+7
`LET k=`i::*8
right=>DQ[`j:::`k::]
right=>spacer
right=>DQS_P`i::
right=>DQS_N`i::
right=>spacer
`END_FOR
;

DDR_DQ_ITER=
right=>DQ[7:0]
right=>spacer
right=>DQS_P0
right=>DQS_N0
right=>spacer
right=>DQ[15:8]
right=>spacer
right=>DQS_P1
right=>DQS_N1
right=>spacer
right=>DQ[23:16]
right=>spacer
right=>DQS_P2
right=>DQS_N2
right=>spacer
right=>DQ[31:24]
right=>spacer
right=>DQS_P3
right=>DQS_N3
right=>spacer
;

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.




  • No labels

0 Comments

You are not logged in. Any changes you make will be marked as anonymous. You may want to Log In if you already have an account.