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

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 

25 

26import re 

27from typing import * 

28 

29import klayout.db as kdb 

30 

31from ..log import ( 

32 info, 

33 warning, 

34) 

35from .extraction_results import ExtractionResults 

36 

37 

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) 

46 

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 

51 

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) 

56 

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) 

62 

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) 

68 

69 fc_gnd_net = top_circuit.create_net('FC_GND') # create GROUND net 

70 vsubs_net = top_circuit.create_net("VSUBS") 

71 

72 summary = extraction_results.summarize() 

73 cap_items = sorted(summary.capacitances.items()) 

74 res_items = sorted(summary.resistances.items()) 

75 

76 # build table: name -> net 

77 name2net: Dict[str, kdb.Net] = {n.expanded_name(): n for n in top_circuit.each_net()} 

78 

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) 

83 

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) 

91 

92 for idx, (key, cap_value) in enumerate(cap_items): 

93 net1 = name2net[key.net1] 

94 net2 = name2net[key.net2] 

95 

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}") 

103 

104 for idx, (key, res_value) in enumerate(res_items): 

105 net1 = name2net[key.net1] 

106 net2 = name2net[key.net2] 

107 

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}") 

115 

116 return expanded_netlist