Coverage for klayout_pex/rcx25/netlist_expander.py: 74%
57 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-05-12 13:45 +0000
« prev ^ index » next coverage.py v7.8.0, created at 2025-05-12 13:45 +0000
1#
2# --------------------------------------------------------------------------------
3# SPDX-FileCopyrightText: 2024 Martin Jan Köhler and Harald Pretl
4# Johannes Kepler University, Institute for Integrated Circuits.
5#
6# This file is part of KPEX
7# (see https://github.com/martinjankoehler/klayout-pex).
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation, either version 3 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program. If not, see <http://www.gnu.org/licenses/>.
21# SPDX-License-Identifier: GPL-3.0-or-later
22# --------------------------------------------------------------------------------
23#
24from __future__ import annotations
26import re
27from typing import *
29import klayout.db as kdb
31from ..log import (
32 info,
33 warning,
34)
35from .extraction_results import ExtractionResults
38class RCX25NetlistExpander:
39 @staticmethod
40 def expand(extracted_netlist: kdb.Netlist,
41 top_cell_name: str,
42 extraction_results: ExtractionResults,
43 blackbox_devices: bool) -> kdb.Netlist:
44 expanded_netlist: kdb.Netlist = extracted_netlist.dup()
45 top_circuit: kdb.Circuit = expanded_netlist.circuit_by_name(top_cell_name)
47 if not blackbox_devices:
48 # TODO: we'll need additional information about the available devices
49 # because we only want to replace resistor / capacitor devices
50 # and for example not transitors
52 for d in top_circuit.each_device():
53 name = d.name or d.expanded_name()
54 info(f"Removing whiteboxed device {name}")
55 top_circuit.remove_device(d)
57 # create capacitor device class
58 cap = kdb.DeviceClassCapacitor()
59 # cap.name = 'KPEX_CAP'
60 cap.description = "Extracted by KPEX/2.5D"
61 expanded_netlist.add(cap)
63 # create resistor device class
64 res = kdb.DeviceClassResistor()
65 # res.name = 'KPEX_RES'
66 res.description = "Extracted by KPEX/2.5D"
67 expanded_netlist.add(res)
69 fc_gnd_net = top_circuit.create_net('FC_GND') # create GROUND net
70 vsubs_net = top_circuit.create_net("VSUBS")
72 summary = extraction_results.summarize()
73 cap_items = sorted(summary.capacitances.items())
74 res_items = sorted(summary.resistances.items())
76 # build table: name -> net
77 name2net: Dict[str, kdb.Net] = {n.expanded_name(): n for n in top_circuit.each_net()}
79 def add_net_if_needed(net_name: str):
80 if net_name in name2net:
81 return
82 name2net[net_name] = top_circuit.create_net(net_name)
84 # add additional nets for new nodes (e.g. created during R extraction of vias)
85 for key, _ in cap_items:
86 add_net_if_needed(key.net1)
87 add_net_if_needed(key.net2)
88 for key, _ in res_items:
89 add_net_if_needed(key.net1)
90 add_net_if_needed(key.net2)
92 for idx, (key, cap_value) in enumerate(cap_items):
93 net1 = name2net[key.net1]
94 net2 = name2net[key.net2]
96 c: kdb.Device = top_circuit.create_device(cap, f"ext_{idx+1}")
97 c.connect_terminal('A', net1)
98 c.connect_terminal('B', net2)
99 c.set_parameter('C', cap_value)
100 if net1 == net2:
101 warning(f"Invalid attempt to create cap {c.name} between "
102 f"same net {net1} with value {'%.12g' % cap_value}")
104 for idx, (key, res_value) in enumerate(res_items):
105 net1 = name2net[key.net1]
106 net2 = name2net[key.net2]
108 r: kdb.Device = top_circuit.create_device(res, f"ext_{idx+1}")
109 r.connect_terminal('A', net1)
110 r.connect_terminal('B', net2)
111 r.set_parameter('R', res_value)
112 if net1 == net2:
113 warning(f"Invalid attempt to create resistor {r.name} between "
114 f"same net {net1} with value {'%.12g' % res_value}")
116 return expanded_netlist