bBox routine to ignore "text" layer

Discussion in 'Cadence' started by PolyPusher, Jan 12, 2010.

  1. PolyPusher

    PolyPusher Guest

    All,

    Here is the routine I came up with to ignore "text" layer. I use it
    for layout. We want to get the dataextent but wanted the ability to
    place text "outside" of the dataextent. Our tapeout data doesnt' have
    the text in it anyways.

    For example, we can place text for pad names, etc....

    Does the routine look solid enough? Any comments to make it better
    would be appreciated.

    Thank you,
    PolyPusher.

    procedure(EFbBox()
    let((cvbox EFbox EFLowestX EFLowestY EFHighestX EFHighestY EFFlag
    EFPrevLowestX EFPrevLowestY EFPrevHighestX EFPrevHighestY Xvar
    EFBoxVar
    EFSkip EFdataExtent dataExtent output EFXlow EFYlow EFXhigh EFYhigh)

    EFLowestX=nil EFLowestY=nil EFHighestX=nil EFHighestY=nil
    EFPrevLowestX=nil EFPrevLowestY=nil EFPrevHighestX=nil
    EFPrevHighestY=nil EFFlag=0 EFSkip=0
    EFXlow=nil EFYlow=nil EFXhigh=nil EFYhigh=nil

    cvBox=geGetEditCellView()
    geSelectAll()

    foreach(EFBox geGetSelectedSet(cvBox)
    EFBoxVar=list(EFBox~>bBox)
    ;lower left

    EFLowestX=car(car(car(EFBoxVar)))
    EFLowestYvar=nil
    EFLowestYvar=car(car(EFBoxVar))
    EFLowestY=cadr(EFLowestYvar)

    ;upper right
    EFHighestXvar=nil
    EFHighestXvar=cadr(car(EFBoxVar))
    EFHighestX=car(EFHighestXvar)
    EFHighestYvar=cadr(car(EFBoxVar))
    EFHighestY=cadr(EFHighestYvar)

    if(EFBox~>layerName!="text"
    then
    ;if this is the first in the foreach, set coordinate
    ;as reference
    if(EFFlag==0
    then EFPrevLowestX=EFLowestX
    EFPrevLowestY=EFLowestY
    EFPrevHighestX=EFHighestX
    EFPrevHighestY=EFHighestY
    );if

    EFFlag=EFFlag+1

    ;println(EFFlag)
    if(EFLowestX<=EFPrevLowestX
    then EFPrevLowestX=EFLowestX
    ;println(EFPrevLowestX)
    )
    if(EFLowestY<=EFPrevLowestY
    then EFPrevLowestY=EFLowestY
    )
    if(EFHighestX>=EFPrevHighestX
    then EFPrevHighestX=EFHighestX
    )
    if(EFHighestY>=EFPrevHighestY
    then EFPrevHighestY=EFHighestY
    )
    );if then for text
    );foreach

    geDeselectAll()
    ;make "dataExtent string" for output.

    print("(( ")
    print(EFPrevLowestX)
    print(" ")
    print(EFPrevLowestY)
    print(" ))")

    print("(( ")
    print(EFPrevHighestX)
    print(" ")
    print(EFPrevHighestY)
    print(" ))")

    EFXlow=sprintf(nil "%f" EFPrevLowestX)
    EFYlow=sprintf(nil "%f" EFPrevLowestY)
    EFXhigh=sprintf(nil "%f" EFPrevHighestX)
    EFYhigh=sprintf(nil "%f" EFPrevHighestY)

    EFdataExtent=append(EFdataExtent list(strcat("(( " EFXlow " " EFYlow
    " )" " " "( " EFXhigh " " EFYhigh " ))")))

    txtFile=strcat("/tmp/" cvBox~>cellName "_extent.txt")
    fp=outfile(txtFile)

    output=sprintf(nil "Data Extent for Cell %s is \n\n %L"
    cvBox~>cellName EFdataExtent)
    fprintf(fp "Data Extent for Cell %s is %L" cvBox~>cellName
    EFdataExtent)
    hiDisplayAppDBox(?name 'noLayerError
    ?dboxBanner "Information"
    ?dboxText output
    ?dialogType hicErrorDialog
    ?buttonLayout 'Close)

    close(fp)
    );end let
    );end procedure
     
    PolyPusher, Jan 12, 2010
    #1
  2. PolyPusher wrote, on 01/12/10 16:09:
    Hi Eric,

    A couple of things about your code above:

    1. It relies on selecting everything - which means that the cellView must be in
    a window, and everything must be selectable.
    2. It seems to do a lot of messing around with strings at the end
    3. It uses a flag to determine if it's the first or not - could just use the
    bBox you're collecting - if it's nil, it's never been set.

    Anyway, I just wrote a general function for finding the data extent, to which
    you can then pass a "selection" function to specify whether the object should be
    included or not:

    /* abDataExtent.ils

    Author A.D.Beckett
    Group Custom IC (UK), Cadence Design Systems Ltd.
    Language SKILL
    Date Jan 19, 2010
    Modified
    By

    Function to find the bBox (data extent) of a cellView, and
    select which objects to include in the calculation.

    For example:

    abDataExtent(?selectFn 'abDataExtentNoText)

    The abDataExtentNoText function is an example of the kind of
    function you can use to include or filter particular objects. It
    needs to return nil or non-nil depending on if you want the object
    omitted or included (respectively) in the data extent calculation

    ***************************************************

    SCCS Info: @(#) abDataExtent.il 01/19/10.13:26:07 1.1

    */


    /***************************************************************
    * *
    * abDataExtentNoText(obj) *
    * *
    * Example predicate function - includes any object except on *
    * Text layer *
    * *
    ***************************************************************/

    procedure(abDataExtentNoText(obj)
    obj~>layerName!="text"
    )

    /**********************************************************************
    * *
    * abDataExtent(@key (cellView geGetEditCellView()) selectFn) *
    * *
    * Function to find the extent of the data in a cellView, but allowing *
    * you to provide a predicate function to only include certain objects *
    * *
    **********************************************************************/

    procedure(abDataExtent(@key (cellView geGetEditCellView()) selectFn)
    let((bBox)
    ;----------------------------------------------------------------
    ; Cope with selectFn being nil - create a selection function
    ; that will include all objects
    ;----------------------------------------------------------------
    unless(selectFn
    selectFn=lambda((_obj) t)
    )
    ;----------------------------------------------------------------
    ; Iterate over each kind of object in the cellView
    ;----------------------------------------------------------------
    foreach(objs
    list(
    cellView~>shapes
    cellView~>instances
    cellView~>vias
    cellView~>figGroups
    cellView~>mosaics
    cellView~>blockages
    cellView~>rows
    cellView~>markers
    cellView~>areaBoundaries
    cellView~>guides
    cellView~>routes
    cellView~>steiners
    list(cellView~>prBoundary)
    list(cellView~>snapBoundary)
    )
    foreach(fig objs
    ;--------------------------------------------------------
    ; Make sure that it's not one of a known object which won't
    ; work, and also see if it is one of the objects you want to
    ; include in the data extent
    ;--------------------------------------------------------
    when(fig && fig~>objType!="mosaicInst" && funcall(selectFn fig)
    if(bBox then
    ;------------------------------------------------
    ; This is a compact way of getting the overall bBox
    ; of two bounding boxes
    ;------------------------------------------------
    bBox=list(
    mapcar('min lowerLeft(bBox) lowerLeft(fig~>bBox))
    mapcar('max upperRight(bBox) upperRight(fig~>bBox))
    )
    else
    bBox=fig~>bBox
    )
    ) ; when
    ) ; foreach fig
    ) ; foreach objs
    bBox
    ) ; let
    ) ; procedure abDataExtent


    If you want to then write the results to a file, you could do:

    procedure(EFbBox(@optional (cv geGetEditCellView()))
    let((txtFile fp bBox)
    bBox=abDataExtent(?cellView cv ?selectFn 'abDataExtentNoText)
    printf("Data Extent is %L\n" bBox)
    txtFile=strcat("/tmp/" cv~>cellName "_extent.txt")
    fp=outfile(txtFile)
    fprintf(fp "Data Extent for Cell %s is %L\n" cv~>cellName bBox)
    close(fp)
    )
    )

    The abDataExtent code should work with both IC61 and IC5141 (I didn't really
    test it exhaustively, and only in IC613).

    Just wanted to give you some ideas as to how this kind of thing can be
    generalized. You can also see the neat way it extends the bBox for each object
    encountered.

    Best Regards,

    Andrew.
     
    Andrew Beckett, Jan 19, 2010
    #2
  3. If all the filtering do is to check the LPP, I'd use cellview->lpps and
    filter directly on the lpp instead of filtering each object. (I first
    though of getting the bbox on the LPP but I can't find the SKILL equivalent
    of the OA API for that -- the lppheader has some bbox, but not the one
    needed here if I'm not mistaken)

    Yours,
     
    Jean-Marc Bourguet, Jan 19, 2010
    #3
  4. Jean-Marc Bourguet wrote, on 01/19/10 14:09:
    Hi Jean-Marc,

    I agree, although I was trying to ensure that I was also including instances and
    other non-shape objects in the calculation - which is why I did it the way I did.

    I also guessed you might do it via a select function such as:

    procedure(abDataExtentNoLabels(obj)
    obj~>objType!="label" && obj~>objType!="textDisplay"
    )

    abDataExtent(?selectFn 'abDataExtentNoLabels)

    As always, your mileage may vary.

    Regards,

    Andrew.
     
    Andrew Beckett, Jan 19, 2010
    #4
  5. PolyPusher

    PolyPusher Guest

    Andrew,

    Thank you for helping us on this. It means a lot as we are asked to
    put text on our finished work for reviews and take them out for
    tapeout. It is a real pain.

    The code seems to work great!(IC5141) I do have questions as I am
    trying to add to my SKILL set.

    Yup, I do see that my code would break because I assume everything is
    selectable. I have some learning to do on handling strings and any
    input on how I learn more would be great. Last, I wasn't really
    happy with the flag either, but I didn't see the obvious, I think you
    mean in the first round my variables would be nil and use an if then
    statement?

    I have some questions in regards to the code and I couldn't find an
    explanation in the online documentation.

    procedure(abDataExtent(@key (cellView geGetEditCellView()) selectFn)

    What does @key do? selectFn?
    ================
    foreach(objs
    list(
    cellView~>shapes
    cellView~>instances
    cellView~>vias
    cellView~>figGroups
    cellView~>mosaics
    cellView~>blockages
    cellView~>rows
    cellView~>markers
    cellView~>areaBoundaries
    cellView~>guides
    cellView~>routes
    cellView~>steiners
    list(cellView~>prBoundary)
    list(cellView~>snapBoundary)
    )
    =================
    I understand you are getting a list of all objects. Is this an
    exhaustive list of all objects that could be in layout?
    We are planning on having this code as part of our tapeout data
    extent, so it needs to be exact. From a user,
    perspective could I have come up with this list?
    =====================
    bBox=list(
    mapcar('min lowerLeft(bBox) lowerLeft
    (fig~>bBox))
    mapcar('max upperRight(bBox) upperRight
    (fig~>bBox))
    )
    else
    bBox=fig~>bBox
    )
    ========================

    Is the "lowerLeft", ect an attribute that the user can retrieve(or
    attribute call, not sure how to word that)? In my program, I
    struggled breaking down the lower x y and upper x y.

    Without all of you Cadence Gurus it would be a cold and dark world!
    Regards,
    Eric
     
    PolyPusher, Jan 19, 2010
    #5
  6. Hi Eric,

    I'll break my usual habit of responding at the end of the post, and intersperse
    my answers throughout, so they can have some context:

    PolyPusher wrote, on 01/19/10 16:25:
    Yes, in your code, you could have just used:

    unless(EFPrevLowestX
    EFPrevLowestX=EFLowestX
    EFPrevLowestY=EFLowestY
    ...
    )

    because EFPrevLowestX will have been initialized to nil in the let().
    In a function definition, if you use @key, it means that the things which follow
    will be keyword arguments (when called). So there are two keyword arguments in
    this case, ?cellView and ?selectFn. If the keyword argument is surrounded by
    parentheses (as with cellView), the second item in the list is the default value
    - so in this case, it will pick up the current cellView if one isn't passed in.
    The selectFn doesn't have a default value specified, so it will default to nil
    if it wasn't passed to the function.

    So this means you can do:

    myCv=dbOpenCellViewByType("lib" "cell" "view")
    abDataExtent(?selectFn 'abDataExtentNoLabels ?cellView myCv)

    As you can see here, I also specified the keyword arguments the other way around
    - they are passed by name, rather than by order.
    Yes. Although this is the list from IC61; in IC5141 it is simpler, as not all
    these objects exist. In fact I wish we had cellView~>figs - that would make life
    simpler (in fact I'm going to file an enhancement request asking for that).
    In IC5141 you don't have vias, figGroups, blockages, rows, markers,
    areaBoundaries, guides, routes, steiners, or a prBoundary or snapBoundary. So
    that just leaves shapes, instances and mosaics. In IC5141 it doesn't do any harm
    to look at the other things, because they won't be there.

    You can figure this out by looking in the documentation, and also at cv~>? to
    see what attributes there are.
    These are built in functions. A bBox is represented like this:

    ((llx lly) (urx ury))

    and lowerLeft() returns the first entry in the bBox list (it's not intelligent -
    it assumes the list is in the right order), and upperRight returns the second.
    Similarly there are xCoord and yCoord to do the same with coordinates.

    You could use functions like car and cadr, and things like cadar and so on, but
    it gets really messy and unreadable. Far easier to say:

    llx=xCoord(lowerLeft(obj~>bBox))

    wouldn't you say?

    I can see (by looking at your code again) that you got a bit confused, and
    you've introduced an additional list around your bBox (when you set EFBoxVar),
    and that has only made it even more confusing!
    No problem. Hopefully I can pass on some of my knowledge so that others can learn!

    Cheers,

    Andrew.
     
    Andrew Beckett, Jan 19, 2010
    #6
  7. PolyPusher

    PolyPusher Guest

    Andrew,

    Appreciate being so detailed. I have started with no knowledge a
    year and half ago of SKILL for Cadence
    and thanks to the Gurus here and the lengthy documentation by Cadence
    I am getting much better.

    Thank you!
    Eric
     
    PolyPusher, Jan 19, 2010
    #7
Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.