pyspice.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 # type: ignore 3 import unittest 4 from typing import cast 5 6 from pdkmaster.technology import primitive as _prm 7 from pdkmaster.design import cell as _cell 8 9 from pdkmaster.io import spice as _sp 10 11 from ...dummy import dummy_tech, dummy_cktfab, dummy_layoutfab, dummy_prims_spiceparams 12 dummy_prims = dummy_tech.primitives 13 14 class PySpiceFactoryTest(unittest.TestCase): 15 def test_error(self): 16 fab = _sp.PySpiceFactory( 17 libfile="test.lib", corners=("fast", "typ", "slow"), conflicts={ 18 "fast": ("typ", "slow"), 19 "typ": ("fast", "slow"), 20 "slow": ("fast", "typ"), 21 }, 22 prims_params=dummy_prims_spiceparams, 23 ) 24 25 #---- 26 # instance ports on net checking 27 ckt = dummy_cktfab.new_circuit(name="test") 28 29 res = ckt.instantiate( 30 cast(_prm.Resistor, dummy_prims.resistor), name="res", 31 width=1.0, height=3.0, 32 ) 33 ckt.new_net(name="res_p1", external=True, childports=res.ports.port1) 34 35 # res.ports.port2 not on a net 36 with self.assertRaises(ValueError): 37 fab.new_pyspicesubcircuit(circuit=ckt) 38 39 ckt.new_net(name="res_p1b", external=True, childports=res.ports.port1) 40 41 # res.ports.port1 on two nets 42 with self.assertRaises(ValueError): 43 fab.new_pyspicesubcircuit(circuit=ckt) 44 45 #---- 46 # wrong corner spec 47 ckt = dummy_cktfab.new_circuit(name="test") 48 49 # wrong corner 50 with self.assertRaises(ValueError): 51 fab.new_pyspicecircuit(corner="error", top=ckt) 52 # conflicting corner 53 with self.assertRaises(ValueError): 54 fab.new_pyspicecircuit(corner=("slow", "fast"), top=ckt) 55 56 #---- 57 # MIMCapacitor in lvs 58 ckt = dummy_cktfab.new_circuit(name="test") 59 60 mim = ckt.instantiate( 61 cast(_prm.MIMCapacitor, dummy_prims.MIMCap), name="mim", 62 width=0.5, height=0.5, 63 ) 64 ckt.new_net(name="mim_bot", external=True, childports=mim.ports.bottom) 65 ckt.new_net(name="mim_top", external=True, childports=mim.ports.top) 66 67 with self.assertRaises(NotImplementedError): 68 fab.new_pyspicesubcircuit(circuit=ckt, lvs=True) 69 70 #---- 71 # MIMCapacitor not a subcircuit model 72 params = _sp.SpicePrimsParamSpec() 73 params.add_device_params( 74 prim=cast(_prm.MIMCapacitor, dummy_prims.MIMCap), is_subcircuit=False, 75 ) 76 fab = _sp.PySpiceFactory( 77 libfile="test.lib", corners=("typ",), conflicts={}, prims_params=params, 78 ) 79 80 ckt = dummy_cktfab.new_circuit(name="test") 81 82 mim = ckt.instantiate( 83 cast(_prm.MIMCapacitor, dummy_prims.MIMCap), name="mim", 84 width=0.5, height=0.5, 85 ) 86 ckt.new_net(name="mim_bot", external=True, childports=mim.ports.bottom) 87 ckt.new_net(name="mim_top", external=True, childports=mim.ports.top) 88 89 with self.assertRaises(NotImplementedError): 90 fab.new_pyspicesubcircuit(circuit=ckt) 91 92 def test_pyspicecircuit(self): 93 # Wrong corner in conflicts 94 with self.assertRaises(ValueError): 95 _sp.PySpiceFactory( 96 libfile="test.lib", corners=("typ",), conflicts={"error": "error2"}, 97 prims_params=dummy_prims_spiceparams, 98 ) 99 100 # Currently only run some code for code coverage. 101 # No checking done ATM. 102 fab = _sp.PySpiceFactory( 103 libfile="test.lib", corners=("typ",), conflicts={}, 104 prims_params=dummy_prims_spiceparams, 105 ) 106 107 mos_cell = _cell.Cell( 108 name="mytest", 109 tech=dummy_tech, cktfab=dummy_cktfab, layoutfab=dummy_layoutfab, 110 ) 111 mos_ckt = mos_cell.new_circuit() 112 mos = mos_ckt.instantiate(cast(_prm.MOSFET, dummy_prims.nmos), name="mos") 113 mos_ckt.new_net(name="s", external=True, childports=mos.ports.sourcedrain1) 114 mos_ckt.new_net(name="g", external=True, childports=mos.ports.gate) 115 mos_ckt.new_net(name="d", external=True, childports=mos.ports.sourcedrain2) 116 mos_ckt.new_net(name="b", external=True, childports=mos.ports.bulk) 117 118 119 ckt = dummy_cktfab.new_circuit(name="test") 120 121 res = ckt.instantiate( 122 cast(_prm.Resistor, dummy_prims.resistor), name="res", 123 width=1.0, height=3.0, 124 ) 125 ckt.new_net(name="res_p1", external=True, childports=res.ports.port1) 126 ckt.new_net(name="res_p2", external=True, childports=res.ports.port2) 127 128 res2 = ckt.instantiate( 129 cast(_prm.Resistor, dummy_prims.metal2res), name="res2", 130 ) 131 ckt.new_net(name="res2_p1", external=True, childports=res2.ports.port1) 132 ckt.new_net(name="res2_p2", external=True, childports=res2.ports.port2) 133 134 ndio = ckt.instantiate( 135 cast(_prm.Diode, dummy_prims.ndiode), name="ndio", 136 ) 137 ckt.new_net(name="ndio_ano", external=True, childports=ndio.ports.anode) 138 ckt.new_net(name="ndio_cath", external=True, childports=ndio.ports.cathode) 139 140 pdio = ckt.instantiate( 141 cast(_prm.Diode, dummy_prims.pdiode), name="pdio", 142 ) 143 ckt.new_net(name="pdio_ano", external=True, childports=pdio.ports.anode) 144 ckt.new_net(name="pdio_cath", external=True, childports=pdio.ports.cathode) 145 146 nmos = ckt.instantiate(mos_cell, name="nmos") 147 ckt.new_net(name="nmos_s", external=True, childports=nmos.ports.s) 148 ckt.new_net(name="nmos_g", external=True, childports=nmos.ports.g) 149 ckt.new_net(name="nmos_d", external=True, childports=nmos.ports.d) 150 ckt.new_net(name="nmos_b", external=True, childports=nmos.ports.b) 151 152 pmos = ckt.instantiate( 153 cast(_prm.MOSFET, dummy_prims.pmos), name="pmos", 154 ) 155 ckt.new_net(name="pmos_s", external=True, childports=pmos.ports.sourcedrain1) 156 ckt.new_net(name="pmos_g", external=True, childports=pmos.ports.gate) 157 ckt.new_net(name="pmos_d", external=True, childports=pmos.ports.sourcedrain2) 158 ckt.new_net(name="pmos_b", external=True, childports=pmos.ports.bulk) 159 160 mim = ckt.instantiate( 161 cast(_prm.MIMCapacitor, dummy_prims.MIMCap), name="mim", 162 width=0.5, height=0.5, 163 ) 164 ckt.new_net(name="mim_bot", external=True, childports=mim.ports.bottom) 165 ckt.new_net(name="mim_top", external=True, childports=mim.ports.top) 166 167 mim2 = ckt.instantiate( 168 cast(_prm.MIMCapacitor, dummy_prims.MIMCap2), name="mim2", 169 ) 170 ckt.new_net(name="mim2_bot", external=True, childports=mim2.ports.bottom) 171 ckt.new_net(name="mim2_top", external=True, childports=mim2.ports.top) 172 173 npn = ckt.instantiate(cast(_prm.Bipolar, dummy_prims.npn), name="npn") 174 ckt.new_net(name="npn_c", external=True, childports=npn.ports.collector) 175 ckt.new_net(name="npn_b", external=True, childports=npn.ports.base) 176 ckt.new_net(name="npn_e", external=True, childports=npn.ports.emitter) 177 178 pnp = ckt.instantiate(cast(_prm.Bipolar, dummy_prims.pnp), name="pnp") 179 ckt.new_net(name="pnp_c", external=True, childports=pnp.ports.collector) 180 ckt.new_net(name="pnp_b", external=True, childports=pnp.ports.base) 181 ckt.new_net(name="pnp_e", external=True, childports=pnp.ports.emitter) 182 183 fab.new_pyspicecircuit(corner="typ", top=ckt) 184 185 186 ckt = dummy_cktfab.new_circuit(name="test") 187 188 res = ckt.instantiate( 189 cast(_prm.Resistor, dummy_prims.metal2res), name="res", 190 width=1.0, height=3.0, 191 ) 192 ckt.new_net(name="res_p1", external=True, childports=res.ports.port1) 193 ckt.new_net(name="res_p2", external=True, childports=res.ports.port2) 194 195 fab.new_pyspicesubcircuit(circuit=ckt, lvs=True)