The Structure and Syntax of the CadEnhance Symbol Description Language (SDL) is described here
Symbol Description Language Structure
The Symbol Description Language (SDL) was designed to be uber-efficient at describing schematic symbol construction, while still being simple to understand and easy to enter.
SDL KEY_WORDS and Constructs are Not case-sensitive.
An SDL File is a collection of ordered SYMBOL_NAME_DEFINITIONS which enclose MATCH_STATEMENTS and SPACER_COMMANDS.
The number of symbols you create is generally greater than or equal to the number of SYMBOL_NAME_DEFINITIONS.
Moving pins from one symbol to another is generally a cut and paste operation to move MATCH_STATEMENTS in between a different SYMBOL_NAME_DEFINTION.
To add another symbol, you just add another SYMBOL_NAME_DEFINTION with a new name and add or move your MATCH_STATEMENTS between the start and end.
SYMBOL_NAME_DEFINITIONS, MATCH_STATEMENTS and SPACER_COMMANDS can also appear between the start and end of LOOP_DIRECTIVES
SDL also supports Simple VARIABLE_SUBSTITUTION commands.
SYMBOL_NAME_DEFINITION
A SYMBOL_NAME_DEFINITION is used to instruct partBuilder to start placing matching pins into a named symbol.
It has 2 parts, a beginning:
SymbolName=
and an end which is just the terminating semicolon.
';'
The SymbolName is the actual name you want to use for the symbol and it should not contain spaces
in the simple sample file, the start of the first SYMBOL_NAME_DEFINITION was
DRAM_ACTL_PINS=
That was followed by several MATCH_STATEMENTS
and was terminated by the
';'
character
It instructed partBuilder to create a Symbol named DRAM_ACTL_PINS as a place to add the pins matching all the MATCH_STATEMENTS that follow until the SYMBOL_NAME_DEFINITION is closed.
A SYMBOL_NAME_STATEMENT may often create more than one symbol if the number of pins that the MATCH_STATEMENTS assign to that symbol are greater than the current Configuration Setting of the SYMBOL_PIN_LIMIT. For instance, a GROUND symbol definition often contains only one MATCH_STATEMENT to assign any pin matching GND to that symbol. If the part has 400 Ground pins and the SYMBOL_PIN_LIMIT is set to 100, it will create 4 SYMBOLS and create a new name for each of the extra symbols it creates (GROUND, GROUND_1, GROUND_2 and GROUND_3)
MATCH_STATEMENTS
MATCH_STATEMENTS are what tell partBuilder which pins to place within the current symbol, what side to place them on and any other modifier to enable creating special graphics or properites for the pins that match.
MATCH_STATEMENTS are built out of LOCATOR, MODIFIER and PIN_MATCH elements
The simplest MATCH_STATEMENT only contains a LOCATOR and a PIN_MATCH, and is entered as
LOCATOR=>PIN_MATCH
The equal-Arrow "=>" separates the PIN_MATCH from the list of LOCATORS and MODIFIERS
MODIFIERS are added on the left hand side of the '=>' either before or after the LOCATOR.
For clarity and easier cut and paste in Excel, our examples will show the LOCATOR first.
MODIFIERS and LOCATORS are separated by the colon character ':' as follows;
LOCATOR:MODIFIER1:MODIFIER2:...MODIFIERn=>PIN_MATCH
There is no restriction on the number of valid MODIFIERS that can be included in a MATCH_STATEMENT.
It should be obvious that only one LOCATOR is used per MATCH_STATEMENT
Some simple MATCH_STATEMENTS are provided in the table below to help get a feel for what they look like as you read more about the structure of them.
Examples of Simple MATCH_STATEMENTS.
MATCH_STATEMENT | Simple Operation* | Notes |
---|---|---|
left=>a[15:0] | puts bus pins a15...a0 on the left hand side of the symbol starting from the current position on the left hand side | |
right:dpair=>clk_p | puts diff_pair mates clk_p and clk_n** consceutively on the right hand side of the symbol using the currently configured defaults for diff pair spacing | **presumably clk_n |
top:is_pin=>1..17 | places pins 1 to pin 17 on the top of the symbol | |
bot:bubble=>reset_n | places pin matching reset_n on the bottom and puts an inversion bubble between the pin and the symbol |
LOCATOR Elements
The purpose of the LOCATOR element is to tell partBuilder what side of the symbol to place the matching pins on.
Part builder creates one list for each side of the symbol, and as it sees a locator, it pushes the matching pins
Valid Locators are mostly obvious, and are explained in the following table
LOCATOR | Effect |
---|---|
LEFT | place matching pins on the Left Hand Side of the symbol |
RIGHT | place matching pins on the Right Hand Side of the symbol |
BOTH | distribute the matching pins equally on the Left and Right Hand sides of the symbol |
TOP | place matching pins on the top side of the symbol |
BOT or BOTTOM | place matching pins on the bottom side of the symbol |
AUTO | place matching INPUT pins on the Left Hand Side of the symbol place matching OUTPUT or INOUT pins on the Right Hand Side of the symbol distribute all other pin_types equally on the Left and Right Hand Sides of the symbol |
MODIFIER Elements
Valid Modifiers are explained in the following table. Modifiers may be further broken down by partBuilder to impart extra information as shown
MODIFIER | Effect | Special Notes |
---|---|---|
DOT or BUBBLE | Instructs PartBuilder to Add an Inversion Bubble in the proper place for any matching pin | |
CLK or CLOCK | Instructs PartBuilder to Add a clock indicator like '>' in the proper place for any matching pin | |
SHORT | Instructs PartBuilder to create a SHORT Pin | works for Eagle and Orcad Symbols |
ZERO | Instructs PartBuilder ORCAD zero Length Pins | |
HIDDEN | Instructs partBuilder to create a Hidden Pin. | This currently only works with AllegroHDL and is not reccomended |
VECTOR or VECTORED | Instructs PartBuilder to create one symbol pin to represent 2 or more pins. | This currently only works with AllegroHDL and can be used to significantly reduce the size of power symbols |
IS_PIN | Instructs PartBuilder that the PIN_MATCH should be applied to the Pin Number instead of the Pin Name | This makes it very easy to build parts where you layout the pins like they appear on the physical symbol. Also very efficient when building connectors organized by row or column |
DPAIR DPAIR_{OPT_SUFFIX} | Instructs PartBuilder to place both the matching diff_pair pin AND its mate pin in sequence | The DPAIR Modifier can be appended with a suffix to impart more information to override the default diff_pair spacing that is configured for partBuilder. |
PSG_{swapGroupName} | Instructs PartBuilder that the matching pins are a member of a PIN_SWAP_GROUP. PartBuilder maintains a list of all the PIN_SWAP group names and properly annotates the matching pins so they can be included in the PIN_SWAP in the PCB side. | The name of the pinSwapGroup must be provided in the suffix to the PSG_ modifier. This is currentyl supported for AllegroHDL |
PIN_MATCH Elements
The PIN_MATCH Element is the string that PartBuilder uses to test all pins in the extracted pinData for a match.
PIN_MATCHES may be entered as a simple string or with a wildcard.
PartBuilder treats all the PIN_MATCHES it extracts from the SDL as a Regular Expression. It actually converts the wildcard '*' internally to the '.*' used in Regular Expressions.
They may also be entered as a valid Perl Regular Expression.
PartBuilder treats all the PIN_MATCHES it extracts from the SDL as a Regular Expression. It actually converts the wildcard '*' internally to the '.*' used in Regular Expressions.
A Regular Expression is a pattern describing a certain amount of Text. The Regular Expression can be very general or very restrictive.
In the simplest context, PartBuilder uses a regular expressions to determine if a Pin contains the PIN_MATCH pattern.
If the PIN_MATCH is entered as "DQ", PartBuilder will match any pin that Contains DQ anywhere in the pinname.
Excellent references for Regular Expressions exist on the web like the one at this link.
PartBuilder Bus-Enhanced Regular Expressions.
PartBuilder does some behind the scenes work to change the PIN_MATCH Regular Expressions to enable placing bussed pins seamlessly
Its not truly necessary to understand this detail, but In a normal regular expression, the '[]' characters in the pattern match enclose a list of characters to match against
If you were comparing a list of pins dq7 dq6 dq5 dq4 dq3 dq2 dq1 and dq0 using the regular Expression 'dq[0:7]' , the pattern would only match dq0 and dq7 (and funny enough dq:).
You could get more useful results with 'dq[0-7]' (because 0-7 inside the square brackets says to match any character between 0 and 7) but unfortunately that would not enforce the order of the pins.
In order to work around this, when PartBuilder sees the 'DQ[0:7]' in a PIN_MATCH it expands it to 8 seperate PIN_MATCHES DQ0, DQ1, DQ2... DQ7** which are then used as pattern matches.
It also maintains the order of the bits so that they will be added to the symbol in LSB→MSB order if you enter busName[0:7] or MSB→LSB order if you enter busName[7:0]. As described in the table below, it also appends whats called a zero-width-lookahead assertion at the end fo each to insure that DQ18 doesn't match DQ1 but it would still allow a match of dq1_p
(**it also appends a zero-width-lookahead assertion to each match to ensure that no other digits are following the ones we want so that DQ18 doesn't match DQ1)
Examples of Useful PIN_MATCH Regular Expressions
PIN_MATCH | Effect | NOTES |
---|---|---|
DQ | Will match any pin that contains DQ | |
DQS | Will match any pin that contains DQS | |
^DQS0 | Will match any pin that STARTS with DQS0 | the caret '^' enforces the start of word boundary |
DQ[7:0] | PartBuilder will expand this to 8 individual matches DQ7, DQ6, DQ5... DQ0** it will match and maintain the order of any pins that contain any of those patterns DQ7,DRAM_DQ6_BUS,DQ5_F would all match DQA7, DQ06... would not match DQ3_P and DQ1_N would match but DQ31_P and DQ18_N would not | In the category of too much information: DQ1 seems like it would match because it contains DQ1, but when partBuilder expands the PIN_MATCH it adds **the zero-width lookahead assertion to assure that any character except another number can match |
^DQ[0:7] | PartBuilder will match any pin that STARTS with DQ0 or DQ1... DQ7 L_DQ0 would not match | |
DQ[0:7]$ | PartBuilder will match any pin that ENDS with DQ0 or DQ1 ... DQ7 DQ0_L would not match since it doesn't end with 0,1,2,3,,4,5,6,or 7 | the dollar Sign '$' enforces the end of word boundary |
^DQ[0:7]$ | PartBuilder will expand to a list of matches ^DQ0$, ^DQ1$, ^DQ2$... ^DQ7$ and will only match DQ0,DQ1,DQ2,DQ3...DQ7... Would not match L_DQ0, DQ00, DQ01 ..... | The caret '^' says it must start with the D and the $ says it must end with the digit at the end |
IO_.*?_35 or IO_*_35 | PartBuilder will match any pin that contains IO_, and _35 it would match: IO__35, IO_A_35, IO1_PIN1_35, IO_THIS_IS_A_LONG_NAME_35 it would not match IO_A_36, IO_A_37 nor would it match IO35 or IO_35 (since we need 2 underscores) | the '.*?' (which could also be be entered as '*') looks for any number of any of characters partBuilder converts the '*' to a '.*?' to make it easier to enter wildcards for those not familiar with Regular Expressions. The ? is special and necessary because it makes the match stop if it sees the _35 after it. This particular regular Expression is very powerful when building parts with Pins that have similar names grouped into numeric banks like FPGAs and CPLDS. |
IO\d+_\d+ | Would match: IO0_5, IO7324_8910 Would not match: IO0A_5 because it is not looking for the 'A' or IO_5 because we need a digit after the IO | the \d+ finds 1 or more consecutive digits in a row. if we used "IO\d*_\d+", it would match IO_5 because \d* says find 0 or more consecutive digits. |
Handling Pins that Match multiple PIN_MATCHES
It takes PartBuilder 2 passes to place matching pins into the proper symbols. It first goes through every pin_match and attaches a list of every MATCH_STATEMENT that each pin matches to the pin. It then makes a second pass, and chooses the MATCH_STATEMENT with the longest PIN_MATCH string to pick the proper MATCH_STATEMENT for that pin.
Lets provide a simple example:
We have a fictional part with 100 pins named GND, 8 pins named SGND and 2 pins named GTH_RX_SGND and 2 named GTH_TX_SGND
We have the following 2 SYMBOL_NAME_DEFINTIONS in the SDL File
GND_SYM= LEFT=>SGND LEFT=>SPACER[1:0] BOTH=>GND ; |
|
GTH_BLOCK= LEFT:dpair=>GTH_RX[7:0]_P RIGHT:dpair=>GTH_RX[7:0]_N !BSS+2 LEFT=>GTH_RX_SGND RIGHT=>GTH_TX_SGND ; |
Because of this 2 pass approach, the user does not need to concern themselves with what order a MATCH_STATEMENT is placed or what SYMBOL_DEFINTION it is placed in.
They do need to be aware that the 2 pass approach is necessary and that they need to assign more specific PIN_MATCHES to seperate Pins like the example that have common strings in them
SPACER_COMMANDS
SPACER_COMMANDS allow the user to easily control spacing between groups of pins
There are 3 types:
- SINGLE_SPACERS:
- LOCATOR=>SPACER,
- MULTIPLE_SPACERS:
- LOCATOR=>SPACER[5:0]
- and SPACER_DIRECTIVES:
- !BALANCE_SYM_SIDES+n (or !BSS+n)
The first 2 resemble the MATCH_STATEMENTS pretty closely and use the LEFT, RIGHT, TOP and BOTTOM LOCATOR commands.
The !BALANCE_SYM_SIDES directive is used to start a new section in the same symbol without having to keep track of the number of pins you have been adding on the sides of your symbols.
For instance if you have 3 pins on the left and 8 pins on the right, The BALANCE_SYM_SIDES+2 directive would add 5 spacer pins on the left to Balance it with the right side, and then add 2 more spacers on each side.
LOOP_DIRECTIVES AND VARIABLE SUBSTITUTION
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.
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, it is making a copy of the lines between
the `FOR and `END_FOR and substituting in 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 loIO_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. |
ITERATVE_LOOP:
`FOR (LOOP_VAR=START_VAL; LOOP_VAR COMP_OPERATOR END_VAL; LOOPVAR INC_DEC_OPERATOR)
SDL_STATEMENTS (some with `VARNAME:: for substitution )
`END_FOR (or `ENDFOR)
The first is 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 useful for building symbols, but can still be used to perform some
simple substitutions to avoid having to add large
`FOR LOOP_VAR IN (LIST_OF_VALUES)
SDL_STATEMENTS (some with `VARNAME:: for LOOP_VARIABLE substitution )
`END_FOR (or `ENDFOR)
`FOR LOOP_VAR_LIST IN (LIST_OF_VALUES)
SDL_STATEMENTS (some with `VARNAME:: for substitution )
`END_FOR (or `ENDFOR)
`REPEAT n LOOP
SDL_STATEMENTS (some with BUSSED INC_DEC operators)
`END_REPEAT
Add Comment