• 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 Design
  3. Creating Circles in layout

Stats

  • Locked Locked
  • Replies 5
  • Subscribers 125
  • Views 18073
  • 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

Creating Circles in layout

RakeshPRG
RakeshPRG over 6 years ago

Hi,

I am trying to create a circle in my layout with smallest possible resolution (PDK suggests 5 nm). For this, I used the SKILL code posted before on this forum. The code works for the radius 1 um and grid size 5 nm and the shape passes the DRC. But I need the circle to be designed for atleast a 20 um radius(circle shown in circle 1um.png). When I try to do this for the 20 um radius (circle 20 um.png), I get a circle chopped off into sectors and the DRC fails. I am new to SKILL and I do not undertsand the reason behind this. Can someone please help me understand this issue and provide a solution that works for 20 um radius without theDRC errors.

The skill code for generating the circle is...

Direction

      5 6 7
      \    |    /
    4 - O - 0
      /  |   \
      3 2 1

--- Using it ---

You'll need to modify the call to pcDefinePCell() below to specify your
preferred library/cell names and possibly the default radius, grid and layer.
Once you've done that just use 'load("/path/to/circlePcell.il")' in the CIW or
the libInit.il file for your library.

*/
(defun RALgetNextPoint (direction X Y grid radius)
  (let (X0 Y0 R0 D0 X1 Y1 R1 D1 X2 Y2 R2 D2 X3 Y3 R3 D3 X4 Y4 R4 D4
    X5 Y5 R5 D5 X6 Y6 R6 D6 X7 Y7 R7 D7 ret)
    
    (if direction == 0 || direction == 1 || direction == 7 then
      (X0 = X + grid)
      (Y0 = Y)
      (R0 = (X0**2 + Y0**2)**0.5)
      (D0 = (abs R0 - radius)))

    (if direction == 1 || direction == 2 || direction == 0 then
      (X1 = X + grid)
      (Y1 = Y - grid)
      (R1 = (X1**2 + Y1**2)**0.5)
      (D1 = (abs R1 - radius)))

    (if direction == 2 || direction == 3 || direction == 1 then
      (X2 = X)
      (Y2 = Y - grid)
      (R2 = (X2**2 + Y2**2)**0.5)
      (D2 = (abs R2 - radius)))

    (if direction == 3 || direction == 4 || direction == 2 then
      (X3 = X - grid)
      (Y3 = Y - grid)
      (R3 = (X3**2 + Y3**2)**0.5)
      (D3 = (abs R3 - radius)))

    (if direction == 4 || direction == 5 || direction == 3 then
      (X4 = X - grid)
      (Y4 = Y)
      (R4 = (X4**2 + Y4**2)**0.5)
      (D4 = (abs R4 - radius)))

    (if direction == 5 || direction == 6 || direction == 4 then
      (X5 = X - grid)
      (Y5 = Y + grid)
      (R5 = (X5**2 + Y5**2)**0.5)
      (D5 = (abs R5 - radius)))

    (if direction == 6 || direction == 7 || direction == 5 then
      (X6 = X)
      (Y6 = Y + grid)
      (R6 = (X6**2 + Y6**2)**0.5)
      (D6 = (abs R6 - radius)))

    (if direction == 7 || direction == 0 || direction == 6 then
      (X7 = X + grid)
      (Y7 = Y + grid)
      (R7 = (X7**2 + Y7**2)**0.5)
      (D7 = (abs R7 - radius)))

    (caseq direction
           (0
            /* Possible 7 0 1 */
            (if D0 < D1 && D0 < D7 then
              /* Go D0 */
              (ret = (list X0 Y0 0))
              else
              (if D1 < D0 && D1 < D7 then
                /* Go D1 */
                (ret = (list X1 Y1 1))
                else
                /* Go D7 */
                (ret = (list X7 Y7 7))
                )
              )
            )

           (1
            /* Possible 0 1 2 */
            (if D1 < D2 && D1 < D0 then
              /* Go D1 */
              (ret = (list X1 Y1 1))
              else
              (if D2 < D1 && D2 < D0 then
                /* Go D2 */
                (ret = (list X2 Y2 2))
                else
                /* Go D0 */
                (ret = (list X0 Y0 0))
                )
              )
            )

           (2
            /* Possible 1 2 3 */
            (if D2 < D3 && D2 < D1 then
              /* Go D2 */
              (ret = (list X2 Y2 2))
              else
              (if D3 < D2 && D3 < D1 then
                /* Go D3 */
                (ret = (list X3 Y3 3))
                else
                /* Go D1 */
                (ret = (list X1 Y1 1))
                )
              )
            )

           (3
            /* Possible 2 3 4 */
            (if D3 < D4 && D3 < D2 then
              /* Go D3 */
              (ret = (list X3 Y3 3))
              else
              (if D4 < D3 && D4 < D2 then
                /* Go D4 */
                (ret = (list X4 Y4 4))
                else
                /* Go D2 */
                (ret = (list X2 Y2 2))
                )
              )
            )

           (4
            /* Possible 3 4 5 */
            (if D4 < D5 && D4 < D3 then
              /* Go D4 */
              (ret = (list X4 Y4 4))
              else
              (if D5 < D4 && D5 < D3 then
                /* Go D5 */
                (ret = (list X5 Y5 5))
                else
                /* Go D3 */
                (ret = (list X3 Y3 3))
                )
              )
            )

           (5
            /* Possible 4 5 6 */
            (if D5 < D6 && D5 < D4 then
              /* Go D5 */
              (ret = (list X5 Y5 5))
              else
              (if D6 < D5 && D6 < D4 then
                /* Go D6 */
                (ret = (list X6 Y6 6))
                else
                /* Go D4 */
                (ret = (list X4 Y4 4))
                )
              )
            )

           (6
            /* Possible 5 6 7 */
            (if D6 < D7 && D6 < D5 then
              /* Go D6 */
              (ret = (list X6 Y6 6))
              else
              (if D7 < D6 && D7 < D5 then
                /* Go D7 */
                (ret = (list X7 Y7 7))
                else
                /* Go D5 */
                (ret = (list X5 Y5 5))
                )
              )
            )

           (7
            /* Possible 6 7 0 */
            (if D7 < D0 && D7 < D6 then
              /* Go D7 */
              (ret = (list X7 Y7 7))
              else
              (if D0 < D7 && D0 < D6 then
                /* Go D0 */
                (ret = (list X0 Y0 0))
                else
                /* Go D6 */
                (ret = (list X6 Y6 6))
                )
              )
            )

         )
  ret
  ))

