基于2PADL的低功耗VLSI设计

基于两相绝热动态逻辑(2PADL)的低功耗超大规模集成电路设计

P. Sasipriya†和V.S.KanchanaBhaaskaran‡电子工程学院,VIT大学,印度泰米 尔纳德邦金奈600127
†sasipriyap@yahoo.com ‡vskanchana@gmail.com
收稿日期:2016年6月30日 接受日期:2017年6月24日 发布日期:2017年7月28日

本文提出了一种由两相正弦时钟信号供电的准绝热逻辑,用于低功耗应用。所提出的逻辑称为两相绝热动态逻辑(2PADL),通过使用门过驱和降低的开关功耗实现了能量高效的优势。它具有单轨输出,并且该逻辑不需要任何变量的互补输入信号。2PADL逻辑由两个作为电源的互补时钟信号驱动。通过对实际电路进行验证,包括:(i)采用能量回收技术的时序电路,适用于存储器电路;(ii)使用2PADL设计的绝热超前进位加法器(CLA),用于研究其速度性能并证明其在多种频率下的能量高效性;以及(iii)与CMOS对应电路相比的2PADL乘法器电路。此外,CLA加法器还使用其他静态绝热逻辑实现,即准静态能量回收逻辑(QSERL)、时钟CMOS绝热逻辑(CCAL)和传统静态CMOS逻辑,以与2PADL进行比较并验证其功耗优势。通过实现广泛使用的CLA电路,测试了CCAL逻辑在高频下的性能。结果证明,该设计具有较高的能量效率,并可工作在高达600MHz的频率下。仿真采用行业标准的CadenceVirtuoso工具,并基于180nm工艺库 ¯les完成。

关键词 :低功耗VLSI设计;能量回收电路;正弦时钟驱动的绝热电路;低功耗CLA加法器;能量回收触发器;基于静态能量恢复电路的低功耗算术电路

1. 引言

低功耗设计已成为VLSI系统设计领域的首要关注点。目前有多种设计技术正在被开发,旨在降低功耗最小化。基于绝热开关原理工作的能量回收电路被证明是各种低功耗设计方法中最具有前景的方法之一。能量回收电路设计为使用缓慢上升和缓慢下降的可变交流电源,即正弦或梯形时钟信号,从而通过使场效应管开关在源极和漏极之间以最小电压降工作而实现功耗降低的优势。此外,存储在节点电容中的电荷在每个周期都会被回收回电源。因此,功耗的降低主要取决于电源的变化率,从而在功耗和延迟之间产生权衡。结果,与静态CMOS对应电路相比,能量回收电路能够以更低的功耗运行。

近年来,已提出多种能量回收电路。1–7,9–18它们均采用单相、两相或多相电源时钟信号来控制级联连接的门,并且这些信号也用作电源。大多数能量回收电路,如2N2P、2N2N2P、ECRL、PFAL、DCPAL和PSAL2–7本质上是动态的,利用多相梯形信号。因此,它们存在以下缺点8:(i)输出节点中的开关活动增加;(ii)需要多相和多个时钟生成,以及在整个电路中并行分配时钟信号;(iii)存在差分信号,增加了信号开销。文献中已提出了几种两相动态能量回收电路,如PAL、SCAL和CAL11–13。与静态CMOS逻辑相比,它们在几百兆赫范围内的较低工作频率下具有较高的能量效率。与动态能量回收电路相比,文献中还提出了静态能量恢复电路14–17,例如准静态能量恢复逻辑(QSERL)、互补能量路径绝热逻辑(CEPAL)、单时钟绝热静态逻辑(ASL)和可级联绝热逻辑(GFCAL)。它们都使用单相或两相的正弦信号对输出节点电容进行充放电。它们的工作频率最高仅能达到100兆赫。一类新的能量回收电路18–20,如升压逻辑、增强型升压逻辑(EBL)和脉冲升压逻辑(PBL),已被提出用于高速运行。它们被称为动态能量回收电路,其运行需要额外电源以及正弦功率时钟信号,同时还需要额外数量的晶体管来实现其升压操作。

本文提出了一种采用两个互补正弦功率时钟信号(2PADL)的准绝热动态能量恢复逻辑电路。该电路类似于CMOS,但增加了两个用于控制输出节点充/放电的附加晶体管。所提出的逻辑通过控制放电操作显著降低了开关活动。此外,它能够在高达600兆赫的相对高工作频率下实现能量回收。因此,2PADL逻辑适用于高频应用。为了研究两相绝热动态逻辑的能量效率和性能,设计了一个基于2PADL的八位CLA加法器,并对其进行了对比分析静态CMOS加法器、静态绝热加法器和动态绝热加法器。尽管现有的动态逻辑(即CCAL)使用反相器链来验证其电路,但本文通过采用八位先行进位加法器作为基准电路,展示了CCAL逻辑在不同频率范围内的性能验证结果。

本文其余部分组织如下。第2节介绍了由两相正弦功率时钟信号驱动的绝热逻辑族的综述。第3节描述了2PADL的结构和工作原理。第4节详细阐述了使用2PADL设计和实现组合和时序电路的方法。第5节给出了基于180nm工艺库设计的绝热电路实现的CLA加法器的仿真结果 ¯。结论在第6节中给出。

2. 绝热逻辑族概述

本节介绍了静态CMOS以及由两相正弦信号驱动的几种绝热逻辑族的回顾。讨论了双轨能量回收电路(即TSEL、CAL、PAL)以及类似于静态CMOS的单轨输出能量回收电路的特性。

静态CMOS逻辑的主要功耗成分是动态功耗,该功耗用于对电路中电容节点的充放电。图1(a)展示了CMOS反相器。对输出节点充电所消耗的总能量为CV²,其中C为输出节点电容,V为电源电压。该能量的一半(1/2CV²)消耗在上拉路径中的PMOS器件的导通电阻上,另一半能量则存储在输出节点的节点电容中。当下一周期输出变为“0”时,存储在输出节点电容上的能量将通过下拉路径中NMOS器件的导通电阻耗散掉。

与静态CMOS相比,能量回收电路在对输出节点进行充放电时消耗更少的能量。13这种能量±效率主要通过使用缓慢变化的电源来实现,该电源用于实现受控在电源时钟和输出节点之间进行电荷转移。因此,开关器件上的电势降被保持在较小值。电源时钟信号的周期足够长,以使开关器件上的电势降最小化。此种情况下消耗的能量为(RC/T)CV²,其中R为器件的有效导通电阻,T为电源时钟的转换时间周期。一种使用四相斜坡信号对输出节点进行充放电的简单绝热电路及其输入/输出波形瞬态如图1(b)所示。

示意图0

