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()