Skip to content

Commit

Permalink
FEAT: Edb configuration distributed ports (#451)
Browse files Browse the repository at this point in the history
* add log scale in siwave syz

* FEAT: distributed ports

* MISC: Auto fixes from pre-commit.com hooks

For more information, see https://pre-commit.ci

* minor

---------

Co-authored-by: ring630 <@gmail.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
  • Loading branch information
hui-zhou-a and pre-commit-ci[bot] authored May 3, 2024
1 parent 769100d commit 53620ce
Show file tree
Hide file tree
Showing 5 changed files with 276 additions and 22 deletions.
45 changes: 45 additions & 0 deletions src/pyedb/configuration/cfg_data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates.
# SPDX-License-Identifier: MIT
#
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

from pyedb.configuration.cfg_ports import CfgPort


class CfgData(object):
"""Manages configure data."""

def __init__(self, pedb, **kwargs):
self.pedb = pedb
self.edb_comps = self.pedb.components.components

self.cfg_general = None
self.cfg_boundaries = None
self.cfg_nets = None
self.cfg_components = None
self.cfg_padstacks = None
self.cfg_pin_groups = None
self.cfg_ports = [CfgPort(self, **port) for port in kwargs.get("ports", [])]
self.cfg_setups = None
self.cfg_stackup = None
self.cfg_s_parameters = None
self.cfg_spice_models = None
self.cfg_package_definition = None
self.cfg_operations = None
149 changes: 149 additions & 0 deletions src/pyedb/configuration/cfg_ports.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
# Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates.
# SPDX-License-Identifier: MIT
#
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

from enum import Enum

from pyedb.dotnet.edb_core.edb_data.padstacks_data import EDBPadstackInstance


class CfgNegTerm:
"""Manage negative terminal."""

class CfgTermType(Enum):
"""Terminal types."""

pin = [list, str]
net = [str]
pin_group = [str]

@property
def pedb(self):
"""Edb."""
return self.pport.pedb

def __init__(self, pport, **kwargs):
self.pport = pport
self.type = kwargs.get("type", None)
self.value = kwargs.get("value", None)

def _get_candidates(self, distributed):
"""Get list of objects."""

def get_pin_obj(pin_name):
port_name = "{}_{}".format(self.pport.reference_designator, pin_name)
return {port_name: self.pport.pdata.edb_comps[self.pport.reference_designator].pins[pin_name]}

def get_pin_group_obj(pin_group_name):
pin_group_obj = self.pedb.siwave.pin_groups[pin_group_name]
return {pin_group_obj.name: pin_group_obj}

term_objs = dict()
if self.type in "pin":
term_objs.update(get_pin_obj(self.value))
elif self.type == "pin_group":
term_objs.update(get_pin_group_obj(self.value))
elif self.type == "net":
pins = self.pport.pdata.pedb.components.get_pin_from_component(self.pport.reference_designator, self.value)
pins = [EDBPadstackInstance(p, self.pedb) for p in pins]

pin_objs = {f"{self.value}_{p.GetName()}": p for p in pins}
if distributed:
term_objs.update(pin_objs)
else:
pg_name = f"pg_{self.pport.reference_designator}_{self.value}"
pin_objs = {p.GetName(): p for p in pin_objs.values()}
if self.pport.type == "coax":
term_objs.update(get_pin_obj(pins[0].GetName()))
else:
temp = self.pport.pdata.pedb.siwave.create_pin_group(
self.pport.reference_designator, list(pin_objs.keys()), pg_name
)
term_objs.update({temp[0]: temp[1]})
return term_objs

def get_candidates(self):
"""Get list of objects."""
return self._get_candidates(False)


class CfgPosTerm(CfgNegTerm):
"""Manage positive terminal."""

def __init__(self, pport, **kwargs):
super().__init__(pport, **kwargs)

def get_candidates(self):
"""Get list of objects."""
return self._get_candidates(self.pport.distributed)


class CfgPort:
"""Manage port."""

class CfgPortType(Enum):
"""Port type."""

circuit = [str]
coax = [str]

@property
def pedb(self):
"""Edb."""
return self.pdata.pedb

def __init__(self, pdata, **kwargs):
self.pdata = pdata
self.name = kwargs.get("name", None)
self.type = kwargs.get("type", None)
self.reference_designator = kwargs.get("reference_designator", None)
pos_term = kwargs.get("positive_terminal", None)
neg_term = kwargs.get("negative_terminal", None)
if pos_term:
self.positive_terminal = CfgPosTerm(
pport=self, type=list(pos_term.keys())[0], value=list(pos_term.values())[0]
)
if neg_term:
self.negative_terminal = CfgPosTerm(
pport=self, type=list(neg_term.keys())[0], value=list(neg_term.values())[0]
)
self.distributed = kwargs.get("distributed", False)

self._port_name = None

def create(self):
"""Create port."""
if self.type == "circuit":
candidates = [i for i in self.negative_terminal.get_candidates().values()][0]
neg_term = candidates.get_terminal(create_new_terminal=True)
else:
neg_term = None
ports = []
for name, p in self.positive_terminal.get_candidates().items():
if self.distributed:
port_name = f"{self.name}_{name}" if self.name else name
else:
port_name = self.name if self.name else name
pos_term = p.get_terminal(port_name, create_new_terminal=True)
is_circuit_port = True if self.type == "circuit" else False
port = self.pedb.create_port(pos_term, neg_term, is_circuit_port)
ports.append(port)
return ports
12 changes: 9 additions & 3 deletions src/pyedb/configuration/configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

import toml

from pyedb.configuration.cfg_data import CfgData
from pyedb.dotnet.edb_core.definition.package_def import PackageDef
from pyedb.generic.general_methods import pyedb_function_handler

Expand All @@ -39,6 +40,7 @@ def __init__(self, pedb):
self.data = {}
self._s_parameter_library = ""
self._spice_model_library = ""
self.cfg_data = None

@pyedb_function_handler
def load(self, config_file, append=True, apply_file=False, output_file=None, open_at_the_end=True):
Expand Down Expand Up @@ -86,6 +88,9 @@ def load(self, config_file, append=True, apply_file=False, output_file=None, ope
self.data[k] = v
else:
self.data[k] = v

self.cfg_data = CfgData(self._pedb, **data)

if apply_file:
original_file = self._pedb.edbpath
if output_file:
Expand Down Expand Up @@ -132,8 +137,8 @@ def run(self):
self._load_pin_groups()

# Configure ports
if "ports" in self.data:
self._load_ports()
for port in self.cfg_data.cfg_ports:
port.create()

# Configure sources
if "sources" in self.data:
Expand Down Expand Up @@ -275,6 +280,7 @@ def _load_components(self):
@pyedb_function_handler
def _load_ports(self):
"""Imports port information from json."""

for port in self.data["ports"]:
port_type = port["type"]

Expand Down Expand Up @@ -315,7 +321,7 @@ def _load_ports(self):
pin_name = negative_terminal_json["pin"]
port_name = "{}_{}_ref".format(ref_designator, pin_name)
neg_terminal = comp_layout.pins[pin_name].get_terminal(port_name, True)
else:
elif "net" in negative_terminal_json:
net_name = negative_terminal_json["net"]
port_name = "{}_{}_ref".format(ref_designator, net_name)
pg_name = "pg_{}".format(port_name)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@
"start": 0,
"stop": 10e9,
"points": 11
},
{
"distribution": "log scale",
"start": 1e6,
"stop": 1e9,
"samples": 10
}
]
}
Expand Down
86 changes: 67 additions & 19 deletions tests/legacy/system/test_edb_config_json.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
import json
import os
from pathlib import Path

