Files
oapy/labs/src/lab25_1_traits.py

257 lines
7.9 KiB
Python
Raw Permalink Normal View History

#!/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()