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

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 

26 

27import klayout.db as kdb 

28 

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 

33 

34 

35class Results: 

36 """ 

37 Extraction results of a given summary 

38 """ 

39 def __init__(self, summary: ExtractionSummary): 

40 self.summary = summary 

41 

42 def summarize(self) -> ExtractionSummary: 

43 return self.summary 

44 

45 

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 

57 

58 

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'} 

63 

64 

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={}) 

71 

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()]) 

81 

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)