layers.py
  1  # SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-or-later OR CERN-OHL-S-2.0+ OR Apache-2.0
  2  from enum import Enum
  3  from typing import Iterable
  4  from warnings import warn
  5  
  6  from .. import rule as _rle, wafer_ as _wfr, technology_ as _tch
  7  
  8  from ._core import (
  9      _MaskPrimitive, _DesignMaskPrimitive, _WidthSpaceDesignMaskPrimitive,
 10  )
 11  
 12  
 13  __all__ = [
 14      "Base", "BaseTypeT", "nBase", "pBase", "undopedBase",
 15      "Marker", "SubstrateMarker", "Auxiliary", "ExtraProcess", "Insulator",
 16      "Implant", "ImplantTypeT", "nImpl", "pImpl", "adjImpl",
 17  ]
 18  
 19  
 20  class Base(_MaskPrimitive):
 21      class BaseType(Enum):
 22          n = "n"
 23          p = "p"
 24          undoped = "undoped"
 25  
 26      def __init__(self, *, type_: "BaseTypeT"):
 27          super().__init__(name="base", mask=_wfr.wafer)
 28  
 29          self._type = type_
 30  
 31      @property
 32      def type_(self) -> "Base.BaseType":
 33          return self._type
 34  
 35      def _generate_rules(self, *,
 36          tech: _tch.Technology, gen_mask: bool = True,
 37      ) -> Iterable[_rle.RuleT]:
 38          return super()._generate_rules(tech=tech, gen_mask=gen_mask)
 39  BaseTypeT = Base.BaseType
 40  nBase = Base.BaseType.n
 41  pBase = Base.BaseType.p
 42  undopedBase = Base.BaseType.undoped
 43  
 44  
 45  class Marker(_DesignMaskPrimitive):
 46      """The Marker primitive represents a layer used by other primitives for definition
 47      of these primitives; typically a recognition.
 48      It does not represent a processing layer and thus no physical mask is corresponding
 49      with this primitive.
 50      """
 51      def __init__(self, **super_args):
 52          super().__init__(**super_args)
 53  
 54      def _generate_rules(self, *,
 55          tech: _tch.Technology,
 56      ) -> Iterable[_rle.RuleT]:
 57          return super()._generate_rules(tech=tech)
 58  
 59  
 60  class SubstrateMarker(Marker):
 61      """Often PDKs provide a marker layer to indicate substrate regions that have a net
 62      connected different than the common ground substrate connection. This marker layer
 63      is reserved for such purposes.
 64      Currently no assumptions are made on how such a marker layer is to be used and thus
 65      no checks on proper use are implemented.
 66      """
 67      pass
 68  
 69  
 70  class Auxiliary(_DesignMaskPrimitive):
 71      """The Auxiliary primitive represents a layer that is defined by a foundry's
 72      technology but not used in other PDKMaster primitives.
 73      """
 74      def __init__(self, **super_args):
 75          super().__init__(**super_args)
 76  
 77      def _generate_rules(self, *,
 78          tech: _tch.Technology,
 79      ) -> Iterable[_rle.RuleT]:
 80          return super()._generate_rules(tech=tech)
 81  
 82  
 83  class ExtraProcess(_WidthSpaceDesignMaskPrimitive):
 84      """ExtraProcess is a layer indicating an ExtraProcess step not handled
 85      by other primitives.
 86  
 87      For example non-silicidation for making active or poly resistors.
 88      """
 89      def __init__(self, **super_args):
 90          super().__init__(**super_args)
 91  
 92      def _generate_rules(self, *,
 93          tech: "_tch.Technology",
 94      ) -> Iterable[_rle.RuleT]:
 95          return super()._generate_rules(tech=tech)
 96  
 97  
 98  class Insulator(_WidthSpaceDesignMaskPrimitive):
 99      """Insulator is a layer representing an insulator layer.
100  
101      Typical use is for thick oxide layer for higher voltage transistors.
102      """
103      def __init__(self, **super_args):
104          super().__init__(**super_args)
105  
106      def _generate_rules(self, *,
107          tech: "_tch.Technology",
108      ) -> Iterable[_rle.RuleT]:
109          return super()._generate_rules(tech=tech)
110  
111  
112  class Implant(_WidthSpaceDesignMaskPrimitive):
113      """Implant is a layer that represent an implantation step in the
114      semiconductor processing.
115  
116      Arguments:
117          type_: type of the implant
118              an "adjust" implant layer is extra implant that can be used on
119              both n-type and p-type regions.
120          super_args: `_WidthSpacePrimitive` and `_DesignMaskPrimitive`
121              arguments
122      """
123      class ImplantType(Enum):
124          """The type of implant.
125          Currently implemented types are: n, p, adjust. The .value of the enum
126          object is the string of the type; e.g. "n", "p", ...
127  
128          These types are also made available as `nImpl`, `pImpl` and `adjImpl`
129          in the primitive module.
130          """
131          n = "n"
132          p = "p"
133          adjust = "adjust"
134  
135          def __hash__(self) -> int:
136              return super().__hash__()
137  
138          def __eq__(self, __o: object) -> bool:
139              if isinstance(__o, str):
140                  warn("Comparison of `ImplantType` with `str` always returns `False`")
141              return super().__eq__(__o)
142  
143      # Implants are supposed to be disjoint unless they are used as combined implant
144      # MOSFET and other primitives
145      def __init__(self, *, type_: ImplantType, **super_args):
146          super().__init__(**super_args)
147  
148          self._type = type_
149  
150      def _generate_rules(self, *,
151          tech: "_tch.Technology",
152      ) -> Iterable[_rle.RuleT]:
153          return super()._generate_rules(tech=tech)
154  
155      @property
156      def type_(self) -> ImplantType:
157          return self._type
158  ImplantTypeT = Implant.ImplantType
159  nImpl = Implant.ImplantType.n
160  pImpl = Implant.ImplantType.p
161  adjImpl = Implant.ImplantType.adjust