什么是PCell
Parameterized Cell (PCell) 顾名思义是一个参数化的cell,通过对它的参数赋值,你可以简单快速地创建出很多个不同的子cell。PCell的存在是为了加速数据的创建流程。
举例来说,假设我现在需要画各种各样的四边形:长方形,正方形,平行四边形,梯形… 如果每画一个新图形,都要一笔一画从头开始,无疑非常费时间。因此,我们可以规定一个参数化描述四边形的PCell,具体参数有:长,宽,每个角的角度,等等。每次建立新图形时,如果需要边长为2的正方形,就输入长=2, 宽=2,四个角度均为90;如果需要一个平行四边形,可以输入长=4,宽=2,四个角度分别为45,135,45,135。可以直观地看到,PCell的存在提高了非常多的效率。
在实际应用中,PCell可以用来快速创建各类电感与变压器, 可以用来进行各种有规律的instance的摆放与连线,无论是shcematic还是layout,包括每个工艺库自带的所有原始器件也都是PCell,用户通过输入w, l, nof等参数快速地初始化并放置器件。理论上来说,得益于SKILL作为一门编程语言的灵活性,任何复杂的东西都可以使用SKILL创建出PCell,然后快速创建多个sub cell, 当然越复杂的东西,使用SKILL创建PCell的难度越高。例如在过去的一年中,我花了接近半年的时间完成了一个功放的layout PCell创建,其中的困难点在于在合法范围内给定任意的电路参数(如w, l, multiplier数,finger数,指定金属层等),由PCell创建出的sub cell均需满足DRC与LVS,并且进行参数提取与后仿。如果由你的PCell快速建立的东西不能正常工作,那么你的PCell也就毫无意义。另外,难度还与工程师本身对于创建内容的理解,例如,应该把什么数据参数化?例如上面四边形的例子,实际上四个角度并不都需要被参数化,工程师可以添加对于长宽的条件判断,当长宽相等时,仅需提供一个角度就可。
使用SKILL创建PCell: pcDefinePCell
下面示例中可能涉及到一些其他的函数,每个函数都可以通过Cadence SKILL API Finder找到说明与使用方法。
pcDefinePCell
函数是最关键的一个函数,它包裹住了PCell需要的一切信息,例如PCell具体所在的路径、PCell的可修改参数以及他们的默认值、主体语句等。
pcDefinePCell
在官方文档中规定需要传入的argument
:
pcDefinePCell(
l_cellIdentifier
l_formalArgs
body_of_code
)
=> d_cellViewId / nil
其中:
l_cellIdentifier
是一组指定PCell所在位置的信息,包括library name, cellview name, cellview type(如schematic, layout等),开头的l代表者应是一个list(list是一个SKILL自有的数据结构,与Python的list无关),如:
list( ddGetObj("my_library") "my_cellview" "layout" )
这表示在my_library
中创建一个layout PCell,并取名为my_cellview
.
ddGetObj
是一个获取Database ID的函数,此处不作展开。
l_formalArgs
是一组PCell参数声明,每个参数必须提供这三个信息:参数名,参数数据类型,默认值,每个参数用一组括号包裹起来。如:
(
(param_1 int 1)
(param_2 float 2.0)
(param_3 float 5.0)
)
这表示要创建的PCell有三个参数param_1
, param_2
, param_3
。param_1
为整型,默认值为1,以此类推。
body_of_code
为代码主体,与普通的编程一致,例如layout就是作图,主要为坐标的计算,以及SKILL一些封装函数的使用,如dbCreatePolygon
,dbCreateLabel
,leCreatePin
等等,从这些函数的名字就能看出他们的功能分别是通过传入坐标来创建多边形,Label和Pin。一般情况下这一部分的代码使用let
语句包裹,let
语句中需要先一次性声明代码中要用到的所有变量名,即在一个括号中给出所有的变量名,以空格分隔:
let(
(variable_1 variable_2 variable_3) ;一次性声明所有变量名
variable_1 = param_1 + param_2 ;这里开始为主体代码
variable_2 = param_1 * param_3
variable_3 = param_1 / param_3
)
let
语句的其他语法细节此处不作展开。
另外值得一提的是,在pcDefinePCell中有一个内部变量pcCellView
,它的值为你正在创建的PCell的Database ID。
pcCellView
搭配运算符~>
非常有用,能够用来指向和当前cell有关的各种属性,例如
pcLib = pcCellView~>lib ;指向当前PCell所在library的Database ID
pcParameters = (pcCellView~>parameters) ~>value ;指向当前PCell的所有参数的集合
;***用来确认PCell的参数并赋值
pcParamProp = car(exists(prop pcParameters
((prop~>name) == "param_1")
)) ;在所有参数中找到param_1,返回到pcParamProp变量,并传入到let语句中的param_1
param_1 = (pcParamProp~>value)