• 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 do a dbLayerAndNot from top-level through the whole...

Stats

  • Replies 3
  • Subscribers 143
  • Views 71
  • Members are here 0

How to do a dbLayerAndNot from top-level through the whole hierarchy?

Sheppie
Sheppie 4 hours ago

Hi,

I hope someone can help me with the following:

Throughout the hierarchy of our layout (IP block that will be used in many chips), we use exclude shapes/layers for dummy fill placement: Whereever there is this polygon/layer, no dummy fill will be created. At top-level, after dummy placement, I want to fill all area's where no exclude polygon/layer is placed lower down the hierarchy, with this exclude layer. This to ensure that at chip level, no new dummy fill is created in the IP. The flow is thus:

  1. add manual dummy fill in lower blocks (where needed, not everywhere of course)
  2. add dummy exclude on those blocks (where needed)
  3. At IP level, add dummy fill
  4. Add dummy fill exclude between all excisting exclude areas

My question is about step 4: how to get all exclude layers through teh whole heirarchy and AND_NOT this with the boundary at IP level.

This resulting polygon must be sized by -0.5 to not touch excisting exclude shapes (this has a reason, not relevant to this problem). In the end, there will be a gap between all excisting exclude polygons/layers and the newly created polygon/layer.

This all has to be checked/done withing the PrBoundary (the P&R Object) . So this is what I want to do, but fail to get working:

dbLayerSize( PrBoundary AND_NOT excludeLayer )
(I know, rubish pseudo code, but just for illustration pupose)

I have looked at dbLayerAndNot, but that only works on the current hierarchical level, not anything below it.
(If you look a the help in the manual, Doc Assistant, for dbLayerAndNot, the exmple given is exactly what I want, but than through the hierarchy.)

Also looked at (and tried) the abe... functions, like abeLayerAndNot, but I fail to get anything meaningfull out of it.

At GDS level, it's rather simple to create rules to extract this, but we have to deliver our IP as a Virtuoso database, so that won't work.

I hope someone can point me in the right direction.

Thanks in advance.

With kind regards,

Sjoerd

  • Cancel
  • Sign in to reply
Parents
  • Aurel B
    Aurel B 4 hours ago

    ABE functions are definitely the way to go!

    Here is something that should do the job:

    (defun and_not_fill ( @key
                          ( cv (geGetEditCellView)  )
                          ( tf (techGetTechFile cv) )
                          existing_lpp
                          filling_lpp
                          @rest _ "ddllg" )
      "Fill CV with FILLING_LPP shapes everywhere EXISTING_LPP is not already present."
      ;; Check inputs
      (foreach (var val) '(existing_lpp filling_lpp) (list existing_lpp filling_lpp)
        ;; Make sure value is a valid LPP
        (assert (and (listp val) (stringp (car val)) (stringp (cadr val)) (not (cddr val)))
          "and_not_fill - ?%s should be a list containing two strings: %N" var val)
        (assert (techGetLP tf val) "and_not_fill - ?%s is not a valid LPP: %N" var val)
        )
      ;; Run ABE commands
      (abeInit cv)
      (unwindProtect
        (let ( ( boundary_points (or cv->prBoundary->points
                                      (warn "No prBoundary found in %N/%N/%N, defaulting to cellview bBox."
                                            cv->libName cv->cellName cv->viewName)
                                      (destructuringBind ( ( x0 y0 ) ( x1 y1 ) ) cv->bBox
                                        (list x0:y0 x1:y0 x1:y1 x0:y1))
                                      ) )
               ( existing_abe    (abeLayerFromCellView (car existing_lpp) ?purpose (cadr existing_lpp)) )
               ( boundary_abe    (abeNewLayer)                                                          )
               ( filling_abe     (abeNewLayer)                                                          )
               )
          ;; Define ABE layer from prBoundary
          (abeLayerOrPtArray boundary_points boundary_abe)
          ;; Do the and not and generate the shapes
          (abeLayerAndNot boundary_abe existing_abe filling_abe)
          (abeLayerToCellView filling_abe (car filling_lpp) ?purpose (cadr filling_lpp))
          )
        (abeDone)
        ))
    
    ;(and_not_fill ?existing_lpp '( "designFlow" "drawing" ) ?filling_lpp '( "designFlow" "drawing1" ))
    
    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Cancel
