Coverage for klayout_pex/pdk_config.py: 85%

41 statements  

« prev     ^ index     » next       coverage.py v7.15.4, created at 2026-08-21 15:48 +0000

1# 

2# -------------------------------------------------------------------------------- 

3# SPDX-FileCopyrightText: 2024-2025 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 

25from __future__ import annotations 

26from enum import StrEnum 

27from dataclasses import dataclass 

28from functools import cached_property 

29import os 

30from typing import * 

31 

32 

33@dataclass 

34class PDKConfig: 

35 name: str 

36 pex_lvs_script_path: str 

37 tech_pb_json_path: str 

38 

39 

40# TODO: this should be externally configurable 

41class PDK(StrEnum): 

42 GF180MCUD = 'gf180mcuD' 

43 IHP_SG13G2 = 'ihp-sg13g2' 

44 IHP_SG13CMOS5L = 'ihp-sg13cmos5l' 

45 SKY130A = 'sky130A' 

46 

47 @classmethod 

48 def from_string(cls, value: str) -> PDK: 

49 return PDK(cls.legacy_aliases().get(value, value)) 

50 

51 @classmethod 

52 def legacy_aliases(cls) -> Dict[str, str]: 

53 aliases = { 

54 'ihp_sg13g2': 'ihp-sg13g2', 

55 } 

56 return aliases 

57 

58 @cached_property 

59 def config(self) -> PDKConfig: 

60 # NOTE: installation paths of resources in the distribution wheel differs from source repo 

61 base_dir = os.path.dirname(os.path.realpath(__file__)) 

62 

63 # NOTE: .git can be dir (standalone clone), or file (in case of submodule) 

64 if os.path.exists(os.path.join(base_dir, '..', '.git')): # in source repo 

65 base_dir = os.path.dirname(base_dir) 

66 tech_pb_json_dir = os.path.join(base_dir, 'klayout_pex_protobuf') 

67 else: # site-packages/klayout_pex -> site-packages/klayout_pex_protobuf 

68 tech_pb_json_dir = os.path.join(os.path.dirname(base_dir), 'klayout_pex_protobuf') 

69 

70 match self: 

71 case PDK.GF180MCUD: 

72 return PDKConfig( 

73 name=self, 

74 pex_lvs_script_path=os.path.join(base_dir, 'pdk', self, 'libs.tech', 'kpex', 'gf180mcu.lvs'), 

75 tech_pb_json_path=os.path.join(tech_pb_json_dir, f"{self}_tech.pb.json") 

76 ) 

77 case PDK.IHP_SG13G2: 

78 return PDKConfig( 

79 name=self, 

80 pex_lvs_script_path=os.path.join(base_dir, 'pdk', self, 'libs.tech', 'kpex', 'sg13g2.lvs'), 

81 tech_pb_json_path=os.path.join(tech_pb_json_dir, f"{self}_tech.pb.json") 

82 ) 

83 case PDK.IHP_SG13CMOS5L: 

84 return PDKConfig( 

85 name=self, 

86 pex_lvs_script_path=os.path.join(base_dir, 'pdk', self, 'libs.tech', 'kpex', 'sg13cmos5l.lvs'), 

87 tech_pb_json_path=os.path.join(tech_pb_json_dir, f"{self}_tech.pb.json") 

88 ) 

89 case PDK.SKY130A: 

90 return PDKConfig( 

91 name=self, 

92 pex_lvs_script_path=os.path.join(base_dir, 'pdk', self, 'libs.tech', 'kpex', 'sky130.lvs'), 

93 tech_pb_json_path=os.path.join(tech_pb_json_dir, f"{self}_tech.pb.json") 

94 ) 

95 case _: 

96 raise NotImplementedError(f"Unhandled enum case {self}") 

97 

98 

99