/ test / unit / dummy.py
dummy.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 cast
  3  
  4  from pdkmaster.typing import GDSLayerSpecDict
  5  from pdkmaster.technology import (
  6      property_ as _prp, geometry as _geo, net as _net, primitive as _prm, technology_ as _tch
  7  )
  8  from pdkmaster.design import (
  9      circuit as _ckt, layout as _lay,  library as _lbry, factory as _fab,
 10  )
 11  from pdkmaster.io.spice import SpicePrimsParamSpec
 12  
 13  class MyNet(_net._Net):
 14      def __init__(self, *, name:str):
 15          super().__init__(name=name)
 16  
 17  
 18  class EmptyTech(_tch.Technology):
 19      @property
 20      def name(self) -> str:
 21          return "Empty"
 22      @property
 23      def grid(self) -> float:
 24          return 0.005
 25  
 26      def __init__(self):
 27          super().__init__(
 28              primitives=_prm.Primitives(_prm.Base(type_=_prm.undopedBase)),
 29          )
 30  empty_tech = EmptyTech()
 31  
 32  
 33  class DummyTech(_tch.Technology):
 34      @property
 35      def name(self) -> str:
 36          return "Dummy"
 37      @property
 38      def grid(self) -> float:
 39          return 0.005
 40      
 41      def __init__(self):
 42          prims = _prm.Primitives(_prm.Base(type_=_prm.nBase))
 43  
 44          substrate = _prm.SubstrateMarker(name="substrate")
 45          prims += substrate
 46  
 47          nwell = _prm.Well(type_=_prm.nImpl, name="nwell", min_width=1.5, min_space=1.5)
 48          deepwell = _prm.DeepWell(
 49              name="deepwell", min_width=3.0, min_space=3.0,
 50              well=nwell, min_well_overlap=0.8, min_well_enclosure=0.8,
 51          )
 52          pwell = _prm.Well(type_=_prm.pImpl, name="pwell", min_width=1.5, min_space=1.5)
 53          nplus = _prm.Implant(type_=_prm.nImpl, name="nplus", min_width=1.0, min_space=1.0)
 54          pplus = _prm.Implant(type_=_prm.pImpl, name="pplus", min_width=1.0, min_space=1.0)
 55          hvox = _prm.Insulator(name="hvox", min_width=0.5, min_space=0.5)
 56          active = _prm.WaferWire(
 57              name="active", min_width=0.3, min_space=0.2,
 58              allow_in_substrate=True,
 59              implant=(nplus, pplus), min_implant_enclosure=_prp.Enclosure(0.2),
 60              implant_abut="none", allow_contactless_implant=False,
 61              well=(nwell, pwell), min_well_enclosure=_prp.Enclosure(1.0),
 62              min_substrate_enclosure=_prp.Enclosure(1.0),
 63              oxide=hvox, min_oxide_enclosure=_prp.Enclosure(0.2),
 64              allow_well_crossing=False,
 65          )
 66          poly = _prm.GateWire(name="poly", min_width=0.25, min_space=0.25)
 67          prims += (nwell, deepwell, pwell, nplus, pplus, hvox, active, poly)
 68  
 69          metalpin = _prm.Marker(name="metalpin")
 70          metal = _prm.MetalWire(
 71              name="metal",
 72              min_width=0.1, min_space=0.1, space_table=((0.2, 0.5), ((1.0, 1.0), 1.0)),
 73              min_area=0.05, min_density=0.20,
 74              pin=metalpin,
 75          )
 76          contact = _prm.Via(
 77              name="contact", width=0.35, min_space=0.35, bottom=(active, poly), top=metal,
 78              min_bottom_enclosure=_prp.Enclosure(0.2), min_top_enclosure=_prp.Enclosure(0.15),
 79          )
 80          prims += (contact, metalpin, metal)
 81  
 82          mimtop = _prm.MIMTop(
 83              name="MIMTop", min_width=0.2, min_space=0.2,
 84          )
 85          prims += mimtop
 86  
 87          metal2pin = _prm.Marker(name="metal2pin")
 88          metal2block = _prm.Marker(name="metal2block")
 89          metal2 = _prm.TopMetalWire(
 90              name="metal2", min_width=0.1, min_space=0.1,
 91              pin=metal2pin, blockage=metal2block,
 92          )
 93          metal2mark = _prm.Marker(name="metal2mark")
 94          metal2res = _prm.Resistor(
 95              name="metal2res", wire=metal2, min_length=0.5,
 96              indicator=metal2mark, min_indicator_extension=0.4,
 97              contact=None,
 98          )
 99          via = _prm.Via(
100              name="via", width=0.35, min_space=0.35,
101              bottom=(metal, mimtop), top=(metal2, metal2res),
102              min_bottom_enclosure=_prp.Enclosure(0.2), min_top_enclosure=_prp.Enclosure(0.15),
103          )
104          prims += (via, metal2pin, metal2block, metal2, metal2mark, metal2res)
105  
106          silblock = _prm.ExtraProcess(
107              name="silblock", min_width=0.4, min_space=0.4, grid=0.010,
108          )
109          resistor = _prm.Resistor(
110              name="resistor", wire=active,
111              implant=nplus, min_implant_enclosure=active.min_implant_enclosure[0],
112              contact=contact, min_contact_space=0.2,
113              indicator=silblock, min_indicator_extension=0.4,
114          )
115          polyres = _prm.Resistor(
116              name="polyres", wire=poly, implant=pplus, contact=contact,
117              min_implant_enclosure=_prp.Enclosure(0.3), min_contact_space=0.2,
118              indicator=silblock, min_indicator_extension=0.4,
119          )
120          prims += (silblock, resistor, polyres)
121  
122          diodemark = _prm.Marker(name="diodemark")
123          ndiode = _prm.Diode(
124              name="ndiode", wire=active,
125              indicator=diodemark, min_indicator_enclosure=_prp.Enclosure(0.2),
126              implant=nplus, min_implant_enclosure=_prp.Enclosure(0.2),
127          )
128          pdiode = _prm.Diode(
129              name="pdiode", wire=active,
130              indicator=diodemark, min_indicator_enclosure=_prp.Enclosure(0.2),
131              implant=pplus, min_implant_enclosure=_prp.Enclosure(0.2),
132              well=nwell, min_well_enclosure=_prp.Enclosure(2.0),
133          )
134          prims += (diodemark, ndiode, pdiode)
135  
136          esd = _prm.Marker(name="esd")
137          mosgate = _prm.MOSFETGate(
138              name="mosgate", active=active, min_sd_width=0.35,
139              max_l=10.0, max_w=50.0,
140              poly=poly, min_polyactive_extension=0.45,
141              contact=contact, min_contactgate_space=0.15,
142          )
143          hvgate = _prm.MOSFETGate(
144              name="hvgate", active=active, oxide=hvox,
145              min_sd_width=0.35, min_gate_space=0.5,
146              poly=poly, min_polyactive_extension=0.45,
147              contact=contact, min_contactgate_space=0.25,
148              min_l=0.5, min_w=0.5,
149          )
150          esdgate = _prm.MOSFETGate(
151              name="esdgate", active=active,
152              oxide=hvox, min_gateoxide_enclosure=_prp.Enclosure(0.4),
153              inside=esd, min_gateinside_enclosure=_prp.Enclosure(0.4),
154              min_sd_width=0.35,
155              poly=poly, min_polyactive_extension=0.45,
156              min_l=0.5, min_w=0.5,
157          )
158          nmos = _prm.MOSFET(
159              name="nmos", gate=mosgate,
160              implant=nplus, min_gateimplant_enclosure=_prp.Enclosure(0.25),
161          )
162          pmos = _prm.MOSFET(
163              name="pmos", gate=mosgate,
164              implant=pplus, min_gateimplant_enclosure=_prp.Enclosure(0.25),
165              well=nwell,
166          )
167          hvnmos = _prm.MOSFET(
168              name="hvnmos", gate=hvgate,
169              implant=nplus, min_gateimplant_enclosure=_prp.Enclosure(0.4),
170          )
171          hvpmos = _prm.MOSFET(
172              name="hvpmos", gate=hvgate,
173              min_l=0.8, max_l=20.0, min_w=0.8, max_w=30.0,
174              implant=pplus, min_gateimplant_enclosure=_prp.Enclosure(0.4),
175              well=nwell,
176          )
177          esdnmos = _prm.MOSFET(
178              name="esdnmos", gate=esdgate, min_gate_space=2.0,
179              min_polyactive_extension=0.4,
180              implant=nplus, min_gateimplant_enclosure=_prp.Enclosure((0.4, 0.6)),
181              contact=contact, min_contactgate_space=0.75,
182              min_sd_width=0.8,
183          )
184          prims += (mosgate, hvgate, esdgate, nmos, pmos, esd, hvnmos, hvpmos, esdnmos)
185  
186          bip = _prm.Marker(name="bip")
187          npn = _prm.Bipolar(name="npn", type_=_prm.npnBipolar, indicator=bip)
188          pnp = _prm.Bipolar(
189              name="pnp", type_=_prm.pnpBipolar, indicator=bip,
190          )
191          prims += (bip, npn, pnp)
192  
193          mimcap = _prm.MIMCapacitor(
194              name="MIMCap", bottom=metal, top=mimtop, via=via,
195              min_bottom_top_enclosure=_prp.Enclosure(0.2),
196              min_bottomvia_top_space=0.25,
197              min_top_via_enclosure=_prp.Enclosure(0.25),
198              min_bottom_space=None, min_top2bottom_space=None,
199          )
200          mimcap2 = _prm.MIMCapacitor(
201              name="MIMCap2", bottom=metal, top=mimtop, via=via,
202              min_bottom_top_enclosure=_prp.Enclosure(0.2),
203              min_bottomvia_top_space=0.25,
204              min_top_via_enclosure=_prp.Enclosure(0.25),
205              min_bottom_space=None, min_top2bottom_space=None,
206          )
207          prims += (mimcap, mimcap2)
208  
209          aux = _prm.Auxiliary(name="anything_goes")
210          prims += aux
211  
212          prims += (
213              _prm.Spacing(
214                  primitives1=(nplus, pplus), primitives2=mosgate, min_space=0.25,
215              ),
216              _prm.Spacing(
217                  primitives1=active, primitives2=hvox, min_space=0.2,
218              ),
219              _prm.Spacing(
220                  primitives1=(nwell, pplus), min_space=2.0,
221              ),
222              _prm.MinWidth(prim=active.in_(hvox), min_width=0.5),
223              _prm.Enclosure(prim=active, by=esd, min_enclosure=_prp.Enclosure(0.1)),
224              _prm.NoOverlap(prim1=nplus, prim2=pplus),
225          )
226  
227          super().__init__(primitives=prims)
228  dummy_tech = DummyTech()
229  dummy_cktfab = _ckt.CircuitFactory(tech=dummy_tech)
230  dummy_layoutfab = _lay.LayoutFactory(tech=dummy_tech)
231  
232  dummy_gdslayers: GDSLayerSpecDict = {
233      mask.name: (i + 1) if i%2 == 0 else (i + 1, 1)
234      for i, mask in enumerate(dummy_tech.designmasks)
235  }
236  dummy_gdslayers["anything_goes"] = None
237  dummy_textgdslayers: GDSLayerSpecDict = {
238      "metalpin": (10, 10),
239  }
240  
241  def _gen_spiceparams() -> SpicePrimsParamSpec:
242      prims = dummy_tech.primitives
243  
244      params = SpicePrimsParamSpec()
245      params.add_device_params(
246          prim=cast(_prm.Resistor, prims.metal2res),
247          model="mres2", sheetres=10.0,
248      )
249      params.add_device_params(
250          prim=cast(_prm.Resistor, prims.resistor), is_subcircuit=True,
251      )
252      params.add_device_params(
253          prim=cast(_prm.Resistor, prims.polyres), is_subcircuit=True,
254          model="polyres", subcircuit_paramalias={"width": "w", "length": "l"},
255      )
256  
257      params.add_device_params(prim=cast(_prm.Diode, prims.ndiode))
258      params.add_device_params(prim=cast(_prm.Diode, prims.pdiode), is_subcircuit=True)
259  
260      params.add_device_params(prim=cast(_prm.MOSFET, prims.nmos))
261      params.add_device_params(prim=cast(_prm.MOSFET, prims.pmos), is_subcircuit=True)
262      params.add_device_params(prim=cast(_prm.MOSFET, prims.hvnmos))
263      params.add_device_params(prim=cast(_prm.MOSFET, prims.hvpmos))
264      params.add_device_params(prim=cast(_prm.MOSFET, prims.esdnmos), model="nmos_5v_esd")
265  
266      params.add_device_params(prim=cast(_prm.Bipolar, prims.npn))
267      params.add_device_params(prim=cast(_prm.Bipolar, prims.pnp), is_subcircuit=True)
268  
269      params.add_device_params(prim=cast(_prm.MIMCapacitor, prims.MIMCap))
270      params.add_device_params(
271          prim=cast(_prm.MIMCapacitor, prims.MIMCap2),
272          model="cap2", subcircuit_paramalias={"width": "w", "height": "h"},
273      )
274  
275      return params
276  dummy_prims_spiceparams = _gen_spiceparams()
277  
278  dummy_lib = _lbry.Library(name="dummy_lib", tech=dummy_tech)
279  dummy_fab = _fab.BaseCellFactory(lib=dummy_lib, cktfab=dummy_cktfab, layoutfab=dummy_layoutfab)
280  def _lib_init():
281      # The dummy_lib will be initialized with different shapes to maximize
282      # code coverage when being used for example in export code etc.
283      prims = dummy_tech.primitives
284      metal = cast(_prm.TopMetalWire, prims.metal)
285  
286      rect1 = _geo.Rect(left=0.0, bottom=0.0, right=1.0, top=1.0)
287      rect2 = _geo.Rect(left=1.0, bottom=0.0, right=2.0, top=1.0)
288      rect12 = _geo.Rect(left=0.0, bottom=0.0, right=2.0, top=1.0)
289      lshape = _geo.Polygon.from_floats(points=(
290          (0.0, 0.0), (0.0, 3.0), (1.0, 3.0), (1.0, 1.0), (2.0, 1.0), (2.0, 0.0), (0.0, 0.0),
291      ))
292  
293      # cell1: rect shape
294      cell1 = dummy_fab.new_cell(name="cell1")
295      ckt = cell1.new_circuit()
296      layouter = cell1.new_circuitlayouter()
297      layout = layouter.layout
298  
299      i = ckt.new_net(name="i", external=True)
300      layouter.add_wire(net=i, wire=metal, pin=prims.metalpin, shape=rect1)
301      layouter.layout.boundary = rect1
302  
303      # cell2: cell instance
304      cell2 = dummy_fab.new_cell(name="cell2")
305      ckt = cell2.new_circuit()
306      layouter = cell2.new_circuitlayouter()
307  
308      inst = ckt.instantiate(cell1, name="inst")
309      i = ckt.new_net(name="i", external=True, childports=inst.ports.i)
310  
311      layouter.place(object_=inst, origin=_geo.Point(x=1.0, y=0.0))
312      layouter.layout.boundary = rect1
313  
314      # cell3: polygon
315      cell3 = dummy_fab.new_cell(name="cell3")
316      ckt = cell3.new_circuit()
317      layouter = cell3.new_circuitlayouter()
318  
319      i = ckt.new_net(name="i", external=True)
320      layouter.add_wire(net=i, wire=metal, pin=prims.metalpin, shape=lshape)
321      layouter.layout.boundary = lshape.bounds
322  
323      # cell4: multipartshape
324      cell4 = dummy_fab.new_cell(name="cell4")
325      ckt = cell4.new_circuit()
326      layouter = cell4.new_circuitlayouter()
327      layout = layouter.layout
328  
329      mps = _geo.MultiPartShape(fullshape=rect12, parts=(rect1, rect2))
330      
331      i1 = ckt.new_net(name="i1", external=False)
332      i2 = ckt.new_net(name="i2", external=False)
333  
334      layout.add_shape(layer=metal, net=i1, shape=mps.parts[0])
335      layout.add_shape(layer=metal, net=i2, shape=mps.parts[1])
336  
337      # cell5: primitive instance
338      cell5 = dummy_fab.new_cell(name="cell5")
339      ckt = cell5.new_circuit()
340      layouter = cell5.new_circuitlayouter()
341      layout = layouter.layout
342  
343      res = ckt.instantiate(
344          cast(_prm.Resistor, prims.resistor), name="res",
345          width=1.0, height=5.0,
346      )
347  
348      ckt.new_net(name="p1", external=True, childports=res.ports.port1)
349      ckt.new_net(name="p2", external=True, childports=res.ports.port2)
350  
351      layouter.place(res)
352  _lib_init()