Technolgy file archetecture revised with dictionary input method

This commit is contained in:
=
2026-06-07 17:07:20 +08:00
parent 8a17f1dde0
commit 54d20eb154
163 changed files with 5948 additions and 1297 deletions
+65 -108
View File
@@ -1,127 +1,84 @@
import argparse
import os
import shutil
from copy import deepcopy
from pathlib import Path
from typing import Any, Dict
import yaml
from mxpic.technologies.manifest_loader import TECHNOLOGIES_ROOT
SILTERRA_EOM1_MANIFEST = TECHNOLOGIES_ROOT / "silterra" / "EMO1_2ML_CU.yml"
def build_silterra_eom1_manifest() -> Dict[str, Any]:
"""Build the Silterra EOM1 manifest consumed by mxpic_EDA."""
layers = {
"WG_HM": {"layer": 275, "datatype": 0},
"WG_STRIP": {"layer": 101, "datatype": 251},
"WG_LOWRIB": {"layer": 100, "datatype": 90},
"WG_SRIB": {"layer": 100, "datatype": 90},
"WG_HIGHRIB": {"layer": 232, "datatype": 0},
"HEATER": {"layer": 29, "datatype": 30},
"CT_SI": {"layer": 268, "datatype": 0},
"CT_GE": {"layer": 35, "datatype": 0},
"UTV": {"layer": 172, "datatype": 0},
"RDL_VIA": {"layer": 194, "datatype": 0},
"UTM": {"layer": 173, "datatype": 0},
"UTM2": {"layer": 197, "datatype": 0},
"RDL_MET": {"layer": 195, "datatype": 0},
"PAD_ELE": {"layer": 100, "datatype": 170},
"PAD_OPTICAL": {"layer": 100, "datatype": 160},
"PAD_AL": {"layer": 145, "datatype": 0},
"WG_N": {"layer": 263, "datatype": 0},
"SiN_Rib_WG": {"layer": 63, "datatype": 30},
"SSIN0": {"layer": 283, "datatype": 0},
"SSIN1": {"layer": 289, "datatype": 0},
"SSIN2": {"layer": 290, "datatype": 0},
"SSIN3": {"layer": 291, "datatype": 0},
"EXCLUSION": {"layer": 57, "datatype": 0},
"SALICIDE": {"layer": 128, "datatype": 60},
"DM_EXL": {"layer": 23, "datatype": 0},
"DM_EXL_FE": {"layer": 23, "datatype": 40},
"DM_EXL_BE": {"layer": 23, "datatype": 41},
"OXIDE_FACET": {"layer": 90, "datatype": 0},
"DT": {"layer": 404, "datatype": 0},
"P": {"layer": 256, "datatype": 0},
"N": {"layer": 257, "datatype": 0},
"PP": {"layer": 258, "datatype": 0},
"NP": {"layer": 259, "datatype": 0},
"PPP": {"layer": 260, "datatype": 0},
"NPP": {"layer": 261, "datatype": 0},
"PD_SIPP": {"layer": 100, "datatype": 140},
"PD_SINP": {"layer": 100, "datatype": 150},
}
"""Load the Silterra EOM1 manifest consumed by mxpic_EDA."""
return _build_export_manifest(SILTERRA_EOM1_MANIFEST)
return {
"schema_version": "1.0.0",
"foundry": "Silterra",
"technology": "EMO1_2ML_CU_Al_RDL",
"source_class": "mxpic.foundries.Silterra.EOM1_2ML_CU_RDL",
"constants": {
"STD_SMWG_WIDTH": 0.45,
"SLAB_GROWTH": 2,
"W_METAL_MIN": 5,
"SPACING_HEATER_MIN": 2,
"SPACING_METAL_MIN": 4,
"W_HEATER_MIN": 3,
},
"layers": layers,
"routing_types": ["euler_bend", "standard_bend"],
"defaults": {
"xsection": "strip",
"family": "optical",
"width": 0.45,
"radius": 10,
"routing_type": "euler_bend",
},
"xsections": {
"strip": {
"family": "optical",
"default_width": 0.45,
"default_radius": 10,
"layers": [
{"layer": "WG_HM", "growx": 0, "growy": 0},
{"layer": "WG_STRIP", "growx": 4, "growy": 4},
],
},
"rib_low": {
"family": "optical",
"default_width": 0.45,
"default_radius": 10,
"layers": [
{"layer": "WG_HM", "growx": 0, "growy": 0},
{"layer": "WG_SRIB", "growx": 3, "growy": 3},
{"layer": "WG_STRIP", "leftedge": [-0.5, -3], "rightedge": [-0.5, -3.5]},
{"layer": "WG_STRIP", "leftedge": [0.5, 3.5], "rightedge": [0.5, 3]},
],
},
"metal_1": {
"family": "electrical",
"default_width": 5,
"default_radius": 10,
"layers": [
{"layer": "UTM", "growx": 0, "growy": 0},
{"layer": "SSIN0", "growx": 2.5, "growy": 2.5},
],
},
"metal_2": {
"family": "electrical",
"default_width": 5,
"default_radius": 10,
"layers": [
{"layer": "UTM2", "growx": 0, "growy": 0},
{"layer": "SSIN1", "growx": 2.5, "growy": 2.5},
],
},
},
}
def _build_export_manifest(manifest_path: Path) -> Dict[str, Any]:
with manifest_path.open("r", encoding="utf-8") as file:
manifest = yaml.safe_load(file) or {}
manifest = deepcopy(manifest)
manifest["layers"] = _export_layers(manifest.get("layers", {}))
return manifest
def _export_layers(layers: Dict[str, Any]) -> Dict[str, Any]:
exported = {}
for name, entry in layers.items():
exported_entry = dict(entry)
layer = exported_entry.pop("layer")
exported_entry["layer"] = int(layer[0])
exported_entry["datatype"] = int(layer[1])
exported[name] = exported_entry
return exported
def export_manifests(destination_root: str) -> None:
"""Export supported technology manifests into an EDA PDK root."""
manifest = build_silterra_eom1_manifest()
technology_dir = os.path.join(destination_root, manifest["foundry"], manifest["technology"])
os.makedirs(technology_dir, exist_ok=True)
output_path = os.path.join(technology_dir, "technology.yml")
with open(output_path, "w", encoding="utf-8") as file:
for manifest_path in _manifest_paths():
_export_manifest(manifest_path, destination_root)
def _manifest_paths() -> list[Path]:
return sorted(
path
for path in TECHNOLOGIES_ROOT.glob("*/*.yml")
if path.is_file()
)
def _export_manifest(manifest_path: Path, destination_root: str) -> None:
manifest = _build_export_manifest(manifest_path)
technology_dir = Path(destination_root) / manifest["foundry"] / manifest["technology"]
technology_dir.mkdir(parents=True, exist_ok=True)
_copy_material_files(manifest, manifest_path.parent, technology_dir)
output_path = technology_dir / "technology.yml"
with output_path.open("w", encoding="utf-8") as file:
yaml.safe_dump(manifest, file, sort_keys=False, allow_unicode=True)
def _copy_material_files(manifest: Dict[str, Any], source_dir: Path, technology_dir: Path) -> None:
for material in manifest.get("materials", {}).values():
data_file = material.get("data_file")
if not data_file:
continue
source = source_dir / data_file
if not source.exists():
continue
target = technology_dir / data_file
target.parent.mkdir(parents=True, exist_ok=True)
shutil.copy2(source, target)
def main() -> None:
parser = argparse.ArgumentParser(description="Export mxpic technology manifests for mxpic_EDA.")
parser.add_argument(