import pytest
Expand Down Expand Up @@ -58,8 +57,6 @@ def test_01_create_edb(self):
for i in [
"components.json",
"setups_hfss.json",
"setups_siwave_syz.json",
"setups_siwave_dc.json",
"sources.json",
]:
with open(self.local_input_folder / i) as f:
Expand Down Expand Up @@ -95,22 +92,67 @@ def test_04_nets(self):
assert not edbapp.nets["SFPA_VCCR"].is_power_ground
edbapp.close()

def test_05_ports(self):
edbapp = Edb(str(self.local_edb), desktop_version)
assert edbapp.configuration.load(
str(self.local_input_folder / "ports_coax.json"),
apply_file=True,
output_file=str(os.path.join(self.local_scratch.path, "exported_1.aedb")),
open_at_the_end=False,
)
assert Path(self.local_scratch.path, "exported_1.aedb").exists()
assert edbapp.configuration.load(
str(self.local_input_folder / "ports_circuit.json"),
apply_file=True,
output_file=str(os.path.join(self.local_scratch.path, "exported_2.aedb")),
open_at_the_end=True,
)
assert Path(self.local_scratch.path, "exported_2.aedb").exists()
def test_05_ports(self, edb_examples):
edbapp = edb_examples.get_si_verse()
assert edbapp.configuration.load(str(self.local_input_folder / "ports_coax.json"), apply_file=True)
assert edbapp.configuration.load(str(self.local_input_folder / "ports_circuit.json"), apply_file=True)
edbapp.close()

