Product Documentation
Virtuoso Parameterized Cell Reference
Product Version IC23.1, September 2023

5


Creating SKILL++ Parameterized Cells

The Pcell source is typically written in SKILL, which is a multi-paradigm language. However, you can also write the Pcell source in SKILL++ along with the existing APIs.

Advantages of SKILL++ Pcells

You can create individual Pcells using SKILL++ classes and methods that leverage the Object Oriented Programming (OOP) concepts. Using multiple class inheritance, it is possible to create a new Pcell by inheriting from other Pcell classes.

Using SKILL++ Pcells renders the following advantages of OOP:

Recommended and Supported SKILL++ Functions for Pcells

The following pc functions can be used for SKILL++ Pcells.

Steps to Create SKILL++ Pcell

The following steps illustrate creation of a simple SKILL++ Pcell using the existing pcDefinePCell API, which has the Pcell source body implemented in SKILL++. To view the complete sample code, see the SKILL++ Pcell Samples section.

  1. Define a base class (PcellParam) with a single slot for holding the Pcell master ID, which is the same as the pcCellView variable used in SKILL Pcell.
  2. Define a class to represent the Pcell. This class is defined by inheriting from PcellParam (or using PcellParam as its superclass).
  3. Define a method (setPcellParams) to transfer the Pcell parameter values to the slots of the Pcell class. This ensures that the Pcell code written in SKILL++ has full access to the same set of Pcell parameters.
  4. Define a method (draw) to construct the Pcell.
  5. Implement the code to call pcDefinePCell to create the supermaster.

SKILL++ Pcell Samples

You need to perform the following steps to setup SKILL++ Pcells:

  1. Load generic.ils, PcellParam.ils, CORE.ils, RING.ils, and WRAP.ils. These files are required for successful Pcell evaluation.
  2. Load genPcell.il. This file is only needed to create the Pcell supermasters.
  3. Load genPcDef.il only if you need to create the pcDefinePCell code from Pcell class.

Refer to the following sample code to setup SKILL++ Pcell.

; Start of file - generic.ils
; Defines the generic function for draw.
; This is placed in its own file as this should be loaded
; once as redefining a generic function will remove all methods 
; defined by previous defgeneric form 
(defgeneric draw (device)
 t
)
; End of file - generic.ils


