在 Cadence Virtuoso 的 SKILL 编程以及日常操作中,大家常常会对 Justification(对齐方式)、Rotation(旋转与镜像)以及坐标变换计算函数 dbConcatTransform 感到迷惑。这些图形变换属性在 Schematic 和 Layout 中无处不在:当放置 Label 或 Pin 时,它是怎样进行原点计算的?当我们把一个 Instance 下移、旋转后,它的实际坐标又是如何通过矩阵推导出来的?
本文将为你揭开这些坐标变换的面纱,并且提供了两个可以在网页上直接交互的演示 Demo,帮助你一目了然地理解这背后的工作原理。
1. Justification 与 Rotation 是怎么互相作用的?
在 Virtuoso 中,当你设置一个文本(Text/Label)的属性时,有两个最关键的参数:
- Justification:指文本的“锚点(Anchor)”或者“原点”在其边界框(Bounding Box)上的什么位置。常见的值包括
lowerLeft,centerCenter,upperRight等共 9 种。 - Rotation / Orient:指基于这个原点,图形如何进行旋转和镜像操作(例如
R0,R90,MX,MYR90等)。
几何法则: Virtuoso 总是先确立图形内部的 Justification(即:原点对齐关系),然后以该原点为轴心执行 Rotation 变换。
🎮 交互式演示 1:Justification 与 Rotation 效果图
尝试在下方切换 Justification 和 Rotation,观察蓝色的字母 "F" 和虚线边框如何相对于红色的十字原点进行变动。
2. 理解嵌套变换的利器:dbConcatTransform
当我们处理拥有层次结构(Hierarchy)的电路层或版图时,经常会遇到坐标系联结的问题。假设:
- P1:顶层中的一个 Instance(比如
I0),它的坐标是(x1, y1),方向是Orient1。 - P2:在这个 Instance 内部的 Cell 中,有一个点(或者子 Instance),其相对坐标是
(x2, y2),方向是Orient2。
如果我们想找出 P2 在顶层坐标系中的绝对坐标和方向,就需要把这两个 Transform 相链接(Concatenate)。Virtuoso 给我们提供了一个极其常用的 API:
absolute_transform = dbConcatTransform( list(x2 y2 Orient2) list(x1 y1 Orient1) )
注意 API 参数顺序:
dbConcatTransform( T1 T2 )表达的数学意思是:先对物体做T1变换,然后再做T2变换。即 $T_{result} = T2 \cdot T1$。它最终计算出的是一个新的list(X Y Orient)。
矩阵推导
一个变换 $T = (D, O)$ 作用于点 $P$ 表示为 $P_{new} = O * P + D$。 先做 $T1 = (D_1, O_1)$,再做 $T2 = (D_2, O_2)$: \(P_{final} = O_2 * (O_1 * P + D_1) + D_2\) 展开得: \(P_{final} = (O_2 * O_1) * P + (O_2 * D_1 + D_2)\) 所以:
- 新旋转:$O_{result} = O_2 \times O_1$(即先 O1,再 O2)
- 新坐标:$D_{result} = O_2 \times D_1 + D_2$(即将 D1 坐标通过 O2 的旋转后,再加上 D2)
🧮 交互式演示 2:dbConcatTransform 计算器与轨迹
在下面填入参数,即可推导出 dbConcatTransform(T1, T2) 的结果。图上会显示字母 F 在基础坐标系(浅蓝) -> 经过 T1 后(橙色) -> 最终经过 T2 后(红色)的坐标推导过程。
T1 (内部 Cell 坐标)
X1: Y1:Orient1:
T2 (Top Instance 坐标)
X2: Y2:Orient2:
dbConcatTransform(...)
3. 常见报错与避坑
在使用 dbConcatTransform 时,许多工程师会因为搞混 T1 和 T2 的顺序导致 Bug。
如果你是要计算底层 term_shape 相对于顶层的坐标,一定是:
- 底层自身的相对坐标与旋转:
T1 - 上级 Instance 的坐标与旋转:
T2 - 组合:
dbConcatTransform( T1 T2 )
此外,dbConcatTransform 返回的是一个列表!在进行下一次运算或写入属性时,记得将列表解包。
例如:
let((abs_tf result_x result_y result_r)
abs_tf = dbConcatTransform(inst_term_tf inst_tf)
result_x = xCoord(abs_tf)
result_y = yCoord(abs_tf)
result_r = nth(2 abs_tf) ; 获取 Orient 字符串
)
希望通过以上两个图解和小程序,你能彻底告别 Virtuoso 中算不清楚坐标变换的噩梦!