def test_05b_ports_coax(self, edb_examples):
ports = [
{
"name": "COAX_U1_AM17",
"reference_designator": "U1",
"type": "coax",
"positive_terminal": {"pin": "AM17"},
},
{
"name": "COAX_U1_PCIe_Gen4_TX2_CAP_N",
"reference_designator": "U1",
"type": "coax",
"positive_terminal": {"net": "PCIe_Gen4_TX2_CAP_N"},
},
]
data = {"ports": ports}
edbapp = edb_examples.get_si_verse()
assert edbapp.configuration.load(data, apply_file=True)
assert edbapp.ports["COAX_U1_AM17"]
assert edbapp.ports["COAX_U1_PCIe_Gen4_TX2_CAP_N"]
edbapp.close()

def test_05c_ports_circuit_pin_net(self, edb_examples):
data = {
"ports": [
{
"name": "CIRCUIT_X1_B8_GND",
"reference_designator": "X1",
"type": "circuit",
"positive_terminal": {"pin": "B8"},
"negative_terminal": {"net": "GND"},
},
]
}
edbapp = edb_examples.get_si_verse()
assert edbapp.configuration.load(data, apply_file=True)
assert edbapp.ports["CIRCUIT_X1_B8_GND"]
assert edbapp.ports["CIRCUIT_X1_B8_GND"].is_circuit_port
edbapp.close()

def test_05c_ports_circuit_net_net_distributed(self, edb_examples):
ports = [
{
"name": "CIRCUIT_U7_VDD_DDR_GND",
"reference_designator": "U7",
"type": "circuit",
"distributed": True,
"positive_terminal": {"net": "VDD_DDR"},
"negative_terminal": {"net": "GND"},
}
]
data = {"ports": ports}
edbapp = edb_examples.get_si_verse()
assert edbapp.configuration.load(data, apply_file=True)
assert edbapp.ports
edbapp.close()

def test_06_s_parameters(self):
Expand Down Expand Up @@ -175,3 +217,9 @@ def test_13_stackup(self, edb_examples):
edbapp = edb_examples.get_si_verse()
assert edbapp.configuration.load(str(self.local_input_folder / "stackup.json"), apply_file=True)
edbapp.close()

def test_14_setup_siwave_syz(self, edb_examples):
edbapp = edb_examples.get_si_verse()
assert edbapp.configuration.load(str(self.local_input_folder / "setups_siwave_syz.json"), apply_file=True)
setup = edbapp.setups["siwave_syz"]
edbapp.close()

0 comments on commit 53620ce

Please sign in to comment.