图2(a)–2(d)分别显示了动态两相能量回收反相器/缓冲器的结构,即PAL、CAL、TSEL和SCAL。PAL与2N2P类似,能够消除非绝热能量耗散。级联的PAL门由具有两相且相互不重叠特性的时钟信号源控制。该反相器的问题在于当输出为逻辑0时处于高阻态,因此该电路仅适用于极低工作频率。CAL是从2N2P衍生而来,增加了一个由辅助时钟信号控制的晶体管以实现其单相操作。由于辅助时钟信号的存在,设计复杂度和开关功耗增加。TSEL是一种准绝热

示意图1

一种利用附加参考电压实现高速和低功耗操作的逻辑。它采用交替的PMOS和NMOS结构进行电路级联。参考电压必须针对特定频率下的低功耗操作进行调谐。SCAL逻辑是TSEL的衍生形式,通过用电流源替代参考电压源而得到。

图3(a)展示了静态能量回收反相器,即QSERL的结构。14 QSERL通过使用二极管降低了开关能量,具有优势。然而,当频率超过50兆赫时,电路中的二极管将无法正常对输出节点进行充/放电。因此,该¯结构不适用于高频应用。图3(b)展示了时钟CMOS绝热逻辑的结构。21该结构是一种类似于静态CMOS的动态绝热逻辑家族。时钟控制部分以如下方式控制输出:仅在时钟周期的高电平阶段,即PC电压幅度比PCBAR电压幅度至少高出Vt时,输出才跟随电源时钟。当时钟频率较高时,输出电压摆幅减小,从而实现低功耗。因此,该电路适用于高频应用。这两个电路均由如图3(c)所示的两个互补正弦时钟信号驱动。

示意图2

3. 两相绝热动态逻辑(2PADL)

本节讨论了两相时钟绝热动态逻辑反相器的结构和工作原理,并给出了能量方程以说明反相器的工作过程。

3.1. 反相器的结构和工作原理

2PADL反相器的基本结构如图4(a)所示。该反相器类似于静态CMOS反相器,但增加了用于能量回收操作的附加晶体管。2PADL反相器由晶体管MP1和一个上拉网络(PUN)组成。

示意图3

顶部的pMOS树控制绝热充电操作,而底部的晶体管MN1、MN2以及nMOS树的下拉网络(PDN)控制绝热放电操作。该电路使用两个互补正弦时钟信号PC和PCBAR。正弦时钟信号包含两个相位,即评估和保持。在评估阶段,电路的操作如下:根据输入信号,控制路径中的两个晶体管之一(MN1和MN2或MP1)开始导通。在评估阶段存在两种可能情况:(i)输出节点为低电平,且上拉或下拉网络处于开启状态;(ii)输出节点为高电平,且上拉或下拉网络处于开启状态。在第一种情况下,如果上拉网络开启,则输出在半周期的高电平部分跟随电源时钟PC,即直到VPC/2;;否则输出保持不变。对于第二种情况,如果下拉网络开启,则输出跟随PCBAR并变为低电平,否则输出保持不变。在保持相位期间,晶体管MP1和MN1均不导通,因此输出节点不会发生变化,保持原有状态。

2PADL反相器电路通过消除输出节点的冗余开关来证明其能量±效率。此外,当输出以最快速度转换时(对于正弦形状时钟为VPC/2),无需跟随电源时钟信号。因此,该反相器在高频范围操作下具有高能效。同时请注意,充放电路径中使用的晶体管可替换为低阈值电压晶体管以实现低功耗操作。2PADL反相器链通过级联反相器构成,如图4(a)所示。这些反相器交替由PC和PCBAR功率时钟信号供电。图4(b)显示了四级反相器链的输入和输出波形。

由于流水线操作,反相器链的每一级之间存在半个时钟周期的延迟。

3.2. 绝热逻辑的能耗

静态CMOS电路每次开关所消耗的总能量22由公式(1)给出。

$$
E_{Total} = E_{static} + E_{dynamic} \tag{1}
$$

  • $E_{static}$是由于关断晶体管的亚阈值导通、栅极漏电流以及源极和漏极扩散区的结漏电流所导致的能量损耗。
  • $E_{dynamic}$是由于输入信号切换和短路电流所导致的能量损耗。

每周期的总能耗10由基于sense放大器的双轨逻辑准绝热电路通过¯给出,如公式 (2)所示。

$$
E_{Total} = E_{adiab} + E_{non-adiab} + E_{opn} \tag{2}
$$

  • $E_{adiab}$是在输出节点切换期间针对梯形/正弦信号所消耗的能量。
  • $E_{non-adiab}$是由于阈值电压降和漏电流造成的能量损失。这部分能量包括反相器在输出节点充放电过程中的阈值电压降损耗以及保持相同输出所需消耗的能量。
  • $E_{opn}$是双轨绝热电路中用于操作灵敏放大器¯所消耗的能量。

3.3. 2PADL的能耗

如图4所示,所提出的反相器的能量耗散通过考虑一个缓慢变化的正弦功率时钟信号作为电源电压来计算。根据输入的不同,输出节点电容要么通过上拉网络绝热充电至电源时钟峰值,要么通过下拉网络绝热放电至PCBAR的低峰值。因此,2PADL反相器的功耗包含两个部分。2PADL的总能量由公式(3)定义。

$$
E_{Total} = E_{ch} + E_{Disch} + E_{opn} \tag{3}
$$

连接到2PADL反相器的电源电压由公式(4 ).

$$
V_{PC} = V_{DD} - \frac{T}{t}; \tag{4}
$$

其中$V_{DD}$ 是电源时钟信号的峰值电压,T是电源时钟的放电周期。

放电期间输出节点电容上的电压由公式(5)给出。

$$
V_{PC} = V_{ND} + V_R + V_C; \tag{5}
$$

其中,$V_{ND}$是输出开始放电时放电控制晶体管MN1和MN2两端的电压,$V_R$是下拉网络导通电阻两端的电压,$V_C$是输出节点电容两端的电压。

$$
V_C = V_{DD} - \frac{T}{t} - R_{ch}C \frac{dV_c}{dt} - V_{ND}:
$$

放电期间消耗的能量由公式(6)给出。

$$
E_{Disch} = C V_{DD} \frac{R_{ch}C}{T} + C V_{DD} V_{ND}
$$

$$
E_{Disch} = C V^2_{DD} \frac{C R_{ch}}{T} + C V_{DD} V_{ND};
\tag{6}
$$

公式(6)中的第二项被忽略,因为$V_{ND}$与$V_{DD}$相比非常小。这明显表明,当T较高,即电源时钟频率较低时,能量耗散最小。可以看出,能量耗散还取决于控制晶体管上的能量损耗。

当输入为逻辑\0”时,上拉网络导通,输出通过控制晶体管MP1开始充电。但晶体管MP1仅在VPC为高电平且VPCBAR为低电平时导通,并且VPC与VPCBAR之间的电压差大于Vth的阈值电压。假设充电期间输出节点的电压摆幅为$V_{sw}$。连接到上拉网络的电源电压表示为$V_{PC} = V_{sw} \frac{T}{t}$;其中,T是电源时钟摆幅的周期。

充电期间输出节点电容上的电压由公式(7)给出。

