This is a short how-to manual on how to make and edit SKILL files to create Pcells for use in CADENCE.

This assumes you already have some experience creating and using Pcells using the graphic editor (Virtuoso) in CADENCE, in particular the stretch, conditional, and repeat commands. If you would like to learn how to make Pcells do things that you can't do from the graphical editor, read on.

We will look at a couple examples, "multiplank" and "honeycomb".

Example 1: "multiplank"

Suppose you want to make a set of rectangles of graduated length. You could draw and copy individual rectangles, and change their lengths by hand. You could also, since you know how to graphically create Pcells, create a repeating rectangle Pcell. However, the rectangles would all be the same length. This is a slight improvement over the first way though, because with a Pcell you can adjust the spacing very precisely. "But theres a dependent stretch field I can can fill in, and I could put in a SKILL formula to make the length vary with the repetition". Think again, CADENCE is too stupid to compile anything where a formula depends on something like pcIndex, because pcIndex has a NULL value until the individual objects are instantiated. So the only way to get around this is to make SKILL code bend to your will.

Here are the steps which make it easy to create and modify SKILL code:

1) Using the graphical editor, draw an approximate version of the Pcell you want to create. In this example, create a Pcell that has repeating rectangles. Don't worry about their length. Leave the default SKILL expression in the "stretch offset" field. (fix(pcRepeat)-1)*pcStep). Make sure that the rectangles have a stretching parameter, call it length. Put "length" in the dependent stretch field when creating the repeat.

2) Compile the Pcell to a SKILL file. By default this will go into your working directory, not the library you are wroking in. Change the cell name so that when you load the modified SKILL file back into CADENCE, you won't overwrite the Pcell that you are starting with.

3) Take a look at the code. It might look something like this:

pcDefinePCell(list(ddGetObj("skillexamples") "varylength" "layout") 
    ((step float 1.0)
	(number float 1.0)
    )
    let((length length0 length0offset pcMember pcStretchGroup
	    stretchOffsetX stretchOffsetY number step pcLib
	    pcMaster pcInst pcTerm pcPin pcPinName
	    pcNet pcTermNet pcNetName pcTermNetName pcMosaicInst
	    tpcParameters pcParamProp pcStep pcStepX pcStepYi
	    pcRepeat pcRepeatX pcRepeatY pcIndexX pcIndexY
	    pcLayer pcPurpose pcLabelText pcLabelHeight pcPropText
	    pcParamText pcCoords pcPathWidth pcPolygonMargin
	)
	(pcLib = (pcCellView~>lib)) 
	(pcParameters = ((pcCellView~>parameters)~>value)) 
	(pcParamProp = car(exists(prop pcParameters
		    ((prop~>name) == "number")
		)
	    ))
	(number = (pcParamProp~>value))
	if(((pcParamProp~>valueType) == "boolean") 
	    (number = (number == "TRUE"))
	)
	(pcParamProp = car(exists(prop pcParameters 
		    ((prop~>name) == "step")
		)
	    )) 
	(step = (pcParamProp~>value)) 
	if(((pcParamProp~>valueType) == "boolean") 
	    (step = (step == "TRUE"))
	) 
	(pcParamProp = car(exists(prop pcParameters 
		    ((prop~>name) == "length")
		)
	    ))
	(length = (pcParamProp~>value)) 
	if(((pcParamProp~>valueType) == "boolean") 
	    (length = (length == "TRUE"))
	) 
	(length0 = length) 
	if(!numberp(length0) 
	    (length0 = 11.0)
	) 
	(pcStepX = 0)
	(pcStep = (pcStepY = step)) 
	(pcRepeatX = 1) 
	(pcRepeat = (pcRepeatY = number)) 
	(length0 = (length0 + ((fix(pcRepeatY) - 1) * pcStepY))) 
	(length0offset = (length0 - 11))
	dbReplaceProp(pcCellView "viewSubType" "string" "maskLayoutParamCell") 
	(pcRepeat = (pcRepeatX = (pcRepeatY = 1.0))) 
	(pcStep = (pcStepX = (pcStepY = 0.0))) 
	(pcStep = (pcStepY = car(errset(step)))) 
	(pcRepeat = (pcRepeatY = number))
	(pcStep = (pcStepY = step)) 
	(pcIndexX = 0) 
	for(pcIndexY 0 
	    (fix(pcRepeatY) - 1) nil 
	    (pcLayer = 13)
	    (pcPurpose = "drawing") 
	    (pcInst = dbCreateRect(pcCellView 
		    list(pcLayer pcPurpose) 
		    list((-5:(-1 + (pcIndexY * pcStepY))) 
			((6 + length0offset):(1 + (pcIndexY * pcStepY)))
		    )
		))
	) t
    )
)

