Coverage for klayout_pex / pdk_config.py: 87%

38 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-04-24 15:46 +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 SKY130A = 'sky130A' 

45 

46 @classmethod 

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

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

49 

50 @classmethod 

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

52 aliases = { 

53 'ihp_sg13g2': 'ihp-sg13g2', 

54 } 

55 return aliases 

56 

57 @cached_property 

58 def config(self) -> PDKConfig: 

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

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

61 

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

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

64 base_dir = os.path.dirname(base_dir) 

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

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

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

68 

69 match self: 

70 case PDK.GF180MCUD: 

71 return PDKConfig( 

72 name=self, 

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

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

75 ) 

76 case PDK.IHP_SG13G2: 

77 return PDKConfig( 

78 name=self, 

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

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

81 ) 

82 case PDK.SKY130A: 

83 return PDKConfig( 

84 name=self, 

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

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

87 ) 

88 case _: 

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

90 

91 

92