Coverage for tests/rcx25/rcx25_netlist_expander_whitebox_test.py: 100%

48 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# 

24 

25import allure 

26import unittest 

27 

28import klayout.db as kdb 

29 

30from klayout_pex.device_models import DeviceModels 

31from klayout_pex.rcx25.extraction_results import CellExtractionResults, ExtractionResults 

32from klayout_pex.rcx25.netlist_expander import RCX25NetlistExpander 

33import klayout_pex_protobuf.kpex.tech.device_models_pb2 as device_models_pb2 

34 

35 

36def device_models(*metal_capacitor_class_names: str) -> DeviceModels: 

37 info = device_models_pb2.DeviceModelsInfo() 

38 for name in metal_capacitor_class_names: 

39 info.device_model_mappings.add(lvs_device_class_name=name, 

40 kind=device_models_pb2.DeviceModelMapping.KIND_METAL_CAPACITOR) 

41 return DeviceModels(info) 

42 

43 

44def whiteboxed_device_names(netlist: kdb.Netlist, device_models: DeviceModels) -> list: 

45 expanded = RCX25NetlistExpander.expand(netlist, 'chip', 

46 ExtractionResults({'chip': CellExtractionResults(cell_name='chip')}), 

47 blackbox_devices=False, 

48 device_models=device_models) 

49 device_class_names = {dc.name for dc in netlist.each_device_class()} 

50 return [d.name for d in expanded.circuit_by_name('chip').each_device() 

51 if d.device_class().name in device_class_names] 

52 

53 

54@allure.parent_suite("Unit Tests") 

55@allure.tag("RCX25", "Netlist Expansion") 

56class Test(unittest.TestCase): 

57 def test_whitebox_removes_all_capacitors(self): 

58 # Removing a device ended the iteration over the devices, 

59 # so only the first capacitor was removed, and the others were counted twice: 

60 # as device and as extracted geometry 

61 netlist = kdb.Netlist() 

62 circuit = kdb.Circuit() 

63 circuit.name = 'chip' 

64 netlist.add(circuit) 

65 mim = kdb.DeviceClassCapacitor() 

66 mim.name = 'mim' 

67 netlist.add(mim) 

68 nmos = kdb.DeviceClassMOS4Transistor() 

69 nmos.name = 'nmos' 

70 netlist.add(nmos) 

71 for name in ('C1', 'C2', 'C3'): 

72 circuit.create_device(mim, name) 

73 circuit.create_device(nmos, 'M1') 

74 

75 self.assertEqual(['M1'], whiteboxed_device_names(netlist, device_models('mim'))) 

76 

77 def test_whitebox_removes_the_metal_capacitors_whatever_their_device_class(self): 

78 # The devices were removed by their device class: sky130A reads VPP caps with 4 terminals as MOS4, 

79 # so they were kept, and counted twice (as device and as extracted geometry), 

80 # while the MOS capacitors are capacitor classes, so they were removed, 

81 # and their capacitance was lost, which the extraction doesn't have 

82 netlist = kdb.Netlist() 

83 circuit = kdb.Circuit() 

84 circuit.name = 'chip' 

85 netlist.add(circuit) 

86 vpp = kdb.DeviceClassMOS4Transistor() 

87 vpp.name = 'vpp' 

88 netlist.add(vpp) 

89 mos_cap = kdb.DeviceClassCapacitor() 

90 mos_cap.name = 'mos_cap' 

91 netlist.add(mos_cap) 

92 circuit.create_device(vpp, 'X1') 

93 circuit.create_device(mos_cap, 'C1') 

94 

95 self.assertEqual(['C1'], whiteboxed_device_names(netlist, device_models('vpp')))