Coverage for klayout_pex/rcx25/extraction_results.py: 99%

91 statements  

« prev     ^ index     » next       coverage.py v7.6.9, created at 2024-12-17 17:24 +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 

25from collections import defaultdict 

26from dataclasses import dataclass, field 

27from typing import * 

28 

29import klayout_pex_protobuf.process_parasitics_pb2 as process_parasitics_pb2 

30 

31 

32NetName = str 

33LayerName = str 

34CellName = str 

35 

36 

37@dataclass 

38class NodeRegion: 

39 layer_name: LayerName 

40 net_name: NetName 

41 cap_to_gnd: float 

42 perimeter: float 

43 area: float 

44 

45 

46@dataclass(frozen=True) 

47class SidewallKey: 

48 layer: LayerName 

49 net1: NetName 

50 net2: NetName 

51 

52 

53@dataclass 

54class SidewallCap: # see Magic EdgeCap, extractInt.c L444 

55 key: SidewallKey 

56 cap_value: float # femto farad 

57 distance: float # distance in µm 

58 length: float # length in µm 

59 tech_spec: process_parasitics_pb2.CapacitanceInfo.SidewallCapacitance 

60 

61 

62@dataclass(frozen=True) 

63class OverlapKey: 

64 layer_top: LayerName 

65 net_top: NetName 

66 layer_bot: LayerName 

67 net_bot: NetName 

68 

69 

70@dataclass 

71class OverlapCap: 

72 key: OverlapKey 

73 cap_value: float # femto farad 

74 shielded_area: float # in µm^2 

75 unshielded_area: float # in µm^2 

76 tech_spec: process_parasitics_pb2.CapacitanceInfo.OverlapCapacitance 

77 

78 

79@dataclass(frozen=True) 

80class SideOverlapKey: 

81 layer_inside: LayerName 

82 net_inside: NetName 

83 layer_outside: LayerName 

84 net_outside: NetName 

85 

86 def __repr__(self) -> str: 

87 return f"{self.layer_inside}({self.net_inside})-"\ 

88 f"{self.layer_outside}({self.net_outside})" 

89 

90 

91@dataclass 

92class SideOverlapCap: 

93 key: SideOverlapKey 

94 cap_value: float # femto farad 

95 

96 def __str__(self) -> str: 

97 return f"(Side Overlap): {self.key} = {round(self.cap_value, 6)}fF" 

98 

99 

100@dataclass(frozen=True) 

101class NetCoupleKey: 

102 net1: NetName 

103 net2: NetName 

104 

105 def __repr__(self) -> str: 

106 return f"{self.net1}-{self.net2}" 

107 

108 # NOTE: we norm net names alphabetically 

109 def normed(self) -> NetCoupleKey: 

110 if self.net1 < self.net2: 

111 return self 

112 else: 

113 return NetCoupleKey(self.net2, self.net1) 

114 

115 

116@dataclass 

117class ExtractionSummary: 

118 capacitances: Dict[NetCoupleKey, float] 

119 

120 @classmethod 

121 def merged(cls, summaries: List[ExtractionSummary]) -> ExtractionSummary: 

122 merged_capacitances = defaultdict(float) 

123 for s in summaries: 

124 for couple_key, cap in s.capacitances.items(): 

125 merged_capacitances[couple_key.normed()] += cap 

126 return ExtractionSummary(merged_capacitances) 

127 

128 

129@dataclass 

130class CellExtractionResults: 

131 cell_name: CellName 

132 

133 overlap_coupling: Dict[OverlapKey, OverlapCap] = field(default_factory=dict) 

134 sidewall_table: Dict[SidewallKey, SidewallCap] = field(default_factory=dict) 

135 sideoverlap_table: Dict[SideOverlapKey, SideOverlapCap] = field(default_factory=dict) 

136 

137 def summarize(self) -> ExtractionSummary: 

138 overlap_summary = ExtractionSummary({ 

139 NetCoupleKey(key.net_top, key.net_bot): cap.cap_value 

140 for key, cap in self.overlap_coupling.items() 

141 }) 

142 

143 sidewall_summary = ExtractionSummary({ 

144 NetCoupleKey(key.net1, key.net2): cap.cap_value 

145 for key, cap in self.sidewall_table.items() 

146 }) 

147 

148 sideoverlap_summary = ExtractionSummary({ 

149 NetCoupleKey(key.net_inside, key.net_outside): cap.cap_value 

150 for key, cap in self.sideoverlap_table.items() 

151 }) 

152 

153 return ExtractionSummary.merged([ 

154 overlap_summary, sidewall_summary, sideoverlap_summary 

155 ]) 

156 

157 

158@dataclass 

159class ExtractionResults: 

160 cell_extraction_results: Dict[CellName, CellExtractionResults] = field(default_factory=dict) 

161 

162 def summarize(self) -> ExtractionSummary: 

163 subsummaries = [s.summarize() for s in self.cell_extraction_results.values()] 

164 return ExtractionSummary.merged(subsummaries)