• Skip to main content
  • Skip to search
  • Skip to footer
Cadence Home
  • This search text may be transcribed, used, stored, or accessed by our third-party service providers per our Cookie Policy and Privacy Policy.

  1. Community Forums
  2. Custom IC SKILL
  3. How to filter the cell list in a Create Instance Form in...

Stats

  • Locked Locked
  • Replies 3
  • Subscribers 143
  • Views 16361
  • Members are here 0
This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

How to filter the cell list in a Create Instance Form in schematic and layout

Sheppie
Sheppie over 5 years ago

Hi,

We're starting on a new project, with a (for us) new process. This process (TSMC N22 Low Power) uses several xVT transistor types: EULVT ULVT LVT SVT HVT UHVT and EUHVT where:

  • E = extreme
  • U = ultra
  • L = low
  • S = standard
  • H = high
  • VT = threshold voltage

We have chosen to only allow ULVT/SVT/UHVT, all others not allowed. In order to limit the chance of using the wrong type of transistors, it is possible to check the entire design at tape-out for devices used, but then it is already too late. What I would like to have: when instantiating a cell, the options in the "Create Instance Form" (schCreateInstForm() and leCreateInstForm()) dialog box should only show the ones valid for every library.

A possible solution would be to hack the PDK/Technology library we got from TSMC, but, in my opinion, that is a definite no-go. I think you should never touch anything you get, if modifications are needed, than just do that on top of what you get, not by modifying the original.Reasons not to do this:

  • The PDK we use is installed on a "read-only" mounted network file server, so I am unable to modify anything of the library. Of course, I could ask the team that installs the PDK to do the modifications, but that is not under my control.
  • As a general rule, we do not modify original packages/PDK's: if we would do this, and we run into issues, it would be difficult to found the source. Is the problem in the package/PDK we got, or in the modifications we made? Therefor, no modifications to anything original.
  • If an update of the PDK is made available by TSMC, we have to redo all the steps, thus ensuring we have to keep doing the same thing over and over again.
  • Since we're not going to be the only team using this process, it would block other groups from making a different choice: they might choose to use other types of transistors.

Therefor, what I would like to do is creating some piece of SKILL code that gets triggered when the "Create Instance Form" dialog box is opened. This has to be for both schematic and layout.

This is what I have tried:

What if I change the bindkey "<Key>i" from schHiCreateInst() to my own SCLSchCreateInstForm() and add some extra code to this new procedure. So this is what I did:

procedure( SCLSchCreateInstForm()
    let( ()
        hiRegTimer( "schCreateInstForm->libraryName->_modifyCallback = \"SCLSchCreateInstFormLibraryNameCB()\"" 1)
        schHiCreateInst()
    ) ;;; end of let
) ;;; end of procedure SCLSchCreateInstForm
hiSetBindKey( "Schematics" "<Key>i" "SCLSchCreateInstForm()" )
procedure( SCLSchCreateInstFormLibraryNameCB()     let( ()         printf("%L\n" schCreateInstForm->cellName->choices )     ) ;;; end of let ) ;;; end of procedure SCLSchCreateInstFormLibraryNameCB

Load this code at start-up of Virtuoso.

Then, whenever you press the "i" key in schematic, it will execute the custom procedure, and from within this procedure the original procedure. With the timer I specify to overwrite the _modifyCallback property of the libraryName form field to execute yet another custom procedure. In the end, this last procedure is where the code will reside to purge illegal devices/cells from the list of devices/cells.

As a test (to verify that the _modifyCallback has been modified and the correct procedure has been executed) I simply print the list of choices of the cellName form field. This all works. However...

... every time the library changes, the custom procedure is executed and it prints the list of devices/cells. AND it returns 2 errors:

("cell1" "cell2" "cell3" "cell4" "cell5" )
*Error* eval: not a function - 'libraryName
*Error* car: Can't take car of atom  - ERROR

Since I don't use the 'libraryName symbol anywhere, I don't understand: why 2 errors?

I have an idea where this 'libraryName comes from: the _callback property of the libraryName form field has this value:

schCreateInstForm->libraryName->_callback
"schiCreateInstLibNameCB(schCreateInstForm 'libraryName)"

