Coverage for klayout_pex/rcx25/netlist_expander.py: 13%
67 statements
« prev ^ index » next coverage.py v7.10.2, created at 2025-08-08 18:54 +0000
« prev ^ index » next coverage.py v7.10.2, created at 2025-08-08 18:54 +0000
1#
2# --------------------------------------------------------------------------------
3# SPDX-FileCopyrightText: 2024-2025 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 match d.device_class().__class__:
55 case kdb.DeviceClassResistor | kdb.DeviceClassResistorWithBulk:
56 pass
58 case kdb.DeviceClassCapacitor | kdb.DeviceClassCapacitorWithBulk:
59 info(f"Removing whiteboxed device {name}")
60 top_circuit.remove_device(d)
62 case kdb.DeviceClassInductor:
63 pass
65 case kdb.DeviceClassBJT3Transistor | kdb.DeviceClassBJT4Transistor | kdb.DeviceClassDiode | \
66 kdb.DeviceClassMOS3Transistor | kdb.DeviceClassMOS4Transistor:
67 pass
69 # create capacitor device class
70 cap = kdb.DeviceClassCapacitor()
71 # cap.name = 'KPEX_CAP'
72 cap.name = 'C'
73 cap.description = "Extracted by KPEX/2.5D"
74 expanded_netlist.add(cap)
76 # create resistor device class
77 res = kdb.DeviceClassResistor()
78 # res.name = 'KPEX_RES'
79 res.name = 'R'
80 res.description = "Extracted by KPEX/2.5D"
81 expanded_netlist.add(res)
83 fc_gnd_net = top_circuit.create_net('FC_GND') # create GROUND net
84 vsubs_net = top_circuit.create_net("VSUBS")
86 summary = extraction_results.summarize()
87 cap_items = sorted(summary.capacitances.items())
88 res_items = sorted(summary.resistances.items())
90 # build table: name -> net
91 name2net: Dict[str, kdb.Net] = {n.expanded_name(): n for n in top_circuit.each_net()}
93 def add_net_if_needed(net_name: str):
94 if net_name in name2net:
95 return
96 name2net[net_name] = top_circuit.create_net(net_name)
98 # add additional nets for new nodes (e.g. created during R extraction of vias)
99 for key, _ in cap_items:
100 add_net_if_needed(key.net1)
101 add_net_if_needed(key.net2)
102 for key, _ in res_items:
103 add_net_if_needed(key.net1)
104 add_net_if_needed(key.net2)
106 for idx, (key, cap_value) in enumerate(cap_items):
107 net1 = name2net[key.net1]
108 net2 = name2net[key.net2]
110 c: kdb.Device = top_circuit.create_device(cap, f"ext_{idx+1}")
111 c.connect_terminal('A', net1)
112 c.connect_terminal('B', net2)
113 c.set_parameter('C', cap_value)
114 if net1 == net2:
115 warning(f"Invalid attempt to create cap {c.name} between "
116 f"same net {net1} with value {'%.12g' % cap_value}")
118 for idx, (key, res_value) in enumerate(res_items):
119 net1 = name2net[key.net1]
120 net2 = name2net[key.net2]
122 r: kdb.Device = top_circuit.create_device(res, f"ext_{idx+1}")
123 r.connect_terminal('A', net1)
124 r.connect_terminal('B', net2)
125 r.set_parameter('R', res_value)
126 if net1 == net2:
127 warning(f"Invalid attempt to create resistor {r.name} between "
128 f"same net {net1} with value {'%.12g' % res_value}")
130 return expanded_netlist