; Start of file - PcellParam.ils
; Base class for all Pcells.  
; cvId will hold the pcCellView value
defclass( PcellParam () 
 (
  (cvId @initarg cvId)
 )
)
; A simple method to populate the Pcell parameters from the supermaster to
; a Pcell device's slots
defmethod( setPcellParams ((device PcellParam) cv)
 when( cv && dbIsId(cv)
  setSlotValue(device 'cvId cv)
  foreach( param cv~>parameters~>value
     setParamValue(device concat(param~>name) param~>value)
  )
 )
)
; A function to define a Pcell parameter stored as a Pcell class' slot.
; The optional argument _isParam is set to 't to indicate this parameter is
; a Pcell parameter
defun( defineParam (g_type g_value @optional (_isParam t))
    list(nil 'type g_type 'value g_value 'isParam _isParam)
)
; A method to get Pcell parameter's type
defmethod( getParamType ((device PcellParam) (propName symbol))
 slotValue(device propName)->type
)
; A method to get Pcell parameter's value
defmethod( getParamValue ((device PcellParam) (propName symbol))
 slotValue(device propName)->value
)
; A method to set Pcell parameter's value
defmethod( setParamValue ((device PcellParam) (propName  symbol) val)
 slotValue(device propName)->value = val
)
; A method to check is the given name a Pcell parameter or not. This is 
; based on the setting of the isParam attribute
defmethod( isParam ((device PcellParam) (propName symbol))
 slotValue(device propName)->isParam
)
; A method to get a list of Pcell parameters with their names, types and
; values
defmethod( getPcellParams ((device PcellParam))
    let((params)
  params = setof( p device->? isParam(device p ))
  params = foreach( mapcar p params
   list( p 
    getParamType(device p) 
    getParamValue(device p)
   )
  )
 )
)
; End of file - PcellParam.ils

; Start of file - CORE.ils
; Defines a CORE class inheriting from PcellParam
; Note, parameter created via defineParam will be treated
; as a Pcell parameter; otherwise it is treated as a normal
; class slot (e.g. coreBBox is not a Pcell parameter)
; You can replace the library name mentioned here with your own library.
defclass( CORE (PcellParam)
 (
  (cyanW @initform defineParam("float" 0.6))   
  (cyanL @initform defineParam("float" 0.2))   
  (greenW @initform defineParam("float" 0.2))  
  (greenL @initform defineParam("float" 0.8))  
  (coreBBox @initarg coreBBox)
 )
)
; Draw a simple cross represented by two rectangles
defmethod( draw ((device CORE))
 let((cv cyanW cyanL greenW greenL rectId llx lly urx ury)
  cyanW = getParamValue(device 'cyanW)
  cyanL = getParamValue(device 'cyanL)
  greenW = getParamValue(device 'greenW)
  greenL = getParamValue(device 'greenL)
  ; layers are choosen for their color's visibility
  ; You can replace the layer names mentioned here with the layer names
  ; present in your library.
  cv = slotValue(device 'cvId)
  rectId = dbCreateRect(cv 
   list("Poly" "drawing") list(0:0 greenL:greenW))
  llx = 0.5 * greenL - 0.5 * cyanL
  lly = 0.5 * greenW - 0.5 * cyanW
  urx = 0.5 * greenL + 0.5 * cyanL
  ury = 0.5 * greenW + 0.5 * cyanW
  rectId = dbCreateRect(cv
   list("Via1" "drawing") list(llx:lly urx:ury))
   setSlotValue(device 'coreBBox list( 0.0:lly greenL:ury))
  callNextMethod()
 )
)
; Returns CORE's bounding box which is stored in the coreBBox slot
defmethod( getCoreBBox ((device CORE))
    slotValue(device 'coreBBox)
)
; End of file - CORE.ils

; Start of file - RING.ils
; Defines a RING class inheriting from PcellParam
defclass( RING (PcellParam)
 (
  (ringW @initform  defineParam("float" 0.1))
  (ringS @initform  defineParam("float" 0.1)) 
 )
)
; Draw a polygon that wraps around the device's coreBBox with a given
; spacing value and width of the polygon
defmethod( draw ((device RING))
 let((cv ringS ringW coreBBox llx lly urx ury pts ring)
  ringS = getParamValue(device 'ringS)
  ringW = getParamValue(device 'ringW)
  coreBBox = getCoreBBox(device)
  llx = xCoord( lowerLeft(coreBBox))
  lly = yCoord( lowerLeft(coreBBox))
  urx = xCoord( upperRight(coreBBox))
  ury = yCoord( upperRight(coreBBox))
  pts = list( 
   llx-ringS:lly-ringS   ; points on inner edges
   urx+ringS:lly-ringS  
   urx+ringS:ury+ringS 
   llx-ringS:ury+ringS 
   llx-ringS:lly-ringS-ringW   ; extending to outer edge
   llx-ringS-ringW:lly-ringS-ringW ; points on outer edges
   llx-ringS-ringW:ury+ringS+ringW  
   urx+ringS+ringW:ury+ringS+ringW 
   urx+ringS+ringW:lly-ringS-ringW  
   llx-ringS:lly-ringS-ringW)
  ; layer is chosen for its color's visibility
  ; You can replace the layer names mentioned here with the layer names 
  ; present in your library.
  cv   = slotValue(device 'cvId)
  ring = dbCreatePolygon( cv list("Via2" "drawing") pts)
  callNextMethod()
 )
)
; This method is called when RING is used on its own.
; Just return a empty box
defmethod(getCoreBBox ((device RING))
 list(0:0 0:0)
)
; End of file - RING.ils

; Start of file - WRAP.ils
; Defines a wrapped core class that inheriting both CORE and RING classes
defclass( WRAP (CORE RING)
 ())
; The draw method for WRAP is just a simple call to callNextMethod and due
; to the specifity of WRAP's superclasses, the draw methods for CORE and RING
; will be called in this order
defmethod(draw ((device WRAP) )
 callNextMethod()
)
; End of file - WRAP.ils

; Start of file - genPcell.il
; Code to create a Pcell supermaster for CORE
pcDefinePCell(
 list(ddGetObj("PDK_devices") "CORE" "layout")
 (
  ( cyanW  "float" 0.6 )
  ( greenL "float" 0.8 )
  ( greenW "float" 0.2 )
  ( cyanL  "float" 0.2 )
 )
 let((pcell)
  pcell =  makeInstance('CORE)
  setPcellParams(pcell pcCellView)
  draw(pcell)
 )
)
; Code to create a Pcell supermaster for RING. 
pcDefinePCell(
 list(ddGetObj("PDK_devices") "RING" "layout")
 (
  ( ringW "float" 0.1 )
  ( ringS "float" 0.1 )
 )
 let((pcell)
  pcell =  makeInstance('RING)
  setPcellParams(pcell pcCellView)
  draw(pcell)
 )
)
; Code to create a Pcell supermaster 
pcDefinePCell(
 list(ddGetObj("PDK_devices") "WRAP" "layout")
 (
  ( ringW  "float" 0.1 )
  ( greenL "float" 0.8 )
  ( greenW "float" 0.2 )
  ( cyanL  "float" 0.2 )
  ( cyanW  "float" 0.6 )
  ( ringS  "float" 0.1 )
 )
 let((pcell)
  pcell =  makeInstance('WRAP)
  setPcellParams(pcell pcCellView)
  draw(pcell)
 )
)
; End of file - genPcell.il

; Start of file - genPcDef.il
; Based on specified class name, lib name, cell name, view name, and draw 
; function name to generate Pcell definition file in user specified directory.
; genPcellCodeFromClass(
;   s_className t_libName t_cellName t_viewName t_pcFilename t_drawFuncName)
; For example,
; genPcellCodeFromClass(
;  'WRAP "PDK_devices" "WRAP" "layout" "./pcWrap.il" "draw")
procedure( genPcellCodeFromClass(
 _className libN cellN viewN filePathName drawFuncName)
 let((oport params device str dirpath)
 when( !filePathName || filePathName == ""
  warn("File path name is empty.\n")
  return()
 )
 str = rindex(filePathName "/")
 when( str
  dirpath = substring(filePathName 1 strlen(filePathName) - strlen(str))
  when(  !isDir(dirpath)
   warn("Directory( %s ) does not exists.\n")
   return()
  )
 )
 oport = outfile(filePathName "w")
 fprintf(oport "pcDefinePCell(\n\tlist(ddGetObj(\"%s\") \"%s\" \"%s\")\n" 
  libN cellN viewN)
 ; Output parameters section
 device = makeInstance(concat(_className))
 fprintf(oport "\t(\n")
 params = getPcellParams(device)
 foreach( param params
  case( cadr(param)
  ("int"
    fprintf(oport "\t\t( %s \"int\" %d )\n" car(param) caddr(param))
  )
  ("float"
    fprintf(oport "\t\t( %s \"float\" %f )\n" car(param) caddr(param))
  )
  ("string"
    fprintf(oport "\t\t( %s \"string\" \"%s\" )\n" car(param) caddr(param))
  )
  ("boolean"
    fprintf(oport "\t\t( %s \"string\" %L )\n" car(param) caddr(param))
  )
  (("ILList" "ilList")
    fprintf(oport "\t\t( %s \"ILList\" %L )\n" car(param) caddr(param))
  )
  (t
   warn("Unsupported type %s on parameter %s skipped\n" cadr(param) car(param))
  )
  )
 )
 fprintf(oport "\t)\n")
 ; Output the standard Pcell code section
 fprintf(oport "\tlet((pcell)\n")
 fprintf(oport "\t\tpcell =  makeInstance('%s)\n" _className)
 fprintf(oport "\t\tsetPcellParams(pcell pcCellView)\n")
 fprintf(oport "\t\t%s(pcell)\n" drawFuncName)
 fprintf(oport "\t)\n")
 fprintf(oport ")\n")
 close(oport)
 ; Auto generate Pcell superMaster by user defined Pcell class
 ; load(filePathName)
 )
)
; End of file - genPcDef.il

Return to top
 ⠀
X