如何创建并管理自己的器件库

在使用流片厂提供的 PDK 进行线路设计时,除了直接调用 PDK 中已有的器件组件,我们通常还会根据具体需求自定义一些器件,以便在后续项目中复用。那么,这些自定义器件应该如何组织和存放?又该如何管理这些器件库,才能提高开发效率并实现良好的可维护性?本教程将介绍如何基于 PDK 构建自定义器件库,并实现规范化的文件结构与集成方式。

1.器件库Library结构

器件库的结构与PDK类似,假设我们基于 si_fab 工艺创建一个名为 pteam_library_si_fab 的自定义器件库,其文件目录结构如下所示
luceda_academy/libraris/pteam_library_si_fab

2. ipkiss文件夹结构说明

在 pteam_library_si_fa 文件夹下,有一个名为ipkiss的子目录,包含该库的所有IPKISS相关代码。其下又细分为以下模块:technology、component、all.py

2.1 technology文件夹

该文件夹用于定义工艺信息。因为我们的自定义器件是基于 si_fab PDK 的,因此可以直接继承其工艺定义。通常只需在 technology/__init__.py 中写入如下内容:
# Note: this file may contain additional technology layers that are required for our small pcells library. # Currently we need to specify this file and load TECH so the library builder knows how to build this library. from si_fab import technology TECH = technology.TECH

2.2 components文件夹

这是Library的核心部分,用于存放所有自定义器件的实现。例如:pteam_library_si_fab\ipkiss\pteam_library_si_fab\components\splitter_tree
其中,cell.py包含器件的主体代码__init__.py 则负责暴露接口,供外部模块导入
cell.py为SplitterTree的代码
from si_fab import all as pdk from ipkiss3 import all as i3 class SplitterTree(i3.Circuit): """This creates a splitter tree PCell, made of 1x2 splitter elements. Users can specify the number of tree levels as PCell parameter. """ splitter = i3.ChildCellProperty(doc="Splitter used") levels = i3.IntProperty(default=3, doc="Number of levels") spacing_x = i3.PositiveNumberProperty( default=100.0, doc="Spacing between the splitters in x-direction in the last level" ) spacing_y = i3.PositiveNumberProperty(default=50.0, doc="Spacing in y-direction") bend_radius = i3.PositiveNumberProperty() def _default_bend_radius(self): return 5.0 def _default_splitter(self): return pdk.MMI1x2Optimized1550() def _default_insts(self): insts = dict() for level in range(self.levels): for sp in range(int(2**level)): insts[f"sp_{level}_{sp}"] = self.splitter return insts def _default_specs(self): specs = [] for level in range(self.levels): for sp in range(int(2**level)): sp_y = self.spacing_y * 2 ** (self.levels - level - 1) specs.append( i3.Place( f"sp_{level}_{sp}", (level * self.spacing_x, -0.5 * (2**level - 1) * sp_y + sp * sp_y), ) ) for level in range(1, self.levels): for sp in range(int(2**level)): if sp % 2 == 0: in_port = f"sp_{level - 1}_{int(sp / 2.0)}:out1" else: in_port = f"sp_{level - 1}_{int(sp / 2.0)}:out2" out_port = f"sp_{level}_{sp}:in1" specs.append(i3.ConnectManhattan(in_port, out_port, bend_radius=self.bend_radius)) return specs
__init__.py 文件如下所示
from .cell import SplitterTree

2.3  all.py 文件

该文件用于统一导入所有器件,便于在主项目中调用。如下所示
from .components.mzi import MZI from .components.heated_mux2 import Mux2Heated from .components.splitter_tree import SplitterTree, RoutedSplitterTree from .components.mzm import MZModulator from .components.tunable_delay import TunableDelayLine from .components.ppc_unit.pcell.cell import PPCUnit from .components.mux2 import Mux2 __all__ = [ "MZI", "Mux2Heated", "SplitterTree", "RoutedSplitterTree", "MZModulator", "TunableDelayLine", "PPCUnit", "Mux2", ]
至此,我们完成了自定义器件库 pteam_library_si_fab 的基本搭建。

3. 如何在项目中调用自定义器件库

 3.1 要在主项目中使用该库,请将 pteam_library_si_fab/ipkiss 目录标记为 source folder,然后在项目代码中通过 import 语句引入:  
将pteam_library_si_fab/ipkiss标为source
3.2  建议在项目目录下新建一个名为 designs 的文件夹,用于存放线路设计脚本。例如:  
新建一个名为desgin的文件夹存放线路设计的代码,如 designs\iq_modulator\example_iqmodulator_packaged_layout.py,并导入pteam_library_si_fab中MZModulator

4. 如何使自定义器件库中的器件在IPKISS Canvas中也能使用呢?

4.1 概念介绍

什么是IPKISS Canvas?
什么是*.iclib?
  • *.iclib定义PDK在Canvas的库文件,包含PDK/Library中所有器件symbol(原理图),是使用 Canvas 功能的基础配置文件。
  • Luceda 的每个PDK通常都会提供一个 .iclib 文件,位于 all.py 同一目录下。如果缺失,请联系 Luceda 支持并提供您使用的PDK版本号,我们会协助与流片厂沟通并更新资源。

4.2 如何为自己的器件库创建*.iclib呢?

通过运行 build_iclib.py 脚本生成对应的 .iclib 文件。流程如下:
  1. 导入自定义库:import pteam_library_si_fab.all as pteam_lib
  2. 给每个器件设置一个symbol:"MZI": {"image": SymbolImage.MZI},
  3. 修改要输出的iclib文件名和library name
  4. 运行代码(build_iclib.py), 生成 .iclib 文件,测试效果
import pteam_library_si_fab.all as pteam_lib # noqa from ipkiss3.all.canvas import export_ipkiss_library, SymbolImage import os import argparse def build_iclib(dst_path=None): lib_path = os.path.dirname(os.path.abspath(pteam_lib.__file__)) if dst_path is None: dst_path = lib_path iclib_dst = os.path.join(dst_path, "pteam_library_si_fab.iclib") print(f"Exporting iclib to {iclib_dst}") export_ipkiss_library( library_path=lib_path, library_name="pteam_library_si_fab", output_path=iclib_dst, symbols={ "MZI": { "image": SymbolImage.MZI, "terms_positions": { "elec1": [-0.4, 1], "elec2": [0.4, 1], "in2": [-1, 0.4], "in1": [-1, -0.5], "out2": [1, 0.4], "out1": [1, -0.5], }, }, "Mux2Heated": { "width": 175, "height": 75, "terms_positions": { "ht_in0": [-0.7, 1], "ht_out0": [-0.5, 1], "ht_in1": [-0.3, 1], "ht_out1": [-0.1, 1], "ht_in2": [0.1, 1], "ht_out2": [0.3, 1], "ht_in3": [0.5, 1], "ht_out3": [0.7, 1], }, }, "TunableDelayLine": { "width": 150, }, "SplitterTree": { "image": SymbolImage.DEMUX, }, "MZModulator": { "image": SymbolImage.MZM, "width": 100, "terms_positions": { "SR_pad": [-0.9, 1], "G3_pad": [-0.6, 1], "SL_pad": [-0.9, -1], "G1_pad": [-0.6, -1], }, }, }, ) parser = argparse.ArgumentParser(description="build pteam_library_si_fab iclib") parser.add_argument("-o", "--output-dir", dest="output_dir") args = parser.parse_args() build_iclib(args.output_dir)
ps: 代码来源于luceda_academy\libraries\pteam_library_si_fab\building\build_iclib.py
2025-06-12
0