• 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. Get the extremes coordinates of a chosen Layer Purpose Pair...

Stats

  • Locked Locked
  • Replies 5
  • Subscribers 143
  • Views 3400
  • 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

Get the extremes coordinates of a chosen Layer Purpose Pair (lpp) in a layout cellview containing instances and matrices within a hierarchy with dbShapeQuery

StevenR
StevenR over 1 year ago

Hello everyone,

This is my first post on the Cadence Forum. I've been learning SKILL for one year and half now and I've always found solutions to my problems by creating new SKILL procedures or finding online support/documentation.

I look for a solution on the forum but did not find anything suitable so here I come to ask your guidance.

My problem is the following :

I have a layout cellview containing several instances, several matrix instances (same instance within a matrix repeated in rows and columns) whose instancing other cells below in the hierarchy.

I want to retrieve the extremes coordinates of a chosen Layer Purpose Pair from the TOP layout cellview coordinates origin.

I tried many things with the procedure dbShapeQuery and I manage to create a procedure that works to a certain extent. I have a matrix instance in my TOP layout that has 2 columns and a distance X delta between the columns, for some reason I cannot retrive the far right coordinate of my target lpp (list("NW" "drawing")).

Please find the code that I tried below :


;PURPOSE : Find the extremes right, bottom, left, top coordinates of a layer purpose pair (lpp) within a cellView
procedure(findExtremesCoordinatesOfLayerFromCv(cv, lpp_value, path)
  let(  ( (matching_elem_list list()) (inst_type "inst") (mosaic_type "mosaic")
          lpp_transform_inst lpp_transform_mosaic (x_transform 0) (y_transform 0) (no_transform list(0.0:0.0 "R0" 1.0))  (max_bbox list(9999:9999 -9999:-9999))
          real_bbox_lpp
          leftEdgesList bottomEdgesList rightEdgesList topEdgesList
          (DRC_rule_DNW_within_NW 1.5) NW_width (DNW "DNW")
      )
      ;**************
      printf("**********\n%L bBox : %L\n\n" cv~>cellName cv~>bBox)
      ;matching_elem_list = setof(x flattenListH(dbShapeQuery(cv, lpp_value, cv~>bBox)) !fixp(x))
      matching_elem_list = dbShapeQuery(cv, lpp_value, cv~>bBox)
      ;printf("matching_elem_list : %L\n" matching_elem_list)
      foreach(elem matching_elem_list
        printf("********\nelem : %L\n" elem)
        lpp_transform_inst = nil
        lpp_transform_mosaic = nil
        if(listp(elem) then
          foreach(elem_i elem
            printf("elem_i : %L\n" elem_i)
            if(listp(elem_i) then
              printf("car(elem_i)~>cellName : %L\n" car(elem_i)~>cellName)
              printf("car(elem_i)~>name : %L\n" car(elem_i)~>name)
              if(car(elem_i)~>objType == mosaic_type then
                x_transform = car(car(elem_i)~>xy) ;car(elem_i)~>uX ;leftEdge(car(elem_i)~>bBox)
                y_transform = cadr(car(elem_i)~>xy)
                lpp_transform_mosaic = append1(lpp_transform_mosaic list(x_transform:y_transform car(car(elem_i)~>tileArray) 1.0))
                printf("lpp_transform_mosaic : %L\n" lpp_transform_mosaic)
              )
            else
              printf("elem_i~>cellName : %L\n" elem_i~>cellName)                
              printf("elem_i~>name : %L\n" elem_i~>name)
              if(elem_i~>objType == inst_type && lpp_transform_inst==nil then
                lpp_transform_inst = append1(lpp_transform_inst elem_i~>transform)
                printf("lpp_transform_inst : %L\n" lpp_transform_inst)
              )
              when(elem_i~>lpp == lpp_value
                printf("elem_i~>bBox : %L\n" elem_i~>bBox)
                foreach(lpp_transf_values '(lpp_transform_mosaic lpp_transform_inst)
                  foreach(lpp_transf eval(lpp_transf_values)
                    real_bbox_lpp = if(lpp_transf!= nil then dbTransformBBox(elem_i~>bBox lpp_transf) else max_bbox)
                    printf("size of lpp : %L\n" real_bbox_lpp)
                    leftEdgesList = append(leftEdgesList list(leftEdge(real_bbox_lpp)))
                    bottomEdgesList = append(bottomEdgesList list(bottomEdge(real_bbox_lpp)))
                    rightEdgesList = append(rightEdgesList list(rightEdge(real_bbox_lpp))
                    topEdgesList = append(topEdgesList list(topEdge(real_bbox_lpp)))
                  )
                )
              )
            )
          )
        else
          when(elem~>lpp == lpp_value
            printf("elem~>bBox : %L\n" elem~>bBox)
            leftEdgesList = append(leftEdgesList list(leftEdge(elem~>bBox)))
            bottomEdgesList = append(bottomEdgesList list(bottomEdge(elem~>bBox)))
            rightEdgesList = append(rightEdgesList list(rightEdge(elem~>bBox)))
            topEdgesList = append(topEdgesList list(topEdge(elem~>bBox)))
          )
        )
      )
      printf("*********\n*********\n")
      when(leftEdgesList leftEdgesList = apply('min sort(CCFunique(leftEdgesList) 'lessp)) printf("leftEdgesList : %L\n" leftEdgesList))
      when(bottomEdgesList bottomEdgesList = apply('min sort(CCFunique(bottomEdgesList) 'lessp)) printf("bottomEdgesList : %L\n" bottomEdgesList))
      when(rightEdgesList rightEdgesList = apply('max sort(CCFunique(rightEdgesList) 'lessp)) printf("rightEdgesList : %L\n" rightEdgesList))
      when(topEdgesList topEdgesList = apply('max sort(CCFunique(topEdgesList) 'lessp)) printf("topEdgesList : %L\n" topEdgesList))
     
      NW_width = DRC_rule_DNW_within_NW*2
      NW_space = (bottomEdgesList*2+round3((NW_width*0.25)*0.5)-0.01)
      when(path dbCreatePath(cv lpp_value
        list( leftEdgesList-NW_width*0.5:bottomEdgesList-NW_space
              rightEdgesList+NW_width*0.5:bottomEdgesList-NW_space
              rightEdgesList+NW_width*0.5:topEdgesList+NW_space
              leftEdgesList-NW_width*0.5:topEdgesList+NW_space
              leftEdgesList-NW_width*0.5:bottomEdgesList-NW_space-NW_width*0.5)
              NW_width)
        dbCreateRect(cv list(DNW cadr(lpp_value)) list(leftEdgesList-NW_width*0.5:bottomEdgesList-NW_space rightEdgesList+NW_width*0.5:topEdgesList+NW_space))
      )
     
      ;**************
  ) ;let
) ;procedure
findExtremesCoordinatesOfLayerFromCv(getEditRep(), list("NW" "drawing"), t)


