Coverage for klayout_pex/magic/magic_runner.py: 29%

45 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 enum import StrEnum 

25import time 

26from typing import * 

27 

28import os 

29import subprocess 

30 

31from ..log import ( 

32 info, 

33 # warning, 

34 rule, 

35 subproc, 

36) 

37from ..version import __version__ 

38 

39 

40class MagicPEXMode(StrEnum): 

41 CC = "CC" 

42 RC = "RC" 

43 DEFAULT = "CC" 

44 

45 

46def prepare_magic_script(gds_path: str, 

47 cell_name: str, 

48 run_dir_path: str, 

49 script_path: str, 

50 output_netlist_path: str, 

51 pex_mode: MagicPEXMode, 

52 c_threshold: float, 

53 r_threshold: float, 

54 halo: Optional[float]): 

55 gds_path = os.path.abspath(gds_path) 

56 run_dir_path = os.path.abspath(run_dir_path) 

57 output_netlist_path = os.path.abspath(output_netlist_path) 

58 

59 halo_scale = 200.0 

60 halo_decl = '' if halo is None else f"\nextract halo {round(halo * halo_scale)}" 

61 

62 script: str = "" 

63 match pex_mode: 

64 case MagicPEXMode.CC: 

65 script = f"""# Generated by kpex {__version__} 

66crashbackups stop 

67drc off 

68gds read {gds_path} 

69load {cell_name} 

70select top cell 

71flatten {cell_name}_flat 

72load {cell_name}_flat 

73cellname delete {cell_name} -noprompt 

74cellname rename {cell_name}_flat {cell_name} 

75select top cell 

76extract path {run_dir_path}{halo_decl} 

77extract all 

78ext2spice cthresh {c_threshold} 

79ext2spice format ngspice 

80ext2spice -p {run_dir_path} -o {output_netlist_path} 

81quit -noprompt""" 

82 case MagicPEXMode.RC: 

83 script = f"""# Generated by kpex {__version__} 

84crashbackups stop 

85drc off 

86gds read {gds_path} 

87load {cell_name} 

88select top cell 

89flatten {cell_name}_flat 

90load {cell_name}_flat 

91cellname delete {cell_name} -noprompt 

92cellname rename {cell_name}_flat {cell_name} 

93select top cell 

94extract path {run_dir_path}{halo_decl} 

95extract do resistance 

96extract all 

97ext2sim labels on 

98ext2sim 

99extresist tolerance {r_threshold} 

100extresist all 

101ext2spice cthresh {c_threshold} 

102ext2spice rthresh {r_threshold} 

103ext2spice extresist on 

104ext2spice format ngspice 

105ext2spice -p {run_dir_path} -o {output_netlist_path} 

106quit -noprompt 

107""" 

108 with open(script_path, 'w') as f: 

109 f.write(script) 

110 

111def run_magic(exe_path: str, 

112 magicrc_path: str, 

113 script_path: str, 

114 log_path: str): 

115 args = [ 

116 exe_path, 

117 '-dnull', # 

118 '-noconsole', # 

119 '-rcfile', # 

120 magicrc_path, # 

121 script_path, # TCL script 

122 ] 

123 

124 info('Calling MAGIC') 

125 subproc(f"{' '.join(args)}, output file: {log_path}") 

126 

127 rule('MAGIC Output') 

128 

129 start = time.time() 

130 

131 proc = subprocess.Popen(args, 

132 stdin=subprocess.DEVNULL, 

133 stdout=subprocess.PIPE, 

134 stderr=subprocess.STDOUT, 

135 universal_newlines=True, 

136 text=True) 

137 with open(log_path, 'w') as f: 

138 while True: 

139 line = proc.stdout.readline() 

140 if not line: 

141 break 

142 subproc(line[:-1]) # remove newline 

143 f.writelines([line]) 

144 proc.wait() 

145 

146 duration = time.time() - start 

147 

148 rule() 

149 

150 if proc.returncode == 0: 

151 info(f"MAGIC succeeded after {'%.4g' % duration}s") 

152 else: 

153 raise Exception(f"MAGIC failed with status code {proc.returncode} after {'%.4g' % duration}s, " 

154 f"see log file: {log_path}") 

155