$$
V_{sw} = V_R + V_C: \tag{7}
$$

充电期间消耗的能量由公式(8)给出。

$$
E_{ch} = 2 \frac{R_{ch}C}{T} C V^2_{sw}; \tag{8}
$$

其中$R_{ch}$为PUN晶体管的导通电阻,C为输出节点电容,$V_{sw}$为输出电压摆幅。能量方程表明,当电源时钟以更快的速度跳变时,$V_{sw}$最小(即接近$V_{DD}/2$),因此在较高开关频率下能量耗散可以降低,如图4(b)所示。

2PADL反相器的总能耗由以下公式给出

$$
E_{Total} = \frac{R_{ch}C}{T} C V^2_{DD} + C V_{DD} V_{ND} + 2 \frac{R_{ch}C}{T} C V^2_{sw} + E_{opn}
$$

这里,能量分量$E_{opn}$包含两个部分。第一部分是充放电输出节点时消耗的非绝热能量,第二部分是由于漏电流和短路电流引起的能量耗散。然而,由于控制晶体管和可变电源的存在,2PADL的漏电流可以忽略不计¯。

能量方程表明,能量损耗取决于输出节点处连接的节点电容和峰值电源时钟电压。图5(a)显示了缓冲器在不同频率下针对各种负载电容所消耗的能量。缓冲器消耗的总能量通过测量缓冲器在充电期间从PC消耗的能量与放电期间从PCBAR消耗的能量之和来计算。结果表明,2PADL在其工作高频范围内(即200MHz至600MHz)具有较高的能量效率。±icientatitshighfrequencyofoperation,viz.intherangeof200MHzto600MHz.

示意图4

图5(b)显示了在400MHz下,缓冲器在不同电源时钟峰值电压下的能量消耗。结果表明,随着电源时钟电压摆幅的降低,能量效率有所提高。图5(c)显示了2PADL反相器链在两个时钟周期内的能量图。反相器的能量曲线描述了通过PC充电和通过PCBAR放电的过程。需要注意的是,在输出节点充电/放电过程中消耗的能量在评估阶段会部分被电源时钟回收。在任意时钟周期内,电源时钟PC或PCBAR中的其中一个会向输出节点提供能量,并在后续过程中将能量回收至电源时钟振荡器。这些结果是在400兆赫频率下运行的仿真环境中获得的。

4. 使用2PADL的电路

通过仿真多个电路来评估2PADL的性能。在本节中,讨论了基于2PADL的全加器和SR触发器的设计。本节还详细阐述了8位先行进位加法器设计。

4.1. 全加器

绝热全加器由三个输入A、B和C实现。SUM和进位生成电路23如图6(a)所示。该全加器电路采用传统的28晶体管镜像加法器CMOS结构,并增加了用于绝热开关的控制晶体管。Sum和Cout的补码布尔方程可表示为公式(9)。

$$
Cout = A \cdot (B + C) + B \cdot C, \quad Sum = \overline{Cout} \cdot (A + B + C) + A \cdot B \cdot C:
\tag{9}
$$

晶体管M1用于控制充电输出,M2、M3用于控制输出节点的放电。和Cout通过下一时钟信号相位的反相器获得,如图6(a)所示。全加器的操作可行性已在不同频率下的各种输入组合中得到验证。为了理解2PADL加法器的功能,我们考虑所有输入(A、B和Cin)均为逻辑\1”的情况。此时,2PADL的下拉网络处于导通状态,在评估阶段Coutbar被放电至逻辑\0”,同时Sumbar输出也被评估为逻辑\0”。由于流水线操作,Sum和Cout的输出在下一个时钟周期的后半段获得。全加器的仿真输出如图6(b)所示。当输入为 A ¼ B ¼ C ¼高时,输出Sum ¼ Cout ¼为高;而当输入为 A ¼ B ¼ C ¼低时,Sum和Cout均为低,如图6(b)所示。

示意图5

4.2. SR触发器

使用先前提出的绝热电路设计时序电路存在一个缺点,即当电源时钟处于零时,缓冲器的输出信号被设置为零下降到零。因此,逻辑状态转换在绝热时序电路中是困难的±。由于能量回收信号的缓慢上升/下降转换,当存储元件驱动标准逻辑(非绝热)时,可能会产生相当大的短路功耗。因此,必须避免触发器中存储元件的能量回收。文献中已提出多种可用于时钟分配网络以实现低功耗的能量回收触发器电路25,26 。采用2PADL实现的触发器通过控制输出端的充放电,消除了上述所有问题。图7(a)展示了基于晶体管的绝热SR触发器的简单电路。该电路具有两个输入S和R以及一个公共时钟触发。信号PC既用作电源时钟也用作时钟信号。电路的工作原理如下:当输入S ¼ 1、R ¼ 0时,输出Q和Qbar分别为

示意图6

评估为1和0。当电源时钟有效时,输出随输入的变化才有效。SR触发器电路的时钟信号有效状态为时钟信号的高电平部分。SR触发器的仿真输出瞬态如图7(b)所示。

4.3. 先行进位加法器

8位超前进位加法器采用2PADL和两个互补双相正弦电源时钟设计而成。图8(a)展示了2PADL加法器的原理图结构。该8位CLA加法器27,28由四个元件组成的五级¯或延迟阶段构成,这四个元件分别为生成‐传播(GP)发生器、缓冲器、异或门以及与或与模块。图8(b)展示了CLA结构中使用的GP发生器和与或与模块。GP发生器的逻辑功能可用下面给出的公式(10)表示。

$$
G_i = A_i \cdot B_i \
P_i = A_i \oplus B_i = [A_i + B_i + A_i \cdot B_i]’
\tag{10}
$$

方程(10)可以使用2PADL逻辑实现的与门和异或门来实现。异或门通过上述函数中给出的级联两级逻辑功能实现。和与进位输出函数的先行进位加法器在公式(11)中由下式给出

$$
S_i = P_i \oplus C_i \
C_{i+1} = G_i + P_i \cdot C_i;
\tag{11}
$$

其中$S_i$和$P_i$分别为和与进位位。

加法器的全定制设计流程包括门级单元的原理图设计和功能分析,并将其实例化于CLA加法器设计中。随后,提取电路寄生参数,并使用SPICE对网表进行布局后仿真。通过这种方式,验证电路的实现,并对加法器结构进行对比分析。

使用基于2PADL实现的CLA加法器测试了电路的能量效率。2PADL加法器的电路采用180nm工艺库进行设计和仿真。采用尺寸相近的晶体管以确保各电路相应的负载条件。所有电路均由具有1.8V峰峰值电压幅度的正弦电源供电。通过在不同功率时钟频率下的比较验证这些电路的操作。

示意图7

