总览与约定
MCP 工具名是稳定的 namespace.verb。每个工具都归属唯一一个领域,同一个领域 token 既是 klink.find_tools domain=<token> 的导航键,也是 --profile <token> 的过滤器。
阅读约定
- 参数表里
name*表示必填,其余为可选。 - 坐标:带
_um后缀是微米(最自然);带_dbu是整数数据库单位。micron = dbu × layout.dbu,dbu来自layout.info。 - 图层写法三选一:图层索引
int、"L/D"字符串(如"1/0")、或{layer, datatype}对象。 - 徽章含义: read 只读 · write 写入 · verify 验证 · escape 逃生舱 · mutates 会改动版图(可 Ctrl+Z 撤销)· long 长耗时(走独立超时)。
shape.insert_boxes / shape.insert_many / instance.insert_many / instance.insert_pcell_many。单件插入只用于调试单个对象。
动态发现工具
目录是实时查询的,不要死记。Python 侧:
from klink import KLinkClient
with KLinkClient() as c:
print([m["name"] for m in c.methods()["methods"]]) # meta.methods
MCP 侧,tools/list 会公布每一个工具,而 klink.find_tools 负责导航:
klink.find_tools # 无参 → 领域索引(每个领域一行)
klink.find_tools domain="routing_backends" # 该领域的工具 + 详细用法
klink.find_tools query="lvs route" # 跨全部工具的关键词排序匹配
不确定用哪个工具时,klink.guide 会报告当前打开了什么、磁盘上已有哪些意图状态(declared nets / LVS 报告 / spec),并给出每个可用意图的字面调用。
Profiles 过滤
--profile 沿两条正交轴过滤 MCP 暴露的工具——意图与领域。默认是 read,write,verify,escape。
| 意图 Profile | 暴露什么 |
|---|---|
| read | 只读探查:layout.info、cell.list、shape.query、view.*、pcell.*、recorder。 |
| write | 版图编辑:shape.insert_*、cell.create、layer.ensure、instance.insert*、edit.undo。 |
| verify | 运行检查:drc.run、lvs.run。 |
| escape | 逃生舱:exec.python、exec.reset、events.*。 |
all | 全部,不过滤。 |
python -m klink.mcp --profile read,write,verify,escape # 默认
python -m klink.mcp --profile read,device_photonics # 混合两轴
python -m klink.mcp --profile routing_backends # 只暴露一个领域
所有本地工具在任意意图 profile 下都始终包含;核心导航工具 klink.find_tools / klink.status / klink.reconnect 永远在。旧别名仍有效:basic→read、draw→write、advanced→escape、drc→verify。
1 · 连接、自检、发现与视图 connection_and_view · 15 tools
不确定时从这里开始。 klink.status 报告连接、当前 session、解释器和可选能力(gdsfactory、klayout.db);klink.guide 报告打开了什么 + 磁盘意图状态 + 下一步字面调用;klink.find_tools 按领域/关键词导航其余工具;klink.reconnect 恢复断掉的连接。View 工具是读为主的画布导航——注意新建的 cell 在 view.show_cell 之前是不可见的。截图(view.screenshot)只是用户要的产物,绝不是 agent 的验证步骤,优先用几何查询。
| 工具 | 参数 | 功能 |
|---|---|---|
klink.status | — | MCP 桥连接状态、当前 session、解释器与上次连接错误。排障第一步。 |
klink.reconnect | — | 关掉过期 client 并尝试重连 KLayout。 |
klink.guide | — | 报告已打开内容、磁盘上的意图状态,以及每个可用意图的字面调用和建议下一步。不知道该干嘛就调它。 |
klink.find_tools | domain, query | 按领域或关键词发现工具。无参→领域索引;domain→该域工具+用法;query→排序匹配。 |
hello | client, protocol | 介绍 client,拿到 server 信息+能力列表。推荐每条新连接的第一次调用。 |
meta.ping | — | 存活探针,回显 params + trace id,用于测往返延迟。 |
meta.methods | — | 返回完整 RPC 方法目录(描述 + JSON schema),可直接喂给 LLM function-calling。 |
meta.debug_signals | fire | SignalHub 诊断日志;fire="selection_changed" 可触发合成事件测投递链路。 |
view.list_tabs | — | 列出该窗口所有 layout tab(索引、标题、文件、active cell、当前 tab)。 |
view.activate_tab mutates | index* | 按索引切换当前 tab;之后所有单 layout RPC 都作用于该 tab。 |
view.show_cell | cell*, zoom_fit | 把当前 cellview 显示的 top cell 切成指定 cell(新建 cell 靠它才可见),默认 zoom-fit。 |
view.screenshot | mode, width_px, height_px, bbox_dbu, path | 渲染 PNG。mode=base64 内嵌 data URL(给有视觉的 LLM);mode=path 存盘返回绝对路径。仅用户请求时用。 |
view.zoom_fit mutates | — | 整幅版图适配视口(等价 GUI 的 Zoom Fit)。 |
view.zoom_box mutates | bbox_dbu* | 缩放到恰好显示给定 bbox(dbu)。 |
view.viewport | — | 报告当前视口:可见 bbox(dbu)、视图像素尺寸、cellview 索引。 |
view.show_lvsdb | path*, kind | 把存盘的 LVS/netlist 数据库载入 Netlist Browser 并显示,交互 cross-probe。kind=lvs 读 .lvsdb,kind=l2n 读 .l2n。 |
示例:连接自检 + 查看当前状态。
# MCP(agent 视角)
klink.status
klink.guide
view.list_tabs
# Python client 等价
from klink import KLinkClient
with KLinkClient() as c:
print(c.hello(client="my-script"))
print(c.layout_info(verbosity="summary"))
print(c.ping(nonce=42))
2 · 多会话注册表与跨会话搬运 multi_session_transfer · 15 tools
klink 用一个 MCP 桥驱动多个 KLayout session(每个是本地注册表里的一个端口,通常 8765、8766……)。所有 session 是平等 peer,没有特权端口——显式传你要的那个。搬运是两阶段、确认安全的:transfer_prepare 构建包并在目标 dry-run 后挂起,transfer_commit 才写入。
| 工具 | 参数 | 功能 |
|---|---|---|
klink.session_list | include_stale | 从本地注册表枚举可发现的 KLayout/klink session。 |
klink.session_status | session_id, include_stale | 返回一条 session 记录,默认当前 MCP session。 |
klink.session_label | session_id*, label*, aliases, description | 给注册的 session 附人类 label 和别名。 |
klink.session_resolve | query* | 把 id / label / 别名 / active cell / top cell 解析成一个 session。 |
klink.session_use | session_id* | 把 MCP 桥的主 RPC 目标切到指定 session。 |
klink.session_set_klive_target | session_id* | 指定 klive 兼容 8082 入口用的 session(gdsfactory c.show() 落点)。 |
klink.transfer_prepare | source_session*, target_session*, target_cell, copy_mode, layer_map, translate_um | 构建两 session 间的 flat-selection 搬运包并在目标 dry-run。 |
klink.transfer_commit | package_id*, dry_run | 提交 transfer_prepare 生成的包。 |
session.mark_klive_target | — | (plugin 侧)把本窗口标记为 klive/gdsfactory 兼容的 8082 目标。 |
session.label_set | session_id*, label*, aliases, description | (plugin 侧)在共享注册表里设 label 和别名。 |
transfer.pending_set | package* | 把已审阅的 flat-selection 包存进本窗口。 |
transfer.pending_status | — | 本窗口挂起搬运包的状态。 |
transfer.pending_clear | — | 清掉挂起包(不写几何)。 |
transfer.paste_pending mutates | dry_run, clear_after | 把挂起的 flat-selection 包粘入本窗口(包内已含最终目标层与坐标)。 |
transfer.import_cell_tree_package mutates long | path*, source_cell*, dry_run | 用 KLayout 原生 Cell.copy_tree 从 GDS/OAS 包导入一棵 cell 树;重名以 $N 解决。 |
示例:给窗口打标签,再把选中几何从一个窗口搬到另一个。
klink.session_list
klink.session_label session_id="klayout-8766" label="scratch" aliases=["test"]
klink.session_resolve query="scratch"
# 两阶段搬运:先 prepare + dry-run,看清目标/cell/layer/统计再 commit
klink.transfer_prepare source_session="klayout-8765" target_session="klayout-8766" copy_mode="flat_selection"
klink.transfer_commit package_id="pkg_0001"
3 · 几何与单元结构 geometry_authoring · 28 tools
核心绘图面。先读:layout.info、cell.list/cell.tree、layer.list、shape.query、instance.query、pcell.*。再用批量 RPC 写。画之前先 layer.ensure。编辑都包在事务里,edit.undo/redo/status 操作它们。破坏性的 layout.clear/cell.delete 只对一次性测试 cell 用,除非用户明确要求,别碰用户的工作 tab。
读取(geometry, not pixels)
| 工具 | 参数 | 功能 |
|---|---|---|
layout.info | verbosity | 当前 layout 快照:视图数、active cellview、top cell、源文件、dbu、top-cell 列表、已注册 layer/datatype。想快速了解当前状态就用它。 |
cell.list | name_prefix, top_only, with_bbox, offset, limit | 扁平分页列出 cell。发现有哪些 cell 用它,层级用 cell.tree。 |
cell.tree | root, max_depth, max_nodes | 从某 cell 起的层级树(受 depth/nodes 限);每个节点的 instances 数说明它被父实例化几次。 |
layer.list | — | 列出所有已定义图层:layer_index(其他 RPC 用的句柄)、layer/datatype、可选 name,附 dbu_um。 |
shape.query long | cell*, layers, bbox_dbu, kinds, limit | 读一个 cell 的形状(不递归)为 JSON。强烈建议用 layers+bbox_dbu 缩小范围并分页(默认 500,最大 5000)。truncated=true 表示还有更多。 |
instance.query | parent*, child, bbox_dbu, bbox_um, limit | 列父 cell 的直接子实例:child 名、bbox、变换、array、PCell 元数据、子 cell 各层形状计数。 |
pcell.libraries | — | 列可用 PCell 库(Basic 恒在;PDK 注册自己的)。 |
pcell.list | library | 列某库(默认 Basic)里全部 PCell 名。 |
pcell.info | library, pcell* | 描述一个 PCell 的参数(name/type/default/description/choices),据此构造 instance.insert_pcell 的 params。 |
写入 · 单元与图层
| 工具 | 参数 | 功能 |
|---|---|---|
cell.create mutates | name | 新建 cell;重名时 KLayout 追加 $1…(返回生效名)。不保证幂等,每次调用建新 cell。 |
cell.rename mutates | cell*, new_name*, allow_suffix | 重命名;重名默认报错(allow_suffix=true 才自动加后缀)。 |
cell.delete mutates | cell*, recursive | 删 cell。recursive=true 连带删孤儿子 cell;默认残留 ghost 引用。破坏性。 |
layer.ensure mutates | layer*, datatype, name | 确保 GDS 层存在(缺则在事务里建),返回 layer_index。纯 upsert,可反复调。 |
写入 · 形状(批量优先)
| 工具 | 参数 | 功能 |
|---|---|---|
shape.insert_boxes mutates | cell, layer, boxes_um / boxes_dbu | 批量:一次 RPC、一个事务插入很多矩形到同一 cell/层。生成式版图首选。 |
shape.insert_many mutates | cell*, items*, dry_run | 批量:一次插入混合形状(box/polygon/path/text),每项带自己的层选择器和几何字段。 |
shape.insert_box mutates | cell, layer, bbox_um / bbox_dbu | 单个轴对齐矩形。调试单对象用。 |
shape.insert_polygon mutates | cell, layer, points_um / points_dbu | 单个多边形(仅外壳,暂不支持洞),≥3 点,自动闭合。 |
shape.insert_path mutates | cell, layer, points, width, begin_ext, end_ext, round_ends | 单条 path(中心线+宽度),可选端延伸与圆头。 |
shape.insert_text mutates | cell, layer, position, size_um | 单个文本标签(非几何注记,不产生掩模)。 |
shape.delete mutates | cell, layer(s), bbox, kinds, dry_run | 按声明式选择器删形状(层 + 可选 bbox + 可选 kinds)。dry_run=true 先看计数。整批一个事务,可一次 undo。 |
写入 · 实例与 PCell(批量优先)
| 工具 | 参数 | 功能 |
|---|---|---|
instance.insert_many mutates | parent*, items*, dry_run | 批量:一次插入很多已存在子 cell 实例。每项含 child + 变换/array 字段。 |
instance.insert_pcell_many mutates | parent*, items*, dry_run | 批量:一次插入很多 PCell 实例(library/pcell/params/变换/array)。 |
instance.insert mutates | parent*, child*, position, rotation, mirror, magnification, array | 把 child 放进 parent。位置微米/dbu,旋转度数,可选 array 建网格。 |
instance.insert_pcell mutates | parent*, library, pcell*, params, position, rotation, … | 从库构建一个 PCell 变体 cell(如 Basic.CIRCLE/TEXT)再插一个实例。先 pcell.info 查参数。相同 params 复用同一变体。 |
instance.query | parent*, child, bbox, limit | (见上)读父 cell 的子实例。 |
instance.delete mutates | parent*, child, bbox, all, limit, dry_run | 按声明式选择器删实例(对子 cell 本身非破坏,只去引用)。一个事务。 |
pcell.register_fitted | name*, fit_table* | 运行期从 fit table 注册一个拟合器件 PCell(klink_transistor_pcell_fit_v1),落到 klink_structdevice 库,无需重载插件。新器件族零插件改动。 |
写入 · Layout 级与编辑历史
| 工具 | 参数 | 功能 |
|---|---|---|
layout.show_file mutates long | path*, mode, keep_position, technology | 载入 GDS/OAS(已开则 reload)。mode=replace 当前视图 / new 新 tab。录制时合并为一行。 |
layout.save_file mutates | path*, cellview_index | 存盘。扩展名决定格式:.gds/.gds2 GDSII,.oas/.oasis OASIS。 |
layout.clear mutates | cellview_index | 破坏性:清空整幅 layout(所有 cell/形状/层级)。 |
edit.undo mutates | — | 撤销最近一次可撤销操作(klink RPC、Macro IDE 编辑或 GUI 编辑)。返回前后栈快照。 |
edit.redo mutates | — | 重做,与 edit.undo 配对。 |
edit.status | debug | 报告当前 undo/redo 可用性;debug=true 暴露 Manager 内省字段。 |
示例:先读当前状态 → 建 cell 与层 → 批量画 → 显示。
# 1) 读
layout.info verbosity="summary"
cell.list top_only=true
# 2) 建 cell + 确保层
cell.create name="MYBLOCK"
layer.ensure layer=1 datatype=0 name="M1"
# 3) 批量画一排矩形(微米)——不要循环单插!
shape.insert_boxes cell="MYBLOCK" layer="1/0" boxes_um=[[0,0,10,4],[20,0,30,4],[40,0,50,4]]
# 4) 混合形状一次插入
shape.insert_many cell="MYBLOCK" items=[
{"kind":"box","layer":"1/0","bbox_um":[0,10,50,14]},
{"kind":"path","layer":"2/0","points_um":[[0,20],[50,20]],"width_um":2},
{"kind":"text","layer":"63/0","position_um":[0,26],"text":"MYBLOCK","size_um":4}
]
# 5) 让它可见(新 cell 在 show_cell 前不可见)
view.show_cell cell="MYBLOCK"
示例:放置 Basic.CIRCLE PCell(先查参数)。
pcell.info library="Basic" pcell="CIRCLE"
instance.insert_pcell parent="MYBLOCK" library="Basic" pcell="CIRCLE" \
params={"l":"1/0","r":5.0,"n":64} position_um=[100,0]
# 一次放一个 8×8 网格
instance.insert parent="TOP" child="MYBLOCK" position_um=[0,0] \
array={"rows":8,"cols":8,"pitch_x_um":60,"pitch_y_um":40}
4 · 选择与 SEND 交互记忆 selection_and_send_memory · 11 tools
两件不同的事。selection.* 是 KLayout 里当前的实时选择;interaction.* 是用户明确 SEND 过(工具栏 SEND,记成 sel_0006 这样的 id)的持久 session 记忆。当用户说“刚发的”“这块区域”“这里”“那一个”时用它们——按顺序/数量解析,不是按时间;把用户措辞绑到这些 id/查询,而不是绑到截图。
| 工具 | 参数 | 功能 |
|---|---|---|
selection.get | limit | 当前视图的选择,每项是 shape(层+bbox)或 instance(目标 cell+bbox)。空选择返回空列表,不是错误。 |
selection.set_box mutates | cell*, bbox_dbu*, layers, limit | 选中 cell 内 bbox 与给定框相交的所有形状(默认全层),替换当前选择,返回选中数。 |
selection.clear mutates | — | 清空当前选择。 |
selection.send_context | source, max_items | 把当前非空选择作为 selection_sent 事件显式发出(agent 侧 SEND)。不在 plugin 存记忆。 |
interaction.selection.latest | — | 本 MCP session 记忆里最新一次 SEND。 |
interaction.selection.recent | limit | 最近若干次 SEND(默认最新 5,按顺序不按时间裁剪)。 |
interaction.selection.get | id* | 按稳定 id 读一条存储选择。 |
interaction.selection.label | id*, label, description | 给某条存储选择加/改 label 和描述。 |
interaction.selection.clear_session | confirm* | 确认后清掉本 MCP session 的持久交互上下文。 |
interaction.context | include_current_selection | 同时返回当前 KLayout 选择 + 最近持久 SEND 记忆。 |
示例:解析“把我刚发的两块连起来”。
# 用户在 KLayout 里选中 A,点 SEND;再选中 B,点 SEND
interaction.selection.recent limit=2 # → [sel_0007(B), sel_0006(A)]
interaction.selection.label id="sel_0006" label="probe pad"
# 现在按 id 去 mark port / 声明 net,而不是靠截图猜位置
5 · Port 与 Anchor(路由标记) ports_and_anchors · 16 tools
Port 是网络端点(klink_Port PCell:带 net + 朝向 + 宽度)。Anchor 是路由约束(klink_Anchor PCell),kind 为 waypoint_region / bend_region / corridor(普通 corridor 是必经通道;给它 choice_group=BUS 才变成可选通道)。路由工具默认 port_layer=999/99、anchor_layer=999/1。Keepout 不是 anchor 类型——它是你传给路由工具的 obstacle_layers(你自己设计里的层);klink 不带默认 keepout 层。这些是路由后端的输入:先 mark Port+Anchor,再调 routing.*。
| 工具 | 参数 | 功能 |
|---|---|---|
port.set_layer mutates | layer* | 配置本 layout 的默认 Port 标记层。 |
port.mark mutates | cell*, name, center, orientation, width_um, port_type, net, target_layer, … | 在 cell 里建一个 klink_Port PCell 实例(一个端点)。 |
port.list | cell*, layer, sort | 列 cell 里的 Port(给 layer 则只列该标记层的)。 |
port.update mutates | cell*, name*, orientation, width_um, net, … | 按不可变 name 更新单个 Port。 |
port.transform mutates | cell*, names / selection, rotate_delta, net, … | 按 names 或 GUI 选择批量更新 Port 参数。 |
port.repair_names mutates | cell*, layer, prefix | 修复重复/空 Port 名(主要给经 GUI PCell 面板手插、绕过唯一性检查的)。 |
port.unmark mutates | cell*, name* | 按 name 删一个 Port。 |
port.delete_all mutates | cell*, layer | 删 cell 里全部 Port。 |
anchor.set_layer mutates | layer* | 配置默认 Anchor 标记层。 |
anchor.mark mutates | cell*, kind, center, net, radius_um, width_um, height_um, path_points, … | 建一个 klink_Anchor PCell 实例(路由约束)。 |
anchor.list | cell*, layer, sort | 列 cell 里的 Anchor。 |
anchor.update mutates | cell*, id*, new_id, kind, net, … | 按不可变 id 更新单个 Anchor。 |
anchor.transform mutates | cell*, ids / names / selection, kind, … | 按 ids 或选择批量更新 Anchor。 |
anchor.repair_ids mutates | cell*, layer, prefix | 修复重复/空 Anchor id(GUI 手插的)。 |
anchor.unmark mutates | cell*, id* | 按 id 删一个 Anchor。 |
anchor.delete_all mutates | cell*, layer | 删 cell 里全部 Anchor。 |
示例:标两个对着的 Port,加一个必经 waypoint,然后路由。
port.mark cell="NET1" name="A" center_um=[0,0] orientation="E" width_um=2 net="sig"
port.mark cell="NET1" name="B" center_um=[80,20] orientation="W" width_um=2 net="sig"
anchor.mark cell="NET1" kind="waypoint_region" center_um=[40,40] radius_um=6 net="sig"
port.list cell="NET1"
routing.tapered_hybrid_cell cell="NET1" angle_mode="manhattan" obstacle_layers=["10/0"]
6 · 路由后端 routing_backends · 9 tools
都读一个 cell 里的 Port/Anchor PCell 并写出路由几何。按拓扑/质量选后端。永远检查结构化结果:ok=false、obstacle_hit_count>0、sibling 重叠、route_count 偏少都算失败。诚实报告 router 局限。障碍处理要传你自己设计的 obstacle_layers(无默认)。
| 工具 | 参数 | 功能 |
|---|---|---|
routing.tapered_hybrid_cell | cell*, spacing_um, angle_mode, clear, port_layer, anchor_layer, obstacle_layers | 主要的 path+patch 后端。angle_mode:any / manhattan / fortyfive。 |
routing.tapered_polygon_cell | cell*, …, route_layer, corner_style, obstacle_layers | 连续 taper 多边形(正式后端,不是备选),corner_style miter/bevel/round。 |
routing.steiner_cell | cell*, route_layer, root_ports, clear, obstacle_layers | 多端网络(>2 port)的直角 Steiner/总线树。星形网否则要拆成 2-port。 |
routing.damped_segment_cell | cell, damping_distance_um, obstacle_layers, … | 显式远离障碍的 damped 段后端(用 hybrid 输出 + 额外软间距)。 |
routing.damped_polygon_cell | cell, damping_distance_um, corner_style, … | damped 连续 taper 多边形版。 |
routing.damped_steiner_cell | cell, damping_distance_um, root_ports, … | damped 多端 trunk/branch 版。 |
routing.global_channel_cell | cell*, spacing_um, angle_mode, safe_distance_um, obstacle_layers | 更强的全局决策路由:障碍感知候选 sink 分配 + corridor 容量负载均衡,再复用 hybrid 几何。非完整 rip-up/reroute。 |
routing.multilayer_escape_cell | cell*, route_layer*, bridge_layer*, via_layer*, spacing_um, obstacle_layers | 用主层 + bridge 层 + via 盒子给被墙挡住的成对网络逃逸(窄;不建模 via enclosure)。 |
routing.gdsfactory_ports | cell*, route_layer*, router, cross_section, separation_um, radius_um, waypoints_um, path_length_match, obstacle_bboxes_um, … | 读 cell 的 Port 标记,用一种命名 gdsfactory 策略路由再写回。需 MCP 解释器里有 gdsfactory。 |
routing.gdsfactory_ports 的 router 策略(选错参数会报错并指出哪些 router 支持它,绝不静默忽略):
| router | 用途 |
|---|---|
bundle(默认) | 带间距的 Manhattan river 路由;也支持 waypoints/steps、radius_um、start/end_straight_um、path_length_match 等长、collision_check_layers。 |
electrical | bundle + 金属默认 + 直角尖角 + 电学端口类型。 |
sbend | 横向偏移、面对面端口的平滑 S 过渡。 |
all_angle | 非 Manhattan bundle(可选 backbone_um 脊线)。 |
single | 每对独立 Manhattan 路由。 |
dubins | 每对基于圆弧的任意朝向路由。 |
astar(实验) | 绕 obstacle_bboxes_um 的网格 A*;gf 的 astar 脆弱,klink 会校验结果,穿墙则报错而不是返回坏路由。可靠避障请用 klink 自己的 tapered_hybrid/damped + obstacle_layers。 |
示例:主路由 + 更强避障 + gdsfactory bundle。
# klink 自带的主路由,Manhattan,避开你的 keepout 层
routing.tapered_hybrid_cell cell="BLOCK" angle_mode="manhattan" spacing_um=20 obstacle_layers=["900/0"]
# 需要更大障碍间距时
routing.damped_segment_cell cell="BLOCK" damping_distance_um=15 obstacle_layers=["900/0"]
# 多端网络(>2 port)
routing.steiner_cell cell="BLOCK" route_layer="1/0"
# gdsfactory river bundle,等长匹配
routing.gdsfactory_ports cell="BLOCK" route_layer="1/0" router="bundle" \
separation_um=5 radius_um=10 path_length_match=true
ok、obstacle_hit_count、sibling overlap 和 route_count。真正的“完成”只有 live LVS match=True。7 · DRC 与 LVS 验证 drc_and_lvs_verification · 2 tools
两个都是长耗时、纯 pya、领域无关的逃生舱式检查。drc.run 跑你提供的任意 DRC DSL(Ruby)脚本——脚本内异常作为结果返回,不会让 RPC 失败。lvs.run 是连通性对应物:把 live 版图抽成器件网表,和你提供的参考网表比对,写 .lvsdb 并(默认 show=true)在 Netlist/LVS 浏览器打开做 cross-probe。一个 P&R/器件阶段只有在真实 live LVS match=True 时才算 DONE——离线 fixture 和 marker 计数都不能替代。structdevice 流程优先用 structdevice.lvs_check。
| 工具 | 参数 | 功能 |
|---|---|---|
drc.run mutates long | (DRC DSL 源码 + 可选 output_rdb / 输入变量) | 在 KLayout 集成 Ruby DRC 引擎跑任意 DRC DSL。含 source() 则 standalone,否则对当前 layout 交互式跑。 |
lvs.run long | cell*, conductors*, vias, devices*, reference*, out_lvsdb, show | 抽取(按 devices 配置的 per-cell 器件抽取器 + 你传的导体层)→ 与参考网表(reference.spice 或结构化 reference.netlist)比对 → 写 .lvsdb 并显示。 |
示例:最小 DRC(间距检查)与 LVS 调用骨架。
# DRC:M1 最小间距 0.2um(交互模式,对当前 layout)
drc.run script="""
m1 = input(1, 0)
m1.space(0.2.um).output("M1_space", "M1 spacing < 0.2um")
"""
# LVS:抽取导体层,和参考 SPICE 比对,打开浏览器
lvs.run cell="BLOCK" conductors=["1/0","3/0"] vias=["2/0"] \
devices={...} reference={"spice":"ref.spice"} out_lvsdb="block.lvsdb" show=true
8 · 自定义器件网表 → 自动 P&R → LVS device_structdevice · 7 tools
这是器件无关的自定义器件 P&R 流。“器件”=任何带任意参数集 + 端子的 cell;klink 不假设参数名/数量,也没有器件词汇表。器件库、工艺 profile、端子来源都是示例/PDK 数据显式传入——MCP 工具不带任何工艺,缺工艺时返回有指导性的错误(“写/跑一个 example”),绝不猜。物理模型很紧凑:器件自己的金属层同时当路由层用;mode 2L/3L 选用其中 2 或 3 层。
| 工具 | 参数 | 功能 |
|---|---|---|
structdevice.build_from_netlist | cell*, netlist*, confirm, mode, rows, cols, session | 一次调用的主流程:给器件级网表({instances, nets, groups}),派生 floorplan → 单趟多层路由 → 绘制 → 器件 LVS 验证一个全新 cell。确认门控:先不带 confirm → 返回 proposal;带 confirm token 再调 → 真正 build。 |
structdevice.declare_nets | recent_sends*, cell*, conductors, vias | 从 SEND 声明电学网络:一次 SEND 框住 ≥2 个端子 = 一个声明网络(持久化到 <cell>.elec_nets.json)。示例驱动,缺 recipe 报指导性错误。 |
structdevice.connect_nets | cell*, session, route_layer, route_width_um, via_cell, min_spacing_um, min_width_um, conductors, vias | 把每个已声明但未连接的网络布线并验证:recipe 派生 attach point、自动 via、自动 keepout、damped 路由,然后 LVS——任何 mismatch 全部撤销。在 declare 之后、spec_write 之前。 |
structdevice.lvs_check | cell*, session, mode, conductors, vias | 一次调用 LVS:派生器件端子(recipe)→ 抽取实际布线做出的网络 → 和 declared 网络对账。mode=net(默认)net 级;device/both 另跑器件级 NetlistComparer → device_lvs。 |
structdevice.spec_write | cell*, layer_roles*, session, device_class, conductors, vias | 把 live cell 投影成 klink.spec.json v1 事实文件:器件、实例、declared/derived 网络及对账。layer_roles 把 L/D 映射到角色名。 |
structdevice.register_pcell | name*, fit_table*, session | 运行期从 fit table 注册拟合器件 PCell(fitter 产出后调)。落到 klink_structdevice 库,零插件改动零重载,GUI 与 instance.insert_pcell 立即可用。 |
pcell.register_fitted | name*, fit_table* | 上面 register_pcell 背后的底层 plugin RPC。 |
示例:从器件级网表两步 build。
# 第 1 步:不带 confirm → 拿 proposal(网格 rows×cols、行距、路由层、器件混合)
structdevice.build_from_netlist cell="RINGOSC" netlist={
"instances":[{"name":"INV0","device":"inv_x1"}, ...],
"nets":[{"name":"a","terminals":["INV0/in","INV2/out"]}, ...],
"groups":[]
} mode="3L"
# → needs_confirmation + proposal + next_action(confirm=...)
# 第 2 步:同样参数 + confirm token → 真正 place/route/draw/LVS
structdevice.build_from_netlist cell="RINGOSC" netlist={...} mode="3L" confirm="CONFIRM-xyz"
示例:SEND 驱动的交互连线。
# 用户为每个网络 SEND 一次(框住该网络的所有端子)
structdevice.declare_nets recent_sends=3 cell="BLOCK" conductors=["1/0","3/0"] vias=["2/0"]
structdevice.connect_nets cell="BLOCK" route_layer="3/0" route_width_um=0.5
structdevice.lvs_check cell="BLOCK" mode="both"
structdevice.spec_write cell="BLOCK" layer_roles={"1/0":"gate","3/0":"metal1"}
9 · 纳米器件(Hall bar / EBL / flake) device_nanodevice · 2 tools
nanodevice.hallbar 用一次调用完成整个流程:它在通用 port 标记 + 路由之上,额外提供参数化的 Hall bar 器件几何——从 HallBarSpec(bar 长宽、contact 数、contact/pad 尺寸、pitch、gap)算并画整个器件(bar + N 对称接触臂 + pad + Port 标记 + label),然后把实际路由交给通用 router 把 contact 接到 pad(开启重叠校验,可选 EBL writefield 墙当 keepout),提交到一次性 cell(支持 dry_run)。失败返回 problems/next_action,什么都不改。
| 工具 | 参数 | 功能 |
|---|---|---|
nanodevice.hallbar | cell, spec, writefield, route_layer, spacing_um, dry_run, session | 一次调用生成 + 路由 + 校验 + 提交一个 Hall bar:从 spec 生成几何 + Port/Anchor,用 klink router 把 contact 接 pad(重叠校验 ON,可选 writefield 墙),写入一次性 cell。 |
nanodevice.detect_commit | cell, traces_path, image, pixel_size_um, coordinate, dry_run, session | 加载(或检测)纳米器件 flake trace 并作为多边形提交进 live cell。traces_path 走预算 traces.json(无额外依赖);image+pixel_size_um 走实时检测(需本解释器有 cv2 + numpy)。 |
示例:生成并路由一个 Hall bar;再从预算 traces 提交 flake。
nanodevice.hallbar cell="HB1" spec={
"bar_length_um":60, "bar_width_um":8, "contact_count":6,
"contact_width_um":4, "pad_size_um":40, "pitch_um":24, "gap_um":6
} route_layer="1/0" dry_run=true
nanodevice.detect_commit cell="FLAKE" traces_path="out/traces.json"
10 · 硅光(gdsfactory 导入 / 连接 / 重路由) device_photonics · 4 tools
光子电路流,需 MCP 解释器里有 gdsfactory。两个端口来源、一个交互循环:photonics.import_gf 一次把成品 gdsfactory 脚本接管进循环(器件实例→真实 KLayout cell+实例,routed/snapped 连接坍缩成器件级网络,per-device port 模板持久化进 spec,网络由 klink 路由);port.harvest_blackbox 从 live blackbox 实例位置按 foundry stub 约定派生 Port。接管后,在 GUI 里拖动组件 → 一次 photonics.reroute 把光学和金属一起重画。这个“拖动→reroute”循环就是重点:版图保持 live 可编辑,不是一次性冻结。
| 工具 | 参数 | 功能 |
|---|---|---|
photonics.import_gf | script_path*, component, cell, route_layer, port_layer, route, session | 一次接管成品 gdsfactory 脚本:跑用户 .py,取它 build 的 Component,把器件实例导入为真实 KLayout cell+实例(批量 RPC),把 routed 连接坍缩成器件级网络,持久化 port 模板 + net 表,并用 klink 路由(脚本自己的路由被替换)。 |
port.harvest_blackbox | cell*, tags*, nets, wg_layer*, stub_size_um*, port_layer, clear | 按 waveguide stub 约定(波导层上的小 stub 盒)从 PDK blackbox 实例派生 Port。Port 由 live 实例位置得来——移动实例后重跑刷新,再路由。 |
photonics.connect | recent_sends*, cell, width_um, radius_um, separation_um, wg_layer, stub_size_um, route_layer | 连接用户刚 SEND 的端口:读最近 N 次 SEND → 变成端口对(一次 SEND 框两个 Port 标记 = 一对)→ 自动命名网络 → 持久化 → 重新 harvest → gdsfactory 路由。session 从 SEND 自动推得。 |
photonics.reroute | cell*, session, wg_layer, stub_size_um, route_layer | 用户移动组件后重路由:读持久 net 表 → 从 live 实例位置重新 harvest → 路由 → 写回。只需 cell 名。多端光学网络需先放 splitter/MMI。 |
示例:接管一个 gdsfactory 脚本,然后拖动后重路由。
# 1) 一次接管成品脚本(脚本里 c = build_mzi(); 供 klink 取用)
photonics.import_gf script_path="my_mzi.py" cell="MZI" route_layer="1/0"
# 2) 在 KLayout GUI 里拖动某个 phase shifter……然后:
photonics.reroute cell="MZI" # 光学 + 金属一起重画,保住你的拖动
# 也可从 blackbox stub 约定派生端口后再连
port.harvest_blackbox cell="MZI" tags=["gc","mmi"] wg_layer="1/0" stub_size_um=0.5
photonics.connect recent_sends=4 cell="MZI" radius_um=10 separation_um=5
11 · Escape hatch(pya exec、事件、recorder) escape_hatch · 8 tools
优先用 typed RPC。 exec.python 跑原始 pya,仅用于没有 typed RPC 覆盖的操作 / 调试 / 紧凑一次性——它仍会触发 recorder + layout-diff 检测。events.* 是桥为 SEND 记忆订阅的 live 事件流(通常你改读 interaction.*)。recorder.* 生成回放脚本(不是字面 RPC 日志);测试前先看 recorder.status,别覆盖用户正在录的东西。
| 工具 | 参数 | 功能 |
|---|---|---|
exec.python mutates | (code + 可选 reset) | 在 KLayout Qt 主线程跑任意 Python。全 pya + 文件系统访问。预绑定 pya, mw, view, layout。同一连接内状态保留(reset=true 清空)。stdout/stderr 捕获返回。 |
exec.reset mutates | — | 清空 exec.python 的 per-connection 命名空间(要个干净沙箱)。 |
events.channels | — | 列 server 能推的事件通道。事件以 NDJSON 帧 {"event":…,"data":…} 投递。 |
events.status | — | 本连接的订阅 + SignalHub 诊断。调试 selection_changed 是否绑定/订阅。 |
events.subscribe | channels* | 订阅一或多个通道(未知通道静默忽略,看返回的 accepted)。 |
events.unsubscribe | channels | 退订;传 * 退全部,空/省略则不变。 |
recorder.start | output_path | 开始把所有改动版图的事件翻译成可回放 Python 脚本。幂等。默认落 ~/Documents/klink_recordings/…。 |
recorder.stop | output_path | 停止并写脚本;返回统计 + wrote。幂等。 |
recorder.status | — | 当前 recorder 状态(是否在录、事件/动作数、输出路径)。随时可调。 |
示例:录制一段会话,用 pya 做一次性操作。
recorder.status # 先确认没在录别人的
recorder.start
# …做一些 typed RPC 编辑 + 手工 GUI 编辑…
recorder.stop # 产出 <name>.py 和可独立跑的 <name>_pya.py
# 没有 typed RPC 覆盖时才用逃生舱
exec.python code="print(layout.top_cell().name); print(len(list(layout.each_cell())))"
recorder 产出两个文件:<name>.py(基于 KLinkClient 的回放)和 <name>_pya.py(可在 KLayout 内独立运行的 pya 版)。