_derived.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 typing import Optional, Tuple, Iterable 3 4 from pdkmaster.technology import mask as _msk 5 6 from ...typing import cast_MultiT 7 from .. import rule as _rle, mask as _msk, technology_ as _tch 8 9 from ._core import _MaskPrimitive 10 11 12 # _DerivedPrimitive and subclasses are considered for internal use only; 13 # not to be used in user land code. User land just sees MaskPrimitiveT 14 __all__ = [] 15 16 17 class _DerivedPrimitive(_MaskPrimitive): 18 """A primitive that is derived from other primitives and not a 19 Primitive that can be part of the primitive list of a technology. 20 """ 21 def _generate_rules(self, *, tech: _tch.Technology) -> Tuple[_rle.RuleT, ...]: 22 """As _DerivedPrimitive will not be added to the list of primitives 23 of a technology node, it does not need to generate rules. 24 """ 25 raise RuntimeError("Internal error") # pragma: no cover 26 27 28 class _Intersect(_DerivedPrimitive): 29 """A derived primitive representing the overlap of a list of primitives 30 """ 31 def __init__(self, *, prims: Iterable[_MaskPrimitive]): 32 prims2: Tuple[_MaskPrimitive, ...] = cast_MultiT(prims) 33 if len(prims2) < 2: 34 raise ValueError(f"At least two prims needed for '{self.__class__.__name__}'") 35 self.prims = prims2 36 37 mask = _msk.Intersect(p.mask for p in prims2) 38 super().__init__(mask=mask) 39 40 41 class _Alias(_DerivedPrimitive): 42 """A derived primitive giving an alias to another mask primitive. 43 This is mainly used to have aliases for rules on the mask of a given 44 MaskPrimitive. 45 """ 46 def __init__(self, *, prim: _MaskPrimitive, alias: str): 47 self._prim = prim 48 super().__init__(mask=prim.mask.alias(alias)) 49 self.mask: _msk._MaskAlias 50 51 class _Outside(_DerivedPrimitive): 52 """A derived primitive representing the part of another primitive 53 """ 54 def __init__(self, *, prim: _MaskPrimitive, where: Tuple[_MaskPrimitive, ...]): 55 where = cast_MultiT(where) 56 if len(where) == 0: 57 raise ValueError( 58 "At least one layer has to be given for Outside derived mask" 59 ) 60 elif len(where) == 1: 61 mask = prim.mask.remove(where[0].mask) 62 else: 63 mask = prim.mask.remove(_msk.Join(w.mask for w in where)) 64 super().__init__(mask=mask)