In the first line, you see that when this is loaded into CADENCE a Pcell called "varylength", of type "layout" will be created in the library "skillexamples". the second and third lines give the default values of step and number, which will appear in the box when you create an instance of varylength. (the type of variable is float). "let" lists all the variables used in the Pcell. If you add any, be sure to add them to this list. Similarly, you should copy the stuff that starts with "(pcParamProp = ..." for each variable. I don't know what this does.

The last ten or so lines is the loop used to create the repeating rectangles. The loop variable is pcIndexY, and varies from 0 to pcRepeatY-1. 13 is the layer (MUMPS Poly0 in this case). dbCreateRect() creates rectangles. They are described by the coordinates of their corners. Note that the y coordinate depends on pcIndexY*pcStepY. This places each new rectangle in a new position. If you wanted to make the length in the x-direction vary, you can edit the code to put in whatever expression you like for the x coordinate, which can depend on pcIndexY. You also need to get rid of the dependence of length0 on the expression (fix(pcRepeatY)-1)*pcStepY. We left it in so that we could easily see what part of the loop depends on the length parameter.

Loading it back into CADENCE

In order for this to be useful, we have to load the edited SKILL code into CADENCE.

In the command window, type

load("varylength")

This instructs CADENCE to take the SKILL code and create a new cell in the library indicated in the first line of the SKILL code, in this case, "skillexamples". THIS NEW PCELL IS NOT EDITABLE WITHIN THE VIRTUOSO EDITOR. That is why we took steps to make sure we changed the name of the cell either when we compile the original Pcell to SKILL code, or changed the name of the created cell by editing the first line of code.

You can now create instances of this new Pcell in your layout the same way as if you had designed the Pcell graphically.

Example 2: The honeycomb

In this Pcell I wanted to make a repeating hexagon shape, where I could vary both the thickness of the walls and the overall size of the cells. Here's the procedure I followed:

1) I sketched out the "unit cell" of a honeycomb on a piece of paper, and calculated the coordinates of the vertices. I assumed for nice round numbers that the side of the hexagon was 100 microns.

2) I then used Virtuoso to sketch out the shape of the unit cell. There's no need to get the vertices in exactly, because they should be fixed when you edit the SKILL file. I used the "path" commend to draw the lines, because the path width is a parameter that can be easily changed in the SKILL file. It makes thing easier if you line up some of the vertices with the origin and/or the axes.

3) I chose the "Repeat in X and Y" option in the Pcell menu, and put in the appropriate distances.

4) Compiled to SKILL file. Put in new variables "width" and "scale". I multiplied all the coordinates of the vertices by "scale", including the value of pcStep. The original and modified code are shown below.

original SKILL code:

pcDefinePCell(list(ddGetObj("deepmirrors") "honeycomb" "layout") 
    ((xnumber float 1.0) 
	(ynumber float 1.0)
    ) 
    let((pcMember pcStretchGroup stretchOffsetX stretchOffsetY ynumber
	    xnumber pcLib pcMaster pcInst pcTerm
	    pcPin pcPinName pcNet pcTermNet pcNetName
	    pcTermNetName pcMosaicInst tpcParameters pcParamProp pcStep
	    pcStepX pcStepY pcRepeat pcRepeatX pcRepeatY
	    pcIndexX pcIndexY pcLayer pcPurpose pcLabelText
	    pcLabelHeight pcPropText pcParamText pcCoords pcPathWidth
	    pcPolygonMargin
	) 
	(pcLib = (pcCellView~>lib)) 
	(pcParameters = ((pcCellView~>parameters)~>value)) 
	(pcParamProp = car(exists(prop pcParameters 
		    ((prop~>name) == "ynumber")
		)
	    )) 
	(ynumber = (pcParamProp~>value))
	if(((pcParamProp~>valueType) == "boolean") 
	    (ynumber = (ynumber == "TRUE"))
	) 
	(pcParamProp = car(exists(prop pcParameters 
		    ((prop~>name) == "xnumber")
		)
	    )) 
	(xnumber = (pcParamProp~>value)) 
	if(((pcParamProp~>valueType) == "boolean") 
	    (xnumber = (xnumber == "TRUE"))
	) 
	dbReplaceProp(pcCellView "viewSubType" "string" "maskLayoutParamCell")
	(pcRepeat = (pcRepeatX = (pcRepeatY = 1.0))) 
	(pcStep = (pcStepX = (pcStepY = 0.0))) 
	(pcStepX = car(errset(173.205))) 
	(pcStepY = car(errset(300))) 
	(pcRepeatX = xnumber)
	(pcRepeatY = ynumber) 
	(pcStepX = 173.205) 
	(pcStepY = 300) 
	for(pcIndexX 0 
	    (fix(pcRepeatX) - 1) 
	    for(pcIndexY 0 
		(fix(pcRepeatY) - 1) nil 
		(pcLayer = 62)
		(pcPurpose = "drawing") 
		(pcInst = dbCreatePath(pcCellView 
			list(pcLayer pcPurpose) 
			list(((87.801 + (pcIndexX * pcStepX)):(149.422 + (pcIndexY * pcStepY))) 
			    ((173.2 + (pcIndexX * pcStepX)):(100 + (pcIndexY * pcStepY)))
			) 2 "truncateExtend"
		    )) 
		(pcLayer = 62) 
		(pcPurpose = "drawing") 
		(pcInst = dbCreatePath(pcCellView 
			list(pcLayer pcPurpose) 
			list(((0 + (pcIndexX * pcStepX)):(0 + (pcIndexY * pcStepY))) 
			    ((0 + (pcIndexX * pcStepX)):(100 + (pcIndexY * pcStepY))) 
			    ((86.8 + (pcIndexX * pcStepX)):(150 + (pcIndexY * pcStepY))) 
			    ((86.6 + (pcIndexX * pcStepX)):(250.1 + (pcIndexY * pcStepY))) 
			    ((173.2 + (pcIndexX * pcStepX)):(300 + (pcIndexY * pcStepY)))
			    ((259.8 + (pcIndexX * pcStepX)):(249.9 + (pcIndexY * pcStepY)))
			) 2 "truncateExtend"
		    ))
	    )
	) t
    )
)

modified code: (lets you control wall width, overall size)

Note that I've created some new variables, scale???, to reduce the number of multiplications within loops. I don't think it helped much though.