pcDefinePCell(list(ddGetObj("ph90wg") "disk1" "layout")
    ((Radius float 1.0) (Grid float 0.005) (Layer string "RX"))
    let(( pcParameters pcParamProp pcLayer pcPurpose polyList
        X Y direction ret cheese points)

    (pcParameters = ((pcCellView~>parameters)~>value))

    (pcParamProp = car(exists(prop pcParameters ((prop~>name) == "Radius"))))
    (Radius = (pcParamProp~>value))

    (pcParamProp = car(exists(prop pcParameters ((prop~>name) == "Grid"))))
    (Grid = (pcParamProp~>value))

    (pcParamProp = car(exists(prop pcParameters ((prop~>name) == "Layer"))))
    (Layer = (pcParamProp~>value))

    (dbReplaceProp pcCellView "viewSubType" "string" "maskLayoutParamCell")

    (polyList = nil)

    (X = 0.0)
    (Y = Radius)
    (direction = 0)

    (pcLayer = Layer)
    (pcPurpose = "drawing")

    (polyList = (tconc polyList (list X Y)))
    (ret = (RALgetNextPoint direction X Y Grid Radius))
    (X = (car ret))
    (Y = (cadr ret))
    (direction = (caddr ret))
    (polyList = (tconc polyList (list X Y)))
    (points = 1)
    (cheese = 0)
    (while !( (abs X) < Grid && (abs Radius-Y) < Grid)
           (points = points + 1)
           (ret = (RALgetNextPoint direction X Y Grid Radius))
           (X = (car ret))
           (Y = (cadr ret))
           (direction = (caddr ret))
           (polyList = (tconc polyList (list X Y)))

           /* Split into multiple polygons if the number of points will exceed
            * the maximum. If this happens, the final polygon must contain an
            * additional point at 0,0 so that it closes properly. This is
            * controlled with the "cheese" variable because the output shape
            * resembles a round cheese chopped into pieces. */
           (if points == 2047 then
             (polyList = (tconc polyList (list 0.0 0.0)))
             (dbCreatePolygon pcCellView
                              (list pcLayer pcPurpose)
                              (car polyList))
             (points = 0)
             (cheese = 1)
             (polyList = (tconc nil (list X Y)))
             )
           )

    (if (onep cheese) then
      (polyList = (tconc polyList (list 0.0 0.0)))
      )

    (dbCreatePolygon pcCellView
                     (list pcLayer pcPurpose)
                     (car polyList))
    t
    )
    )

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

    As far as I can see, if you use this PCell with a radius of 20, and a grid of 0.005, all the points in the various slices are all on-grid. I assume this came from this post: https://community.cadence.com/cadence_technology_forums/f/custom-ic-design/11890/creating-circle-in-virtuoso/15769#15769 

    The chopping into sections is because Virtuoso has a historical limit of 4000 points per polygon, and so you can't create a polygon directly that has more than that number of points - this code works (as far as I can see) by creating a number of different slices when the point count is exceeded.

    I didn't run Calibre on this (because I don't have it, nor do I have the rules you're using), but I placed an instance, flattened it, and then ran:

    let((shapeOffGrid)
        foreach(shape geGetEditCellView()~>shapes
            shapeOffGrid=nil
            foreach(point shape~>points
                when(mod(round(xCoord(point)*1000) 5)!=0 ||
                    mod(round(yCoord(point)*1000) 5)!=0
                    printf("Off grid %L\n" point)
                    shapeOffGrid=t
                )
            )
            when(shapeOffGrid
                geSelectFig(shape)
            )
        )
    )

    Regards,

    Andrew

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • RakeshPRG
    RakeshPRG over 6 years ago in reply to Andrew Beckett

    Hi Andrew,

    Thanks for the reply. I don't know how to use the snippet of the code you mentioned above. I tried to run it in a separate skill file and also added it to the existing skill code. The structure created using the above code does not comply with the DRC rules. I am trying to circumvent this problem. So I also used another SKILL code you have provided in one of the previous forums. The code goes as

    procedure(abGriddedCircle(cellView lpp radius grid)
        let((point numSteps radSq pointList y)
            radSq=radius**2
            numSteps=round(radius/grid)
            foreach(sign '(1 -1)
                for(step -numSteps numSteps
                    y=round(sign*sqrt(radSq-(step*grid)**2)/grid)*grid
                    point=step*grid:y
                    when(pointList
                        pointList=cons(xCoord(car(pointList)):y pointList)
                    )
                    pointList=cons(point pointList)
                )
            )
            dbCreatePolygon(cellView lpp pointList)
        )
    )

    and then using the abgriddedCircle function, I could create circles of different radii and also multiple circle in the same layout very conveniently. But I face an error when I try the 20 um radius and 0.005 grid. The error details invalid point list (as shown in the attached fig). Can you suggest how to overcome this and create the circle?

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • Andrew Beckett
    Andrew Beckett over 6 years ago in reply to RakeshPRG
    RakeshPRG said:
    Thanks for the reply. I don't know how to use the snippet of the code you mentioned above. I tried to run it in a separate skill file and also added it to the existing skill code

    To use it, I placed an instance of your pcell, flattened it, and then just did load("checkCode.il") in the CIW where checkCode.il is the file containing the grid checking code I provided. I didn't add much fanciness around it because it was just a quick check - so I suggest you don't try running it on a layout which has anything other than one flattened instance of the pcell. It makes no sense to  include it in the pcell code itself.

    That said, I can't really comment on what your DRC checks are doing as I don't have any visibility on these.

    The abGriddedCircle fails because it makes no attempt to ensure that there are fewer than 4000 points in the polygon, and such a large circle will result in more points. I made a change to the code below, and now it will produce a set of abutting polygons representing slices of the circle so that no polygon has too many points:

    /* abGriddedCircle.il
    
    Author     A.D.Beckett
    Group      Custom IC (UK), Cadence Design Systems Ltd.
    Language   SKILL
    Date       Nov 11, 2018 
    Modified   
    By         
    
    Have updated abGriddedCircle to split into pieces with
    fewer than 4000 points
    
    ***************************************************
    
    SCCS Info: @(#) abGriddedCircle.il 11/11/18.17:30:10 1.2
    
    */
    
    /*****************************************************************
    *                                                                *
    *           abGriddedCircle(cellView lpp radius grid)            *
    *                                                                *
    * Draw a circle as a polygon, with all the points on a specified *
    *               grid, with all angles 90 degrees.                *
    *                                                                *
    *****************************************************************/
    
    procedure(abGriddedCircle(cellView lpp radius grid)
        let((point numSteps radSq pointList halfPointList 
                listOfHalfPointLists y (pointCount 0))
            radSq=radius**2
            numSteps=round(radius/grid)
            for(step -numSteps numSteps
                y=round(sqrt(radSq-(step*grid)**2)/grid)*grid
                point=step*grid:y
                when(halfPointList
                    halfPointList=cons(xCoord(car(halfPointList)):y halfPointList)
                )
                halfPointList=cons(point halfPointList)
                ;------------------------------------------------------------
                ; Note that there are really two points added for each pointCount
                ; so check when we reach a quarter of the maximum number of points
                ;------------------------------------------------------------
                pointCount++
                when(pointCount>=960
                    listOfHalfPointLists=cons(halfPointList listOfHalfPointLists)
                    halfPointList=list(point)
                    pointCount=0
                )
            )
            ;----------------------------------------------------------------
            ; Add the remaining halfPointList on, unless only just started
            ;----------------------------------------------------------------
            unless(zerop(pointCount)
                listOfHalfPointLists=cons(halfPointList listOfHalfPointLists)
            )
            ;----------------------------------------------------------------
            ; Iterate over all the half point lists, and create polygons from
            ; each half point list, together with the flipped other half
            ;----------------------------------------------------------------
            foreach(mapcar halfPointList listOfHalfPointLists
                pointList=nil
                ;----------------------------------------------------------------
                ; Build the complete point list from two halves, one flipped
                ;----------------------------------------------------------------
                pointList=lconc(pointList 
                    foreach(mapcar xy reverse(halfPointList) xCoord(xy):-yCoord(xy))
                )
                pointList=lconc(pointList halfPointList)
                dbCreatePolygon(cellView lpp car(pointList))
            )
        )
    )
    

    So perhaps give that a try. Not sure why this should be any better in terms of being on-grid than the original code, but at least all the segments are orthogonal (which they aren't in the earlier code you were trying).

    Regards,

    Andrew.

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • RakeshPRG
    RakeshPRG over 6 years ago in reply to Andrew Beckett

    Hi Andrew,

    Thanks. Using this code, I could generate the required circle. I am curious point count bound 960 specified in the code. I believe its like one fourth of the maximum which could be like 3840. How did you determine these maximum number of points?

    -Rakesh.

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
Reply
  • RakeshPRG
    RakeshPRG over 6 years ago in reply to Andrew Beckett

    Hi Andrew,

    Thanks. Using this code, I could generate the required circle. I am curious point count bound 960 specified in the code. I believe its like one fourth of the maximum which could be like 3840. How did you determine these maximum number of points?

    -Rakesh.

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
Children
  • Andrew Beckett
    Andrew Beckett over 6 years ago in reply to RakeshPRG

    The limit is 4000. I just picked a number which was less than a quarter of that without me needing to think too carefully about precisely how I was counting the number of points. So I arbitrarily picked 960 as it's less than 1000. 1000 wouldn't have worked (I just tried) as some of the point lists end up too long.

    So it was mostly laziness - I didn't want to think about it too much!

    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