primitive.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 Callable, Optional 3 4 from ..technology import primitive as _prm 5 from ..technology.primitive.conductors import _WaferWireIntersect, _ViaIntersect 6 7 8 class PrimitiveDispatcher: 9 """Dispatch to class method based on type of `_Primitive` subclasses. 10 11 This dispatcher follows the common way of working in the `dispatch` module. 12 """ 13 def __init__(self): 14 self._parent_call: Optional[Callable] = None 15 16 def __call__(self, prim: _prm.PrimitiveT, *args, **kwargs): 17 # Reset _parent_call 18 self._parent_call = None 19 20 classname = prim.__class__.__name__.split(".")[-1] 21 return getattr(self, classname, self._pd_unhandled)(prim, *args, **kwargs) 22 23 def _pd_unhandled(self, prim, *args, **kwargs): 24 raise RuntimeError( 25 "Internal error: unhandled dispatcher for object of type " 26 f"{prim.__class__.__name__}" 27 ) 28 29 ### primitive._core 30 31 def _Primitive(self, prim: _prm.PrimitiveT, *args, **kwargs): 32 """Currently _PinAttribute and _BlockageAttribute are not handled by the 33 dispatcher. It can be handled by overloading this _Primitive method and 34 checking there oneself if the provided primitive is an instance of one 35 of these classes. 36 """ 37 raise NotImplementedError( 38 f"No dispatcher implemented for object of type {prim.__class__.__name__}" 39 ) 40 41 def _MaskPrimitive(self, prim: _prm.MaskPrimitiveT, *args, **kwargs): 42 return self._Primitive(prim, *args, **kwargs) 43 44 def _DesignMaskPrimitive(self, 45 prim: _prm.DesignMaskPrimitiveT, *args, **kwargs, 46 ): 47 return self._MaskPrimitive(prim, *args, **kwargs) 48 49 def _WidthSpacePrimitive(self, prim: _prm.WidthSpacePrimitiveT, *args, **kwargs): 50 if isinstance(prim, _prm.DesignMaskPrimitiveT): 51 return self._DesignMaskPrimitive(prim, *args, **kwargs) 52 else: 53 return self._MaskPrimitive(prim, *args, **kwargs) 54 55 def _WidthSpaceDesignMaskPrimitive(self, 56 prim: _prm.WidthSpaceDesignMaskPrimitiveT, *args, **kwargs, 57 ): 58 # _DesignMaskPrimitive is handled by _WidthSpacePrimitive() if needed. 59 return self._WidthSpacePrimitive(prim, *args, **kwargs) 60 61 ### primitive._derived 62 63 def _DerivedPrimitive(self, prim: _prm._derived._DerivedPrimitive, *args, **kwargs): 64 """ 65 API Notes: 66 * No backwards compatiblity is provided for overloading this function 67 in user land code. _DerivedPrimitive is considered for internal use only. 68 """ 69 return self._MaskPrimitive(prim, *args, **kwargs) 70 71 def _Intersect(self, prim: _prm._derived._Intersect, *args, **kwargs): 72 """ 73 API Notes: 74 * No backwards compatiblity is provided for overloading this function 75 in user land code. _Intersect is considered for internal use only. 76 """ 77 return self._DerivedPrimitive(prim, *args, **kwargs) 78 79 def _Outside(self, prim: _prm._derived._Outside, * args, **kwargs): 80 """ 81 API Notes: 82 * No backwards compatiblity is provided for overloading this function 83 in user land code. _Outside is considered for internal use only. 84 """ 85 return self._DerivedPrimitive(prim, *args, **kwargs) 86 87 ### primitive.layers 88 89 def Base(self, prim: _prm.Base, *args, **kwargs): 90 return self._MaskPrimitive(prim, *args, **kwargs) 91 92 def Marker(self, prim: _prm.Marker, *args, **kwargs): 93 return self._DesignMaskPrimitive(prim, *args, **kwargs) 94 95 def SubstrateMarker(self, prim: _prm.Marker, *args, **kwargs): 96 return self.Marker(prim, *args, **kwargs) 97 98 def Auxiliary(self, prim: _prm.Auxiliary, *args, **kwargs): 99 return self._DesignMaskPrimitive(prim, *args, **kwargs) 100 101 def ExtraProcess(self, prim: _prm.ExtraProcess, *args, **kwargs): 102 return self._WidthSpaceDesignMaskPrimitive(prim, *args, **kwargs) 103 104 def Insulator(self, prim: _prm.Insulator, *args, **kwargs): 105 return self._WidthSpaceDesignMaskPrimitive(prim, *args, **kwargs) 106 107 def Implant(self, prim: _prm.Implant, *args, **kwargs): 108 if self._parent_call is None: 109 call = self._WidthSpaceDesignMaskPrimitive 110 else: 111 call = self._parent_call 112 self._parent_call = None 113 return call(prim, *args, **kwargs) 114 115 ### primitive.conductors 116 117 def _Conductor(self, 118 prim: _prm.ConductorT, *args, **kwargs, 119 ): 120 if isinstance(prim, _prm.WidthSpacePrimitiveT): 121 return self._WidthSpacePrimitive(prim, *args, **kwargs) 122 else: 123 return self._DesignMaskPrimitive(prim, *args, **kwargs) 124 125 def _WidthSpaceConductor(self, 126 prim: _prm.WidthSpaceConductorT, *args, **kwargs, 127 ): 128 return self._Conductor(prim, *args, **kwargs) 129 130 def Well(self, prim: _prm.Well, *args, **kwargs): 131 self._parent_call = self._WidthSpaceConductor 132 return self.Implant(prim=prim, *args, **kwargs) 133 134 def DeepWell(self, prim: _prm.DeepWell, *args, **kwargs): 135 self._parent_call = self._WidthSpaceConductor 136 return self.Implant(prim=prim, *args, **kwargs) 137 138 def WaferWire(self, prim: _prm.WaferWire, *args, **kwargs): 139 return self._WidthSpaceConductor(prim, *args, **kwargs) 140 141 def _WaferWireIntersect(self, prim: _WaferWireIntersect, *args, **kwargs): 142 return self._Intersect(prim, *args, **kwargs) 143 144 def GateWire(self, prim: _prm.GateWire, *args, **kwargs): 145 return self._WidthSpaceConductor(prim, *args, **kwargs) 146 147 def MetalWire(self, prim: _prm.MetalWire, *args, **kwargs): 148 return self._WidthSpaceConductor(prim, *args, **kwargs) 149 150 def MIMTop(self, prim: _prm.MIMTop, *args, **kwargs): 151 return self.MetalWire(prim, *args, **kwargs) 152 153 def TopMetalWire(self, prim: _prm.TopMetalWire, *args, **kwargs): 154 return self.MetalWire(prim, *args, **kwargs) 155 156 def Via(self, prim, *args: _prm.Via, **kwargs): 157 return self._Conductor(prim, *args, **kwargs) 158 159 def _ViaIntersect(self, prim: _ViaIntersect, *args, **kwargs): 160 return self._Intersect(prim, *args, **kwargs) 161 162 def PadOpening(self, prim: _prm.PadOpening, *args, **kwargs): 163 return self._WidthSpaceConductor(prim, *args, **kwargs) 164 165 ### primitive.devices 166 167 def _DevicePrimitive(self, prim: _prm.DevicePrimitiveT, *args, **kwargs): 168 if isinstance(prim, _prm.MaskPrimitiveT): 169 return self._MaskPrimitive(prim=prim, *args, **kwargs) 170 else: 171 return self._Primitive(prim=prim, *args, **kwargs) 172 173 def Resistor(self, prim: _prm.Resistor, *args, **kwargs): 174 return self._DevicePrimitive(prim, *args, **kwargs) 175 176 def _Capacitor(self, prim: _prm.CapacitorT, *args, **kwargs): 177 return self._DevicePrimitive(prim, *args, **kwargs) 178 179 def MIMCapacitor(self, prim: _prm.MIMCapacitor, *args, **kwargs): 180 return self._Capacitor(prim, *args, **kwargs) 181 182 def Diode(self, prim: _prm.Diode, *args, **kwargs): 183 return self._DevicePrimitive(prim, *args, **kwargs) 184 185 def MOSFETGate(self, prim: _prm.MOSFETGate, *args, **kwargs): 186 return self._WidthSpacePrimitive(prim, *args, **kwargs) 187 188 def MOSFET(self, prim: _prm.MOSFET, *args, **kwargs): 189 return self._DevicePrimitive(prim, *args, **kwargs) 190 191 def Bipolar(self, prim: _prm.Bipolar, *args, **kwargs): 192 return self._DevicePrimitive(prim, *args, **kwargs) 193 194 ### primitive.rules 195 196 def _RulePrimitive(self, prim: _prm.RulePrimitiveT, *args, **kwargs): 197 return self._Primitive(prim, *args, **kwargs) 198 199 def MinWidth(self, prim: _prm.MinWidth, *args, **kwargs): 200 return self._RulePrimitive(prim, *args, **kwargs) 201 202 def Spacing(self, prim: _prm.Spacing, *args, **kwargs): 203 return self._RulePrimitive(prim, *args, **kwargs) 204 205 def Enclosure(self, prim: _prm.Enclosure, *args, **kwargs): 206 return self._RulePrimitive(prim, *args, **kwargs) 207 208 def NoOverlap(self, prim: _prm.NoOverlap, *args, **kwargs): 209 return self._RulePrimitive(prim, *args, **kwargs)