Coverage for tests/rcx25/rcx25_netlist_expander_substrate_test.py: 100%
39 statements
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-02 23:32 +0000
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-02 23:32 +0000
1#
2# --------------------------------------------------------------------------------
3# SPDX-FileCopyrightText: 2024-2026 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/iic-jku/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#
24import allure
25import unittest
27import klayout.db as kdb
29from klayout_pex.device_models import DeviceModels
30from klayout_pex.rcx25.extraction_results import ExtractionSummary, NetCoupleKey
31from klayout_pex.rcx25.netlist_expander import RCX25NetlistExpander
32import klayout_pex_protobuf.kpex.tech.device_models_pb2 as device_models_pb2
35class Results:
36 """
37 Extraction results of a given summary
38 """
39 def __init__(self, summary: ExtractionSummary):
40 self.summary = summary
42 def summarize(self) -> ExtractionSummary:
43 return self.summary
46def netlist() -> kdb.Netlist:
47 """
48 The nets D and B, with a pin each
49 """
50 netlist = kdb.Netlist()
51 circuit = kdb.Circuit()
52 circuit.name = 'chip'
53 netlist.add(circuit)
54 for name in ('D', 'B'):
55 circuit.connect_pin(circuit.create_pin(name), circuit.create_net(name))
56 return netlist
59def capacitances(expanded: kdb.Netlist) -> dict:
60 circuit = expanded.circuit_by_name('chip')
61 return {frozenset((d.net_for_terminal('A').name, d.net_for_terminal('B').name)): d.parameter('C') * 1e15
62 for d in circuit.each_device() if d.device_class().name == 'PEX_CAP'}
65@allure.parent_suite("Unit Tests")
66@allure.tag("RCX25", "Netlist Expansion")
67class Test(unittest.TestCase):
68 # the capacitances to the substrate are on VSUBS in the summary
69 SUMMARY = ExtractionSummary(capacitances={NetCoupleKey('D', 'VSUBS'): 1.0, NetCoupleKey('B', 'VSUBS'): 2.0},
70 resistances={})
72 def test_capacitances_to_the_substrate_are_on_its_net(self):
73 expanded = RCX25NetlistExpander.expand(netlist(), 'chip', Results(self.SUMMARY), blackbox_devices=True,
74 device_models=DeviceModels(device_models_pb2.DeviceModelsInfo()),
75 substrate_net_name='B')
76 circuit = expanded.circuit_by_name('chip')
77 # NOTE: the capacitance of B to the substrate is shorted, as B is the substrate net
78 self.assertEqual({frozenset(('D', 'B')): 1.0}, capacitances(expanded))
79 self.assertIsNone(circuit.net_by_name('VSUBS'))
80 self.assertEqual(['D', 'B'], [p.name() for p in circuit.each_pin()])
82 def test_substrate_without_net_is_a_port(self):
83 # e.g. a metal test pattern, without taps or transistors
84 expanded = RCX25NetlistExpander.expand(netlist(), 'chip', Results(self.SUMMARY), blackbox_devices=True,
85 device_models=DeviceModels(device_models_pb2.DeviceModelsInfo()),
86 substrate_net_name='sky130_gnd')
87 circuit = expanded.circuit_by_name('chip')
88 self.assertEqual({frozenset(('D', 'sky130_gnd')): 1.0, frozenset(('B', 'sky130_gnd')): 2.0},
89 capacitances(expanded))
90 self.assertEqual(['D', 'B', 'sky130_gnd'], [p.name() for p in circuit.each_pin()])
91 self.assertEqual('sky130_gnd', circuit.net_for_pin(circuit.pin_by_name('sky130_gnd').id()).name)