import argparse import os from typing import Any, Dict import yaml 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}, } 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 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: yaml.safe_dump(manifest, file, sort_keys=False, allow_unicode=True) def main() -> None: parser = argparse.ArgumentParser(description="Export mxpic technology manifests for mxpic_EDA.") parser.add_argument( "--dest", default=os.path.abspath(os.path.join(os.getcwd(), "..", "mxpic_EDAX", "mxpic", "PDKs")), help="Destination mxpic_EDA PDK root.", ) args = parser.parse_args() export_manifests(os.path.abspath(args.dest)) if __name__ == "__main__": main()