• 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. connect two metal nets

Stats

  • Locked Locked
  • Replies 15
  • Subscribers 145
  • Views 14298
  • 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

connect two metal nets

Deeksha D
Deeksha D over 2 years ago

Hello,

I am trying to connect two metal nets (objType~>path).

if both metal net layers are same then simply align nets abutted.

if nets have different metal layers then check if metals layers can be connected using VIA .

eg if metals layers are M1 and M2 then connect using VIA1 taking via's  min.  width and min. enclosure by metal from techfile, 

  • Cancel
Parents
  • Andrew Beckett
    Andrew Beckett over 2 years ago
    Deeksha D said:
    I am trying to connect two metal nets (objType~>path).

    Did you have a question?

    Andrew

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • Deeksha D
    Deeksha D over 2 years ago in reply to Andrew Beckett

    Hi Andrew I Posted my question below for your understanding

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • Andrew Beckett
    Andrew Beckett over 2 years ago in reply to Deeksha D
    Deeksha D said:
    Yes, I have partially selected metal bus (path/path seg) in horizontal and vertical path. I want to connect these metals using skill and if the metal types are different Vias need to be add at the meeting point of this paths.

    You still didn't actually ask a question. You just stated what you wanted to do.

    I've been travelling the last week with very limited time, so hadn't thought about what it was you might want. However, whilst out on a walk this morning I thought through how I might implement this myself. First of all, I wondered whether you might have connectivity information on the tracks to determine which vertical track should be connected to which horizontal track, but I decided in the end to implement something that just used the shortest Manhattan distance to determine which pair should be connected first.

    Anyway, here's some code to do this - ended up being a bit longer than I thought, mainly because of breaking it down into small functions and using a class-based way of implementing it (the comments also lengthen the code) - the logic itself is fairly short and I hope easy to understand. I used the C-style syntax as it's an example that you might want to modify.

    Regards,

    Andrew

    /* abJoinTrackSegs.ils
    
    Author     A.D.Beckett
    Group      Custom IC (UK), Cadence Design Systems Ltd.
    Language   SKILL
    Date       Jan 21, 2023 
    Modified   May 02, 2023 
    By         A.D.Beckett
    
    Provides a function to take a set of selected points on a set of pathSegs
    (the code only works with pathSegs, not paths), and join the vertical 
    pathSegs to the horizontal pathSegs. It connects the nearest pair first, 
    then the next nearest and so on. It handles pathSegs on the same layer or
    different layers, and also copes with different widths. If the layers are
    different, vias are added from the specified constraint group (defaults
    to the constraint group given for vias in the Editor Options form), and
    also minNumCuts can be specified:
    
    abJoinTrackSegs()
    abJoinTrackSegs(?minNumCuts 2)
    
    See the comment above the abJoinTrackSegs functions below for more details.
    
    Note that this uses the SKILL++ object system to create container objects
    for the pathSegs (called track segments within) and for pairs of trackSegs.
    This allows a natural object-oriented way of dealing with the objects, as
    well as creation of a lot of small utility functions to make the logic 
    clearer.
    
    ***************************************************
    
    SCCS Info: @(#) abJoinTrackSegs.ils 05/02/23.22:25:05 1.2
    
    */
    
    ;------------------------------------------------------------------------
    ; Classes to store the track segments. There's a root class
    ; abTrackSeg and then child classes for vertical and horizontal
    ; segments.
    ;------------------------------------------------------------------------
    
    defclass(abTrackSeg ()
      (
        ; database id of the actual pathSeg
        (dbId @initarg dbId @reader abGetTrackSegDbId)
        ; x coordinate of the selected end of the pathSeg
        (x @initarg x @reader abGetTrackSegX)
        ; y coordinate of the selected end of the pathSeg
        (y @initarg y @reader abGetTrackSegY)
        ; name of the point which is selected (beginPt/endPt)
        (ptName @initarg ptName @reader abGetTrackSegPtName)
        ; this is set once that segment is modified to rule it
        ; out of further possible movements
        (modified @initform nil @reader abGetTrackSegModified 
          @writer abSetTrackSegModified)
      )
    )
    
    defclass(abVerticalTrackSeg (abTrackSeg)
      ()
    )
    
    defclass(abHorizontalTrackSeg (abTrackSeg)
      ()
    )
    
    ;------------------------------------------------------------------------
    ; A class to store a pair of track segments. Not all pairs will be
    ; connected - they will be sorted by the routing distance to
    ; join the nearest pair first.
    ;------------------------------------------------------------------------
    
    defclass(abTrackSegPair ()
      (
        (vertical @initarg vertical @reader abGetTrackSegPairVertical)
        (horizontal @initarg horizontal @reader abGetTrackSegPairHorizontal)
        (routingDist @reader abGetTrackSegPairRoutingDist)
      )
    )
    
    /***************************************************************
    *                                                              *
    *             initializeInstance(pair @rest _args)             *
    *                                                              *
    *  initializeInstance @after method for abTrackSegPair which   *
    * computes the manhattan distance between the selected points. *
    *                                                              *
    ***************************************************************/
    
    defmethod(initializeInstance @after ((pair abTrackSegPair) @rest _args)
      pair->routingDist=
        abs(pair->vertical->y-pair->horizontal->y)+
        abs(pair->vertical->x-pair->horizontal->x)
    )
    
    /***************************************************************
    *                                                              *
    *                  abTrackSegIsVertical(seg)                   *
    *                                                              *
    *   Determines whether the track segment is vertical or not    *
    *                                                              *
    ***************************************************************/
    
    defgeneric(abTrackSegIsVertical (seg))
    
    defmethod(abTrackSegIsVertical ((_seg abVerticalTrackSeg))
      t
    )
    
    defmethod(abTrackSegIsVertical ((_seg abHorizontalTrackSeg))
      nil
    )
    
    /***************************************************************
    *                                                              *
    *                   abTrackSegStyleName(seg)                   *
    *                                                              *
    *  Get the name of the style attribute to set (beginStyle or   *
    *                endStyle) based on the ptName                 *
    *                                                              *
    ***************************************************************/
    
    defgeneric(abTrackSegStyleName (seg))
    
    defmethod(abGetTrackSegStyleName ((seg abTrackSeg))
      if(eq(abGetTrackSegPtName(seg) 'beginPt) 'beginStyle 'endStyle)
    )
    
    /***************************************************************
    *                                                              *
    *                    abTrackSegExtName(seg)                    *
    *                                                              *
    *   Get the name of the extension attribute to set (beginExt   *
    *                or endExt) based on the ptName                *
    *                                                              *
    ***************************************************************/
    
    defgeneric(abTrackSegExtName (seg))
    
    defmethod(abGetTrackSegExtName ((seg abTrackSeg))
      if(eq(abGetTrackSegPtName(seg) 'beginPt) 'beginExt 'endExt)
    )
    
    /***************************************************************
    *                                                              *
    *                abTrackSegMovePt(trackSeg x y)                *
    *                                                              *
    * Update the beginPt or endPt to the given x and y coordinate  *
    *                                                              *
    ***************************************************************/
    
    defgeneric(abTrackSegMovePt (trackSeg x y))
    
    defmethod(abTrackSegMovePt ((trackSeg abTrackSeg) x y)
      putprop(abGetTrackSegDbId(trackSeg) list(x y) abGetTrackSegPtName(trackSeg))
    )
    
    /***************************************************************
    *                                                              *
    *             abTrackSegPairNeitherModified(pair)              *
    *                                                              *
    *   Determine whether neither trackSeg in the pair has been    *
    *   modified - if so, it is a valid candidate to be joined.    *
    *                                                              *
    ***************************************************************/
    
    defgeneric(abTrackSegPairNeitherModified (pair))
    
    defmethod(abTrackSegPairNeitherModified ((pair abTrackSegPair))
      !(abGetTrackSegModified(pair->vertical) ||
        abGetTrackSegModified(pair->horizontal)
       )
    )
    
    /***************************************************************
    *                                                              *
    *                abTrackSegPairSameLayer(pair)                 *
    *                                                              *
    *      Are both trackSegs in the pair on the same layer?       *
    *                                                              *
    ***************************************************************/
    
    defgeneric(abTrackSegPairSameLayer (pair))
    
    defmethod(abTrackSegPairSameLayer ((pair abTrackSegPair))
      abGetTrackSegDbId(pair->vertical)->layerName==
      abGetTrackSegDbId(pair->horizontal)->layerName
    )
    
    /***************************************************************
    *                                                              *
    *                abTrackSegPairSameWidth(pair)                 *
    *                                                              *
    *      Do both trackSegs in the pair have the same width?      *
    *                                                              *
    ***************************************************************/
    
    defgeneric(abTrackSegPairSameWidth (pair))
    
    defmethod(abTrackSegPairSameWidth ((pair abTrackSegPair))
      abGetTrackSegDbId(pair->vertical)->width==
      abGetTrackSegDbId(pair->horizontal)->width
    )
    
    /***************************************************************
    *                                                              *
    *         abTrackSegPairAddVia(pair minNumCuts cgName)         *
    *                                                              *
    *  Add a via at the intersection of the two trackSegs in the   *
    *    pair, with the given minumum number of cuts using the     *
    *    vias and constraint in the given constraint group name    *
    *                                                              *
    ***************************************************************/
    
    defgeneric(abTrackSegPairAddVia (pair minNumCuts cgName))
    
    defmethod(abTrackSegPairAddVia ((pair abTrackSegPair) minNumCuts cgName)
      flet(
        (
          ;------------------------------------------------------------------
          ; local function to find constraint group in the
          ; design or in a referenced tech lib
          ;------------------------------------------------------------------
          (findConstraintGroup (cv tf cgName)
            let(
              (
                (split parseString(cgName ":"))
                (parenPart pcreCompile("[(][^)]*[)]$"))
              )
              case(car(split)
                ("dsn" cstFindConstraintGroupIn(cv cadr(split)))
                ("tech" 
                  cstFindConstraintGroupIn(
                    tf
                    pcreReplace(parenPart cadr(split) "" 0)
                  ))
                (t
                  cstFindConstraintGroupIn(tf cgName))
              )
            ))
        )
        letseq(
          (
            (cv abGetTrackSegDbId(pair->vertical)->cellView)
            (tf techGetTechFile(cv))
            (cg findConstraintGroup(cv tf cgName))
            (viaOpts viaGetViaOptions(cg))
          )
          viaOpts->createInRoute=t
          viaOpts->automatic->printStatisticsReport=nil
          viaOpts->automatic->minNumCuts=minNumCuts
          viaGenerateViasAtPoint(
            cv 
            abGetTrackSegX(pair->vertical):abGetTrackSegY(pair->horizontal)
            viaOpts
          )
        )
      )
    )
    
    /***************************************************************
    *                                                              *
    *                  abTrackSegPairExtend(pair)                  *
    *                                                              *
    *   This is used if the two trackSegs are on the same layer.   *
    *  It modifies the beginStyle/endStyle and beginExt/endExt to  *
    *              ensure that the ends fully overlap              *
    *                                                              *
    ***************************************************************/
    
    defgeneric(abTrackSegPairExtend (pair))
    
    defmethod(abTrackSegPairExtend ((pair abTrackSegPair))
      let(
        (
          (verticalStyleName abGetTrackSegStyleName(pair->vertical))
          (horizontalStyleName abGetTrackSegStyleName(pair->horizontal))
          (verticalDbId abGetTrackSegDbId(pair->vertical))
          (horizontalDbId abGetTrackSegDbId(pair->horizontal))
        )
        if(abTrackSegPairSameWidth(pair) then
          putprop(verticalDbId "extend" verticalStyleName)
          putprop(horizontalDbId "extend" horizontalStyleName)
        else
          putprop(verticalDbId "variable" verticalStyleName)
          putprop(horizontalDbId "variable" horizontalStyleName)
          putprop(
            verticalDbId 
            horizontalDbId~>width/2.0 
            abGetTrackSegExtName(pair~>vertical)
          )
          putprop(
            horizontalDbId 
            verticalDbId~>width/2.0 
            abGetTrackSegExtName(pair~>horizontal)
          )
        )
        t
      )
    )
    
    /********************************************************************
    *                                                                   *
    *            abTrackSegPairJoin(pair minNumCuts cgName)             *
    *                                                                   *
    *    Join the two trackSegs in the pair by moving the end points    *
    *  to the same location, and then either adding a via or adjusting  *
    * the style/extension depending on whether the layers are the same. *
    *  Vias are added with the given minumum number of cuts using the   *
    *      vias and constraints in the given constraint group name      *
    *                                                                   *
    ********************************************************************/
    
    defgeneric(abTrackSegPairJoin (pair minNumCuts cgName))
    
    defmethod(abTrackSegPairJoin ((pair abTrackSegPair) minNumCuts cgName)
      abTrackSegMovePt(
        pair->vertical 
        abGetTrackSegX(pair->vertical)
        abGetTrackSegY(pair->horizontal)
      )
      abTrackSegMovePt(
        pair->horizontal 
        abGetTrackSegX(pair->vertical)
        abGetTrackSegY(pair->horizontal)
      )
      if(abTrackSegPairSameLayer(pair) then
        abTrackSegPairExtend(pair)
      else
        abTrackSegPairAddVia(pair minNumCuts cgName)
      )
      abSetTrackSegModified(pair->vertical t)
      abSetTrackSegModified(pair->horizontal t)
    )
    
    /*****************************************************************
    *                                                                *
    *                    abCreateTrackSeg (dbId)                     *
    *                                                                *
    *   Create a abTrackSeg object starting from the dbId. Checks    *
    * to see that the dbId is a pathSeg which is partially selected; *
    *                     if not it returns nil.                     *
    *                                                                *
    *****************************************************************/
    
    defun(abCreateTrackSeg (dbId)
      let((whichPt otherPt xy otherXy trackType)
        when(dbId~>objType=="pathSeg" && geIsObjectPartiallySelected(dbId)
          whichPt=
            car(
              foreach(mapcan (ptName isSel) '(beginPt endPt) 
                  geGetSelSetFigPoint(dbId)
                when(isSel list(ptName))
              )
            )
        )
        when(whichPt
          xy=get(dbId whichPt)
          otherPt=if(eq(whichPt 'beginPt) 'endPt 'beginPt)
          otherXy=get(dbId otherPt)
          trackType=
            cond(
              (xCoord(xy)==xCoord(otherXy) 'abVerticalTrackSeg)
              (yCoord(xy)==yCoord(otherXy) 'abHorizontalTrackSeg)
            )
        )
        when(trackType
          makeInstance(trackType ?dbId dbId ?x xCoord(xy) ?y yCoord(xy)
            ?ptName whichPt
          )
        )
      )
    )
    
    /*****************************************************************
    *                                                                *
    *            abJoinTrackSegs([?objects geGetSelSet()]            *
    *                        [?minNumCuts 1]                         *
    *                 [?constraintGroupName cgName]                  *
    *                               )                                *
    *                                                                *
    *   Join the path segments which are selected. Joins vertical    *
    *  segments to horizontal segments, adding vias fromm the given  *
    *  constraint group name (uses the "Via" constraint group from   *
    * the Editor Options), with the specified minimum number of cuts *
    *                                                                *
    *****************************************************************/
    
    defun(abJoinTrackSegs (@key 
        (objects geGetSelSet())
        (minNumCuts 1)
        (constraintGroupName 
          cstGetDefaultConstraintGroupName(geGetEditCellView() "Via"))
      )
      let(
        (
          verticalTrackSegs
          horizontalTrackSegs
          trackSeg
          trackSegPairs
        )
        ;--------------------------------------------------------------------
        ; First create a list of horizontal and vertical track segments
        ;--------------------------------------------------------------------
        foreach(obj objects
          trackSeg=abCreateTrackSeg(obj)
          when(trackSeg
            if(abTrackSegIsVertical(trackSeg) then
              verticalTrackSegs=cons(trackSeg verticalTrackSegs)
            else
              horizontalTrackSegs=cons(trackSeg horizontalTrackSegs)
            )
          )
        )
        ;--------------------------------------------------------------------
        ; Then create a pair between each vertical and each horizontal
        ; track segment. Not all of these will be connected, but they
        ; are candidates for joining.
        ;--------------------------------------------------------------------
        foreach(vertical verticalTrackSegs
          foreach(horizontal horizontalTrackSegs
            trackSegPairs=cons(
              makeInstance(
                'abTrackSegPair ?vertical vertical ?horizontal horizontal
              )
              trackSegPairs
            )
          )
        )
        ;--------------------------------------------------------------------
        ; Sort the pairs of track segments to have those with the shortest
        ; manhattan distance between the selected points first
        ;--------------------------------------------------------------------
        trackSegPairs=sort(trackSegPairs 
          lambda((a b) 
            abGetTrackSegPairRoutingDist(a)<abGetTrackSegPairRoutingDist(b)
          )
        )
        ;--------------------------------------------------------------------
        ; Iterate through the sorted list of pairs, joining any pair that
        ; has not had one of its trackSegments already modified (joined)
        ;--------------------------------------------------------------------
        foreach(trackSegPair trackSegPairs
          when(abTrackSegPairNeitherModified(trackSegPair)
            abTrackSegPairJoin(trackSegPair minNumCuts constraintGroupName)
          )
        )
        t
      )
    )
    

    • Cancel
    • Vote Up +1 Vote Down
    • Cancel
  • RicardoGV1
    RicardoGV1 over 2 years ago in reply to Andrew Beckett

    Hi Andrew, I'm having an error when using this code. The first time I used it was done correctly, but after that time, I'm getting the error even rebooting cadence.
       
    Is this something I need to check with support? or do you know why this happens? 


    Best regards,
    R.Gómez

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • Andrew Beckett
    Andrew Beckett over 2 years ago in reply to RicardoGV1

    I'm using the viaGenerateViasAtPoint() SKILL function to place the vias. It turns out that if you are not using VLS EAD (in IC6.1.8) or VLS EXL (in ICADVM20.1), then it checks out GXL tokens instead. Potentially it could use lxComputeViaParams instead to compute the parameters (this requires VLS XL licensing) and then create the via using dbCreateVia. That's not as convenient as using the via.* functions though as it's more work.

    Andrew

    • Cancel
    • Vote Up +1 Vote Down
    • Cancel
  • RicardoGV1
    RicardoGV1 over 2 years ago in reply to Andrew Beckett

    Thanks a lot Andrew

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • Vallabha
    Vallabha over 2 years ago in reply to Andrew Beckett

    Hi Andrew,

    I am interested in the code which you posted.

    The code is giving me the following error:

    I am using the Virtuoso Version ICADVM20.1.

    Regards,
    Vallabha

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • Andrew Beckett
    Andrew Beckett over 2 years ago in reply to Vallabha

    Vallabha,

    First of all, what does:

    cstGetDefaultConstraintGroupName(geGetEditCellView() "Via")

    return with the layout window active? 

    Secondly, if you do this:

    tf=techGetTechFile(geGetEditCellView())
    cg=cstFindConstraintGroupIn(tf "theNameFromFirstFunc")

    where theNameFromFirstFunc is what the cstGetDefaultConstraintGroupName returned, what happens? 

    My guess is that either the default constraint group name mis-specified in the environment, or that constraint group does not exist in the tech file.

    Andrew

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • Vallabha
    Vallabha over 2 years ago in reply to Andrew Beckett

    Hi Andrew

    Thanks for the quick reply.

    cstGetDefaultConstraintGroupName(geGetEditCellView() "Via") 

    returning a constraint group that is defined in the reference tech lib.

    tf=techGetTechFile(geGetEditCellView())
    cg=cstFindConstraintGroupIn(tf "theNameFromFirstFunc")

    returning nil, I think it's because the constraints group is coming from the reference tech lib.

    The code is working fine after I changed the Via Constraints Group to "foundry".

    Regards,
    Vallabha

     

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • Andrew Beckett
    Andrew Beckett over 2 years ago in reply to Vallabha

    Vallabha,

    I've updated the code above (I edited the original post to replace with a newer version) which should handle the constraint group either being in a reference technology library, or even in the design. Apologies for this - a silly oversight on my part.

    Hopefully you can try that and it should (I hope) work for you.

    Regards,

    Andrew

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
Reply
  • Andrew Beckett
    Andrew Beckett over 2 years ago in reply to Vallabha

    Vallabha,

    I've updated the code above (I edited the original post to replace with a newer version) which should handle the constraint group either being in a reference technology library, or even in the design. Apologies for this - a silly oversight on my part.

    Hopefully you can try that and it should (I hope) work for you.

    Regards,

    Andrew

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
Children
  • Vallabha
    Vallabha over 2 years ago in reply to Andrew Beckett

    Thanks Andrew for the updated code.

    The updated code is giving me the following error.

    Regards,
    Vallabha

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • Andrew Beckett
    Andrew Beckett over 2 years ago in reply to Vallabha

    Vallabha,

    Please ensure that the code is in a file with a ".ils" suffix (not ".il") before loading it. This ensures it will be read using SKILL++ semantics (that's what the SCHEME message is about). That should fix the problem.

    Regards,

    Andrew

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • Vallabha
    Vallabha over 2 years ago in reply to Andrew Beckett

    Andrew,

    The code is working perfectly.
    Thank you very much!

    Regards,
    Vallabha

    • 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