def test_model_instantiation(testmos): M1 = Instance(name='m1', model=testmos, pins={ 'd': 'net01', 'G': 'Net02', 's': 'NET03', 'B': 'NeT04' }, parameters={ 'PARAM1': 'nf*4', 'param2': '2.0' }) M2 = Instance(name='m2', model=testmos, pins={ 'd': 'net03', 'G': 'Net02', 's': 'NET01', 'B': 'NeT04' }, parameters={ 'PARAM1': '2.0', 'param2': 'nf*4' }) assert M1 != M2 assert M1.name != M2.name assert M1.pins != M2.pins assert M1.parameters != M2.parameters assert M1.model == M2.model assert id(M1.model) == id(M2.model)
def test_instance_pins(testmos): with pytest.raises(Exception): M1 = Instance(name='M1', model=testmos, pins={'D': 'NET01'}) with pytest.raises(Exception): M1 = Instance(name='M1', model=testmos, pins={ 'D': 'NET01', 'G': 'NET02', 'S': 'NET03', 'B': 'NET04' }, parameters={'garbage': 'NET05'}) with pytest.raises(Exception): M1 = Instance(name='M1', model=testmos, pins={ 'D': 'NET01', 'G': 'NET02', 'S': 'NET03', 'B': 'NET04' }, parameters={'garbage': 'dfddfd'}) M1 = Instance(name='M1', model=testmos, pins={ 'D': 'NET01', 'G': 'NET02', 'S': 'NET03', 'B': 'NET04' }) assert M1.name == 'M1' assert M1.model.name == 'TESTMOS' assert M1.pins == {'D': 'NET01', 'G': 'NET02', 'S': 'NET03', 'B': 'NET04'} assert M1.parameters == {'PARAM1': "1.0", 'PARAM2': "2"}
def test_instance_name(testmos): with pytest.raises(Exception): M1 = Instance(model=testmos) with pytest.raises(Exception): M1 = Instance(name='M1') with pytest.raises(Exception): M1 = Instance(name='M1', model=testmos)
def test_PMOS(library): assert 'PMOS' in library with pytest.raises(Exception): inst = Instance( name='M1', model=library['PMOS'], pins={'D': 'NET10', 'G': 'NET12', 'S': 'NET13'}) with pytest.raises(Exception): inst = Instance( name='X1', model=library['PMOS'], pins={'D': 'NET10', 'G': 'NET12', 'S': 'NET13', 'B': 'VSS'}) inst = Instance( name='M1', model=library['PMOS'], pins={'D': 'NET10', 'G': 'NET12', 'S': 'NET13', 'B': 'VSS'}) assert inst.name == 'M1' assert inst.model.name == 'PMOS' assert inst.pins == {'D': 'NET10', 'G': 'NET12', 'S': 'NET13', 'B': 'VSS'} assert list(inst.parameters.keys()) == ['W', 'L', 'NFIN'] assert inst.parameters['W'] == '0' assert inst.parameters['L'] == '0' assert inst.parameters['NFIN'] == '1' inst = Instance( name='M1', model=library['PMOS'], pins={'D': 'NET10', 'G': 'NET12', 'S': 'NET13', 'B': 'VSS'}, parameters={'NFIN': 2}) assert inst.parameters['NFIN'] == '2'
def test_model_instantiation(circuit): with set_context(circuit.elements): M1 = Instance(name='m1', model='testmos', pins={ 'd': 'net01', 'G': 'Net02', 's': 'NET03', 'B': 'NeT04' }, parameters={ 'PARAM1': 'nf*4', 'param2': '2.0' }, generator='MOS') M2 = Instance(name='m2', model='testmos', pins={ 'd': 'net03', 'G': 'Net02', 's': 'NET01', 'B': 'NeT04' }, parameters={ 'PARAM1': '2.0', 'param2': 'nf*4' }, generator='MOS') assert M1 != M2 assert M1.name != M2.name assert M1.pins != M2.pins assert M1.parameters != M2.parameters assert M1.model == M2.model
def test_instance_init_parameters(circuit): with set_context(circuit.elements): M1 = Instance(name='M1', model='testmos', pins={ 'D': 'NET01', 'G': 'NET02', 'S': 'NET03', 'B': 'NET04' }, parameters={'PARAM1': 'NF*4'}, generator='MOS') assert M1.parameters == {'PARAM1': 'NF*4', 'PARAM2': "2"} with set_context(circuit.elements): M1 = Instance(name='M1', model='testmos', pins={ 'D': 'NET01', 'G': 'NET02', 'S': 'NET03', 'B': 'NET04' }, parameters={ 'PARAM1': '12', 'PARAM2': '13' }, generator='MOS') assert M1.parameters == {'PARAM1': "12", 'PARAM2': "13"}
def test_PMOS(library, test_ckt): assert any(x.name == 'PMOS' for x in library) with set_context(test_ckt.elements): with pytest.raises(Exception): inst = Instance( name='M1', model='PMOS', pins={'D': 'NET10', 'G': 'NET12', 'S': 'NET13'}, generator='MOS') with pytest.raises(Exception): inst = Instance( name='X1', model='PMOS', pins={'D': 'NET10', 'G': 'NET12', 'S': 'NET13', 'B': 'VSS'}, generator='MOS') inst = Instance( name='M1', model='PMOS', pins={'D': 'NET10', 'G': 'NET12', 'S': 'NET13', 'B': 'VSS'}, generator='MOS') assert inst.name == 'M1' assert inst.model == 'PMOS' assert inst.pins == {'D': 'NET10', 'G': 'NET12', 'S': 'NET13', 'B': 'VSS'} assert list(inst.parameters.keys()) == ['W', 'L', 'NFIN'] assert inst.parameters['W'] == '0' assert inst.parameters['L'] == '0' assert inst.parameters['NFIN'] == '1' with set_context(test_ckt.elements): inst = Instance( name='M1', model='PMOS', pins={'D': 'NET10', 'G': 'NET12', 'S': 'NET13', 'B': 'VSS'}, parameters={'NFIN': 2}, generator='MOS') assert inst.parameters['NFIN'] == '2'
def test_instance_name(circuit): with set_context(circuit.elements): with pytest.raises(Exception): M1 = Instance(model='testmos') with pytest.raises(Exception): M1 = Instance(name='M1') with pytest.raises(Exception): M1 = Instance(name='M1', model='testmos')
def test_cap(library): assert 'CAP' in library with pytest.raises(Exception): inst = Instance(name='C1', model=library['CAP'], pins={'+': 'NET10'}) with pytest.raises(Exception): inst = Instance(name='X1', model=library['CAP'], pins={'+': 'NET10', '-':'NET12'}, parameters={'VALUE': '1.3'}) inst = Instance(name='C1', model=library['CAP'], pins={'+': 'NET10', '-':'NET12'}, parameters={'VALUE': '1.3'}) assert inst.name == 'C1' assert inst.model.name == 'CAP' assert inst.pins == {'+': 'NET10', '-': 'NET12'} assert inst.parameters['VALUE'] == '1.3'
def test_instance_model(circuit): with set_context(circuit.elements): with pytest.raises(Exception): M1 = Instance() with pytest.raises(Exception): M1 = Instance(name='M1', pins={ 'D': 'NET01', 'G': 'NET02', 'S': 'NET03', 'B': 'NET04' }, generator='MOS') with pytest.raises(Exception): M1 = Instance(name='M1', pins={ 'D': 'NET01', 'G': 'NET02', 'S': 'NET03', 'B': 'NET04' }, parameters={ 'PARAM1': '12', 'PARAM2': '13' }, generator='MOS') with pytest.raises(Exception): M1 = Instance(name='M1', model='undefinedmos', pins={ 'D': 'NET01', 'G': 'NET02', 'S': 'NET03', 'B': 'NET04' }, parameters={ 'PARAM1': '12', 'PARAM2': '13' }, generator='MOS') M1 = Instance(name='M1', model='testmos', pins={ 'D': 'NET01', 'G': 'NET02', 'S': 'NET03', 'B': 'NET04' }, parameters={ 'PARAM1': '12', 'PARAM2': '13' }, generator='MOS')
def test_ind(library, test_ckt): assert any(x.name == 'IND' for x in library) with set_context(test_ckt.elements): with pytest.raises(Exception): inst = Instance(name='L1', model='IND', pins={'PLUS': 'NET10'},generator='MOS') with pytest.raises(Exception): inst = Instance(name='X1', model='IND', pins={'PLUS': 'NET10', 'MINUS':'NET12'}, parameters={'VALUE': '1.3'},generator='MOS') inst = Instance(name='L1', model='IND', pins={'PLUS': 'NET10', 'MINUS':'NET12'}, parameters={'VALUE': '1.3'},generator='MOS') assert inst.name == 'L1' assert inst.model == 'IND' assert inst.pins == {'PLUS': 'NET10', 'MINUS': 'NET12'} assert inst.parameters['VALUE'] == '1.3'
def test_instance_json(testmos): M1 = Instance(name='M1', model=testmos, pins={ 'D': 'NET01', 'G': 'NET02', 'S': 'NET03', 'B': 'NET04' }, parameters={'PARAM1': 'NF*4'}) assert M1.json( ) == '{"model": {"name": "TESTMOS", "base": null, "pins": ["D", "G", "S", "B"], "parameters": {"PARAM1": "1.0", "PARAM2": "2"}, "prefix": null}, "name": "M1", "pins": {"D": "NET01", "G": "NET02", "S": "NET03", "B": "NET04"}, "parameters": {"PARAM1": "NF*4", "PARAM2": "2"}}'
def test_instance_json(circuit): with set_context(circuit.elements): M1 = Instance(name='M1', model='testmos', pins={ 'D': 'NET01', 'G': 'NET02', 'S': 'NET03', 'B': 'NET04' }, parameters={'PARAM1': 'NF*4'}, generator='MOS') assert M1.json( ) == '{"model": "TESTMOS", "name": "M1", "pins": {"D": "NET01", "G": "NET02", "S": "NET03", "B": "NET04"}, "parameters": {"PARAM1": "NF*4", "PARAM2": "2"}, "generator": "MOS", "abstract_name": null}'
def test_find_subgraph_matches(simple_circuit, matching_subckt, ThreeTerminalDevice, TwoTerminalDevice): netlist, matching_netlist = Graph(simple_circuit), Graph(matching_subckt) # Validate true match assert len(netlist.find_subgraph_matches(matching_netlist)) == 1 assert netlist.find_subgraph_matches(matching_netlist)[0] == { 'X3': 'X1', 'NET3': 'PIN3', 'NET1': 'PIN1', 'X4': 'X2', 'NET2': 'PIN2' } # Validate false match subckt2 = SubCircuit(name='test_subckt2', pins=['PIN1', 'PIN2', 'PIN3', 'PIN4', 'PIN5']) subckt2.add( Instance(name='X1', model=ThreeTerminalDevice, pins={ 'A': 'PIN1', 'B': 'PIN3', 'C': 'PIN4' })) subckt2.add( Instance(name='X2', model=ThreeTerminalDevice, pins={ 'A': 'PIN2', 'B': 'PIN3', 'C': 'PIN5' })) assert len(netlist.find_subgraph_matches(Graph(subckt2))) == 0 # Validate filtering of redundant subgraphs (There are 4 matches. Only 1 should be returned) subckt3 = SubCircuit(name='test_subckt3', pins=['PIN1', 'PIN2', 'PIN3', 'PIN4']) subckt3.add( Instance(name='X1', model=TwoTerminalDevice, pins={ 'A': 'PIN1', 'B': 'PIN2' })) subckt3.add( Instance(name='X2', model=TwoTerminalDevice, pins={ 'A': 'PIN3', 'B': 'PIN4' })) assert len(netlist.find_subgraph_matches(Graph(subckt3))) == 1
def remove_dummies(library, dummy_hiers, top): for dh in dummy_hiers: if dh == top: logger.debug("Cant delete top hierarchy {top}") return ckt = library.find(dh) assert ckt, f"No subckt with name {dh} found" with set_context(library): logger.info(f"Flattening dummy hierarchy {ckt.name}") for other_ckt in library: if isinstance(other_ckt, SubCircuit) and not other_ckt.name == ckt.name: replace = {} for inst in other_ckt.elements: if inst.model == ckt.name: logger.debug( f"Removing instance {inst} with instance {ckt.elements[0].model}" ) replace[inst.name] = ckt.elements[0] # @Parijat, is there a better way to modify? with set_context(other_ckt.elements): for x, y in replace.items(): ele = other_ckt.get_element(x) assert ele pins = {} for p, v in y.pins.items(): pins[p] = ele.pins[v] y.parameters.update({ k: v for k, v in ele.parameters.items() if k in y.parameters }) logger.debug( f"new instance parameters: {y.parameters}") _prefix = library.find(y.model).prefix if not _prefix: _prefix = "M" # default value, used in testing other_ckt.elements.append( Instance( name=ele.name.replace("X", _prefix), model=y.model, pins=pins, parameters=y.parameters, generator=y.generator, )) logger.info( f"updating {other_ckt.name} element {other_ckt.elements[-1]}" ) other_ckt.elements.remove(ele) all_subckt = [ module.name for module in library if isinstance(module, SubCircuit) ] library.remove(ckt) logger.info(f"Removing hierarchy {dh} from {all_subckt}") all_subckt_updated = [ module.name for module in library if isinstance(module, SubCircuit) ] assert library.find(dh) == None, f"{all_subckt_updated}"
def simple_circuit(TwoTerminalDevice, ThreeTerminalDevice, circuit): CustomDevice = Model(name='CustomDevice', base=ThreeTerminalDevice, parameters={'myparameter': 1}) circuit.add( Instance(name='X1', model=CustomDevice, pins={ 'A': 'NET1', 'B': 'in1', 'C': 'net01' })) circuit.add( Instance(name='X2', model=CustomDevice, pins={ 'A': 'NET2', 'B': 'in2', 'C': 'net02' })) circuit.add( Instance(name='X3', model=CustomDevice, pins={ 'A': 'NET3', 'B': 'NET1', 'C': 'NET1' })) circuit.add( Instance(name='X4', model=CustomDevice, pins={ 'A': 'NET3', 'B': 'NET1', 'C': 'NET2' })) circuit.add( Instance(name='X5', model=TwoTerminalDevice, pins={ 'A': 'net01', 'B': 'net00' })) circuit.add( Instance(name='X6', model=TwoTerminalDevice, pins={ 'A': 'net02', 'B': 'net00' })) circuit.add( Instance(name='X7', model=TwoTerminalDevice, pins={ 'A': 'NET3', 'B': 'net03' })) return circuit
def test_instance_pins(circuit): with set_context(circuit.elements): with pytest.raises(Exception): M1 = Instance(name='M1', model='testmos', pins={'D': 'NET01'}, generator='MOS') with pytest.raises(Exception): M1 = Instance(name='M1', model='testmos', pins={ 'D': 'NET01', 'G': 'NET02', 'S': 'NET03', 'B': 'NET04' }, parameters={'garbage': 'NET05'}, generator='MOS') with pytest.raises(Exception): M1 = Instance(name='M1', model='testmos', pins={ 'D': 'NET01', 'G': 'NET02', 'S': 'NET03', 'B': 'NET04' }, parameters={'garbage': 'dfddfd'}, generator='MOS') M1 = Instance(name='M1', model='testmos', pins={ 'D': 'NET01', 'G': 'NET02', 'S': 'NET03', 'B': 'NET04' }, generator='MOS') assert M1.name == 'M1' assert M1.model == 'TESTMOS' assert M1.pins == {'D': 'NET01', 'G': 'NET02', 'S': 'NET03', 'B': 'NET04'} assert M1.parameters == {'PARAM1': "1.0", 'PARAM2': "2"}
def heirarchical_ckt(matching_subckt, ThreeTerminalDevice, circuit): ckt = circuit subckt = SubCircuit(name='parent_subckt', pins=['PIN1', 'PIN2']) subckt.add( Instance(name='X1', model=matching_subckt, pins={ 'PIN1': 'PIN1', 'PIN2': 'PIN2', 'PIN3': 'NET1' }, parameters={'MYPARAMETER': '2'})) subckt.add( Instance(name='X2', model=ThreeTerminalDevice, pins={ 'A': 'NET1', 'B': 'PIN1', 'C': 'PIN2' }, parameters={'MYPARAMETER': '1'})) ckt.add( Instance(name='XSUB1', model=subckt, pins={ 'PIN1': 'NET1', 'PIN2': 'NET2' })) ckt.add( Instance(name='XSUB2', model=matching_subckt, pins={ 'PIN1': 'NET1', 'PIN2': 'NET2', 'PIN3': 'NET3' }, parameters={'MYPARAMETER': '3'})) return ckt
def test_netlist(TwoTerminalDevice, ThreeTerminalDevice, circuit): X1 = circuit.add( Instance(name='X1', model=TwoTerminalDevice, pins={ 'A': 'NET1', 'B': 'NET2' })) X2 = circuit.add( Instance(name='X2', model=ThreeTerminalDevice, pins={ 'A': 'NET1', 'B': 'NET2', 'C': 'NET3' })) netlist = Graph(circuit) assert netlist.elements == circuit.elements assert netlist.nets == circuit.nets # Advanced graphx functionality test nodes = ['X1', 'X2', 'NET1', 'NET2', 'NET3'] assert all(x in netlist.nodes for x in nodes) assert all(x in nodes for x in netlist.nodes) edges = [ # X1, net, pin ('X1', 'NET1', {'A'}), ('X1', 'NET2', {'B'}), ('NET1', 'X1', {'A'}), ('NET2', 'X1', {'B'}), # X2, net, pin ('X2', 'NET1', {'A'}), ('X2', 'NET2', {'B'}), ('X2', 'NET3', {'C'}), ('NET1', 'X2', {'A'}), ('NET2', 'X2', {'B'}), ('NET3', 'X2', {'C'}) ] assert all(x in netlist.edges.data('pin') for x in edges), netlist.edges assert all(x in edges for x in netlist.edges.data('pin')), netlist.edges
def matching_subckt(ThreeTerminalDevice): subckt = SubCircuit(name='TEST_SUBCKT', pins=['PIN1', 'PIN2', 'PIN3'], parameters={'MYPARAMETER': 1}) subckt.add( Instance(name='X1', model=ThreeTerminalDevice, pins={ 'A': 'PIN3', 'B': 'PIN1', 'C': 'PIN1' }, parameters={'MYPARAMETER': 1})) subckt.add( Instance(name='X2', model=ThreeTerminalDevice, pins={ 'A': 'PIN3', 'B': 'PIN1', 'C': 'PIN2' }, parameters={'MYPARAMETER': 'MYPARAMETER'})) return subckt
def test_instance_model(testmos): with pytest.raises(Exception): M1 = Instance() with pytest.raises(Exception): M1 = Instance(name='M1', pins={ 'D': 'NET01', 'G': 'NET02', 'S': 'NET03', 'B': 'NET04' }) with pytest.raises(Exception): M1 = Instance(name='M1', pins={ 'D': 'NET01', 'G': 'NET02', 'S': 'NET03', 'B': 'NET04' }, parameters={ 'PARAM1': '12', 'PARAM2': '13' }) with pytest.raises(Exception): M1 = Instance(name='M1', model='testmos', pins={ 'D': 'NET01', 'G': 'NET02', 'S': 'NET03', 'B': 'NET04' }, parameters={ 'PARAM1': '12', 'PARAM2': '13' })
def test_instance_init_parameters(testmos): M1 = Instance(name='M1', model=testmos, pins={ 'D': 'NET01', 'G': 'NET02', 'S': 'NET03', 'B': 'NET04' }, parameters={'PARAM1': 'NF*4'}) assert M1.parameters == {'PARAM1': 'NF*4', 'PARAM2': "2"} M1 = Instance(name='M1', model=testmos, pins={ 'D': 'NET01', 'G': 'NET02', 'S': 'NET03', 'B': 'NET04' }, parameters={ 'PARAM1': '12', 'PARAM2': '13' }) assert M1.parameters == {'PARAM1': "12", 'PARAM2': "13"}
def test_instance_case_insensitivity(testmos): ''' Everything should be converted to uppercase internally (SPICE is case-insensitive) ''' M1 = Instance(name='m1', model=testmos, pins={ 'd': 'net01', 'G': 'Net02', 's': 'NET03', 'B': 'NeT04' }, parameters={ 'PARAM1': 'nf*4', 'param2': '2.0' }) assert M1.name == 'M1' assert M1.pins == {'D': 'NET01', 'G': 'NET02', 'S': 'NET03', 'B': 'NET04'} assert M1.parameters == {'PARAM1': 'NF*4', 'PARAM2': "2.0"}
def test_instance_case_insensitivity(circuit): ''' Everything should be converted to uppercase internally (SPICE is case-insensitive) ''' with set_context(circuit.elements): M1 = Instance(name='m1', model='testmos', pins={ 'd': 'net01', 'G': 'Net02', 's': 'NET03', 'B': 'NeT04' }, parameters={ 'PARAM1': 'nf*4', 'param2': '2.0' }, generator='MOS') assert M1.name == 'M1' assert M1.pins == {'D': 'NET01', 'G': 'NET02', 'S': 'NET03', 'B': 'NET04'} assert M1.parameters == {'PARAM1': 'NF*4', 'PARAM2': "2.0"} assert M1.generator == 'MOS'