Reply
  • Aurel B
    Aurel B 4 hours ago

    ABE functions are definitely the way to go!

    Here is something that should do the job:

    (defun and_not_fill ( @key
                          ( cv (geGetEditCellView)  )
                          ( tf (techGetTechFile cv) )
                          existing_lpp
                          filling_lpp
                          @rest _ "ddllg" )
      "Fill CV with FILLING_LPP shapes everywhere EXISTING_LPP is not already present."
      ;; Check inputs
      (foreach (var val) '(existing_lpp filling_lpp) (list existing_lpp filling_lpp)
        ;; Make sure value is a valid LPP
        (assert (and (listp val) (stringp (car val)) (stringp (cadr val)) (not (cddr val)))
          "and_not_fill - ?%s should be a list containing two strings: %N" var val)
        (assert (techGetLP tf val) "and_not_fill - ?%s is not a valid LPP: %N" var val)
        )
      ;; Run ABE commands
      (abeInit cv)
      (unwindProtect
        (let ( ( boundary_points (or cv->prBoundary->points
                                      (warn "No prBoundary found in %N/%N/%N, defaulting to cellview bBox."
                                            cv->libName cv->cellName cv->viewName)
                                      (destructuringBind ( ( x0 y0 ) ( x1 y1 ) ) cv->bBox
                                        (list x0:y0 x1:y0 x1:y1 x0:y1))
                                      ) )
               ( existing_abe    (abeLayerFromCellView (car existing_lpp) ?purpose (cadr existing_lpp)) )
               ( boundary_abe    (abeNewLayer)                                                          )
               ( filling_abe     (abeNewLayer)                                                          )
               )
          ;; Define ABE layer from prBoundary
          (abeLayerOrPtArray boundary_points boundary_abe)
          ;; Do the and not and generate the shapes
          (abeLayerAndNot boundary_abe existing_abe filling_abe)
          (abeLayerToCellView filling_abe (car filling_lpp) ?purpose (cadr filling_lpp))
          )
        (abeDone)
        ))
    
    ;(and_not_fill ?existing_lpp '( "designFlow" "drawing" ) ?filling_lpp '( "designFlow" "drawing1" ))
    
    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Cancel
Children
  • Sheppie
    Sheppie 2 hours ago in reply to Aurel B

    Hi Aurel,

    Thank you for your very quick response.

    Those abe... functions are very new to me, still used to the old-fashioned functions and traversing hierarchy.

    I'll give your code a try and will try to understand what you do, to learn.

    Once again, thank you.

    WIth kind regards,

    Sjoerd

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Cancel
  • Aurel B
    Aurel B 2 hours ago in reply to Sheppie

    So the ABE functions are very efficient to do DRC-like (Boolean) operations directly in SKILL inside Virtuoso

    They are not very consistent with the rest of the SKILL API but they are super fast.
    The only drawback is that it is limited to 45° angles so in very few cases you cannot trust their results.

    (It can be the case if you are working with pixels or RF designs with rounded edges but usually most layers only contain Manhattan polygons)

    You have to init and close the ABE session using abeInit and abeDone, the unwindProtect call is here to guarantee that the session is always closed properly.

    Then most operations abeLayerAnd, abeLayerAndNot, ... are simply adding shapes to an existing ABE layer object (which you can consider as an optimized list of polygons).

    This is why I create the layers using abeNewLayer before adding polygons to them.
    The only exception is abeLayerFromCellView which creates a new layer from cell view shapes and return it. (Yet again another inconsistency...)

    abeLayerOrPtArray has a very confusing name but it simply adds a polygons to an ABE Layer.
    In my previous snippet, it is used to fetch the prBoundary (or the cellview bBox) which is not a regular layer.

    Then abeLayerToCellView generates the shapes from an ABE layer.

    I hope this is clear enough, if you have more questions, don't hesitate.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • 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