2PADL加法器的仿真结果与相同晶体管尺寸的静态CMOS逻辑实现的加法器进行了比较。仿真使用了随机生成且相互独立的输入向量。输出波形如图8(c)所示。当 A和B的所有输入均为逻辑\1”时,输出为和[7:0]¼8‘b11111110以及Cout ¼ 1。尽管使用了 ¯级门电路,但无需 ¯个时钟周期,而只需2.5T(5 T/2 ¼ 2.5T)即可得到输出。由于2PADL加法器采用流水线双相操作,每一级的输出可在每个时钟周期的半周期内进行评估。因此,8位CLA加法器的延迟为2.5个时钟周期。

4.4. 乘法器

通过设计更复杂的乘法器结构来评估2PADL的性能。该流水线乘法器结构采用两相正弦电源时钟设计。绝热乘法器的结构14如图9(a)所示。每个部分积通过使用与门生成。部分积经过全加器传递,以产生 ¯8位乘积项的最终结果。乘法器的最后一级为CLA加法器。全加器的结构类似于CMOS结构,但在上拉网络和下拉网络中增加了控制晶体管,如图9(b)所示。控制晶体管M1、M2和M3用于对输出节点进行绝热充放电。该绝热乘法器针对多组4位长度的随机数据进行了仿真和测试。该绝热四位乘法器的延迟为7,需要3.5个时钟周期才能产生 ¯最终结果。

示意图8

5. 结果与讨论

8位CLA加法器和八级反相器链采用2PADL实现。为了进行比较,使用静态CMOS逻辑的电路也在相同的180纳米工艺技术下进行了仿真。本节展示并讨论了仿真结果。平均功耗通过在 ¯个时钟周期的仿真时间内对功耗进行积分直接测得。在该计算中,未计入电源时钟发生器电路的功耗,且所有绝热电路均在不同的电源时钟频率下进行了仿真。

示意图9

图10展示了基于2PADCL、29 CCAL、2PADL和静态CMOS的绝热八级反相器链功耗比较的仿真结果。绝热电路的功耗通过计算PC和PCBAR功率时钟产生的功耗得出。虽然CMOS反相器链的功耗随频率线性增加,但基于2PADL的反相器链从10兆赫开始正常工作,并可超过1吉赫。基于CCAL的反相器链在低频范围内无法产生正确输出。2PADCL适用于低频范围,仅能在最高50兆赫的频率下产生正确输出。因此,2PADL在高频区域运行时,相比其他绝热逻辑如2PADCL和CCAL,证明具有更高的能量效率。

示意图10

图11展示了基于QSERL、CCAL、2PADL和静态CMOS的绝热CLA加法器在流水线结构下的功耗比较仿真结果。功耗通过计算绝热电路在和输出(s0‐s7)及进位输出无负载情况下,由PC和PCBAR功率时钟引起的加法器功耗得出。虽然 CMOS加法器的功耗随频率呈线性增加,但2PADL加法器的功耗在10兆赫至600MHz范围内上升缓慢。2PADL下拉网络中存在一个晶体管逻辑在高频下无法控制输出的充放电操作。这导致2PADL加法器在超过600MHz时产生错误输出。从结果可以看出,基于QSERL的静态加法器仅在低频范围内高效,即仅在100MHz以下有效。而基于CCAL的动态加法器在高频下表现出能量效率,并且仅在超过200MHz的高频应用中适用。

示意图11

图12显示了基于2PADL的CLA加法器与CMOS加法器之间的能耗比较。当时钟频率升高时,为确保电路正常工作,PUN和PDN中存在的控制晶体管必须相应增大尺寸。因此,基于2PADL的能量回收电路适用于200MHz至600兆赫的频率范围内。在200MHz到600MHz的频率范围内,基于2PADL的加法器相比传统静态CMOS加法器能耗降低了50%到65%。此外,当电源时钟以更快的速度跳变时,输出电压摆幅会减小(VPC/2用于正弦时钟),如第 3.3节所述。在仿真过程中发现,由于存在保持相位,输入信号相对于PCs的相对时序对2PADL电路的能量效率至关重要。如果输入数据频率相对于电源时钟频率保持较低,则CLA加法器的功耗降低,且电路可在600MHz以上工作。针对所有频率测量了2PADL加法器的电荷恢复。通过观察能量图中PC和PCBAR的输出节点耗散的能量以及电源时钟回收的能量来测量电荷恢复情况。在200MHz至600MHz的时钟频率下,电源时钟几乎能回收60–75%的能量。需要注意的是,在所有频率范围内,电源时钟PC和PCbar的电荷恢复情况相同。

示意图12

图13显示了基于2PADL和CLA的乘法器在不同电源时钟频率下的功耗。仿真结果表明,该乘法器工作 ¯正常,直至开关频率达到200MHz。该结果与2PADL加法器观察到的结果相当。为了提高基于2PADL的乘法器的能量效率,可在流水线各级之间引入使用CMOS的接口电路19,27。

6. 结论

本文提出了一种由两相正弦时钟信号驱动的准绝热逻辑,称为2PADL。采用电荷恢复技术的2PADL具有门过驱和降低的开关功耗的优点。单轨该逻辑的两相操作消除了信号布线问题,适用于低功耗和高速操作。使用所提出的逻辑实现触发器证明了电荷恢复技术在存储器电路中应用的可行性。采用2PADL设计了一个绝热超前进位加法器。CLA加法器的仿真结果表明,在50兆赫至600兆赫的频率范围内,与CMOS相比,所提出的2PADL逻辑实现了1.6至2.3的绝热增益。基于2PADL的绝热加法器在600MHz下实现了高达75%电荷恢复。绝热乘法器的实现展示了2PADL设计在复杂电路中的正确操作。

