在高重复性的 EMX 仿真工作中,手动重复设置扫频范围、网格精度等参数非常低效。本文总结了适配 EMX 23.x 和 25.x 的最佳实践,旨在通过 emxconfig.il 实现高度自动化的仿真工作流。


一、 定制优先级与最佳建议

在定制 EMX 接口时,我们建议遵循以下优先级顺序:

  1. 第一优先级:利用 EMX_ 全局变量 如果 emxconfig.il 中已存在专门控制某个字段或功能的全局变量(如 EMX_signals_init),应优先使用。这种方式最为稳健且符合官方设计。
  2. 第二优先级:使用 Hook 函数 对于扫频范围(Start/Stop/Step)等没有直接对应变量的字段,或者需要复杂的逻辑判断时,再考虑使用 EMX_form_create_hook (25.x) 或 EMX_form_init_proc (23.x+25.x)。

二、 第一级:全局变量定制手册 (Variable-First)

以下变量直接映射到界面中的特定字段或核心开关,应作为定制的首选方案。

类别 变量名 控制的 UI 字段 / 功能
引脚与网络 EMX_signals_init 设置 Signals 字段的初始值(字符串)。
精度与控制 EMX_accuracy 对应高级表单中的 Accuracy (–accuracy) 开关。
  EMX_memory 对应高级表单中的 Memory (–recommended-memory) 开关。
  EMX_surface 对应主表单中的 Surface metals 字段。
数据输出 EMX_save_outputs 定义输出类型 (s/y) 和格式。
  EMX_save_PSF 控制是否输出 PSF 格式文件。
批处理 EMX_remote_machine 对应 Use bsub/qsub 相关的提交命令。
  EMX_use_job_monitor 决定何时显示作业监控窗口。
基础配置 EMX_auto_config 控制接口功能根据 EMX 版本自动启用。
  EMX_working_dir 设置默认仿真工作路径(Work dir)。

三、 第二级:进阶 Hook 深度定制

当全局变量无法满足需求(如需设置特定的扫频步长)时,使用钩子函数。

1. EMX_form_create_hook (仅限 25.x)

在 Widget 创建之前拦截并修改描述符。支持动态隐藏字段或更改默认默认值。

  • 注意:必须在 load 核心代码之后赋值,否则会被系统内置逻辑重置。

2. EMX_form_init_proc (23.x与25.x均可)

在界面对象构建之后触发。这是最稳健的方案,底层使用 fboundp 直接访问函数注册表,避开了常见的环境变量命名冲突问题。


3. 核心参考:UI 标签与 SKILL 属性映射

在使用 Hook 设置具体字段值时,需要通过属性名定位。

  • 默认规则:将 UI 标签(Label)中的空格替换为下划线 (_)。例如 Edge mesh -> Edge_mesh
  • 显式定义:若描述符由 symbol 定义,则以此为准(如 (float "Start freq" ... Start) 属性名为 Start)。
界面 UI 标签 (Label) SKILL 属性名
Basic Start freq Start
Basic Stop Stop
Basic Step Step
Basic Edge mesh Edge_mesh
Advanced Capacitive vias Capacitive
Advanced Inductive Inductive

emxconfig.il 内的 hook 模板:

; --- EMX 25.x: form-descriptor hook ---
; Set AFTER the load so emxform.ils cannot reset it to '().
EMX_form_create_hook=(list
  (lambda (which form_desc)
    (mapcar
      (lambda (item)
        (cond
          ; basic: frequency
          ((and (equal which 'basic) (listp item) (not (null item))
                (equal (car item) 'float) (equal (cadr item) "Start freq"))
           (list 'float "Start freq" 0.0 0.0 "infinity" 'Start))
          ((and (equal which 'basic) (listp item) (not (null item))
                (equal (car item) 'float) (equal (cadr item) "Stop"))
           (list 'float "Stop" 2e11 0.0 "infinity"))
          ((and (equal which 'basic) (listp item) (not (null item))
                (equal (car item) 'string) (equal (cadr item) "Step"))
           (list 'string "Step" "1e+08"))
          ; basic: mesh / merge
          ((and (equal which 'basic) (listp item) (not (null item))
                (equal (car item) 'float) (equal (cadr item) "Edge mesh"))
           (list 'float "Edge mesh" 0.1 0.0001 "infinity"))
          ((and (equal which 'basic) (listp item) (not (null item))
                (equal (car item) 'float) (equal (cadr item) "Thickness"))
           (list 'float "Thickness" 0.1 0.0001 "infinity"))
          ((and (equal which 'basic) (listp item) (not (null item))
                (equal (car item) 'float) (equal (cadr item) "Via merge"))
           (list 'float "Via merge" 0.1 0.0 "infinity"))
          ; advanced: vias
          ((and (equal which 'advanced) (listp item) (not (null item))
                (equal (car item) 'string) (equal (cadr item) "Capacitive vias"))
           (list 'string "Capacitive vias" "*" 'Capacitive))
          ((and (equal which 'advanced) (listp item) (not (null item))
                (equal (car item) 'string) (equal (cadr item) "Inductive"))
           (list 'string "Inductive" "*"))
          (t item)))
      form_desc)))

; --- EMX 23.x + 25.x: post-creation init proc ---
; Directly sets field values on the live form objects.
; Field names: EMX_nospaces(label), or explicit symbol in descriptor.
(procedure (emx_custom_defaults bgui agui)
  bgui->Start->value=0.0
  bgui->Stop->value=2e11
  bgui->Step->value="1e+08"
  bgui->Edge_mesh->value=0.1
  bgui->Thickness->value=0.1
  bgui->Via_merge->value=0.1
  agui->Capacitive->value="*"
  agui->Inductive->value="*"
)
EMX_form_init_proc='emx_custom_defaults

四、 避坑指南:常见 Bug 与排查汇总

# 症状 根因 解决方法
1 Hook 无反应 设置语句在 load 之前,被 boundp 重置 移至 load 语句之后
2 字段匹配失败 混淆了 basicadvanced 作用域 检查 which 参数的判断逻辑
3 保存后失效 存在 EMX_defaults cellview 模拟器优先加载本地 CV,需手动删除
4 语法错误 .il 文件中误用 == (应为 equal) 改用标准 SKILL 前缀函数

五、 环境管理:动态路径建议

利用 Shell 环境变量实现多版本无偏运行:

(if (getShellEnvVar "EMXHOME")
  EMX_interface_path = (sprintf nil "%s/share/emx/virtuoso_ui/emxinterface" (getShellEnvVar "EMXHOME"))
  EMX_interface_path = (pwd)
)
EMX_path = (strcat (or (getShellEnvVar "EMXHOME") (getShellEnvVar "CDSHOME")) "/bin")

[!IMPORTANT] 结论 “变量优先,Hook 补位”是最高效的定制准则。同时请牢记:加载顺序(Load Order)是影响定制能否生效的最关键因素。