Files
oapy/labs/src/lab25_1_traits.py
opencad-abu 1e26b0dff7 Add labs: 59 Python lab scripts + tools + run_lab.sh
- labs/src/: 59 lab scripts covering OA API (Ch2-Ch25 + extras)
  - All C++ references removed, oapy-only documentation
- labs/tools/: debug and test utilities
- labs/run_lab.sh: lab runner with LD_PRELOAD and env setup
2026-06-02 16:59:08 +08:00

257 lines
7.9 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""
oapy Lab 25-1: traits — Python Type Dispatch for InstTerm Types
功能: 使用 Python 类型分派实现 traits 类型分派模式,统一处理三种 InstTerm:
oaInstTerm (Block domain), oaModInstTerm (Module domain),
oaOccInstTerm (Occurrence domain)
运行: cd /workarea/ai/openclaw/oapy && labs/run_lab.sh labs/lab25_1_traits.py
"""
import os, shutil
from utils import init_oa, make_oa_string, make_oa_name, get_namespace, c_str
from oapy._oa import _design, _base, _dm
def _s(v):
if isinstance(v, str):
return v
if hasattr(v, 'c_str'):
return c_str(v)
try:
op = getattr(v, 'operator[]', None)
if op:
return ''.join(op(i) for i in range(v.getLength()))
except:
pass
return str(v)
LIB = "LibTest25"
LIB_PATH = "../data/LibDir25_1"
CELL_INV = "Inverter"
CELL_TOP = "Top"
VIEW = "abstract"
def _sn(sn):
if isinstance(sn, str): return sn
s = make_oa_string(); sn.get(s); return c_str(s)
# ═══════════════════════════════════════════════════════════════════════════
# Traits-style dispatch functions
# ═══════════════════════════════════════════════════════════════════════════
def traits_get_num_pins(term):
"""Get number of pins — only Block domain Terms have getPins()."""
if term is None:
return 0
try:
pins = term.getPins(0)
return pins.getCount()
except:
return 0
def traits_get_mod_inst_term(inst_term):
"""从 Block-domain InstTerm 获取对应的 ModInstTerm."""
try:
occ = inst_term.getOccInstTerm()
if occ:
return occ.getModInstTerm()
except:
pass
return None
def traits_type_name(obj):
"""获取 InstTerm 的类型名称OA 风格)"""
if obj is None:
return "NULL"
try:
return obj.getType().getName()
except:
return type(obj).__name__
def traits_get_container_name(inst_term):
"""获取 InstTerm 容器的类型名Block/Module/Occurrence"""
try:
ot = _s(inst_term.getType().getName())
if "Occ" in ot:
return "Occurrence"
elif "ModInstTerm" in ot:
return "Module"
elif "InstTerm" in ot:
return "Block"
return "Unknown"
except:
return "Unknown"
def get_master_info(it, term_names=None):
"""打印任意 InstTerm 的 Master 信息traits 分派)"""
if it is None:
return
container_type = traits_get_container_name(it)
term = None
try:
ot = _s(it.getType().getName())
except:
ot = ""
if "OccInstTerm" in ot:
try:
occ_term = it.getTerm(False)
if occ_term:
try:
term = occ_term.getTerm()
except:
term = None
except:
term = None
else:
try:
term = it.getTerm()
except:
term = None
# 获取 Term 类型名
if "OccInstTerm" in ot:
term_type_name = "OccTerm"
else:
term_type_name = traits_type_name(term) if term else "UNBINDABLE"
# Pin 数量(不同 Domain 行为不同)
num_pins = traits_get_num_pins(term) if term else 0
# Term 名称
if "OccInstTerm" in ot:
try:
t_name = it.getTermName(get_namespace("native"))
except:
t_name = "UNBINDABLE"
elif term:
try:
ns = get_namespace("native")
t_name = term.getName(ns)
if not isinstance(t_name, str):
t_name = _sn(t_name)
except:
t_name = str(term_names.get(int(term.__hash__()), "?")) if term_names else "?"
else:
t_name = "UNBINDABLE"
print(f" {_s(term_type_name):20s} {_s(container_type):14s} {int(num_pins):5d} {_s(t_name)}")
def main():
print("=" * 60)
print("oapy Lab 25-1: Traits Pattern (Python Type Dispatch)")
print("=" * 60)
init_oa()
for d in [LIB_PATH, "../data/lib.defs"]:
if os.path.exists(d):
(shutil.rmtree(d) if os.path.isdir(d) else os.remove(d))
os.makedirs(LIB_PATH, exist_ok=True)
ns = get_namespace("native")
# ── Create Lib ──
sn_lib = make_oa_name(ns, LIB)
lib = _dm.oaLib.create(sn_lib, make_oa_string(LIB_PATH),
_dm.oaLibMode(_dm.oaLibModeEnum.oacSharedLibMode),
make_oa_string('oaDMFileSys'), _dm.oaDMAttrArray(0))
print(f"\n Created Lib '{LIB}'")
ST = _design.oaSigTypeEnum; BV = _design.oaBlockDomainVisibilityEnum
sig = _design.oaSigType(ST.oacSignalSigType)
vis = _design.oaBlockDomainVisibility(BV.oacInheritFromTopBlock)
vt = _dm.oaViewType.find(make_oa_string("netlist"))
# ── Create Inverter Design ──
sn_inv = make_oa_name(ns, CELL_INV)
sn_top = make_oa_name(ns, CELL_TOP)
sn_view = make_oa_name(ns, VIEW)
des_inv = _design.oaDesign.open(sn_lib, sn_inv, sn_view, vt, 'w')
des_top = _design.oaDesign.open(sn_lib, sn_top, sn_view, vt, 'w')
block_inv = _design.oaBlock.create(des_inv, True)
block_top = _design.oaBlock.create(des_top, True)
print(f" Created Blocks for {CELL_INV} and {CELL_TOP}")
# ── Create Nets, Terms, Pins in Inverter ──
net_i = _design.oaScalarNet.create(block_inv, make_oa_name(ns, "netIn"), sig, 1, vis)
net_o = _design.oaScalarNet.create(block_inv, make_oa_name(ns, "netOut"), sig, 1, vis)
term_i = _design.oaScalarTerm.create(net_i, make_oa_name(ns, "TermIn"))
term_o = _design.oaScalarTerm.create(net_o, make_oa_name(ns, "TermOut"))
# Create Pins (only Block domain terms have pins)
_design.oaPin.create(term_i, 0)
_design.oaPin.create(term_i, 1)
_design.oaPin.create(term_o, 0)
print(f" Created 2 Pins on TermIn, 1 Pin on TermOut")
# ── Instantiate Inverter in Top ──
xform = _base.oaTransform(0, 0, _base.oaOrient(_base.oaOrientEnum.oacR0))
inst_inv = _design.oaScalarInst.create(block_top, des_inv,
make_oa_name(ns, "Inv1"),
xform, _base.oaParamArray(0),
vis,
_design.oaPlacementStatus(_design.oaPlacementStatusEnum.oacUnplacedPlacementStatus))
print(f" Created Inst: Inv1")
# ── Create InstTerms ──
it_i = _design.oaInstTerm.create(None, inst_inv, term_i, vis)
it_o = _design.oaInstTerm.create(None, inst_inv, term_o, vis)
print(f" Created InstTerms: it_i, it_o")
# ── Get OccInstTerms ──
oit_i = it_i.getOccInstTerm()
oit_o = it_o.getOccInstTerm()
print(f" OccInstTerms: oit_i={oit_i is not None}, oit_o={oit_o is not None}")
# ── Get ModInstTerms ──
mit_i = traits_get_mod_inst_term(it_i)
mit_o = traits_get_mod_inst_term(it_o)
print(f" ModInstTerms: mit_i={mit_i is not None}, mit_o={mit_o is not None}")
# ── Print Master Info (traits dispatch) ──
print(f"\n{'='*60}")
print(f"OBJECT TYPE CONTAINER #PINS TERM NAME")
print(f"{'='*60}")
term_names = {}
for it in [it_i, mit_i, it_o, mit_o]:
if it:
get_master_info(it, term_names)
# Also try OccInstTerms
for oit in [oit_i, oit_o]:
if oit:
get_master_info(oit, term_names)
print(f"{'='*60}")
des_inv.save(); des_top.save()
des_inv.close(); des_top.close()
lib.close()
for d in [LIB_PATH, "../data/lib.defs"]:
if os.path.exists(d):
(shutil.rmtree(d) if os.path.isdir(d) else os.remove(d))
print(f"\n✅ oapy Lab 25-1 完成!")
if __name__ == "__main__":
main()