This is the only place where I could find 'libraryName.

What may cause this error? Can it be avoided?

Then I decided just to ignore the errors, and test my assumption: just change the choices property of the cellName form field and I'm done. This is what I did:

procedure( SCLSchCreateInstFormLibraryNameCB()
    let( (    ( newList nil ) ( listToRemove nil ) )
        listToRemove = list("cell1" "cell2")
        printf("1:\n%L\n" schCreateInstForm->cellName->choices )
        newList = SCLRemoveElementWithValueFromList( listToRemove schCreateInstForm->cellName->choices )
        printf("2:\n%L\n" newList )
        schCreateInstForm->cellName->choices = newList
    ) ;;; end of let
) ;;; end of procedure SCLSchCreateInstFormLibraryNameCB

The code of procedure SCLRemoveElementWithValueFromList():

procedure( SCLRemoveElementWithValueFromList( valueList theList "ll" )
    let( (    ( outputList nil ) )
        foreach( element theList
            unless( member( element valueList )
                outputList = append( outputList list( element ) )
            ) ;;; end of unless
        ) ;;; end of foreach
        outputList
    ) ;;; end of let
) ;;; end of procedure SCLRemoveElementWithValueFromList

This did not work (this is reported in the CIW):

1:
("cell1" "cell2" "cell3" "cell4" "cell5" )
2:
("cell3" "cell4" "cell5" )
*WARNING* putCustomProperty, 'choices' is a read-only property
*Error* eval: not a function - 'libraryName
*Error* car: Can't take car of atom  - ERROR

As it reports, the property choices is read-only...

This looks like a permanent road-block.

Is there a way to get around this? Or has anybody else implemented something similar, without modifying/touching the PDK?

With kind regards,

Sjoerd

