diff --git a/src/pya/unit_tests/pya.cc b/src/pya/unit_tests/pya.cc index b9a019457..6c13beff2 100644 --- a/src/pya/unit_tests/pya.cc +++ b/src/pya/unit_tests/pya.cc @@ -104,6 +104,7 @@ PYTHONTEST (dbPolygonTest, "dbPolygonTest.py") PYTHONTEST (dbTransTest, "dbTransTest.py") PYTHONTEST (dbLayoutToNetlist, "dbLayoutToNetlist.py") PYTHONTEST (dbLayoutVsSchematic, "dbLayoutVsSchematic.py") +PYTHONTEST (dbNetlistCrossReference, "dbNetlistCrossReference.py") PYTHONTEST (tlTest, "tlTest.py") #if defined(HAVE_QT) && defined(HAVE_QTBINDINGS) PYTHONTEST (qtbinding, "qtbinding.py") diff --git a/testdata/python/dbNetlistCrossReference.py b/testdata/python/dbNetlistCrossReference.py new file mode 100644 index 000000000..b89340176 --- /dev/null +++ b/testdata/python/dbNetlistCrossReference.py @@ -0,0 +1,187 @@ + +# encoding: UTF-8 + +# KLayout Layout Viewer +# Copyright (C) 2006-2019 Matthias Koefferlein +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +import pya +import unittest +import sys +import os + +class DBLayoutToNetlistTests(unittest.TestCase): + + def test_1_Basic(self): + + ut_testsrc = os.getenv("TESTSRC") + + xref = pya.NetlistCrossReference() + + lvs = pya.LayoutVsSchematic() + infile = os.path.join(ut_testsrc, "testdata", "algo", "lvs_test1b_au.lvsdb") + lvs.read(infile) + + reader = pya.NetlistSpiceReader() + nl = pya.Netlist() + nl.read(os.path.join(ut_testsrc, "testdata", "algo", "lvs_test_1.spi"), reader) + + self.assertEqual(xref.circuit_count(), 0) + + # A NetlistCrossReference object can act as a receiver for a netlist comparer + comp = pya.NetlistComparer() + comp.compare(lvs.netlist(), nl, xref) + + self.assertEqual(xref.circuit_count(), 3) + + xref.clear() + self.assertEqual(xref.circuit_count(), 0) + + def name_or_nil(self, s): + if s: + return s.name + else: + return "(nil)" + + def terminal_def_name_or_nil(self, s): + if s: + return s.terminal_def().name + else: + return "(nil)" + + def pin_name_or_nil(self, s): + if s: + return s.pin().name() + else: + return "(nil)" + + def name_call_or_nil(self, s): + if s: + return s.name() + else: + return "(nil)" + + def test_2_CircuitPairs(self): + + ut_testsrc = os.getenv("TESTSRC") + + lvs = pya.LayoutVsSchematic() + input = os.path.join(ut_testsrc, "testdata", "algo", "lvs_test2b_au.lvsdb") + lvs.read(input) + + xref = lvs.xref() + self.assertEqual(xref.circuit_count(), 4) + + info = [] + for cp in xref.each_circuit_pair(): + info.append("/".join([ self.name_or_nil(s) for s in [ cp.first(), cp.second() ] ]) + ":" + str(cp.status())) + self.assertEqual(",".join(info), "(nil)/INV2PAIRX:Mismatch,INV2/INV2:Match,INV2PAIR/INV2PAIR:NoMatch,RINGO/RINGO:Skipped") + + cp_inv2 = None + for cp in xref.each_circuit_pair(): + if cp.first() and cp.first().name == "INV2": + cp_inv2 = cp + + self.assertEqual(cp_inv2 != None, True) + + info = [] + for p in xref.each_pin_pair(cp_inv2): + info.append("/".join([ self.name_call_or_nil(s) for s in [ p.first(), p.second() ] ]) + ":" + str(p.status())) + self.assertEqual(",".join(info), "/:Match,BULK/:Match,IN/:Match,OUT/:Match,VDD/:Match,VSS/:Match") + + info = [] + for p in xref.each_net_pair(cp_inv2): + info.append("/".join([ self.name_or_nil(s) for s in [ p.first(), p.second() ] ]) + ":" + str(p.status())) + self.assertEqual(",".join(info), "/1:Match,BULK/6:Match,IN/2:Match,OUT/3:Match,VDD/5:Match,VSS/4:Match") + + netp_bulk = None + for p in xref.each_net_pair(cp_inv2): + if p.first().name == "BULK": + netp_bulk = p + + info = [] + for p in xref.each_net_terminal_pair(netp_bulk): + info.append("/".join([ self.terminal_def_name_or_nil(s) for s in [ p.first(), p.second() ] ])) + self.assertEqual(",".join(info), "B/B") + + info = [] + for p in xref.each_net_pin_pair(netp_bulk): + info.append("/".join([ self.pin_name_or_nil(s) for s in [ p.first(), p.second() ] ])) + self.assertEqual(",".join(info), "BULK/") + + info = [] + for p in xref.each_net_subcircuit_pin_pair(netp_bulk): + info.append("/".join([ self.name_or_nil(s) for s in [ p.first(), p.second() ] ])) + self.assertEqual(",".join(info), "") + + info = [] + for p in xref.each_device_pair(cp_inv2): + info.append("/".join([ self.name_or_nil(s) for s in [ p.first(), p.second() ] ]) + ":" + str(p.status())) + self.assertEqual(",".join(info), "/$1:Match,/$3:Match") + + info = [] + for p in xref.each_subcircuit_pair(cp_inv2): + info.append("/".join([ self.name_or_nil(s) for s in [ p.first(), p.second() ] ]) + ":" + str(p.status())) + self.assertEqual(",".join(info), "") + + cp_inv2pair = None + for cp in xref.each_circuit_pair(): + if cp.first() and cp.first().name == "INV2PAIR": + cp_inv2pair = cp + + self.assertEqual(cp_inv2pair != None, True) + + info = [] + for p in xref.each_pin_pair(cp_inv2pair): + info.append("/".join([ self.name_call_or_nil(s) for s in [ p.first(), p.second() ] ]) + ":" + str(p.status())) + self.assertEqual(",".join(info), "(nil)/:Mismatch,/(nil):Mismatch,/:Match,/:Match,/:Match,/:Match,/:Match,BULK/:Match") + + info = [] + for p in xref.each_net_pair(cp_inv2pair): + info.append("/".join([ self.name_or_nil(s) for s in [ p.first(), p.second() ] ]) + ":" + str(p.status())) + self.assertEqual(",".join(info), "/(nil):Mismatch,/2:Mismatch,/3:Mismatch,/4:Match,/6:Match,/7:Mismatch,BULK/1:Mismatch") + + info = [] + for p in xref.each_device_pair(cp_inv2pair): + info.append("/".join([ self.name_or_nil(s) for s in [ p.first(), p.second() ] ]) + ":" + str(p.status())) + self.assertEqual(",".join(info), "") + + info = [] + for p in xref.each_subcircuit_pair(cp_inv2pair): + info.append("/".join([ self.name_or_nil(s) for s in [ p.first(), p.second() ] ]) + ":" + str(p.status())) + self.assertEqual(",".join(info), "(nil)/$2:Mismatch,/(nil):Mismatch,/(nil):Mismatch") + + def test_3_StatusEnums(self): + + st = pya.NetlistCrossReference.Status() + self.assertEqual(st.to_i(), 0) + self.assertEqual(str(st), "None") + + st = pya.NetlistCrossReference.Status.Match + self.assertEqual(str(st), "Match") + + st = pya.NetlistCrossReference.Skipped + self.assertEqual(str(st), "Skipped") + + +# run unit tests +if __name__ == '__main__': + suite = unittest.TestLoader().loadTestsFromTestCase(DBLayoutToNetlistTests) + + if not unittest.TextTestRunner(verbosity = 1).run(suite).wasSuccessful(): + sys.exit(1) + +