pcDefinePCell(list(ddGetObj("deepmirrors") "honeycomb" "layout") 
    ((xnumber float 20.0) 
	(ynumber float 15.0)
	(width float 65.0)
	(scale float 1.0)
    ) 
    let((pcMember pcStretchGroup stretchOffsetX stretchOffsetY ynumber
		width scale
	    xnumber pcLib pcMaster pcInst pcTerm
	    pcPin pcPinName pcNet pcTermNet pcNetName
	    pcTermNetName pcMosaicInst tpcParameters pcParamProp pcStep
	    pcStepX pcStepY pcRepeat pcRepeatX pcRepeatY
	    pcIndexX pcIndexY pcLayer pcPurpose pcLabelText
	    pcLabelHeight pcPropText pcParamText pcCoords pcPathWidth
	    pcPolygonMargin
	) 
	(pcLib = (pcCellView~>lib)) 
	(pcParameters = ((pcCellView~>parameters)~>value)) 
	(pcParamProp = car(exists(prop pcParameters 
		    ((prop~>name) == "ynumber")
		)
	    )) 
	(ynumber = (pcParamProp~>value))
	if(((pcParamProp~>valueType) == "boolean") 
	    (ynumber = (ynumber == "TRUE"))
	) 
	(pcParamProp = car(exists(prop pcParameters 
		    ((prop~>name) == "width")
		)
	    )) 
	(width = (pcParamProp~>value)) 
	if(((pcParamProp~>valueType) == "boolean") 
	    (width = (width == "TRUE"))
	) 
	(pcParamProp = car(exists(prop pcParameters 
		    ((prop~>name) == "scale")
		)
	    )) 
	(scale = (pcParamProp~>value)) 
	if(((pcParamProp~>valueType) == "boolean") 
	    (scale = (scale == "TRUE"))
	) 
	(pcParamProp = car(exists(prop pcParameters 
		    ((prop~>name) == "xnumber")
		)
	    )) 
	(xnumber = (pcParamProp~>value)) 
	if(((pcParamProp~>valueType) == "boolean") 
	    (xnumber = (xnumber == "TRUE"))
	) 
	dbReplaceProp(pcCellView "viewSubType" "string" "maskLayoutParamCell")
	(pcRepeat = (pcRepeatX = (pcRepeatY = 1.0))) 
	(pcStep = (pcStepX = (pcStepY = 0.0))) 
	(pcStepX = car(errset(scale*173.205))) 
	(pcStepY = car(errset(scale*300))) 
	(pcRepeatX = xnumber)
	(pcRepeatY = ynumber) 
	(pcStepX = scale*173.205) 
	(pcStepY = scale*300) 
	(scale86 = scale*86.6)
	(scale100 = scale*100)
	(scale150 = scale*150)
	(scale173 = scale*173.2)
	(scale250 = scale*250)
	(scale259 = scale*259.8)
	(scale300 = scale*300)
	for(pcIndexX 0 
	    (fix(pcRepeatX) - 1) 
	    for(pcIndexY 0 
		(fix(pcRepeatY) - 1) nil 
		(pcLayer = 62)
		(pcPurpose = "drawing") 
		(pcInst = dbCreatePath(pcCellView 
			list(pcLayer pcPurpose) 
			list(((scale86 + (pcIndexX * pcStepX)):(scale150 + (pcIndexY * pcStepY))) 
			    ((scale173 + (pcIndexX * pcStepX)):(scale100 + (pcIndexY * pcStepY)))
			) width "truncateExtend"
		    )) 
		(pcLayer = 62) 
		(pcPurpose = "drawing") 
		(pcInst = dbCreatePath(pcCellView 
			list(pcLayer pcPurpose) 
			list(((0 + (pcIndexX * pcStepX)):(0 + (pcIndexY * pcStepY))) 
			    ((0 + (pcIndexX * pcStepX)):(scale100 + (pcIndexY * pcStepY))) 
			    ((scale86 + (pcIndexX * pcStepX)):(scale150 + (pcIndexY * pcStepY))) 
			    ((scale86 + (pcIndexX * pcStepX)):(scale250 + (pcIndexY * pcStepY))) 
			    ((scale173 + (pcIndexX * pcStepX)):(scale300 + (pcIndexY * pcStepY)))
			    ((scale259 + (pcIndexX * pcStepX)):(scale250 + (pcIndexY * pcStepY)))
			) width "truncateExtend"
		    ))
	    )
	) t
    )
)

Questions? contact me at jneumann@ece.cmu.edu
Last updated August 4, 1998