ps:
Due to the reasons mentioned, solutions like creating a "Hidden" category in the PDK library will not be possible.

  • Cancel
  • AurelBuche
    AurelBuche over 5 years ago

    Hi,

    Personally I would recreate the form myself then replace the banner menu (using hiGetBannerMenus, hiGetMenuItems...) and the 'I' shortcut to display it

    The form is quite simple so it should be easy to create using ddHiCreateLibraryComboField, ddHiCreateCellComboField and ddHiCreateViewComboField
    (just remember to instantiate the form before linking the fields: hiInstantiateForm, ddHiLinkFields)

    For filtering your instances, you could improve clarity and efficiency:

    (defun SCLRemoveElementWithValueFromList (toRemove full "ll") (setof elt full (not (member elt toRemove))))

    Cheers,

    Aurel

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • Andrew Beckett
    Andrew Beckett over 5 years ago in reply to AurelBuche

    The way I'd do this is not to prevent the instantiation (which is a bit messy) but to check it at check-and-save time. You can register a custom check which will look for such components, and then flag them as a problem. I wouldn't hack the create instance form - it's just asking for things to break at some point (even assuming you can make it work). I didn't try to debug it, partly because I don't have time before vacation, but mostly because I wouldn't recommend to do it that way...

    I have some code which (sort-of) did this - although it checked against presence in a specific category in a library, but you could easily adapt that. Since writing that code (many years ago), there's a new cleaner way of registering schematic checks, so I'll start by giving some example code which shows that, and then below I'll show the older code which does other checks. I'm sure you can adapt it to suit your specific requirements.

    /* abExampleSchematicCheckNew.ils
    
    Author     A.D.Beckett
    Group      Custom IC (UK), Cadence Design Systems Ltd.
    Language   SKILL
    Date       Oct 28, 2011 
    Modified   
    By         
    
    This is a reimplementation of some of the checks in abExampleSchematicCheck.ils
    but taking advantage of the new interface in IC615 to register checks with
    the system. As a result it is much simpler, and does not have to take care
    of creating marker objects itself; also gives the user the ability to override
    the check, or change the severity if needed.
    
    To register, call:
    
    abRegExampleSchematicCheckNew("Your Customer Name")
    
    (with no arguments, it just calls the rule group "Customer")
    
    ***************************************************
    
    SCCS Info: @(#) abExampleSchematicCheckNew.ils 10/28/11.10:55:00 1.1
    
    */
    
    ;------------------------------------------------------------------------
    ; The let is to create a lexical scope, so that there can be
    ; private functions which are used for some of the implementation
    ;------------------------------------------------------------------------
    let(()
    
        /***************************************************************
        *                                                              *
        *  abRegExampleSchematicCheckNew([?customerName "Customer"])   *
        *                                                              *
        * PUBLIC GLOBAL function used to register the new check group  *
        * and any specific check - in this case an example of a naming *
        *                         convention.                          *
        *                                                              *
        ***************************************************************/
        defglobalfun(abRegExampleSchematicCheckNew (@optional (customerName "Customer"))
            ;----------------------------------------------------------------
            ; This registers a new tab on Check->Rules Setup
            ;----------------------------------------------------------------
            schRegisterCheckGroup(
                ?name concat(customerName)
                ?description strcat(customerName " checks")
            )
            ;----------------------------------------------------------------
            ; This registers the specific rule and default severity
            ;----------------------------------------------------------------
            schRegisterCheckRule(
                ?title "Naming conventions"
                ?name 'namingConventions
                ?groupName concat(customerName)
                ?severity 'error
                ?checkCB checkNamingConventions
            )
        )
    
        /*********************************************************************
        *                                                                    *
        *               checkNamingConventions(cv ruleObject)                *
        *                                                                    *
        * INTERNAL function used to actually implement the naming convention *
        *                               check.                               *
        *                                                                    *
        *********************************************************************/
        defun(checkNamingConventions (cv ruleObject)
            let((obj label netTable signals sigTable)
                ;------------------------------------------------------------
                ; Check that terminal names are in upper case
                ;------------------------------------------------------------
                foreach(term cv~>terminals
                    unless(term~>name==upperCase(term~>name)
                        ;----------------------------------------------------
                        ; Place the marker on the first pin - no need to
                        ; put it on every pin if there are multiple pins
                        ;----------------------------------------------------
                        obj=car(term~>pins~>fig) || cv
                        schReportCheckFailure(
                            ?object obj
                            ?checkRule ruleObject
                            ?short "Terminals not upper case"
                            ?message
                                sprintf(nil "Terminals must be in upper case: %s" 
                                    term~>name
                                ) 
                        ) 
                    ) ; unless
                ) ; foreach
                ;------------------------------------------------------------
                ; Check for internal nets which have a lower case name
                ;------------------------------------------------------------
                foreach(net cv~>nets
                    ;--------------------------------------------------------
                    ; Only worry about nets which have a label
                    ;--------------------------------------------------------
                    label=car(exists(fig net~>figs fig~>objType=="label"))
                    when(label
                        when(exists(sig net~>signals 
                            ;------------------------------------------------
                            ; Check that the signal is not part of a 
                            ; terminal, and is not in lowercase
                            ;------------------------------------------------
                            !sig~>memTerms && sig~>name!=lowerCase(sig~>name))
                            schReportCheckFailure(
                                ?object label
                                ?checkRule ruleObject
                                ?short "Internal nets not lower case"
                                ?message
                                    sprintf(nil "Internal net names must be in lower case: %s"
                                        net~>name
                                    ) 
                            ) 
                        ) ; when there is a lower internal net name on net
                    ) ; when there's a label
                ) ; foreach
                ;------------------------------------------------------------
                ; Check for any nets which only differ in case
                ;------------------------------------------------------------
                ;------------------------------------------------------------
                ; record all the signals together in a table indexed by
                ; the flattened case. Then use a table to record all
                ; member nets which have a mixed-case problem
                ;------------------------------------------------------------
                sigTable=makeTable('sigTable nil)
                netTable=makeTable('netTable nil)
                foreach(sig cv~>signals
                    sigTable[lowerCase(sig~>name)]=
                        cons(sig sigTable[lowerCase(sig~>name)])
                ) ; foreach
                foreach(tableEntry sigTable
                    signals=sigTable[tableEntry]
                    ;--------------------------------------------------------
                    ; If there was more than one signal with the
                    ; same flattened case, then there's
                    ; a mixed name problem. Record the member nets
                    ; in a table (to avoid duplication)
                    ;--------------------------------------------------------
                    when(cdr(signals)
                        foreach(sig signals
                            foreach(memNet sig~>memNets
                                netTable[car(memNet)]=signals
                            ) ; foreach memNet
                        ) ; foreach sig
                    ) ; when
                ) ; foreach 
                foreach(net netTable
                    ;--------------------------------------------------------
                    ; Find something suitable to put the marker on
                    ;--------------------------------------------------------
                    cond(
                        ;----------------------------------------------------
                        ; Use the pin if there is one
                        ;----------------------------------------------------
                        (net~>term~>pins
                            obj=car(net~>term~>pins~>fig)
                        )
                        ;----------------------------------------------------
                        ; Otherwise use the label
                        ;----------------------------------------------------
                        (obj=car(
                            exists(shape net~>figs 
                                shape~>objType=="label"))
                            t
                        )
                        ;----------------------------------------------------
                        ; Next try a wire
                        ;----------------------------------------------------
                        (obj=car(
                                exists(shape net~>figs
                                    shape~>objType=="line" ||
                                    shape~>objType=="path")
                            )
                            t
                        )
                        ;----------------------------------------------------
                        ; Finally, if nothing else, use the cellView
                        ;----------------------------------------------------
                        (t
                            obj=cv
                        )
                    ) ; cond
                    schReportCheckFailure(
                        ?object obj 
                        ?checkRule ruleObject
                        ?short "Net differing only in case"
                        ?message
                            sprintf(nil 
                                "Net %L cannot differ only in case from others: %L" 
                                net~>name
                                netTable[net]~>name
                            )
                    )
                ) ; foreach
            ) ; let
        ) ; defun checkNamingConventions
    
    )
    

    Here's the second (older) bit of code:

    /* abExampleSchematicCheck.ils
    
    vim:syntax=skill
    
    Author     A.D.Beckett
    Group      Custom IC (UK), Cadence Design Systems Ltd.
    Language   SKILL
    Date       Dec 11, 2006 
    Modified   Jan 19, 2007 
    By         A.D.Beckett
    
    Example of a schematic check. This code uses SKILL++
    semantics, and so should keep the .ils suffix.
    
    To register the check, call:
    
    abRegExampleSchematicCheck()
    
    The check itself can be found in the function
    exampleSchematicCheck() below. It calls some local,
    private functions which keep track of numbers
    of warnings/errors, as well as create markers.
    
    In the code, the warning/error reason is stored
    in a property "CSRWhy" which means that the
    find marker command will see the marker as belonging
    to a tool called "CSR". If you want the tool to be 
    shown as something else (e.g. "mytool"), make the property
    that tool followed by "Why" (e.g. "mytoolWhy"). The
    property is set in local private functions
    placeObjMarker() and placeCellViewMarker(), so the
    code would need changing there.
    
    ***************************************************
    
    SCCS Info: @(#) abExampleSchematicCheck.ils 06/20/07.14:26:30 1.5
    
    */
    
    ;------------------------------------------------------------------------
    ; Define two names which will be the global functions
    ;------------------------------------------------------------------------
    define(abExampleSchematicCheck nil)
    define(abRegExampleSchematicCheck nil)
    define(abExampleSchematicCheckDefinePdkName nil)
    define(abExampleSchematicCheckGetIllegalParams nil)
    
    ;------------------------------------------------------------------------
    ; A lexical scope, to contain counts etc, and the local
    ; functions. This is the mechanism to provide local, private
    ; functions which are not visible from outside.
    ;------------------------------------------------------------------------
    let((newErrs newWarns connCurrent pdkName categCache illegalParamCache)
    
        /***************************************************************
        *                                                              *
        *  placeObjMarker(obj reason @optional (severity "warning"))   *
        *                                                              *
        * Private function to place a marker on an object (e.g. label, *
        *      instance, etc) with the size of the object's bBox       *
        *                                                              *
        ***************************************************************/
    
        defun(placeObjMarker (obj reason @optional (severity "warning"))
            let((marker bBox (minGrid 0.00625))
                bBox=obj~>bBox
                ;------------------------------------------------------------
                ; if bounding box is too small, make it a bit bigger
                ;------------------------------------------------------------
                cond(
                    (xCoord(upperRight(bBox))-xCoord(lowerLeft(bBox)) < minGrid
                        bBox=list(
                            xCoord(lowerLeft(bBox))-minGrid:
                                yCoord(lowerLeft(bBox))
                            xCoord(upperRight(bBox))+minGrid:
                                yCoord(upperRight(bBox))
                        )
                    )
                    (yCoord(upperRight(bBox))-yCoord(lowerLeft(bBox)) < minGrid
                        bBox=list(
                            xCoord(lowerLeft(bBox)):
                                yCoord(lowerLeft(bBox))-minGrid
                            xCoord(upperRight(bBox)):
                                yCoord(upperRight(bBox))+minGrid
                        )
                    )
                )
                marker=dbCreateRect(obj~>cellView list("marker" severity) bBox)
                marker~>CSRWhy=reason
            )
        )
    
        /*****************************************************************
        *                                                                *
        *  placeCellViewMarker(cv reason @optional (severity "warning")) *
        *                                                                *
        *   Private function to place a marker in the lower left of the  *
        *                             cellView                           *
        *                                                                *
        *****************************************************************/
    
        defun(placeCellViewMarker (cv reason @optional (severity "warning"))
            let((marker ll (size 0.25:0.25))
                ll=lowerLeft(cv~>bBox)
                marker=dbCreateRect(cv list("marker" severity)
                    list(ll mapcar('plus ll size))
                )
                marker~>CSRWhy=reason
            )
        )
    
        /***************************************************************
        *                                                              *
        *  placeMarker(objOrCv reason @optional (severity "warning"))  *
        *                                                              *
        * Private function to place a marker and increment the counts  *
        *                                                              *
        ***************************************************************/
    
        defun(placeMarker (objOrCv reason @optional (severity "warning"))
            ;----------------------------------------------------------------
            ; Add on the standard prefix to the reason
            ;----------------------------------------------------------------
            reason=strcat(
                case(severity
                    ("error" "Error: ")
                    ("warning" "Warning: ")
                    (t "")
                )
                reason
            )
            ;----------------------------------------------------------------
            ; Place a marker either on the object, or in the lower left
            ; of the cellView
            ;----------------------------------------------------------------
            if(objOrCv~>objType=="cellView" then
                placeCellViewMarker(objOrCv reason severity)
            else
                placeObjMarker(objOrCv reason severity)
            )
            ;----------------------------------------------------------------
            ; Print the message to the CIW
            ;----------------------------------------------------------------
            printf("%s\n" reason)
            ;----------------------------------------------------------------
            ; Increment the counts
            ;----------------------------------------------------------------
            case(severity
                ("error" ++newErrs)
                ("warning" ++newWarns)
            )
        )
    
        /***************************************************************
        *                                                              *
        *                    resetErrorsAndWarns(cv)                   *
        *                                                              *
        *        Private function to reset all the counts, and         *
        *     also record whether the connectivity was up to date      *
        *                        when we start                         *
        *                                                              *
        ***************************************************************/
    
        defun(resetErrorsAndWarns (cv)
            newErrs=0
            newWarns=0
            connCurrent=dbIsConnCurrent(cv)
        )
    
        /***************************************************************
        *                                                              *
        *                   updateErrorsAndWarns(cv)                   *
        *                                                              *
        *    Tell sch about how many errors and warnings we found,     *
        *   and then set connectivity to be up to date, or outdated,   *
        *   depending on errors added, or if the connectivty was up    *
        *                       to date before.                        *
        *                                                              *
        ***************************************************************/
    
        defun(updateErrorsAndWarns (cv)
            schUpdateUserSRCErrorAndWarn(newErrs newWarns)
            cond(
                ;------------------------------------------------------------
                ; Make sure connectivity is up to date, if it
                ; started off current, and no errors were introduced
                ;------------------------------------------------------------
                (connCurrent && newErrs==0
                    dbSetConnCurrent(cv)
                )
                ;------------------------------------------------------------
                ; Otherwise, if the connectivity appears up to date, and
                ; we're on CDB, make it look out of date by subtracting
                ; 1 second from the lastSchematicExtraction. On OA this
                ; should not be necessary because counters should prevent
                ; the connectivity from appearing current (problem is 
                ; due to 1 second granularity of time stamp).
                ;------------------------------------------------------------
                (dbIsConnCurrent(cv) && dbGetDatabaseType()=="CDBA"
                    dbReplaceProp(cv "lastSchematicExtraction" "time"
                        timeToString(stringToTime(cv~>lastSchematicExtraction)-1)
                    ) ; dbReplaceProp
                ) ; dbIsConnCurrent...  
            ) ; cond
        ) ; defun
    
        /***************************************************************
        *                                                              *
        *   checkComponentsInCategory (cv libName categName severity)  *
        *                                                              *
        *      Private function to check for any components which      *
        *    are in a category of the PDK intended not to be used.     *
        *                                                              *
        ***************************************************************/
    
        defun(checkComponentsInCategory (cv libName categName severity)
            let((catId libId)
                ;------------------------------------------------------------
                ; If the cache has not been populated yet, do so now
                ;------------------------------------------------------------
                when(libName && !categCache
                    libId=ddGetObj(libName)
                    when(libId
                        categCache=makeTable('categCache nil)
                        catId=ddCatOpen(libId categName "r")
                        foreach(catMember catId && ddCatGetCatMembers(catId)
                            when(cadr(catMember)=="cell"
                                categCache[car(catMember)]=t
                            )
                        )
                        when(catId
                            ddCatClose(catId)
                        )
                    )
                )
                ;------------------------------------------------------------
                ; Check for any instances which are from the PDK, and are
                ; in the cache of the disallowed category
                ;------------------------------------------------------------
                when(libName && categCache
                    foreach(inst cv~>instances
                        when(inst~>libName==libName && categCache[inst~>cellName]
                            placeMarker(inst 
                                sprintf(nil "%s is in the %s category of %s" 
                                    inst~>cellName
                                    categName
                                    libName
                                ) ; sprintf
                                severity
                            ) ; placeMarker
                        )
                    )
                ) ; when libName && categCache
            ) ; let
        ) ; defun
    
        /************************************************************************
        *                                                                       *
        *                        getIllegalParams (inst)                        *
        *                                                                       *
        * Public function (exported as abExampleSchematicCheckGetIllegalParams) *
        *     to find any parameters which should not exist on the instance     *
        *               (i.e. should remain in the CDF defaults).               *
        *                                                                       *
        ************************************************************************/
    
        defun(getIllegalParams (inst)
            let((illegalParams cdf)
                when(inst~>master && inst~>libName==pdkName
                    illegalParams=illegalParamCache[inst~>cellName]
                    unless(listp(illegalParams)
                        cdf=cdfGetBaseCellCDF(inst~>master~>cell)
                        rexCompile("iPar")
                        illegalParams=foreach(mapcar
                            paramInf
                            setof(param cdf~>parameters
                                param~>display=="nil" &&
                                param~>paramType=="string" &&
                                rexExecute(param~>defValue)
                            )
                            paramInf~>name
                        )
                        illegalParamCache[inst~>cellName]=illegalParams
                    )
                )
                illegalParams
            ) ; let
        ) ; defun
    
        /******************************************************************
        *                                                                 *
        *           checkIllegalParamsOnInstances (cv severity)           *
        *                                                                 *
        * Private function to check for any parameters which should never *
        * exist on the instance. Such local properties must get removed,  *
        *           otherwise this could compromise netlisting.           *
        *                                                                 *
        ******************************************************************/
    
        defun(checkIllegalParamsOnInstances (cv severity)
            foreach(inst cv~>instances
                foreach(param getIllegalParams(inst)
                    when(dbFindProp(inst param)
                        placeMarker(inst 
                            sprintf(nil "Instance %s has local modified property %s"
                                inst~>name
                                param
                            ) ; sprintf
                            severity
                        ) ; placeMarker
                    )
                )
            )
        ) ; defun
    
        /***************************************************************
        *                                                              *
        *             checkNamingConventions (cv severity)             *
        *                                                              *
        * Private func to check that terminal names are in upper case, *
        *   internal nets are in lower case, upper/lower clashes etc.  *
        *                                                              *
        ***************************************************************/
    
        defun(checkNamingConventions (cv severity)
            let((obj label netTable signals sigTable)
                ;------------------------------------------------------------
                ; Check that terminal names are in upper case
                ;------------------------------------------------------------
                foreach(term cv~>terminals
                    unless(term~>name==upperCase(term~>name)
                        ;----------------------------------------------------
                        ; Place the marker on the first pin - no need to
                        ; put it on every pin if there are multiple pins
                        ;----------------------------------------------------
                        obj=car(term~>pins~>fig) || cv
                        placeMarker(obj 
                            sprintf(nil "Terminals must be in upper case: %s" 
                                term~>name
                            ) ; sprintf
                            severity
                        ) ; placeMarker
                    ) ; unless
                ) ; foreach
                ;------------------------------------------------------------
                ; Check for internal nets which have a lower case name
                ;------------------------------------------------------------
                foreach(net cv~>nets
                    ;--------------------------------------------------------
                    ; Only worry about nets which have a label
                    ;--------------------------------------------------------
                    label=car(exists(fig net~>figs fig~>objType=="label"))
                    when(label
                        when(exists(sig net~>signals 
                            ;------------------------------------------------
                            ; Check that the signal is not part of a 
                            ; terminal, and is not in lowercase
                            ;------------------------------------------------
                            !sig~>memTerms && sig~>name!=lowerCase(sig~>name))
                            placeMarker(label
                                sprintf(nil "Internal net names must be in lower case: %s"
                                    net~>name
                                ) ; sprintf
                                severity
                            ) ; placeMarker
                        ) ; when there is a lower internal net name on net
                    ) ; when there's a label
                ) ; foreach
                ;------------------------------------------------------------
                ; Check for any nets which only differ in case
                ;------------------------------------------------------------
                ;------------------------------------------------------------
                ; record all the signals together in a table indexed by
                ; the flattened case. Then use a table to record all
                ; member nets which have a mixed-case problem
                ;------------------------------------------------------------
                sigTable=makeTable('sigTable nil)
                netTable=makeTable('netTable nil)
                foreach(sig cv~>signals
                    sigTable[lowerCase(sig~>name)]=
                        cons(sig sigTable[lowerCase(sig~>name)])
                ) ; foreach
                foreach(tableEntry sigTable
                    signals=sigTable[tableEntry]
                    ;--------------------------------------------------------
                    ; If there was more than one signal with the
                    ; same flattened case, then there's
                    ; a mixed name problem. Record the member nets
                    ; in a table (to avoid duplication)
                    ;--------------------------------------------------------
                    when(cdr(signals)
                        foreach(sig signals
                            foreach(memNet sig~>memNets
                                netTable[car(memNet)]=signals
                            ) ; foreach memNet
                        ) ; foreach sig
                    ) ; when
                ) ; foreach 
                foreach(net netTable
                    ;--------------------------------------------------------
                    ; Find something suitable to put the marker on
                    ;--------------------------------------------------------
                    cond(
                        ;----------------------------------------------------
                        ; Use the pin if there is one
                        ;----------------------------------------------------
                        (net~>term~>pins
                            obj=car(net~>term~>pins~>fig)
                        )
                        ;----------------------------------------------------
                        ; Otherwise use the label
                        ;----------------------------------------------------
                        (obj=car(
                            exists(shape net~>figs 
                                shape~>objType=="label"))
                            t
                        )
                        ;----------------------------------------------------
                        ; Next try a wire
                        ;----------------------------------------------------
                        (obj=car(
                                exists(shape net~>figs
                                    shape~>objType=="line" ||
                                    shape~>objType=="path")
                            )
                            t
                        )
                        ;----------------------------------------------------
                        ; Finally, if nothing else, use the cellView
                        ;----------------------------------------------------
                        (t
                            obj=cv
                        )
                    ) ; cond
                    placeMarker(obj 
                        sprintf(nil 
                            "Net %L cannot differ only in case from others: %L" 
                            net~>name
                            netTable[net]~>name
                        ) ; sprintf
                        severity
                    ) ; placeMarker
                ) ; foreach
            ) ; let
        ) ; defun checkNamingConventions
    
        /***************************************************************
        *                                                              *
        *            exampleSchematicCheck(cv _errs _warns)            *
        *                                                              *
        * Public Function, exported as abExampleSchematicCHeck, which  *
        *                  actually does the checks.                   *
        *                                                              *
        ***************************************************************/
    
        defun(exampleSchematicCheck (cv _errs _warns)
            resetErrorsAndWarns(cv)
            ;----------------------------------------------------------------
            ; Check naming conventions
            ;----------------------------------------------------------------
            checkNamingConventions(cv "warning")
            ;----------------------------------------------------------------
            ; Look for components in the "do_not_use" category of the PDK
            ;----------------------------------------------------------------
            checkComponentsInCategory(cv pdkName "do_not_use" "warning")
            ;----------------------------------------------------------------
            ; Check for any illegal parameters (e.g. invisible
            ; parameters which have values different than the PDK
            ; defValue) on an instance
            ;----------------------------------------------------------------
            checkIllegalParamsOnInstances(cv "error")
            ;----------------------------------------------------------------
            ; Now update the count of warnings and errors
            ;----------------------------------------------------------------
            updateErrorsAndWarns(cv)
        ) ; defun
    
        /**********************************************************************
        *                                                                     *
        * Public function, exported as abExampleSchematicCheckDefinePdkName() *
        *                                                                     *
        *     This allows the PDK name to be defined for check-and-save.      *
        *                                                                     *
        **********************************************************************/
        defun(definePdkName (libName)
            pdkName=libName
        )
    
        /***************************************************************
        *                                                              *
        *                  regExampleSchematicCheck()                  *
        *                                                              *
        *  Public function, exported as abRegExampleSchematicCheck()   *
        *         which registers the check-and-save trigger.          *
        *                                                              *
        ***************************************************************/
    
        defun(regExampleSchematicCheck ()
            abExampleSchematicCheck=exampleSchematicCheck
            schRegPostCheckTrigger('abExampleSchematicCheck)
        )
    
        ;--------------------------------------------------------------------
        ; Initialise some variables
        ;--------------------------------------------------------------------
        pdkName=getShellEnvVar("PROCESS_PDK")
        illegalParamCache=makeTable('illegalParamCache t)
    
        ;--------------------------------------------------------------------
        ; Export the functions we want to be globally available
        ;--------------------------------------------------------------------
        abRegExampleSchematicCheck=regExampleSchematicCheck
        abExampleSchematicCheckDefinePdkName=definePdkName
        abExampleSchematicCheckGetIllegalParams=getIllegalParams
    )
    
    

    Hope that helps!

    Andrew.

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • Sheppie
    Sheppie over 5 years ago in reply to AurelBuche

    Thank you for your reply Aurel.

    I have been thinking about creating my own form, however, I have no idea how I would cope with different properties/parameters for each device. This form had to work for all libraries and all cells: a resistor has different properties/parameters than a transistor, and the form has to adapt to that. Of course, it is possible to write some code that (once the lib/cell/view names are specified) looks at the CDF parameters and build the form with that information, but that would just be the start, and might need continuous support (would it still work in a newer Virtuoso version?). So I decided not to go down that path.

    Regarding your code suggestion for the SCLRemoveElementWithValueFromList() procedure: this is a very efficient and simple solution. The code I shared was from an older version of the procedure; in the current version it is possible to specify per value-to-remove whether or not all of the occurrences should be removed, or just the first one, two, three,.... So it is a bit more complicated. Having said that, I have included your setof() as well: if all occurrences of all values to remove have to be removed, it will do the setof(). I've compared it with my original implementation (removing 1, 2 and 3 from a list with 100.000 randomized integers between 0 and 10) and it is much quicker.

    Regards,

    Sjoerd

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel

Community Guidelines

The Cadence Design Communities support Cadence users and technologists interacting to exchange ideas, news, technical information, and best practices to solve problems and get the most from Cadence technology. The community is open to everyone, and to provide the most value, we require participants to follow our Community Guidelines that facilitate a quality exchange of ideas and information. By accessing, contributing, using or downloading any materials from the site, you agree to be bound by the full Community Guidelines.

© 2025 Cadence Design Systems, Inc. All Rights Reserved.

  • Terms of Use
  • Privacy
  • Cookie Policy
  • US Trademarks
  • Do Not Sell or Share My Personal Information