The purpose is to get the 4 extremes coordinates extracted from the two blue points showed in the screenshot below. Exactly like how the bBox is computed automatically for a layout cellView and retrieved by : cvLayout~>bBox but to shrink/filter it to only a chosen Layer Purpose Pair.


If you have questions, I will detail more and share more screenshots.
Thank you in advance for taking time to read my message, any suggestions is welcomed, I hope we can solve this problem together.

Cordially, Steven.

  • Cancel
  • StevenR
    StevenR over 1 year ago
    Hello everyone, after fighting hard with the mosaic hierarchy, I managed to get the extreme coordinates in any rotation value of instances, mosaic instancing instances or standard cell directly (first has a level of hierarchy more than if was for the second). Please find my code below.
    I am conscious it is a first version and improvements can be made, please tell me what do you think and if this function can be of use to you.

    ;PURPOSE : Find the extremes right, bottom, left, top coordinates of a layer purpose pair (lpp) within a cellView
    procedure(findExtremesCoordinatesOfLayerFromCv(cv, lpp_value, path)
      let(  ( (matching_elem_list list()) (inst_type "inst") (mosaic_type "mosaic")
              mosaic_type_found lpp_transform_inst lpp_transform_mosaic
              inst_in_mosaic_transform mosaic_rotation
              (x_transform 0) (y_transform 0) (x_transform_rot 0) (y_transform_rot 0)
              (no_transform list(0.0:0.0 "R0" 1.0))  (max_bbox list(9999:9999 -9999:-9999))
              real_bbox_lpp
              leftEdgesList bottomEdgesList rightEdgesList topEdgesList
              (DRC_rule_DNW_within_NW 1.5) NW_width NW_space (DNW "DNW")
          )
          ;**************
          printf("**********\n%L bBox : %L\n\n" cv~>cellName cv~>bBox)
          ;matching_elem_list = setof(x flattenListH(dbShapeQuery(cv, lpp_value, cv~>bBox)) !fixp(x))
          matching_elem_list = dbShapeQuery(cv, lpp_value, cv~>bBox)
          ;printf("matching_elem_list : %L\n" matching_elem_list)
          foreach(elem matching_elem_list
            printf("********\nelem : %L\n" elem)
            lpp_transform_inst = nil
            lpp_transform_mosaic = nil
            if(listp(elem) then
              mosaic_type_found = nil
              inst_in_mosaic_transform = nil
              foreach(elem_i elem
                printf("elem_i : %L\n" elem_i)
                if(listp(elem_i) then
                  printf("car(elem_i)~>cellName : %L\n" car(elem_i)~>cellName)
                  printf("car(elem_i)~>name : %L\n" car(elem_i)~>name)
                  if(car(elem_i)~>objType == mosaic_type then
                    mosaic_type_found = t
                    cond(
                          (car(car(elem_i)~>tileArray) == "R0"
                            x_transform_rot = caddr(elem_i)*car(elem_i)~>uX
                            y_transform_rot = cadr(elem_i)*car(elem_i)~>uY
                          )
                          (car(car(elem_i)~>tileArray) == "R90"
                            x_transform_rot = 0 - cadr(elem_i)*car(elem_i)~>uY
                            y_transform_rot = caddr(elem_i)*car(elem_i)~>uX
                          )
                          (car(car(elem_i)~>tileArray) == "R180"
                            x_transform_rot = 0 - caddr(elem_i)*car(elem_i)~>uX
                            y_transform_rot = 0 - cadr(elem_i)*car(elem_i)~>uY
                          )
                          (car(car(elem_i)~>tileArray) == "R270"
                            x_transform_rot = cadr(elem_i)*car(elem_i)~>uY
                            y_transform_rot = 0 - caddr(elem_i)*car(elem_i)~>uX
                          )
                          (car(car(elem_i)~>tileArray) == "MY"
                            x_transform_rot = 0 - caddr(elem_i)*car(elem_i)~>uX
                            y_transform_rot = cadr(elem_i)*car(elem_i)~>uY
                          )
                          (car(car(elem_i)~>tileArray) == "MYR90"
                            x_transform_rot = 0 - cadr(elem_i)*car(elem_i)~>uY
                            y_transform_rot = 0 - caddr(elem_i)*car(elem_i)~>uX
                          )
                          (car(car(elem_i)~>tileArray) == "MX"
                            x_transform_rot = caddr(elem_i)*car(elem_i)~>uX
                            y_transform_rot = 0 - cadr(elem_i)*car(elem_i)~>uY
                          )
                          (car(car(elem_i)~>tileArray) == "MXR90"
                            x_transform_rot = cadr(elem_i)*car(elem_i)~>uY
                            y_transform_rot = caddr(elem_i)*car(elem_i)~>uX
                          )
                    )
                    x_transform = car(car(elem_i)~>xy) + x_transform_rot
                    y_transform = cadr(car(elem_i)~>xy) + y_transform_rot
                    printf("car(elem_i)~>xy : %L\n" car(elem_i)~>xy)
                    mosaic_rotation = car(car(elem_i)~>tileArray)
                    lpp_transform_mosaic = append1(lpp_transform_mosaic list(x_transform:y_transform car(car(elem_i)~>tileArray) 1.0))
                    printf("lpp_transform_mosaic : %L\n" lpp_transform_mosaic)
                  )
                else
                  printf("elem_i~>cellName : %L\n" elem_i~>cellName)                
                  printf("elem_i~>name : %L\n" elem_i~>name)
                  printf("elem_i~>xy : %L\n" elem_i~>xy)
                  printf("elem_i~>transform : %L\n" elem_i~>transform)
                  if(mosaic_type_found == nil then
                    if(elem_i~>objType == inst_type && lpp_transform_inst==nil then
                      lpp_transform_inst = append1(lpp_transform_inst elem_i~>transform)
                      printf("lpp_transform_inst : %L\n" lpp_transform_inst)
                    )
                    else  
                      when(elem_i~>objType == inst_type inst_in_mosaic_transform = elem_i~>transform)
                  )
                  when(elem_i~>lpp == lpp_value
                    printf("elem_i~>bBox : %L\n" elem_i~>bBox)
                    real_bbox_lpp = elem_i~>bBox
                    printf("elem_i~>transform : %L\n" elem_i~>transform)
                    when(mosaic_type_found && inst_in_mosaic_transform!= nil real_bbox_lpp = dbTransformBBox(real_bbox_lpp inst_in_mosaic_transform))
                    foreach(lpp_transf_values '(lpp_transform_mosaic lpp_transform_inst)
                      foreach(lpp_transf eval(lpp_transf_values)
                        real_bbox_lpp = if(lpp_transf!= nil then dbTransformBBox(real_bbox_lpp lpp_transf) else max_bbox)
                        printf("size of lpp : %L\n" real_bbox_lpp)
                        leftEdgesList = append(leftEdgesList list(leftEdge(real_bbox_lpp)))
                        bottomEdgesList = append(bottomEdgesList list(bottomEdge(real_bbox_lpp)))
                        rightEdgesList = append(rightEdgesList list(rightEdge(real_bbox_lpp)))
                        topEdgesList = append(topEdgesList list(topEdge(real_bbox_lpp)))
                      )
                    )
                  )
                )
              )
            else
              when(elem~>lpp == lpp_value
                printf("elem~>bBox : %L\n" elem~>bBox)
                leftEdgesList = append(leftEdgesList list(leftEdge(elem~>bBox)))
                bottomEdgesList = append(bottomEdgesList list(bottomEdge(elem~>bBox)))
                rightEdgesList = append(rightEdgesList list(rightEdge(elem~>bBox)))
                topEdgesList = append(topEdgesList list(topEdge(elem~>bBox)))
              )
            )
          )
          printf("*********\n*********\n")
          foreach(to_print '(leftEdgesList bottomEdgesList rightEdgesList topEdgesList) printf("%L : %L\n" to_print sort(CCFunique(eval(to_print)) 'lessp)))
          printf("*********\n*********\n")
          when(leftEdgesList leftEdgesList = apply('min sort(CCFunique(leftEdgesList) 'lessp)) printf("leftEdgesList : %L\n" leftEdgesList))
          when(bottomEdgesList bottomEdgesList = apply('min sort(CCFunique(bottomEdgesList) 'lessp)) printf("bottomEdgesList : %L\n" bottomEdgesList))
          when(rightEdgesList rightEdgesList = apply('max sort(CCFunique(rightEdgesList) 'lessp)) printf("rightEdgesList : %L\n" rightEdgesList))
          when(topEdgesList topEdgesList = apply('max sort(CCFunique(topEdgesList) 'lessp)) printf("topEdgesList : %L\n" topEdgesList))
          )
         
          ;**************
      ) ;let
    ) ;procedure
    ;findExtremesCoordinatesOfLayerFromCv(getEditRep(), list("NW" "drawing"), nil) 


    Cordially, Steven.
    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • Andrew Beckett
    Andrew Beckett over 1 year ago in reply to StevenR

    Steven,

    I think this is a bit more complicated than it needs to be, but a good attempt nevertheless! I think it might generate a lot of data by building lists of edges, plus you're appending to the end each time which could get slow for a large set of data. I've not really reviewed the code (sorry, just back from vacation and so don't have too much time). You might want to take a look at the approach for handling mosaics here (sorry, it's in LISP syntax, but hopefully you'll get the idea):

    How to flatten a specific layer and measure the total area of that layer ?

    However, if the data is always orthogonal or 45-degree (quite likely), you could take advantage of the abe functions (Advanced Boolean Engine). This code would do what you want quite efficiently and with little code (it handles the hierarchy automatically). I wrote it in C-style to match what you were doing:

    /***************************************************************
    *                                                              *
    *   abLayerExtent(lpp @optional (cvId geGetEditCellView()))    *
    *                                                              *
    *     First argument is either a layer name (in which case     *
    *  "drawing" is used as the purpose, or a list of layer name   *
    * and purpose. The second optional arguments is the cellView.  *
    *                                                              *
    ***************************************************************/
    
    procedure(abLayerExtent(lpp @optional (cvId geGetEditCellView()))
        let((lay iterator polygon ollx olly ourx oury firstPoint)
            when(stringp(lpp)
                lpp=list(lpp "drawing")
            )
            ;----------------------------------------------------------------
            ; The unwindProtect is to ensure the abeDone happens
            ; even if an error occurs in this block of code
            ;----------------------------------------------------------------
            unwindProtect(
                {
                    abeInit(cvId)
                    lay=abeLayerFromCellView(car(lpp) ?purpose cadr(lpp))
                    iterator=abeIslandIterator(lay)
                    while(polygon=iterator->next
                        unless(ollx 
                            firstPoint=car(polygon)
                            ollx=xCoord(firstPoint)
                            olly=yCoord(firstPoint)
                            ourx=ollx
                            oury=olly
                        )
                        foreach(point polygon
                            destructuringBind((x y) point
                                ollx=min(ollx x)
                                olly=min(olly y)
                                ourx=max(ourx x)
                                oury=max(oury y)
                            )
                        )
                    )
                }
                abeDone()
            )
            ;----------------------------------------------------------------
            ; if no points were found return nil, otherwise the
            ; bounding box
            ;----------------------------------------------------------------
            ollx && list(ollx:olly ourx:oury)
        )
    )

    Regards,

    Andrew

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • StevenR
    StevenR over 1 year ago in reply to Andrew Beckett

    Andrew, 

    Thank you for providing a detailed and clear explanation and code. You are right, I tried to work with dbShapeQuery but with a mosaic instancing another custom instance it was just complicated to handle and it made the code messy.

    This is working perfectly fine and the shapes that I'm working with are always orthogonal (can be any rotation but those are always 90°/180°/270°/360°) which will work with what you provided.

    The ABE is really useful and I will try to learn more about it.

    The mosaics were really problematic to handle with dbShapeQuery(), do you think this layout structure is okay to work with or is it better to use another form of "instance matrix" such as the groupeArrays ?

    I saw this and it looks promising and easier to define with flipping every even row for better Standard cells abutment for example.

    Thank you again for your answer.

    Steven.

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • StevenR
    StevenR over 1 year ago in reply to StevenR

    Okay I checked the groupArrays of instances and we can only get it from a window human interface interaction from a mosaic of instances which is problematic when trying to make an automative SKILL program.

    Also for the function :

    lxCreateGroupArray(d_cvId l_figList [ ?name t_name ] [ ?rows x_rows ] [ ?columns x_cols ] [ ?X x_xValue ] [ ?Y x_yValue ] [ ?orients l_orientList ] [ ?mode 'pitch | 'spacing ] [ ?lpp l_refLPP ])
    It is not specify the origin of the groupArray created, I guess it is the same origin as the object which the array is made of which is not great either. 
    And the argument "l_figList" is problematic when trying to make a groupArray not with shapes but with instances directly and I do not know if this is supported or intended to use that way. 
    Last but not least, I saw your post talking about the workaround "leMakeCell()" but this is not what I want.
    Steven.
    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • Andrew Beckett
    Andrew Beckett over 1 year ago in reply to StevenR

    Steven,

    Answering your last two posts is on my to-do list. I didn't have time to get to it today because of commitments in the day job. Hopefully tomorrow.

    Andrew

    • 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