• 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. Cadence Layout SKILL: Automating alignment of instances...

Stats

  • Locked Locked
  • Replies 6
  • Subscribers 144
  • Views 11067
  • 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

Cadence Layout SKILL: Automating alignment of instances using prBoundary as reference

Phuc Bui
Phuc Bui over 2 years ago

Hi all,

I'm trying to automate the alignment of two components in Virtuoso Layout (IC 6.1.8-64b) by using some SKILL functions, and I'm wondering if anyone here has experience with coding that sort of script. The process I am trying to automate is in the image. I have two components, which both have prBoundaries defining where they should align. Manually doing Quick Align using the centre of the boundaries is viable for a small component, but the full device has plenty of these little alignments to do and I want to at least try and automate it with SKILL before resorting to optimise the manual Quick Align process. Has anyone here encountered something similar before?

Digging through the Virtuoso Layout SKILL Reference manual suggests that the leAlign function might be the key, but the difficulty is in defining where exactly the objects will be aligned. Ideally the automated script should identify both prBoundaries and snap them together but leAlign looks like it might need a lot of further modification to get that sort of boundary recognition implemented.

  • Cancel
Parents
  • Andrew Beckett
    Andrew Beckett over 2 years ago

    Not a SKILL solution as such, but one implemented as a PCell Designer "App Cell" (see appCell demo library (add-on to CDNLive EMEA 2019 CUS-Techtorial V)). Since there's no procedural interface to quick align, any SKILL-based solution would involve finding the prBoundary object in the lower level cells, transforming the coordinates, finding the centres of the appropriate edges and then computing the amount to move by. I managed to achieve the same thing with a few minutes of interactive work in PCell Designer by creating an appCell that worked on the selected objects. This works out which two edges are nearest and then aligns those (the edges of the prBoundary) using the built-in distance and align commands. 

    I've uploaded a gzipped tar file containing the deployed library (so you don't need PCell Designer to use this):

     forumPCDutils.tar.gz

    To use it, put the library into your cds.lib, and then select the two instances to align and then use: 

    ddGetObj("forumPCDutils" "alignTwoBlocks" "layout")->commands->AlignBoundaries()

    (you could put this on a bindkey). The first selected object is the one that stays still - the second is aligned to it.

    If you want to see how this is done, a screenshot of the structure in PCell Designer is here:

    and the pcd.txt file you can import into PCell Designer is here (you'll need the PCell Designer license for this):

    Fullscreen alignTwoBlocks_layout.pcd.txt Download
    ;;; PCell Designer File (format version 2.2)
    
    ;;; File-out of the PCell Designer pcell "NmosDemo24"/"alignTwoBlocks"/"layout"
    
    (pcdPcell
    
    ;; Mixins
    ?mixins
    nil
    
    ;; Create CDF?
    ?createCDF
    t
    
    ;; Reference cell for CDF
    ?referenceCDF
    nil
    
    ;; Main points
    ?mainPoints
    nil
    
    ;; Initial size
    ?initSize
    nil
    
    ;; Device Variables
    ?devVars
    nil
    
    ;; Device Variables visible to the commands
    ?guiVisibleDevVarNames
    nil
    
    ;; Methods used as commands
    ?methodCommands
    nil
    
    ;; Methods available as AppCell editors
    ?appCellEditors
    ((nil
      commandName AlignBoundaries
      parameters nil
      metaData (nil
                formCaption ""))
     )
    
    ;; PCell and CDF Parameters
    ?classEditorChanges
    ()
    
    ;; Simulation Information
    ?simulation
    (simulation)
    
    ;; Source Cell View
    ?sourceCellView
    ("NmosDemo24" "alignTwoBlocks" "layout")
    
    ;; Last Edited with PCell Designer Version
    ?pcdVersion
    "2-5-21"
    
    ;; Method definitions
    ?methods
    (
      (newCommand command (newCommand
                           ?name AlignBoundaries
                           ?commandClass pcmdCommand
                           ?category "MyAppCells"
                           ?help ""
                           ?parameters nil)
        body (
        (count 
          name (lvalue "numObjects" ?valuep t ?requiredp t ?isExpression nil ?keyword nil)
          source (geo (geo type "Expression" points nil group "" name nil net nil expression (append (selected))) ?lazyp nil ?valuep t ?requiredp t ?isExpression t ?keyword t))
        (unless 
          condition (string "numObjects==2" ?valuep t ?requiredp t ?isExpression t ?keyword nil ?help "The condition to check.")
          else 
          (body (
            (error 
              condition (string "t" ?valuep t ?requiredp t ?isExpression t ?keyword t ?help "The condition for generating the error.")
              style (enumeration "error" ?choices ("error_marker" "warning_marker" "error") ?allowOther nil ?valuep t ?requiredp t ?isExpression nil ?keyword t ?help "The kind of error to generate.")
              message (string "Must only have two objects selected" ?valuep t ?requiredp t ?isExpression nil ?keyword t ?help "The error message to display."))
            )
            ?valuep t
            ?requiredp t
            ?isExpression t
            ?keyword nil
          ))
        (set 
          settings (settings (("second" "nil" ?alert nil ?comment "" ?disabled nil)) ?valuep t ?requiredp t ?isExpression nil ?keyword nil ?help "The name/value pairs to set."))
        (each 
          name (binding "obj" ?valuep t ?requiredp t ?isExpression nil ?keyword nil ?help "Each time the body is executed, <i>name</i> will be set to a single result from <i>source</i>. <i>name</i> is only visible within the body.")
          source (geo (geo type "Expression" points nil group "" name nil net nil expression (append (selected))) ?lazyp nil ?valuep t ?requiredp t ?isExpression t ?keyword nil ?help "The geometry query go loop through.")
          body 
          (body (
            (set 
              settings (settings (("first" "second" ?alert nil ?comment "" ?disabled nil) ("second" "obj" ?alert nil ?comment "" ?disabled nil)) ?valuep t ?requiredp t ?isExpression nil ?keyword nil ?help "The name/value pairs to set."))
            )
            ?valuep t
            ?requiredp t
            ?isExpression t
            ?keyword nil
          )
          style (each_style items ?valuep t ?requiredp t ?isExpression nil ?keyword t ?help "When looping over a set of shapes, controls whether the body is executed once for every shape, for every edge in every shape, or for every corner in every shape. Shapes are processed clockwise."))
        (distance 
          ?comment "Measure distances of bottom of one object to top of the other"
          name (lvalue "firstBotToTop" ?valuep t ?requiredp nil ?isExpression nil ?keyword nil ?help "The shortest distance of those measured.")
          from (geo (geo type "Expression" points nil group "" name "first" net nil expression (append (bbox (points (name "first"))))) ?lazyp nil ?valuep t ?requiredp t ?isExpression t ?keyword nil ?help "One or more points, outlines, or shapes.")
          from_handle (handle (edge south) ?valuep t ?requiredp nil ?isExpression nil ?keyword t ?help "Handle at the source shape for the measurement.")
          to (geo (geo type "Expression" points nil group "" name "second" net nil expression (append (bbox (points (name "second"))))) ?lazyp nil ?valuep t ?requiredp t ?isExpression t ?keyword nil ?help "One or more points, outlines, or shapes.")
          to_handle (handle (edge north) ?valuep t ?requiredp nil ?isExpression nil ?keyword t ?help "Handle for the measurement target.")
          result_type (distance_type y_distance ?valuep t ?requiredp t ?isExpression nil ?keyword nil ?help "The format to return the disantce in.")
          body 
          (body (
            )
            ?valuep t
            ?requiredp t
            ?isExpression t
            ?keyword nil
          ))
        (distance 
          name (lvalue "secondBotToTop" ?valuep t ?requiredp nil ?isExpression nil ?keyword nil ?help "The shortest distance of those measured.")
          from (geo (geo type "Expression" points nil group "" name "second" net nil expression (append (bbox (points (name "second"))))) ?lazyp nil ?valuep t ?requiredp t ?isExpression t ?keyword nil ?help "One or more points, outlines, or shapes.")
          from_handle (handle (edge south) ?valuep t ?requiredp nil ?isExpression nil ?keyword t ?help "Handle at the source shape for the measurement.")
          to (geo (geo type "Expression" points nil group "" name "first" net nil expression (append (bbox (points (name "first"))))) ?lazyp nil ?valuep t ?requiredp t ?isExpression t ?keyword nil ?help "One or more points, outlines, or shapes.")
          to_handle (handle (edge north) ?valuep t ?requiredp nil ?isExpression nil ?keyword t ?help "Handle for the measurement target.")
          result_type (distance_type y_distance ?valuep t ?requiredp t ?isExpression nil ?keyword nil ?help "The format to return the disantce in.")
          body 
          (body (
            )
            ?valuep t
            ?requiredp t
            ?isExpression t
            ?keyword nil
          ))
        (if 
          ?comment "Depending which distance is the shorter, align the second to the first appropriately"
          condition (string "abs(firstBotToTop)<abs(secondBotToTop)" ?valuep t ?requiredp t ?isExpression t ?keyword nil ?help "The condition.")
          then 
          (body (
            (align 
              source (geo (geo grow 0 type "Group" points nil group nil name nil net nil expression nil) ?lazyp nil ?valuep nil ?requiredp nil ?isExpression t ?keyword nil ?help "Shapes to move.")
              from_shape (geo (geo type "Name" points nil group nil name "second" net nil expression nil) ?lazyp nil ?valuep t ?requiredp t ?isExpression t ?keyword nil ?help "Reference shape for the alignment.")
              from_handle (handle (point north) ?valuep t ?requiredp t ?isExpression nil ?keyword nil ?help "Handle at the reference shape for the alignment.")
              target_shape (geo (geo type "Name" points nil group nil name "first" net nil expression nil) ?lazyp nil ?valuep t ?requiredp t ?isExpression t ?keyword nil ?help "Target shape to align to.")
              target_handle (handle (point south) ?valuep t ?requiredp t ?isExpression nil ?keyword nil ?help "Handle for the alignment target.")
              dx (float "0.0" ?valuep t ?requiredp t ?isExpression t ?keyword nil ?help "Additional x offset applied to the shapes after aligning.")
              dy (float "0.0" ?valuep t ?requiredp t ?isExpression t ?keyword nil ?help "Additional x offset applied to the shapes after aligning.")
              stretch (boolean nil ?valuep t ?requiredp t ?isExpression nil ?keyword nil ?help "If true, stretch the shapes to align instead of moving them."))
            )
            ?valuep t
            ?requiredp t
            ?isExpression t
            ?keyword nil
          )
          else 
          (body (
            (align 
              source (geo (geo type "Name" points nil group nil name "second" net nil expression nil) ?lazyp nil ?valuep t ?requiredp nil ?isExpression t ?keyword nil ?help "Shapes to move.")
              from_shape (geo (geo type "Expression" points nil group nil name "second" net nil expression (append (bbox (points (name "second"))))) ?lazyp nil ?valuep t ?requiredp t ?isExpression t ?keyword nil ?help "Reference shape for the alignment.")
              from_handle (handle (point south) ?valuep t ?requiredp t ?isExpression nil ?keyword nil ?help "Handle at the reference shape for the alignment.")
              target_shape (geo (geo type "Expression" points nil group nil name "first" net nil expression (append (bbox (points (name "first"))))) ?lazyp nil ?valuep t ?requiredp t ?isExpression t ?keyword nil ?help "Target shape to align to.")
              target_handle (handle (point north) ?valuep t ?requiredp t ?isExpression nil ?keyword nil ?help "Handle for the alignment target.")
              dx (float "0.0" ?valuep t ?requiredp t ?isExpression t ?keyword nil ?help "Additional x offset applied to the shapes after aligning.")
              dy (float "0.0" ?valuep t ?requiredp t ?isExpression t ?keyword nil ?help "Additional x offset applied to the shapes after aligning.")
              stretch (boolean nil ?valuep t ?requiredp t ?isExpression nil ?keyword nil ?help "If true, stretch the shapes to align instead of moving them."))
            )
            ?valuep t
            ?requiredp t
            ?isExpression t
            ?keyword nil
          ))
        
        ))
        
      (method command draw
        body (
        (group 
          ?renderInfo (?renderAsFigGroup nil)
          name (group "toAlign" ?valuep t ?requiredp t ?isExpression nil ?keyword nil ?help "The name of the group to create")
          body 
          (body (
            (instance 
              name (lvalue "" ?valuep t ?requiredp nil ?isExpression nil ?keyword nil ?help "The created instances, if any.")
              master (master ("pcell->libName" "\"blockwithpr\"" "\"layout\"") ?valuep t ?requiredp t ?isExpression t ?keyword nil ?help "The PCell master or standard cell view to make an instance of.")
              source (geo (geo type "Points" points ((0 0))) ?lazyp nil ?valuep t ?requiredp t ?isExpression t ?keyword nil ?help "The origins of the instances to create.")
              inst_name (string "" ?valuep t ?requiredp nil ?isExpression nil ?keyword t ?help "If given, the instance name. If ommitted, the instances will be named automatically.")
              array (sexp "(1 1)" ?valuep nil ?requiredp nil ?isExpression nil ?keyword t ?help "If given, create a mosaic of the requested number of columns and rows.")
              dx (float "0.0" ?valuep nil ?requiredp nil ?isExpression t ?keyword t ?help "When creating a mosaic, the x spacing. May be omitted.")
              dy (float "0.0" ?valuep nil ?requiredp nil ?isExpression t ?keyword t ?help "When creating a mosaic, the x spacing. May be omitted.")
              copy_terminals (boolean nil ?valuep t ?requiredp t ?isExpression nil ?keyword t ?help "If true, all terminals will be copied up to the current instance: the pin figures will be copied, on pins of the same name, on terminals of the same name.")
              transform (transformation ((2.695 -1.375) "R0" 1.0) ?valuep t ?requiredp t ?isExpression t ?keyword t ?help "Each origin point given in source is transformed by this transform; if there is an active current transform, this is taken into account.")
              user_edits (sexp nil ?valuep t ?requiredp t ?isExpression t ?keyword t)
              param_whitelist (sexp nil ?valuep nil ?requiredp nil ?isExpression t ?keyword t)
              param_blacklist (sexp nil ?valuep nil ?requiredp nil ?isExpression t ?keyword t)
              edit_master (boolean nil ?valuep t ?requiredp t ?isExpression nil ?keyword t)
              edit_transform (boolean t ?valuep t ?requiredp t ?isExpression nil ?keyword t)
              parameters (pcell_params (nil nil) ?valuep t ?requiredp t ?isExpression t ?keyword t ?help "Name-value pairs corresponding to the PCell parameters. To use a PCell's CDF interface, use the <code>edit parameters</code> command instead."))
            (instance 
              name (lvalue "" ?valuep t ?requiredp nil ?isExpression nil ?keyword nil ?help "The created instances, if any.")
              master (master ("pcell->libName" "\"blockwithpr\"" "\"layoutTwo\"") ?valuep t ?requiredp t ?isExpression t ?keyword nil ?help "The PCell master or standard cell view to make an instance of.")
              source (geo (geo type "Points" points ((0 0))) ?lazyp nil ?valuep t ?requiredp t ?isExpression t ?keyword nil ?help "The origins of the instances to create.")
              inst_name (string "" ?valuep t ?requiredp nil ?isExpression nil ?keyword t ?help "If given, the instance name. If ommitted, the instances will be named automatically.")
              array (sexp "(1 1)" ?valuep nil ?requiredp nil ?isExpression nil ?keyword t ?help "If given, create a mosaic of the requested number of columns and rows.")
              dx (float "0.0" ?valuep nil ?requiredp nil ?isExpression t ?keyword t ?help "When creating a mosaic, the x spacing. May be omitted.")
              dy (float "0.0" ?valuep nil ?requiredp nil ?isExpression t ?keyword t ?help "When creating a mosaic, the x spacing. May be omitted.")
              copy_terminals (boolean nil ?valuep t ?requiredp t ?isExpression nil ?keyword t ?help "If true, all terminals will be copied up to the current instance: the pin figures will be copied, on pins of the same name, on terminals of the same name.")
              transform (transformation ((10.48 5.39) "R0" 1.0) ?valuep t ?requiredp t ?isExpression t ?keyword t ?help "Each origin point given in source is transformed by this transform; if there is an active current transform, this is taken into account.")
              user_edits (sexp nil ?valuep t ?requiredp t ?isExpression t ?keyword t)
              param_whitelist (sexp nil ?valuep nil ?requiredp nil ?isExpression t ?keyword t)
              param_blacklist (sexp nil ?valuep nil ?requiredp nil ?isExpression t ?keyword t)
              edit_master (boolean nil ?valuep t ?requiredp t ?isExpression nil ?keyword t)
              edit_transform (boolean t ?valuep t ?requiredp t ?isExpression nil ?keyword t)
              parameters (pcell_params (nil nil) ?valuep t ?requiredp t ?isExpression t ?keyword t ?help "Name-value pairs corresponding to the PCell parameters. To use a PCell's CDF interface, use the <code>edit parameters</code> command instead."))
            )
            ?valuep t
            ?requiredp t
            ?isExpression t
            ?keyword nil
          )
          lock (boolean nil ?valuep t ?requiredp t ?isExpression nil ?keyword t ?help "Add the shapes to a figGroup rather than a group"))
        (select 
          source (geo (geo grow 0 type "Group" points nil group "toAlign" name nil net nil expression nil) ?lazyp nil ?valuep t ?requiredp t ?isExpression t ?keyword t ?help "The shapes to select.")
          reference (geo (geo grow 0 type "Group" points nil group nil name nil net nil expression nil) ?lazyp nil ?valuep nil ?requiredp nil ?isExpression t ?keyword t ?help "Reference for partially selecting shapes")
          reset (boolean nil ?valuep t ?requiredp t ?isExpression nil ?keyword t ?help "Clear selection before selecting the shapes"))
        (AlignBoundaries )
        
        ))
        )
    
    ;; Imported local (Skill++) definitions
    ?importedCode
    nil
    
    ;; Saved state of the GUI
    ?guiData
    (nil
     selectedCommands nil
     activeTab "AlignBoundaries"
     openTabs ("AlignBoundaries" "draw")
     commandPaletteSelection (MyAppCells_AlignBoundaries)
     commandPalette (nil
                     Control\ Flow t
                     Measure t
                     Follow t
                     MyAppCells t))
    
    )
    

    Regards,

    Andrew

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

    If you prefer using a SKILL solution you could use this example as a starting point.

    Regards,

    Matthias

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

    If you prefer using a SKILL solution you could use this example as a starting point.

    Regards,

    Matthias

    • Cancel
    • Vote Up +1 Vote Down
    • Cancel
Children
  • Phuc Bui
    Phuc Bui over 2 years ago in reply to mschw

    Hi Matthias,

    Thank you very much for posting this solution, it has been very useful for finding a SKILL solution for this problem. This solution uses the ROD functions that Cadence has, and it uses the ROD object boundary as the marker, so is there any way I could redefine the ROD object boundary? I'm connecting up two devices whose routing is enclosed by other layers so if I line them up purely with that function, it only connects up the enclosure layers and not the routing itself, and I'm seeing whether I could connect the routing directly without needing to add any device-specific spacing into the arguments of that AbutAlign function.

    Thank you very much for pointing me to this solution, it has been very helpful.

    Best,

    Phuc

    • 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