/* 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 */ #include "dbNetlistWriter.h" #include "dbNetlistSpiceWriter.h" #include "dbNetlist.h" #include "dbNetlistDeviceClasses.h" #include "tlUnitTest.h" #include "tlStream.h" #include "tlFileUtils.h" TEST(1_WriterResistorDevices) { db::Netlist nl; db::DeviceClass *rcls = new db::DeviceClassResistor (); db::DeviceClass *ccls = new db::DeviceClassCapacitor (); db::DeviceClass *lcls = new db::DeviceClassInductor (); db::DeviceClass *dcls = new db::DeviceClassDiode (); db::DeviceClass *m3cls = new db::DeviceClassMOS3Transistor (); db::DeviceClass *m4cls = new db::DeviceClassMOS4Transistor (); rcls->set_name ("RCLS"); lcls->set_name ("LCLS"); ccls->set_name ("CCLS"); dcls->set_name ("DCLS"); m3cls->set_name ("M3CLS"); m4cls->set_name ("M4CLS"); nl.add_device_class (rcls); nl.add_device_class (lcls); nl.add_device_class (ccls); nl.add_device_class (dcls); nl.add_device_class (m3cls); nl.add_device_class (m4cls); db::Circuit *circuit1 = new db::Circuit (); circuit1->set_name ("C1"); nl.add_circuit (circuit1); db::Net *n1, *n2, *n3; n1 = new db::Net (); n1->set_name ("n1"); circuit1->add_net (n1); n2 = new db::Net (); n2->set_name ("n2"); circuit1->add_net (n2); n3 = new db::Net (); n3->set_name ("n3"); circuit1->add_net (n3); db::Device *rdev1 = new db::Device (rcls); rdev1->set_parameter_value (db::DeviceClassResistor::param_id_R, 1.7); db::Device *rdev2 = new db::Device (rcls); rdev2->set_parameter_value (db::DeviceClassResistor::param_id_R, 42e-6); circuit1->add_device (rdev1); circuit1->add_device (rdev2); size_t pid1 = circuit1->add_pin ("p1").id (); size_t pid2 = circuit1->add_pin ("p2").id (); circuit1->connect_pin (pid1, n1); circuit1->connect_pin (pid2, n2); rdev1->connect_terminal (rdev1->device_class ()->terminal_id_for_name ("A"), n1); rdev1->connect_terminal (rdev1->device_class ()->terminal_id_for_name ("B"), n3); rdev2->connect_terminal (rdev2->device_class ()->terminal_id_for_name ("A"), n3); rdev2->connect_terminal (rdev2->device_class ()->terminal_id_for_name ("B"), n2); // verify against the input std::string path = tmp_file ("tmp_nwriter1.txt"); { tl::OutputStream stream (path); db::NetlistSpiceWriter writer; writer.write (stream, nl, "written by unit test"); } std::string au_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "nwriter1_au.txt"); tl::InputStream is (path); tl::InputStream is_au (au_path); if (is.read_all () != is_au.read_all ()) { _this->raise (tl::sprintf ("Compare failed - see\n actual: %s\n golden: %s", tl::absolute_file_path (path), tl::absolute_file_path (au_path))); } } TEST(2_WriterCapacitorDevices) { db::Netlist nl; db::DeviceClass *rcls = new db::DeviceClassResistor (); db::DeviceClass *ccls = new db::DeviceClassCapacitor (); db::DeviceClass *lcls = new db::DeviceClassInductor (); db::DeviceClass *dcls = new db::DeviceClassDiode (); db::DeviceClass *m3cls = new db::DeviceClassMOS3Transistor (); db::DeviceClass *m4cls = new db::DeviceClassMOS4Transistor (); rcls->set_name ("RCLS"); lcls->set_name ("LCLS"); ccls->set_name ("CCLS"); dcls->set_name ("DCLS"); m3cls->set_name ("M3CLS"); m4cls->set_name ("M4CLS"); nl.add_device_class (rcls); nl.add_device_class (lcls); nl.add_device_class (ccls); nl.add_device_class (dcls); nl.add_device_class (m3cls); nl.add_device_class (m4cls); db::Circuit *circuit1 = new db::Circuit (); circuit1->set_name ("C1"); nl.add_circuit (circuit1); db::Net *n1, *n2, *n3; n1 = new db::Net (); n1->set_name ("n1"); circuit1->add_net (n1); n2 = new db::Net (); n2->set_name ("n2"); circuit1->add_net (n2); n3 = new db::Net (); n3->set_name ("n3"); circuit1->add_net (n3); db::Device *cdev1 = new db::Device (ccls); cdev1->set_parameter_value (db::DeviceClassCapacitor::param_id_C, 1.7e-12); db::Device *cdev2 = new db::Device (ccls); cdev2->set_parameter_value (db::DeviceClassCapacitor::param_id_C, 42e-15); circuit1->add_device (cdev1); circuit1->add_device (cdev2); size_t pid1 = circuit1->add_pin ("p1").id (); size_t pid2 = circuit1->add_pin ("p2").id (); circuit1->connect_pin (pid1, n1); circuit1->connect_pin (pid2, n2); cdev1->connect_terminal (cdev1->device_class ()->terminal_id_for_name ("A"), n1); cdev1->connect_terminal (cdev1->device_class ()->terminal_id_for_name ("B"), n3); cdev2->connect_terminal (cdev2->device_class ()->terminal_id_for_name ("A"), n3); cdev2->connect_terminal (cdev2->device_class ()->terminal_id_for_name ("B"), n2); // verify against the input std::string path = tmp_file ("tmp_nwriter2.txt"); { tl::OutputStream stream (path); db::NetlistSpiceWriter writer; writer.write (stream, nl, "written by unit test"); } std::string au_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "nwriter2_au.txt"); tl::InputStream is (path); tl::InputStream is_au (au_path); if (is.read_all () != is_au.read_all ()) { _this->raise (tl::sprintf ("Compare failed - see\n actual: %s\n golden: %s", tl::absolute_file_path (path), tl::absolute_file_path (au_path))); } } TEST(3_WriterInductorDevices) { db::Netlist nl; db::DeviceClass *rcls = new db::DeviceClassResistor (); db::DeviceClass *ccls = new db::DeviceClassCapacitor (); db::DeviceClass *lcls = new db::DeviceClassInductor (); db::DeviceClass *dcls = new db::DeviceClassDiode (); db::DeviceClass *m3cls = new db::DeviceClassMOS3Transistor (); db::DeviceClass *m4cls = new db::DeviceClassMOS4Transistor (); rcls->set_name ("RCLS"); lcls->set_name ("LCLS"); ccls->set_name ("CCLS"); dcls->set_name ("DCLS"); m3cls->set_name ("M3CLS"); m4cls->set_name ("M4CLS"); nl.add_device_class (rcls); nl.add_device_class (lcls); nl.add_device_class (ccls); nl.add_device_class (dcls); nl.add_device_class (m3cls); nl.add_device_class (m4cls); db::Circuit *circuit1 = new db::Circuit (); circuit1->set_name ("C1"); nl.add_circuit (circuit1); db::Net *n1, *n2, *n3; n1 = new db::Net (); n1->set_name ("n1"); circuit1->add_net (n1); n2 = new db::Net (); n2->set_name ("n2"); circuit1->add_net (n2); n3 = new db::Net (); n3->set_name ("n3"); circuit1->add_net (n3); db::Device *ldev1 = new db::Device (lcls); ldev1->set_parameter_value (db::DeviceClassInductor::param_id_L, 1.7e-10); db::Device *ldev2 = new db::Device (lcls); ldev2->set_parameter_value (db::DeviceClassInductor::param_id_L, 42e-9); circuit1->add_device (ldev1); circuit1->add_device (ldev2); size_t pid1 = circuit1->add_pin ("p1").id (); size_t pid2 = circuit1->add_pin ("p2").id (); circuit1->connect_pin (pid1, n1); circuit1->connect_pin (pid2, n2); ldev1->connect_terminal (ldev1->device_class ()->terminal_id_for_name ("A"), n1); ldev1->connect_terminal (ldev1->device_class ()->terminal_id_for_name ("B"), n3); ldev2->connect_terminal (ldev2->device_class ()->terminal_id_for_name ("A"), n3); ldev2->connect_terminal (ldev2->device_class ()->terminal_id_for_name ("B"), n2); // verify against the input std::string path = tmp_file ("tmp_nwriter3.txt"); { tl::OutputStream stream (path); db::NetlistSpiceWriter writer; writer.write (stream, nl, "written by unit test"); } std::string au_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "nwriter3_au.txt"); tl::InputStream is (path); tl::InputStream is_au (au_path); if (is.read_all () != is_au.read_all ()) { _this->raise (tl::sprintf ("Compare failed - see\n actual: %s\n golden: %s", tl::absolute_file_path (path), tl::absolute_file_path (au_path))); } } TEST(4_WriterDiodeDevices) { db::Netlist nl; db::DeviceClass *rcls = new db::DeviceClassResistor (); db::DeviceClass *ccls = new db::DeviceClassCapacitor (); db::DeviceClass *lcls = new db::DeviceClassInductor (); db::DeviceClass *dcls = new db::DeviceClassDiode (); db::DeviceClass *m3cls = new db::DeviceClassMOS3Transistor (); db::DeviceClass *m4cls = new db::DeviceClassMOS4Transistor (); rcls->set_name ("RCLS"); lcls->set_name ("LCLS"); ccls->set_name ("CCLS"); dcls->set_name ("DCLS"); m3cls->set_name ("M3CLS"); m4cls->set_name ("M4CLS"); nl.add_device_class (rcls); nl.add_device_class (lcls); nl.add_device_class (ccls); nl.add_device_class (dcls); nl.add_device_class (m3cls); nl.add_device_class (m4cls); db::Circuit *circuit1 = new db::Circuit (); circuit1->set_name ("C1"); nl.add_circuit (circuit1); db::Net *n1, *n2, *n3; n1 = new db::Net (); n1->set_name ("n1"); circuit1->add_net (n1); n2 = new db::Net (); n2->set_name ("n2"); circuit1->add_net (n2); n3 = new db::Net (); n3->set_name ("n3"); circuit1->add_net (n3); db::Device *ddev1 = new db::Device (dcls); ddev1->set_parameter_value (db::DeviceClassDiode::param_id_A, 1.7e-10); db::Device *ddev2 = new db::Device (dcls); ddev2->set_parameter_value (db::DeviceClassDiode::param_id_A, 42e-9); circuit1->add_device (ddev1); circuit1->add_device (ddev2); size_t pid1 = circuit1->add_pin ("p1").id (); size_t pid2 = circuit1->add_pin ("p2").id (); circuit1->connect_pin (pid1, n1); circuit1->connect_pin (pid2, n2); ddev1->connect_terminal (ddev1->device_class ()->terminal_id_for_name ("A"), n1); ddev1->connect_terminal (ddev1->device_class ()->terminal_id_for_name ("C"), n3); ddev2->connect_terminal (ddev2->device_class ()->terminal_id_for_name ("A"), n3); ddev2->connect_terminal (ddev2->device_class ()->terminal_id_for_name ("C"), n2); // verify against the input std::string path = tmp_file ("tmp_nwriter4.txt"); { tl::OutputStream stream (path); db::NetlistSpiceWriter writer; writer.write (stream, nl, "written by unit test"); } std::string au_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "nwriter4_au.txt"); tl::InputStream is (path); tl::InputStream is_au (au_path); if (is.read_all () != is_au.read_all ()) { _this->raise (tl::sprintf ("Compare failed - see\n actual: %s\n golden: %s", tl::absolute_file_path (path), tl::absolute_file_path (au_path))); } } TEST(5_WriterMOS3Devices) { db::Netlist nl; db::DeviceClass *rcls = new db::DeviceClassResistor (); db::DeviceClass *ccls = new db::DeviceClassCapacitor (); db::DeviceClass *lcls = new db::DeviceClassInductor (); db::DeviceClass *dcls = new db::DeviceClassDiode (); db::DeviceClass *m3cls = new db::DeviceClassMOS3Transistor (); db::DeviceClass *m4cls = new db::DeviceClassMOS4Transistor (); rcls->set_name ("RCLS"); lcls->set_name ("LCLS"); ccls->set_name ("CCLS"); dcls->set_name ("DCLS"); m3cls->set_name ("M3CLS"); m4cls->set_name ("M4CLS"); nl.add_device_class (rcls); nl.add_device_class (lcls); nl.add_device_class (ccls); nl.add_device_class (dcls); nl.add_device_class (m3cls); nl.add_device_class (m4cls); db::Circuit *circuit1 = new db::Circuit (); circuit1->set_name ("C1"); nl.add_circuit (circuit1); db::Net *n1, *n2, *n3, *n4; n1 = new db::Net (); n1->set_name ("n1"); circuit1->add_net (n1); n2 = new db::Net (); n2->set_name ("n2"); circuit1->add_net (n2); n3 = new db::Net (); n3->set_name ("n3"); circuit1->add_net (n3); n4 = new db::Net (); n4->set_name ("n4"); circuit1->add_net (n4); db::Device *ddev1 = new db::Device (m3cls); ddev1->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_L, 0.25); ddev1->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_W, 0.18); ddev1->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_AS, 1.2); ddev1->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_AD, 0.75); db::Device *ddev2 = new db::Device (m3cls); ddev2->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_L, 1.4); ddev2->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_W, 0.25); ddev2->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_AS, 1.3); ddev2->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_AD, 0.85); circuit1->add_device (ddev1); circuit1->add_device (ddev2); size_t pid1 = circuit1->add_pin ("p1").id (); size_t pid2 = circuit1->add_pin ("p2").id (); size_t pid3 = circuit1->add_pin ("p3").id (); circuit1->connect_pin (pid1, n1); circuit1->connect_pin (pid2, n2); circuit1->connect_pin (pid3, n4); ddev1->connect_terminal (ddev1->device_class ()->terminal_id_for_name ("S"), n1); ddev1->connect_terminal (ddev1->device_class ()->terminal_id_for_name ("G"), n4); ddev1->connect_terminal (ddev1->device_class ()->terminal_id_for_name ("D"), n3); ddev2->connect_terminal (ddev2->device_class ()->terminal_id_for_name ("S"), n3); ddev2->connect_terminal (ddev1->device_class ()->terminal_id_for_name ("G"), n4); ddev2->connect_terminal (ddev2->device_class ()->terminal_id_for_name ("D"), n2); // verify against the input std::string path = tmp_file ("tmp_nwriter5.txt"); { tl::OutputStream stream (path); db::NetlistSpiceWriter writer; writer.write (stream, nl, "written by unit test"); } std::string au_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "nwriter5_au.txt"); tl::InputStream is (path); tl::InputStream is_au (au_path); if (is.read_all () != is_au.read_all ()) { _this->raise (tl::sprintf ("Compare failed - see\n actual: %s\n golden: %s", tl::absolute_file_path (path), tl::absolute_file_path (au_path))); } } TEST(6_WriterMOS4Devices) { db::Netlist nl; db::DeviceClass *rcls = new db::DeviceClassResistor (); db::DeviceClass *ccls = new db::DeviceClassCapacitor (); db::DeviceClass *lcls = new db::DeviceClassInductor (); db::DeviceClass *dcls = new db::DeviceClassDiode (); db::DeviceClass *m3cls = new db::DeviceClassMOS3Transistor (); db::DeviceClass *m4cls = new db::DeviceClassMOS4Transistor (); rcls->set_name ("RCLS"); lcls->set_name ("LCLS"); ccls->set_name ("CCLS"); dcls->set_name ("DCLS"); m3cls->set_name ("M3CLS"); m4cls->set_name ("M4CLS"); nl.add_device_class (rcls); nl.add_device_class (lcls); nl.add_device_class (ccls); nl.add_device_class (dcls); nl.add_device_class (m3cls); nl.add_device_class (m4cls); db::Circuit *circuit1 = new db::Circuit (); circuit1->set_name ("C1"); nl.add_circuit (circuit1); db::Net *n1, *n2, *n3, *n4, *n5; n1 = new db::Net (); n1->set_name ("n1"); circuit1->add_net (n1); n2 = new db::Net (); n2->set_name ("n2"); circuit1->add_net (n2); n3 = new db::Net (); n3->set_name ("n3"); circuit1->add_net (n3); n4 = new db::Net (); n4->set_name ("n4"); circuit1->add_net (n4); n5 = new db::Net (); n5->set_name ("n5"); circuit1->add_net (n5); db::Device *ddev1 = new db::Device (m4cls); ddev1->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_L, 0.25); ddev1->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_W, 0.18); ddev1->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_AS, 1.2); ddev1->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_AD, 0.75); db::Device *ddev2 = new db::Device (m4cls); ddev2->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_L, 1.4); ddev2->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_W, 0.25); ddev2->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_AS, 1.3); ddev2->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_AD, 0.85); circuit1->add_device (ddev1); circuit1->add_device (ddev2); size_t pid1 = circuit1->add_pin ("p1").id (); size_t pid2 = circuit1->add_pin ("p2").id (); size_t pid3 = circuit1->add_pin ("p3").id (); size_t pid4 = circuit1->add_pin ("p4").id (); circuit1->connect_pin (pid1, n1); circuit1->connect_pin (pid2, n2); circuit1->connect_pin (pid3, n4); circuit1->connect_pin (pid4, n5); ddev1->connect_terminal (ddev1->device_class ()->terminal_id_for_name ("S"), n1); ddev1->connect_terminal (ddev1->device_class ()->terminal_id_for_name ("G"), n4); ddev1->connect_terminal (ddev1->device_class ()->terminal_id_for_name ("D"), n3); ddev1->connect_terminal (ddev1->device_class ()->terminal_id_for_name ("B"), n5); ddev2->connect_terminal (ddev2->device_class ()->terminal_id_for_name ("S"), n3); ddev2->connect_terminal (ddev1->device_class ()->terminal_id_for_name ("G"), n4); ddev2->connect_terminal (ddev2->device_class ()->terminal_id_for_name ("D"), n2); ddev2->connect_terminal (ddev1->device_class ()->terminal_id_for_name ("B"), n5); // verify against the input std::string path = tmp_file ("tmp_nwriter6.txt"); { tl::OutputStream stream (path); db::NetlistSpiceWriter writer; writer.write (stream, nl, "written by unit test"); } std::string au_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "nwriter6_au.txt"); tl::InputStream is (path); tl::InputStream is_au (au_path); if (is.read_all () != is_au.read_all ()) { _this->raise (tl::sprintf ("Compare failed - see\n actual: %s\n golden: %s", tl::absolute_file_path (path), tl::absolute_file_path (au_path))); } } TEST(7_WriterAnyDevices) { db::Netlist nl; db::DeviceClass *cls = new db::DeviceClass (); cls->add_terminal_definition (db::DeviceTerminalDefinition ("A", "a")); cls->add_terminal_definition (db::DeviceTerminalDefinition ("B", "b")); cls->add_parameter_definition (db::DeviceParameterDefinition ("U", "u")); cls->add_parameter_definition (db::DeviceParameterDefinition ("V", "v")); cls->set_name ("XCLS"); nl.add_device_class (cls); db::Circuit *circuit1 = new db::Circuit (); circuit1->set_name ("C1"); nl.add_circuit (circuit1); db::Net *n1, *n2, *n3; n1 = new db::Net (); n1->set_name ("n1"); circuit1->add_net (n1); n2 = new db::Net (); n2->set_name ("n2"); circuit1->add_net (n2); n3 = new db::Net (); n3->set_name ("n3"); circuit1->add_net (n3); db::Device *ddev1 = new db::Device (cls); ddev1->set_parameter_value (0, -17); ddev1->set_parameter_value (1, 42); db::Device *ddev2 = new db::Device (cls); ddev2->set_parameter_value (0, 17); ddev2->set_parameter_value (1, -42); circuit1->add_device (ddev1); circuit1->add_device (ddev2); size_t pid1 = circuit1->add_pin ("p1").id (); size_t pid2 = circuit1->add_pin ("p2").id (); circuit1->connect_pin (pid1, n1); circuit1->connect_pin (pid2, n2); ddev1->connect_terminal (ddev1->device_class ()->terminal_id_for_name ("A"), n1); ddev1->connect_terminal (ddev1->device_class ()->terminal_id_for_name ("B"), n3); ddev2->connect_terminal (ddev2->device_class ()->terminal_id_for_name ("A"), n3); ddev2->connect_terminal (ddev2->device_class ()->terminal_id_for_name ("B"), n2); // verify against the input std::string path = tmp_file ("tmp_nwriter7.txt"); { tl::OutputStream stream (path); db::NetlistSpiceWriter writer; writer.write (stream, nl, "written by unit test"); } std::string au_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "nwriter7_au.txt"); tl::InputStream is (path); tl::InputStream is_au (au_path); if (is.read_all () != is_au.read_all ()) { _this->raise (tl::sprintf ("Compare failed - see\n actual: %s\n golden: %s", tl::absolute_file_path (path), tl::absolute_file_path (au_path))); } } TEST(8_WriterSubcircuits) { db::Netlist nl; db::DeviceClass *rcls = new db::DeviceClassResistor (); db::DeviceClass *ccls = new db::DeviceClassCapacitor (); db::DeviceClass *lcls = new db::DeviceClassInductor (); db::DeviceClass *dcls = new db::DeviceClassDiode (); db::DeviceClass *m3cls = new db::DeviceClassMOS3Transistor (); db::DeviceClass *m4cls = new db::DeviceClassMOS4Transistor (); rcls->set_name ("RCLS"); lcls->set_name ("LCLS"); ccls->set_name ("CCLS"); dcls->set_name ("DCLS"); m3cls->set_name ("M3CLS"); m4cls->set_name ("M4CLS"); nl.add_device_class (rcls); nl.add_device_class (lcls); nl.add_device_class (ccls); nl.add_device_class (dcls); nl.add_device_class (m3cls); nl.add_device_class (m4cls); db::Circuit *circuit1 = new db::Circuit (); circuit1->set_name ("C1"); nl.add_circuit (circuit1); { db::Net *n1, *n2, *n3, *n4, *n5; n1 = new db::Net (); n1->set_name ("n1"); circuit1->add_net (n1); n2 = new db::Net (); n2->set_name ("n2"); circuit1->add_net (n2); n3 = new db::Net (); n3->set_name ("n3"); circuit1->add_net (n3); n4 = new db::Net (); n4->set_name ("n4"); circuit1->add_net (n4); n5 = new db::Net (); n5->set_name ("n5"); circuit1->add_net (n5); db::Device *ddev1 = new db::Device (m4cls); ddev1->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_L, 0.25); ddev1->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_W, 0.18); ddev1->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_AS, 1.2); ddev1->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_AD, 0.75); db::Device *ddev2 = new db::Device (m4cls); ddev2->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_L, 1.4); ddev2->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_W, 0.25); ddev2->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_AS, 1.3); ddev2->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_AD, 0.85); circuit1->add_device (ddev1); circuit1->add_device (ddev2); size_t pid1 = circuit1->add_pin ("p1").id (); size_t pid2 = circuit1->add_pin ("p2").id (); size_t pid3 = circuit1->add_pin ("p3").id (); size_t pid4 = circuit1->add_pin ("p4").id (); circuit1->connect_pin (pid1, n1); circuit1->connect_pin (pid2, n2); circuit1->connect_pin (pid3, n4); circuit1->connect_pin (pid4, n5); ddev1->connect_terminal (ddev1->device_class ()->terminal_id_for_name ("S"), n1); ddev1->connect_terminal (ddev1->device_class ()->terminal_id_for_name ("G"), n4); ddev1->connect_terminal (ddev1->device_class ()->terminal_id_for_name ("D"), n3); ddev1->connect_terminal (ddev1->device_class ()->terminal_id_for_name ("B"), n5); ddev2->connect_terminal (ddev2->device_class ()->terminal_id_for_name ("S"), n3); ddev2->connect_terminal (ddev1->device_class ()->terminal_id_for_name ("G"), n4); ddev2->connect_terminal (ddev2->device_class ()->terminal_id_for_name ("D"), n2); ddev2->connect_terminal (ddev1->device_class ()->terminal_id_for_name ("B"), n5); } db::Circuit *circuit2 = new db::Circuit (); circuit2->set_name ("C2"); nl.add_circuit (circuit2); { db::Net *n1, *n2, *n3, *n4, *n5; n1 = new db::Net (); n1->set_name ("n1"); circuit2->add_net (n1); n2 = new db::Net (); n2->set_name ("n2"); circuit2->add_net (n2); n3 = new db::Net (); n3->set_name ("n3"); circuit2->add_net (n3); n4 = new db::Net (); n4->set_name ("n4"); circuit2->add_net (n4); n5 = new db::Net (); n5->set_name ("n5"); circuit2->add_net (n5); db::SubCircuit *sc1 = new db::SubCircuit (circuit1, "SC1"); circuit2->add_subcircuit (sc1); sc1->connect_pin (0, n1); sc1->connect_pin (1, n3); sc1->connect_pin (2, n4); sc1->connect_pin (3, n3); db::SubCircuit *sc2 = new db::SubCircuit (circuit1, "SC2"); circuit2->add_subcircuit (sc2); sc2->connect_pin (0, n3); sc2->connect_pin (1, n2); sc2->connect_pin (2, n4); sc2->connect_pin (3, n3); size_t pid1 = circuit2->add_pin ("p1").id (); size_t pid2 = circuit2->add_pin ("p2").id (); size_t pid3 = circuit2->add_pin ("p3").id (); circuit2->connect_pin (pid1, n1); circuit2->connect_pin (pid2, n2); circuit2->connect_pin (pid3, n4); } // verify against the input std::string path = tmp_file ("tmp_nwriter8.txt"); { tl::OutputStream stream (path); db::NetlistSpiceWriter writer; writer.write (stream, nl, "written by unit test"); } std::string au_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "nwriter8_au.txt"); tl::InputStream is (path); tl::InputStream is_au (au_path); if (is.read_all () != is_au.read_all ()) { _this->raise (tl::sprintf ("Compare failed - see\n actual: %s\n golden: %s", tl::absolute_file_path (path), tl::absolute_file_path (au_path))); } } TEST(10_WriterLongLines) { db::Netlist nl; db::DeviceClass *rcls = new db::DeviceClassResistor (); rcls->set_name ("RCLS"); nl.add_device_class (rcls); db::Circuit *circuit1 = new db::Circuit (); circuit1->set_name ("C1withaverylongextensionthatgoesbeyondmultiplelinesunlessipasteeverythingtogetherwhichmakesithardtoreadbutexactlythatisthereasonwhyiwriteitthisway"); nl.add_circuit (circuit1); db::Net *n0 = new db::Net (); n0->set_name ("n0"); circuit1->add_net (n0); size_t pid0 = circuit1->add_pin ("p0").id (); circuit1->connect_pin (pid0, n0); for (int i = 0; i < 100; ++i) { db::Net *n = new db::Net (); n->set_name ("n" + tl::to_string (i + 1)); circuit1->add_net (n); size_t pid = circuit1->add_pin ("p" + tl::to_string (i + 1)).id (); circuit1->connect_pin (pid, n); db::Device *ddev = new db::Device (rcls); circuit1->add_device (ddev); ddev->connect_terminal (db::DeviceClassResistor::terminal_id_A, n0); ddev->connect_terminal (db::DeviceClassResistor::terminal_id_B, n); } // verify against the input std::string path = tmp_file ("tmp_nwriter10.txt"); { tl::OutputStream stream (path); db::NetlistSpiceWriter writer; writer.write (stream, nl, "written by unit test"); } std::string au_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "nwriter10_au.txt"); tl::InputStream is (path); tl::InputStream is_au (au_path); if (is.read_all () != is_au.read_all ()) { _this->raise (tl::sprintf ("Compare failed - see\n actual: %s\n golden: %s", tl::absolute_file_path (path), tl::absolute_file_path (au_path))); } } namespace { class MyDelegate : public db::NetlistSpiceWriterDelegate { public: MyDelegate () : db::NetlistSpiceWriterDelegate () { } void write_header () const { emit_line ("*** My special header"); } void write_device_intro (const db::DeviceClass &cls) const { emit_line ("*** My intro for class " + cls.name ()); } void write_device (const db::Device &dev) const { emit_line ("*** Before device " + dev.expanded_name ()); db::NetlistSpiceWriterDelegate::write_device (dev); emit_line ("*** After device " + dev.expanded_name ()); } }; } TEST(20_Delegate) { db::Netlist nl; db::DeviceClass *rcls = new db::DeviceClassResistor (); db::DeviceClass *ccls = new db::DeviceClassCapacitor (); db::DeviceClass *lcls = new db::DeviceClassInductor (); db::DeviceClass *dcls = new db::DeviceClassDiode (); db::DeviceClass *m3cls = new db::DeviceClassMOS3Transistor (); db::DeviceClass *m4cls = new db::DeviceClassMOS4Transistor (); rcls->set_name ("RCLS"); lcls->set_name ("LCLS"); ccls->set_name ("CCLS"); dcls->set_name ("DCLS"); m3cls->set_name ("M3CLS"); m4cls->set_name ("M4CLS"); nl.add_device_class (rcls); nl.add_device_class (lcls); nl.add_device_class (ccls); nl.add_device_class (dcls); nl.add_device_class (m3cls); nl.add_device_class (m4cls); db::Circuit *circuit1 = new db::Circuit (); circuit1->set_name ("C1"); nl.add_circuit (circuit1); db::Net *n1, *n2, *n3; n1 = new db::Net (); n1->set_name ("n1"); circuit1->add_net (n1); n2 = new db::Net (); n2->set_name ("n2"); circuit1->add_net (n2); n3 = new db::Net (); n3->set_name ("n3"); circuit1->add_net (n3); db::Device *rdev1 = new db::Device (rcls); rdev1->set_parameter_value (db::DeviceClassResistor::param_id_R, 1.7); db::Device *rdev2 = new db::Device (rcls); rdev2->set_parameter_value (db::DeviceClassResistor::param_id_R, 42e-6); circuit1->add_device (rdev1); circuit1->add_device (rdev2); size_t pid1 = circuit1->add_pin ("p1").id (); size_t pid2 = circuit1->add_pin ("p2").id (); circuit1->connect_pin (pid1, n1); circuit1->connect_pin (pid2, n2); rdev1->connect_terminal (rdev1->device_class ()->terminal_id_for_name ("A"), n1); rdev1->connect_terminal (rdev1->device_class ()->terminal_id_for_name ("B"), n3); rdev2->connect_terminal (rdev2->device_class ()->terminal_id_for_name ("A"), n3); rdev2->connect_terminal (rdev2->device_class ()->terminal_id_for_name ("B"), n2); // verify against the input std::string path = tmp_file ("tmp_nwriter20.txt"); { tl::OutputStream stream (path); MyDelegate delegate; db::NetlistSpiceWriter writer (&delegate); writer.write (stream, nl, "written by unit test"); } std::string au_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "nwriter20_au.txt"); tl::InputStream is (path); tl::InputStream is_au (au_path); if (is.read_all () != is_au.read_all ()) { _this->raise (tl::sprintf ("Compare failed - see\n actual: %s\n golden: %s", tl::absolute_file_path (path), tl::absolute_file_path (au_path))); } }