解释如下函数代码: def metalLink(tkcell,device,linkW=2,linkS=1,location=3,offset=['center',0],tkW=None,padW=None,padL=None,pitch=None,pad1offset=None,**pinset): '''把device放到tkcell中,并根据设置连线''' '''PADcell必须用pad画的, 否则需设置padW等参数''' '''location指device放到哪个PAD的右边, offset有3个值,center, up,down, 指放到pad哪个位置,默认为center,放到pad中间,up指放pad上面,大小写不敏感''' '''offset为列表, 当设置为center时, value一定是0, 当设置为非center时, eg offset=['up',10]指放到pad上面,离pad 10um''' '''如果把pin定义成字典, 必须提前定义, 参数前面加**来引用, 或者直接写成,G=11,D=12,S=11...''' '''写成字典形式: pinset={'G':12,'D':12,'S':11},引用 metalLink2(....,**pinset)''' pass metalCD=3 #转向PAD时的metal CD, device在pad上或下的时候会用到 metalCD2=4 #接触pad的metal CD metalS=3 #当metal会穿过PAD时,自动隔离的距离 pad_cell=gdspy.current_library.cell_dict.get(tkcell,tkcell) tkW=pad_cell.tkW if tkW==None else tkW padW=pad_cell.padW if padW==None else padW padL=pad_cell.padL if padL==None else padL pitch=pad_cell.pitch if pitch==None else pitch pad1offset=pad_cell.pad1offset if pad1offset==None else pad1offset metal2edge=(tkW-padW)/2-linkS-linkW #metal到edge的距离 d_cell=gdspy.current_library.cell_dict.get(device,device) ''' put in device ''' offset0=offset[0] if offset0.lower()=='center': d_cell.align(None,cc,pad_cell,cl,(location-1)*pitch+pad1offset+padL+(pitch-padL)/2,0) elif offset0.lower()=='up': bbox1=pad_cell.get_bounding_box() x1=bbox1[0][0] y1=bbox1[0][1] x_cc=(location-1)*pitch+pad1offset+padL+(pitch-padL)/2-d_cell.xCoord(None,cc)+x1 y_cc=tkW+offset[1]+d_cell.Width/2-d_cell.yCoord(None,cc)+y1 d_cell.insert(pad_cell,origin=(x_cc,y_cc)) # d_cell.align(None,cc,pad_cell,cl,(location-1)*pitch+pad1offset+padL+(pitch-padL)/2,tkW/2+d_cell.Width/2+offset[offset0]) elif offset0.lower()=='down': bbox1=pad_cell.get_bounding_box() x1=bbox1[0][0] y1=bbox1[0][1] x_cc=(location-1)*pitch+pad1offset+padL+(pitch-padL)/2-d_cell.xCoord(None,cc)+x1 y_cc=-(d_cell.Width/2+d_cell.yCoord(None,cc))-offset[1]+y1 d_cell.insert(pad_cell,origin=(x_cc,y_cc)) # d_cell.align(None,cc,pad_cell,cl,(location-1)*pitch+pad1offset+padL+(pitch-padL)/2,-(tkW/2+d_cell.Width/2+offset[offset0])) '''center 连线,(CD,layer,dir,loaction)''' pin_dict=d_cell.pin x1=d_cell.originX(pad_cell,'ll') y1=d_cell.originY(pad_cell,'ll') if offset0.lower()=='center': for pin1 in pin_dict: p_start=(pin_dict[pin1][3][0]+x1,pin_dict[pin1][3][1]+y1) Layer1=pin_dict[pin1][1] if pin_dict[pin1][2]=='+x': #右引线 path1=gdspy.Path(pin_dict[pin1][0],p_start) length1=location*pitch+pad1offset-p_start[0]+2 if length1>0: Layer1=pin_dict[pin1][1] path1.segment(length1,'+x',layer=gdsNo(Layer1),datatype=dtype(Layer1)) pad_cell.add(path1) if pin_dict[pin1][2]=='-x': #左引线 path1=gdspy.Path(pin_dict[pin1][0],p_start) length1=p_start[0]-((location-1)*pitch+pad1offset+padL)+2 if length1>0: Layer1=pin_dict[pin1][1] path1.segment(length1,'-x',layer=gdsNo(Layer1),datatype=dtype(Layer1)) pad_cell.add(path1) if pin_dict[pin1][2]=='+y': #上引线 Length1=tkW+pad_cell.yCoord(None,lc)-metal2edge-linkW/2-p_start[1] length3=(tkW-padW)/2-metal2edge-linkW/2+2 if pin1 in pinset: if pinset[pin1]>location: #device在PAD左边 Length2=(pinset[pin1]-1)*pitch+pad1offset+padL/2-p_start[0] turn1=-linkW/pin_dict[pin1][0] turn2=-metalCD2/pin_dict[pin1][0] else: #device在PAD右边 Length2=p_start[0]-((pinset[pin1]-1)*pitch+pad1offset+padL/2) turn1=linkW/pin_dict[pin1][0] turn2=metalCD2/pin_dict[pin1][0] length=[Length1,Length2,length3] turn=[turn1,turn2] path1=gdspy.L1Path(p_start,'+y',pin_dict[pin1][0],length,turn,layer=gdsNo(Layer1),datatype=dtype(Layer1)) pad_cell.add(path1) if pin_dict[pin1][2]=='-y': #下引线 Length1=p_start[1]-(metal2edge+linkW/2)-pad_cell.yCoord(None,lc) length3=(tkW-padW)/2-metal2edge-linkW/2+2 if pin1 in pinset: if pinset[pin1]>location: #device在PAD左边 Length2=(pinset[pin1]-1)*pitch+pad1offset+padL/2-p_start[0] turn1=linkW/pin_dict[pin1][0] turn2=metalCD2/pin_dict[pin1][0] else: #device在PAD右边 Length2=p_start[0]-((pinset[pin1]-1)*pitch+pad1offset+padL/2) turn1=-linkW/pin_dict[pin1][0] turn2=-metalCD2/pin_dict[pin1][0] length=[Length1,Length2,length3] turn=[turn1,turn2] path1=gdspy.L1Path(p_start,'-y',pin_dict[pin1][0],length,turn,layer=gdsNo(Layer1),datatype=dtype(Layer1)) pad_cell.add(path1) return pad_cell '''device放到pad上面''' if offset0.lower()=='up': for pin1 in pin_dict: p_start=(pin_dict[pin1][3][0]+x1,pin_dict[pin1][3][1]+y1) Layer1=pin_dict[pin1][1] if pin_dict[pin1][2]=='+x': #右引线 if pin1 in pinset: pad_num=pinset[pin1] #读取pin对应的PADnumber length1=(pad_num-1)*pitch+pad1offset-p_start[0]+2 #右边pin脚到PAD edge的距离 length2=p_start[1]-tkW+(tkW-padW)/2+2 #上面到PAD edge的距离 if length1>0: #pin脚在pad左边 length=[length1+metalCD/2,length2] turn=[-metalCD/pin_dict[pin1][0]] path1=gdspy.L1Path(p_start,'+x',pin_dict[pin1][0],length,turn,layer=gdsNo(Layer1),datatype=dtype(Layer1)) elif abs(length1)<=padL-metalCD: #pin脚正好落在PAD上方 p_start=(p_start[0]+metalCD/2,p_start[1]+pin_dict[pin1][0]/2) path1=gdspy.Path(metalCD,p_start) path1.segment(length2+pin_dict[pin1][0]/2,'-y',layer=gdsNo(Layer1),datatype=dtype(Layer1)) elif abs(length1)>padL-metalCD and abs(length1)<=pitch-metalCD-metalS: p_start=(p_start[0]+metalCD/2,p_start[1]+pin_dict[pin1][0]/2) length3=p_start[0]-((pad_num-1)*pitch+pad1offset+padL) length=[length2+pin_dict[pin1][0]/2+metalCD2/2,length3] turn=[-metalCD2/metalCD] path1=gdspy.L1Path(p_start,'-y',metalCD,length,turn,layer=gdsNo(Layer1),datatype=dtype(Layer1)) else: p_start=(p_start[0]+metalCD/2,p_start[1]+pin_dict[pin1][0]/2) length3=p_start[0]-((pad_num-1)*pitch+pad1offset+padL)+metalCD/2 length4=metalS+metalCD/2 length=[length2+pin_dict[pin1][0]/2-metalS-metalCD/2,length3,length4] turn=[-1,1] path1=gdspy.L1Path(p_start,'-y',metalCD,length,turn,layer=gdsNo(Layer1),datatype=dtype(Layer1)) pad_cell.add(path1) if pin_dict[pin1][2]=='-x': #左引线 if pin1 in pinset: pad_num=pinset[pin1] length1=p_start[0]-((pad_num-1)*pitch+pad1offset+padL)+2 #左边pin脚到PAD edge的距离 length2=p_start[1]-tkW+(tkW-padW)/2+2 #上面到PAD edge的距离 if length1>0: #pin脚在pad左边 length=[length1+metalCD/2,length2] turn=[metalCD/pin_dict[pin1][0]] path1=gdspy.L1Path(p_start,'-x',pin_dict[pin1][0],length,turn,layer=gdsNo(Layer1),datatype=dtype(Layer1)) elif abs(length1)<=padL-metalCD: #pin脚正好落在PAD上方 p_start=(p_start[0]-metalCD/2,p_start[1]+pin_dict[pin1][0]/2) path1=gdspy.Path(metalCD,p_start) path1.segment(length2+pin_dict[pin1][0]/2,'-y',layer=gdsNo(Layer1),datatype=dtype(Layer1)) elif abs(length1)>padL-metalCD and abs(length1)<=pitch-metalCD-metalS: p_start=(p_start[0]-metalCD/2,p_start[1]+pin_dict[pin1][0]/2) length3=((pad_num-1)*pitch+pad1offset)-p_start[0] length=[length2+pin_dict[pin1][0]/2+metalCD2/2,length3] turn=[metalCD2/metalCD] path1=gdspy.L1Path(p_start,'-y',metalCD,length,turn,layer=gdsNo(Layer1),datatype=dtype(Layer1)) else: p_start=(p_start[0]-metalCD/2,p_start[1]+pin_dict[pin1][0]/2) length3=((pad_num-1)*pitch+pad1offset)-p_start[0]+metalCD/2 length4=metalS+metalCD/2 length=[length2+pin_dict[pin1][0]/2-metalS-metalCD/2,length3,length4] turn=[1,-1] path1=gdspy.L1Path(p_start,'-y',metalCD,length,turn,layer=gdsNo(Layer1),datatype=dtype(Layer1)) pad_cell.add(path1) if pin_dict[pin1][2]=='-y': #下引线 Length1=p_start[1]-(metal2edge+linkW/2) length3=(tkW-padW)/2-metal2edge-linkW/2+2 if pin1 in pinset: if pinset[pin1]>location: #device在PAD左边 Length2=(pinset[pin1]-1)*pitch+pad1offset+padL/2-p_start[0] turn1=linkW/pin_dict[pin1][0] turn2=metalCD2/pin_dict[pin1][0] else: #device在PAD右边 Length2=p_start[0]-((pinset[pin1]-1)*pitch+pad1offset+padL/2) turn1=-linkW/pin_dict[pin1][0] turn2=-metalCD2/pin_dict[pin1][0] length=[Length1,Length2,length3] turn=[turn1,turn2] path1=gdspy.L1Path(p_start,'-y',pin_dict[pin1][0],length,turn,layer=gdsNo(Layer1),datatype=dtype(Layer1)) pad_cell.add(path1) if pin_dict[pin1][2]=='+y': #上引线 if pin1 in pinset: pad_num=pinset[pin1] if pad_num>location: p_start=(p_start[0]-pin_dict[pin1][0]/2,p_start[1]+metalCD/2) if (pad_num-1)*pitch+pad1offset>=d_cell.xCoord(pad_cell,cr): #如果PAD在device右边 length1=(pad_num-1)*pitch+pad1offset-p_start[0]+metalCD/2 #pin脚到PAD edge的距离 length2=p_start[1]-tkW+(tkW-padW)/2 #上面到PAD edge的距离 length=[length1,length2] turn=[-1] path1=gdspy.L1Path(p_start,'+x',metalCD,length,turn,layer=gdsNo(Layer1),datatype=dtype(Layer1)) elif (pad_num-1)*pitch+pad1offset<d_cell.xCoord(pad_cell,cr) and (pad_num-1)*pitch+pad1offset+padL>=d_cell.xCoord(pad_cell,cr): #PAD在device下面,但没跨过PAD length1=d_cell.xCoord(pad_cell,cr)-p_start[0]+metalCD+metalS+metalCD/2 #metal延伸到device右边, 并keep metalS length2=p_start[1]-tkW+(tkW-padW)/2 #上面到PAD的距离 length=[length1,length2] turn=[-1] path1=gdspy.L1Path(p_start,'+x',metalCD,length,turn,layer=gdsNo(Layer1),datatype=dtype(Layer1)) elif (pad_num-1)*pitch+pad1offset<d_cell.xCoord(pad_cell,cr) and (pad_num-1)*pitch+pad1offset+pitch-metalS>d_cell.xCoord(pad_cell,cr): #PAD在device下面,但没跨过PAD length1=d_cell.xCoord(pad_cell,cr)-p_start[0]+metalCD+metalS+metalCD/2 #metal延伸到device右边, 并keep metalS length2=p_start[1]-tkW+(tkW-padW)/2+metalCD/2 #上面到PAD的距离 length3=d_cell.xCoord(pad_cell,cr)+metalCD+metalS+metalCD/2-((pad_num-1)*pitch+pad1offset+padL) #转弯与pad相连 length=[length1,length2,length3] turn=[-1,-1] path1=gdspy.L1Path(p_start,'+x',metalCD,length,turn,layer=gdsNo(Layer1),datatype=dtype(Layer1)) else: length1=d_cell.xCoord(pad_cell,cr)-p_start[0]+metalCD+metalS+metalCD/2 #metal延伸到device右边, 并keep metalS length2=p_start[1]-tkW+(tkW-padW)/2-metalS-metalCD/2 #上面到PAD的距离 length3=d_cell.xCoord(pad_cell,cr)+metalCD+metalS+metalCD/2-((pad_num-1)*pitch+pad1offset+padL)+metalCD/2 #转弯与pad相连 length4=metalS+metalCD/2 length=[length1,length2,length3,length4] turn=[-1,-1,1] path1=gdspy.L1Path(p_start,'+x',metalCD,length,turn,layer=gdsNo(Layer1),datatype=dtype(Layer1)) if pad_num<location: p_start=(p_start[0]+pin_dict[pin1][0]/2,p_start[1]+metalCD/2) if (pad_num-1)*pitch+pad1offset+padL<=d_cell.xCoord(pad_cell,cl): #如果PAD在device左边 length1=p_start[0]-((pad_num-1)*pitch+pad1offset+padL)+metalCD/2 #左边pin脚到PAD edge的距离 length2=p_start[1]-tkW+(tkW-padW)/2 #上面到PAD edge的距离 length=[length1,length2] turn=[1] path1=gdspy.L1Path(p_start,'-x',metalCD,length,turn,layer=gdsNo(Layer1),datatype=dtype(Layer1)) elif (pad_num-1)*pitch+pad1offset+padL>d_cell.xCoord(pad_cell,cl) and (pad_num-1)*pitch+pad1offset<=d_cell.xCoord(pad_cell,cl): #PAD在device下面,但没跨过PAD length1=p_start[0]-d_cell.xCoord(pad_cell,cl)+metalCD+metalS+metalCD/2 #左边pin脚到PAD edge的距离 length2=p_start[1]-tkW+(tkW-padW)/2 #上面到PAD的距离 length=[length1,length2] turn=[1] path1=gdspy.L1Path(p_start,'-x',metalCD,length,turn,layer=gdsNo(Layer1),datatype=dtype(Layer1)) elif (pad_num-1)*pitch+pad1offset>d_cell.xCoord(pad_cell,cl) and (pad_num-1)*pitch+pad1offset-(pitch-padL)+metalS<=d_cell.xCoord(pad_cell,cl): #PAD在device下面,但没跨过PAD length1=p_start[0]-d_cell.xCoord(pad_cell,cl)+metalCD+metalS+metalCD/2 #左边pin脚到PAD edge的距离 length2=p_start[1]-tkW+(tkW-padW)/2+metalCD/2 #上面到PAD的距离 length3=(pad_num-1)*pitch+pad1offset-d_cell.xCoord(pad_cell,cl)+metalCD+metalS+metalCD/2 #转弯与pad相连 length=[length1,length2,length3] turn=[1,1] path1=gdspy.L1Path(p_start,'-x',metalCD,length,turn,layer=gdsNo(Layer1),datatype=dtype(Layer1)) else: length1=p_start[0]-d_cell.xCoord(pad_cell,cl)+metalCD+metalS+metalCD/2 #左边pin脚到PAD edge的距离 length2=p_start[1]-tkW+(tkW-padW)/2-metalS-metalCD/2 #上面到PAD的距离 length3=(pad_num-1)*pitch+pad1offset-d_cell.xCoord(pad_cell,cl)+metalCD+metalS+metalCD/2+metalCD/2 #转弯与pad相连 length4=metalS+metalCD/2 length=[length1,length2,length3,length4] turn=[1,1,-1] path1=gdspy.L1Path(p_start,'-x',metalCD,length,turn,layer=gdsNo(Layer1),datatype=dtype(Layer1)) pad_cell.add(path1) return pad_cell '''device放到pad下面''' if offset0.lower()=='down': for pin1 in pin_dict: p_start=(pin_dict[pin1][3][0]+x1,pin_dict[pin1][3][1]+y1) Layer1=pin_dict[pin1][1] if pin_dict[pin1][2]=='+x': #右引线 if pin1 in pinset: pad_num=pinset[pin1] length1=(pad_num-1)*pitch+pad1offset-p_start[0] #右边pin脚到PAD edge的距离 length2=abs(p_start[1])+(tkW-padW)/2 #上面到PAD edge的距离 if length1>0: #pin脚在pad左边 length=[length1+metalCD/2,length2] turn=[metalCD/pin_dict[pin1][0]] path1=gdspy.L1Path(p_start,'+x',pin_dict[pin1][0],length,turn,layer=gdsNo(Layer1),datatype=dtype(Layer1)) elif abs(length1)<=padL-metalCD: p_start=(p_start[0]+metalCD/2,p_start[1]-pin_dict[pin1][0]/2) path1=gdspy.Path(metalCD,p_start) path1.segment(length2+pin_dict[pin1][0]/2,'+y',layer=gdsNo(Layer1),datatype=dtype(Layer1)) elif abs(length1)>padL-metalCD and abs(length1)<=pitch-metalCD-metalS: p_start=(p_start[0]+metalCD/2,p_start[1]-pin_dict[pin1][0]/2) length3=p_start[0]-((pad_num-1)*pitch+pad1offset+padL) length=[length2+pin_dict[pin1][0]/2+metalCD2/2,length3] turn=[metalCD2/metalCD] path1=gdspy.L1Path(p_start,'+y',metalCD,length,turn,layer=gdsNo(Layer1),datatype=dtype(Layer1)) else: p_start=(p_start[0]+metalCD/2,p_start[1]-pin_dict[pin1][0]/2) length3=p_start[0]-((pad_num-1)*pitch+pad1offset+padL)+metalCD/2 length4=metalS+metalCD/2 length=[length2+pin_dict[pin1][0]/2-metalS-metalCD/2,length3,length4] turn=[1,-1] path1=gdspy.L1Path(p_start,'+y',metalCD,length,turn,layer=gdsNo(Layer1),datatype=dtype(Layer1)) pad_cell.add(path1) if pin_dict[pin1][2]=='-x': #左引线 if pin1 in pinset: pad_num=pinset[pin1] length1=p_start[0]-((pad_num-1)*pitch+pad1offset+padL) #左边pin脚到PAD edge的距离 length2=abs(p_start[1])+(tkW-padW)/2 #上面到PAD edge的距离 if length1>0: #pin脚在pad左边 length=[length1+metalCD/2,length2] turn=[-metalCD/pin_dict[pin1][0]] path1=gdspy.L1Path(p_start,'-x',pin_dict[pin1][0],length,turn,layer=gdsNo(Layer1),datatype=dtype(Layer1)) elif abs(length1)<=padL-metalCD: p_start=(p_start[0]-metalCD/2,p_start[1]-pin_dict[pin1][0]/2) path1=gdspy.Path(metalCD,p_start) path1.segment(length2+pin_dict[pin1][0]/2,'+y',layer=gdsNo(Layer1),datatype=dtype(Layer1)) elif abs(length1)>padL-metalCD and abs(length1)<=pitch-metalCD-metalS: p_start=(p_start[0]-metalCD/2,p_start[1]-pin_dict[pin1][0]/2) length3=((pad_num-1)*pitch+pad1offset)-p_start[0] length=[length2+pin_dict[pin1][0]/2+metalCD2/2,length3] turn=[-metalCD2/metalCD] path1=gdspy.L1Path(p_start,'+y',metalCD,length,turn,layer=gdsNo(Layer1),datatype=dtype(Layer1)) else: p_start=(p_start[0]-metalCD/2,p_start[1]-pin_dict[pin1][0]/2) length3=((pad_num-1)*pitch+pad1offset)-p_start[0]+metalCD/2 length4=metalS+metalCD/2 length=[length2+pin_dict[pin1][0]/2-metalS-metalCD/2,length3,length4] turn=[-1,1] path1=gdspy.L1Path(p_start,'+y',metalCD,length,turn,layer=gdsNo(Layer1),datatype=dtype(Layer1)) pad_cell.add(path1) if pin_dict[pin1][2]=='-y': #下引线 if pin1 in pinset: pad_num=pinset[pin1] if pad_num>location: p_start=(p_start[0]-pin_dict[pin1][0]/2,p_start[1]-metalCD/2) if (pad_num-1)*pitch+pad1offset>=d_cell.xCoord(pad_cell,cr): #如果PAD在device右边 length1=(pad_num-1)*pitch+pad1offset-p_start[0]+metalCD/2 #pin脚到PAD edge的距离 length2=d_cell.Width+metalCD/2+offset[1]+(tkW-padW)/2 #上面到PAD edge的距离 length=[length1,length2] turn=[1] path1=gdspy.L1Path(p_start,'+x',metalCD,length,turn,layer=gdsNo(Layer1),datatype=dtype(Layer1)) elif (pad_num-1)*pitch+pad1offset<d_cell.xCoord(pad_cell,cr) and (pad_num-1)*pitch+pad1offset+padL>=d_cell.xCoord(pad_cell,cr): #PAD在device下面,但没跨过PAD length1=d_cell.xCoord(pad_cell,cr)-p_start[0]+metalCD+metalS+metalCD/2 #metal延伸到device右边, 并keep metalS length2=d_cell.Width+metalCD/2+offset[1]+(tkW-padW)/2 #上面到PAD edge的距离 length=[length1,length2] turn=[1] path1=gdspy.L1Path(p_start,'+x',metalCD,length,turn,layer=gdsNo(Layer1),datatype=dtype(Layer1)) elif (pad_num-1)*pitch+pad1offset<d_cell.xCoord(pad_cell,cr) and (pad_num-1)*pitch+pad1offset+pitch-metalS>d_cell.xCoord(pad_cell,cr): #PAD在device下面,但没跨过PAD length1=d_cell.xCoord(pad_cell,cr)-p_start[0]+metalCD+metalS+metalCD/2 #metal延伸到device右边, 并keep metalS length2=d_cell.Width+metalCD/2+offset[1]+(tkW-padW)/2 +metalCD/2 length3=d_cell.xCoord(pad_cell,cr)+metalCD+metalS+metalCD/2-((pad_num-1)*pitch+pad1offset+padL) #转弯与pad相连 length=[length1,length2,length3] turn=[1,1] path1=gdspy.L1Path(p_start,'+x',metalCD,length,turn,layer=gdsNo(Layer1),datatype=dtype(Layer1)) else: length1=d_cell.xCoord(pad_cell,cr)-p_start[0]+metalCD+metalS+metalCD/2 #metal延伸到device右边, 并keep metalS length2=d_cell.Width+metalCD/2+offset[1]+(tkW-padW)/2-metalS-metalCD/2 length3=d_cell.xCoord(pad_cell,cr)+metalCD+metalS+metalCD/2-((pad_num-1)*pitch+pad1offset+padL)+metalCD/2 #转弯与pad相连 length4=metalS+metalCD/2 length=[length1,length2,length3,length4] turn=[1,1,-1] path1=gdspy.L1Path(p_start,'+x',metalCD,length,turn,layer=gdsNo(Layer1),datatype=dtype(Layer1)) if pad_num<location: p_start=(p_start[0]+pin_dict[pin1][0]/2,p_start[1]-metalCD/2) if (pad_num-1)*pitch+pad1offset+padL<=d_cell.xCoord(pad_cell,cl): #如果PAD在device左边 length1=p_start[0]-((pad_num-1)*pitch+pad1offset+padL)+metalCD/2 #左边pin脚到PAD edge的距离 length2=d_cell.Width+metalCD/2+offset[1]+(tkW-padW)/2 length=[length1,length2] turn=[-1] path1=gdspy.L1Path(p_start,'-x',metalCD,length,turn,layer=gdsNo(Layer1),datatype=dtype(Layer1)) elif (pad_num-1)*pitch+pad1offset+padL>d_cell.xCoord(pad_cell,cl) and (pad_num-1)*pitch+pad1offset<=d_cell.xCoord(pad_cell,cl): #PAD在device下面,但没跨过PAD length1=p_start[0]-d_cell.xCoord(pad_cell,cl)+metalCD+metalS+metalCD/2 #左边pin脚到PAD edge的距离 length2=d_cell.Width+metalCD/2+offset[1]+(tkW-padW)/2 #上面到PAD edge的距离 length=[length1,length2] turn=[-1] path1=gdspy.L1Path(p_start,'-x',metalCD,length,turn,layer=gdsNo(Layer1),datatype=dtype(Layer1)) elif (pad_num-1)*pitch+pad1offset>d_cell.xCoord(pad_cell,cl) and (pad_num-1)*pitch+pad1offset-(pitch-padL)+metalS<=d_cell.xCoord(pad_cell,cl): #PAD在device下面,但没跨过PAD length1=p_start[0]-d_cell.xCoord(pad_cell,cl)+metalCD+metalS+metalCD/2 #左边pin脚到PAD edge的距离 length2=d_cell.Width+metalCD/2+offset[1]+(tkW-padW)/2 +metalCD/2 length3=(pad_num-1)*pitch+pad1offset-d_cell.xCoord(pad_cell,cl)+metalCD+metalS+metalCD/2 #转弯与pad相连 length=[length1,length2,length3] turn=[-1,-1] path1=gdspy.L1Path(p_start,'-x',metalCD,length,turn,layer=gdsNo(Layer1),datatype=dtype(Layer1)) else: length1=p_start[0]-d_cell.xCoord(pad_cell,cl)+metalCD+metalS+metalCD/2 #左边pin脚到PAD edge的距离 length2=d_cell.Width+metalCD/2+offset[1]+(tkW-padW)/2-metalS-metalCD/2 length3=(pad_num-1)*pitch+pad1offset-d_cell.xCoord(pad_cell,cl)+metalCD+metalS+metalCD/2+metalCD/2 #转弯与pad相连 length4=metalS+metalCD/2 length=[length1,length2,length3,length4] turn=[-1,-1,1] path1=gdspy.L1Path(p_start,'-x',metalCD,length,turn,layer=gdsNo(Layer1),datatype=dtype(Layer1)) pad_cell.add(path1) if pin_dict[pin1][2]=='+y': #上引线 Length1=tkW-metal2edge-linkW/2-p_start[1] length3=(tkW-padW)/2-metal2edge-linkW/2 if pin1 in pinset: if pinset[pin1]>location: #device在PAD左边 Length2=(pinset[pin1]-1)*pitch+pad1offset+padL/2-p_start[0] turn1=-linkW/pin_dict[pin1][0] turn2=-metalCD2/pin_dict[pin1][0] else: #device在PAD右边 Length2=p_start[0]-((pinset[pin1]-1)*pitch+pad1offset+padL/2) turn1=linkW/pin_dict[pin1][0] turn2=metalCD2/pin_dict[pin1][0] length=[Length1,Length2,length3] turn=[turn1,turn2] path1=gdspy.L1Path(p_start,'+y',pin_dict[pin1][0],length,turn,layer=gdsNo(Layer1),datatype=dtype(Layer1)) pad_cell.add(path1) return pad_cell
10-21
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值