From 020b87408390e6551a579cce33d323a6864afc95 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 14 Jun 2019 20:41:38 +0200 Subject: [PATCH] WIP: more device classes - unit tests for classes --- src/db/db/dbNetlistDeviceClasses.cc | 3 + src/db/db/dbNetlistDeviceClasses.h | 1 + src/db/db/dbNetlistDeviceExtractor.cc | 2 +- src/db/db/dbNetlistDeviceExtractorClasses.cc | 74 +++ src/db/db/dbNetlistDeviceExtractorClasses.h | 57 +- src/db/db/gsiDeclDbNetlistDeviceExtractor.cc | 30 + .../unit_tests/dbNetlistDeviceClassesTests.cc | 433 +++++++++++- .../laybasic/images/icon_device_bjt_16.png | Bin 0 -> 323 bytes .../laybasic/images/icon_device_bjt_24.png | Bin 0 -> 373 bytes .../laybasic/images/icon_device_bjt_32.png | Bin 0 -> 485 bytes .../laybasic/images/icon_device_bjt_48.png | Bin 0 -> 689 bytes .../laybasic/images/icon_device_diode_16.png | Bin 0 -> 374 bytes .../laybasic/images/icon_device_diode_24.png | Bin 0 -> 399 bytes .../laybasic/images/icon_device_diode_32.png | Bin 0 -> 505 bytes .../laybasic/images/icon_device_diode_48.png | Bin 0 -> 752 bytes src/laybasic/laybasic/images/icons.svg | 614 +++++++++++++++++- .../laybasic/layNetlistBrowserModel.cc | 18 +- src/laybasic/laybasic/laybasicResources.qrc | 8 + 18 files changed, 1217 insertions(+), 23 deletions(-) create mode 100644 src/laybasic/laybasic/images/icon_device_bjt_16.png create mode 100644 src/laybasic/laybasic/images/icon_device_bjt_24.png create mode 100644 src/laybasic/laybasic/images/icon_device_bjt_32.png create mode 100644 src/laybasic/laybasic/images/icon_device_bjt_48.png create mode 100644 src/laybasic/laybasic/images/icon_device_diode_16.png create mode 100644 src/laybasic/laybasic/images/icon_device_diode_24.png create mode 100644 src/laybasic/laybasic/images/icon_device_diode_32.png create mode 100644 src/laybasic/laybasic/images/icon_device_diode_48.png diff --git a/src/db/db/dbNetlistDeviceClasses.cc b/src/db/db/dbNetlistDeviceClasses.cc index 232f4736d..c2357fd58 100644 --- a/src/db/db/dbNetlistDeviceClasses.cc +++ b/src/db/db/dbNetlistDeviceClasses.cc @@ -278,6 +278,7 @@ void DeviceClassInductor::serial (Device *a, Device *b) const // DeviceClassInductor implementation DB_PUBLIC size_t DeviceClassDiode::param_id_A = 0; +DB_PUBLIC size_t DeviceClassDiode::param_id_P = 1; DB_PUBLIC size_t DeviceClassDiode::terminal_id_A = 0; DB_PUBLIC size_t DeviceClassDiode::terminal_id_C = 1; @@ -288,6 +289,7 @@ DeviceClassDiode::DeviceClassDiode () add_terminal_definition (db::DeviceTerminalDefinition ("C", "Cathode")); add_parameter_definition (db::DeviceParameterDefinition ("A", "Area (square micrometer)", 0.0)); + add_parameter_definition (db::DeviceParameterDefinition ("P", "Perimeter (micrometer)", 0.0)); } bool DeviceClassDiode::combine_devices (Device *a, Device *b) const @@ -301,6 +303,7 @@ bool DeviceClassDiode::combine_devices (Device *a, Device *b) const if (na1 == nb1 && na2 == nb2) { a->set_parameter_value (0, a->parameter_value (0) + b->parameter_value (0)); + a->set_parameter_value (1, a->parameter_value (1) + b->parameter_value (1)); a->join_terminals (0, b, 0); a->join_terminals (1, b, 1); diff --git a/src/db/db/dbNetlistDeviceClasses.h b/src/db/db/dbNetlistDeviceClasses.h index fc90ef368..439ec7039 100644 --- a/src/db/db/dbNetlistDeviceClasses.h +++ b/src/db/db/dbNetlistDeviceClasses.h @@ -193,6 +193,7 @@ public: DeviceClassDiode (); static size_t param_id_A; + static size_t param_id_P; static size_t terminal_id_A; static size_t terminal_id_C; diff --git a/src/db/db/dbNetlistDeviceExtractor.cc b/src/db/db/dbNetlistDeviceExtractor.cc index 8216eb425..b2b4218a0 100644 --- a/src/db/db/dbNetlistDeviceExtractor.cc +++ b/src/db/db/dbNetlistDeviceExtractor.cc @@ -521,7 +521,7 @@ Device *NetlistDeviceExtractor::create_device () return device; } -void NetlistDeviceExtractor::define_terminal (Device *device, size_t terminal_id, size_t layer_index, const db::Region ®ion) +void NetlistDeviceExtractor::define_terminal (Device *device, size_t terminal_id, size_t geometry_index, const db::Region ®ion) { tl_assert (mp_layout != 0); tl_assert (geometry_index < m_layers.size ()); diff --git a/src/db/db/dbNetlistDeviceExtractorClasses.cc b/src/db/db/dbNetlistDeviceExtractorClasses.cc index 08f2336c2..3f6d25b2e 100644 --- a/src/db/db/dbNetlistDeviceExtractorClasses.cc +++ b/src/db/db/dbNetlistDeviceExtractorClasses.cc @@ -504,4 +504,78 @@ void NetlistDeviceExtractorBipolarTransistor::extract_devices (const std::vector } } +// --------------------------------------------------------------------------------- +// NetlistDeviceExtractorDiode implementation + +NetlistDeviceExtractorDiode::NetlistDeviceExtractorDiode (const std::string &name) + : db::NetlistDeviceExtractor (name) +{ + // .. nothing yet .. +} + +void NetlistDeviceExtractorDiode::setup () +{ + define_layer ("P", "P region"); // #0 + define_layer ("N", "N region"); // #1 + define_layer ("tA", 0, "A terminal output"); // #2 -> P + define_layer ("tC", 1, "C terminal output"); // #3 -> N + + register_device_class (new db::DeviceClassDiode ()); +} + +db::Connectivity NetlistDeviceExtractorDiode::get_connectivity (const db::Layout & /*layout*/, const std::vector &layers) const +{ + tl_assert (layers.size () >= 2); + + unsigned int pregion = layers [0]; + unsigned int nregion = layers [1]; + + // The layer definition is plate1, plate2 + db::Connectivity conn; + // collect all connected plate 1 shapes + conn.connect (pregion, pregion); + // collect all connected plate 1 shapes + conn.connect (nregion, nregion); + // connect the plates (NOTE that this is a logical, not a physical connection) + conn.connect (pregion, nregion); + return conn; +} + +void NetlistDeviceExtractorDiode::extract_devices (const std::vector &layer_geometry) +{ + size_t pregion_geometry_index = 0; + size_t nregion_geometry_index = 1; + size_t a_terminal_geometry_index = 2; + size_t c_terminal_geometry_index = 3; + + const db::Region &pregion = layer_geometry [pregion_geometry_index]; + const db::Region &nregion = layer_geometry [nregion_geometry_index]; + + db::Region overlap (pregion); + overlap.set_base_verbosity (pregion.base_verbosity ()); + overlap &= nregion; + + for (db::Region::const_iterator p = overlap.begin_merged (); !p.at_end (); ++p) { + + db::Device *device = create_device (); + + device->set_trans (db::DCplxTrans ((p->box ().center () - db::Point ()) * dbu ())); + + double area = p->area () * dbu () * dbu (); + + device->set_parameter_value (db::DeviceClassDiode::param_id_A, area); + device->set_parameter_value (db::DeviceClassDiode::param_id_P, dbu () * p->perimeter ()); + + define_terminal (device, db::DeviceClassDiode::terminal_id_A, a_terminal_geometry_index, *p); + define_terminal (device, db::DeviceClassDiode::terminal_id_C, c_terminal_geometry_index, *p); + + // allow derived classes to modify the device + modify_device (*p, layer_geometry, device); + + // output the device for debugging + device_out (device, db::Region (*p)); + + } +} + } diff --git a/src/db/db/dbNetlistDeviceExtractorClasses.h b/src/db/db/dbNetlistDeviceExtractorClasses.h index 95426e893..05821fb31 100644 --- a/src/db/db/dbNetlistDeviceExtractorClasses.h +++ b/src/db/db/dbNetlistDeviceExtractorClasses.h @@ -108,6 +108,10 @@ private: * The device class produced by this extractor is DeviceClassResistor. * The extractor extracts the three parameters of this class: R, A and P. * A is the area of the wire and P is the perimeter. + * + * The layers are R for the "wire" and "C" for the two contacts and the + * end of the wire. "tA" and "tB" are the layers on which the A and B + * terminals are produced. */ class DB_PUBLIC NetlistDeviceExtractorResistor : public db::NetlistDeviceExtractor @@ -171,7 +175,7 @@ public: * The extractor extracts the three parameters of this class: C, A and P. * A is the area of the overlap area and P is the perimeter. * - * The layers are P1 and P2 for the plates. A and B are layers where + * The layers are P1 and P2 for the plates. tA and tB are layers where * the terminals for A and B are produced respectively. */ class DB_PUBLIC NetlistDeviceExtractorCapacitor @@ -273,6 +277,51 @@ protected: } }; +/** + * @brief A device extractor for a planar diode + * + * This class supplies the generic extractor for a planar diode. + * The diode is defined by two layers whose overlap area forms + * the diode. The p-type layer forms the anode, the n-type layer + * the cathode. + * + * The device class produced by this extractor is DeviceClassDiode. + * The extractor extracts the two parameters of this class: A and P. + * A is the area of the overlap area and P is the perimeter. + * + * The layers are "P" and "N" for the p and n region respectively. + * The terminal output layers are "tA" and "tC" for anode and + * cathode respectively. + */ +class DB_PUBLIC NetlistDeviceExtractorDiode + : public db::NetlistDeviceExtractor +{ +public: + NetlistDeviceExtractorDiode (const std::string &name); + + virtual void setup (); + virtual db::Connectivity get_connectivity (const db::Layout &layout, const std::vector &layers) const; + virtual void extract_devices (const std::vector &layer_geometry); + +protected: + /** + * @brief A callback when the device is produced + * This callback is provided as a debugging port + */ + virtual void device_out (const db::Device * /*device*/, const db::Region & /*diode_area*/) + { + // .. no specific implementation .. + } + + /** + * @brief Allow derived classes to modify the device + */ + virtual void modify_device (const db::Polygon & /*diode_area*/, const std::vector & /*layer_geometry*/, db::Device * /*device*/) + { + // .. no specific implementation .. + } +}; + } namespace tl @@ -320,6 +369,12 @@ template<> struct type_traits : pub typedef tl::false_tag has_default_constructor; }; +template<> struct type_traits : public tl::type_traits +{ + typedef tl::false_tag has_copy_constructor; + typedef tl::false_tag has_default_constructor; +}; + } #endif diff --git a/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc b/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc index c5769d143..40e759fbc 100644 --- a/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc +++ b/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc @@ -622,4 +622,34 @@ Class decl_NetlistDeviceExtractorBi "This class has been introduced in version 0.26." ); +db::NetlistDeviceExtractorDiode *make_diode_extractor (const std::string &name) +{ + return new db::NetlistDeviceExtractorDiode (name); +} + +Class decl_NetlistDeviceExtractorDiode (decl_dbNetlistDeviceExtractor, "db", "DeviceExtractorDiode", + gsi::constructor ("new", &make_diode_extractor, gsi::arg ("name"), + "@brief Creates a new device extractor with the given name." + ), + "@brief A device extractor for a planar diode\n" + "\n" + "This class supplies the generic extractor for a planar diode.\n" + "The diode is defined by two layers whose overlap area forms\n" + "the diode. The p-type layer forms the anode, the n-type layer\n" + "the cathode.\n" + "\n" + "The device class produced by this extractor is DeviceClassDiode.\n" + "The extractor extracts the two parameters of this class: A and P.\n" + "A is the area of the overlap area and P is the perimeter.\n" + "\n" + "The layers are \"P\" and \"N\" for the p and n region respectively.\n" + "The terminal output layers are \"tA\" and \"tC\" for anode and \n" + "cathode respectively.\n" + "\n" + "This class is a closed one and methods cannot be reimplemented. To reimplement " + "specific methods, see \\DeviceExtractor.\n" + "\n" + "This class has been introduced in version 0.26." +); + } diff --git a/src/db/unit_tests/dbNetlistDeviceClassesTests.cc b/src/db/unit_tests/dbNetlistDeviceClassesTests.cc index d522698f5..5a97e9c71 100644 --- a/src/db/unit_tests/dbNetlistDeviceClassesTests.cc +++ b/src/db/unit_tests/dbNetlistDeviceClassesTests.cc @@ -840,12 +840,10 @@ TEST(15_SerialDiodes) db::Device *d1 = new db::Device (diode, "d1"); d1->set_parameter_value (db::DeviceClassDiode::param_id_A, 2.0); - d1->set_parameter_value (db::DeviceClassResistor::param_id_A, 5.0); - d1->set_parameter_value (db::DeviceClassResistor::param_id_P, 10.0); + d1->set_parameter_value (db::DeviceClassDiode::param_id_P, 5.0); db::Device *d2 = new db::Device (diode, "d2"); - d2->set_parameter_value (db::DeviceClassCapacitor::param_id_C, 3.0); - d2->set_parameter_value (db::DeviceClassResistor::param_id_A, 1.0); - d2->set_parameter_value (db::DeviceClassResistor::param_id_P, 2.0); + d2->set_parameter_value (db::DeviceClassDiode::param_id_A, 3.0); + d2->set_parameter_value (db::DeviceClassDiode::param_id_P, 1.0); db::Circuit *circuit = new db::Circuit (); nl.add_circuit (circuit); @@ -873,8 +871,8 @@ TEST(15_SerialDiodes) EXPECT_EQ (nl.to_string (), "circuit '' (A=n1,B=n3);\n" - " device '' d1 (A=n1,C=n2) (A=2);\n" - " device '' d2 (A=n2,C=n3) (A=3);\n" + " device '' d1 (A=n1,C=n2) (A=2,P=5);\n" + " device '' d2 (A=n2,C=n3) (A=3,P=1);\n" "end;\n" ); @@ -885,8 +883,8 @@ TEST(15_SerialDiodes) EXPECT_EQ (nl.to_string (), "circuit '' (A=n1,B=n3);\n" - " device '' d1 (A=n1,C=n2) (A=2);\n" - " device '' d2 (A=n2,C=n3) (A=3);\n" + " device '' d1 (A=n1,C=n2) (A=2,P=5);\n" + " device '' d2 (A=n2,C=n3) (A=3,P=1);\n" "end;\n" ); } @@ -900,8 +898,10 @@ TEST(16_ParallelDiodes) db::Device *d1 = new db::Device (diode, "d1"); d1->set_parameter_value (db::DeviceClassDiode::param_id_A, 1.0); + d1->set_parameter_value (db::DeviceClassDiode::param_id_P, 5.0); db::Device *d2 = new db::Device (diode, "d2"); d2->set_parameter_value (db::DeviceClassDiode::param_id_A, 3.0); + d2->set_parameter_value (db::DeviceClassDiode::param_id_P, 2.0); db::Circuit *circuit = new db::Circuit (); nl.add_circuit (circuit); @@ -926,8 +926,8 @@ TEST(16_ParallelDiodes) EXPECT_EQ (nl.to_string (), "circuit '' (A=n1,B=n2);\n" - " device '' d1 (A=n1,C=n2) (A=1);\n" - " device '' d2 (A=n1,C=n2) (A=3);\n" + " device '' d1 (A=n1,C=n2) (A=1,P=5);\n" + " device '' d2 (A=n1,C=n2) (A=3,P=2);\n" "end;\n" ); @@ -936,7 +936,7 @@ TEST(16_ParallelDiodes) EXPECT_EQ (nl.to_string (), "circuit '' (A=n1,B=n2);\n" - " device '' d1 (A=n1,C=n2) (A=4);\n" + " device '' d1 (A=n1,C=n2) (A=4,P=7);\n" "end;\n" ); } @@ -950,8 +950,10 @@ TEST(17_AntiParallelDiodes) db::Device *d1 = new db::Device (diode, "d1"); d1->set_parameter_value (db::DeviceClassDiode::param_id_A, 1.0); + d1->set_parameter_value (db::DeviceClassDiode::param_id_P, 5.0); db::Device *d2 = new db::Device (diode, "d2"); d2->set_parameter_value (db::DeviceClassDiode::param_id_A, 3.0); + d2->set_parameter_value (db::DeviceClassDiode::param_id_P, 2.0); db::Circuit *circuit = new db::Circuit (); nl.add_circuit (circuit); @@ -976,8 +978,8 @@ TEST(17_AntiParallelDiodes) EXPECT_EQ (nl.to_string (), "circuit '' (A=n1,B=n2);\n" - " device '' d1 (A=n1,C=n2) (A=1);\n" - " device '' d2 (A=n2,C=n1) (A=3);\n" + " device '' d1 (A=n1,C=n2) (A=1,P=5);\n" + " device '' d2 (A=n2,C=n1) (A=3,P=2);\n" "end;\n" ); @@ -988,8 +990,8 @@ TEST(17_AntiParallelDiodes) EXPECT_EQ (nl.to_string (), "circuit '' (A=n1,B=n2);\n" - " device '' d1 (A=n1,C=n2) (A=1);\n" - " device '' d2 (A=n2,C=n1) (A=3);\n" + " device '' d1 (A=n1,C=n2) (A=1,P=5);\n" + " device '' d2 (A=n2,C=n1) (A=3,P=2);\n" "end;\n" ); } @@ -1662,3 +1664,402 @@ TEST(34_ParallelMOS4TransistorsDifferentLength) ); } +TEST(35_SerialCapacitorsWithBulk) +{ + db::DeviceClassCapacitorWithBulk *cap = new db::DeviceClassCapacitorWithBulk (); + + db::Netlist nl; + nl.add_device_class (cap); + + db::Device *c1 = new db::Device (cap, "c1"); + c1->set_parameter_value (db::DeviceClassCapacitorWithBulk::param_id_C, 2.0); + c1->set_parameter_value (db::DeviceClassResistor::param_id_A, 5.0); + c1->set_parameter_value (db::DeviceClassResistor::param_id_P, 10.0); + db::Device *c2 = new db::Device (cap, "c2"); + c2->set_parameter_value (db::DeviceClassCapacitorWithBulk::param_id_C, 3.0); + c2->set_parameter_value (db::DeviceClassResistor::param_id_A, 1.0); + c2->set_parameter_value (db::DeviceClassResistor::param_id_P, 2.0); + + db::Circuit *circuit = new db::Circuit (); + nl.add_circuit (circuit); + + db::Pin pin_a = circuit->add_pin ("A"); + db::Pin pin_b = circuit->add_pin ("B"); + db::Pin pin_bulk = circuit->add_pin ("BULK"); + + circuit->add_device (c1); + circuit->add_device (c2); + + db::Net *nb = new db::Net ("nb"); + circuit->add_net (nb); + circuit->connect_pin (pin_bulk.id (), nb); + c1->connect_terminal (db::DeviceClassCapacitorWithBulk::terminal_id_W, nb); + + db::Net *n1 = new db::Net ("n1"); + circuit->add_net (n1); + circuit->connect_pin (pin_a.id (), n1); + c1->connect_terminal (db::DeviceClassCapacitorWithBulk::terminal_id_A, n1); + + db::Net *n2 = new db::Net ("n2"); + circuit->add_net (n2); + c1->connect_terminal (db::DeviceClassCapacitorWithBulk::terminal_id_B, n2); + c2->connect_terminal (db::DeviceClassCapacitorWithBulk::terminal_id_A, n2); + c2->connect_terminal (db::DeviceClassCapacitorWithBulk::terminal_id_W, n2); + + db::Net *n3 = new db::Net ("n3"); + circuit->add_net (n3); + c2->connect_terminal (db::DeviceClassCapacitorWithBulk::terminal_id_B, n3); + circuit->connect_pin (pin_b.id (), n3); + + EXPECT_EQ (nl.to_string (), + "circuit '' (A=n1,B=n3,BULK=nb);\n" + " device '' c1 (A=n1,B=n2,W=nb) (C=2,A=5,P=10);\n" + " device '' c2 (A=n2,B=n3,W=n2) (C=3,A=1,P=2);\n" + "end;\n" + ); + + nl.combine_devices (); + + // no combination because bulk terminals are connected differently + EXPECT_EQ (nl.to_string (), + "circuit '' (A=n1,B=n3,BULK=nb);\n" + " device '' c1 (A=n1,B=n2,W=nb) (C=2,A=5,P=10);\n" + " device '' c2 (A=n2,B=n3,W=n2) (C=3,A=1,P=2);\n" + "end;\n" + ); + + c2->connect_terminal (db::DeviceClassCapacitorWithBulk::terminal_id_W, nb); + + EXPECT_EQ (nl.to_string (), + "circuit '' (A=n1,B=n3,BULK=nb);\n" + " device '' c1 (A=n1,B=n2,W=nb) (C=2,A=5,P=10);\n" + " device '' c2 (A=n2,B=n3,W=nb) (C=3,A=1,P=2);\n" + "end;\n" + ); + + nl.combine_devices (); + + EXPECT_EQ (nl.to_string (), + "circuit '' (A=n1,B=n3,BULK=nb);\n" + " device '' c1 (A=n1,B=n3,W=nb) (C=1.2,A=6,P=12);\n" + "end;\n" + ); +} + +TEST(36_ParallelCapacitorsWithBulk) +{ + db::DeviceClassCapacitorWithBulk *cap = new db::DeviceClassCapacitorWithBulk (); + + db::Netlist nl; + nl.add_device_class (cap); + + db::Device *c1 = new db::Device (cap, "c1"); + c1->set_parameter_value (db::DeviceClassCapacitorWithBulk::param_id_C, 1.0); + c1->set_parameter_value (db::DeviceClassResistor::param_id_A, 5.0); + c1->set_parameter_value (db::DeviceClassResistor::param_id_P, 10.0); + db::Device *c2 = new db::Device (cap, "c2"); + c2->set_parameter_value (db::DeviceClassCapacitorWithBulk::param_id_C, 3.0); + c2->set_parameter_value (db::DeviceClassResistor::param_id_A, 1.0); + c2->set_parameter_value (db::DeviceClassResistor::param_id_P, 2.0); + + db::Circuit *circuit = new db::Circuit (); + nl.add_circuit (circuit); + + db::Pin pin_a = circuit->add_pin ("A"); + db::Pin pin_b = circuit->add_pin ("B"); + db::Pin pin_bulk = circuit->add_pin ("BULK"); + + circuit->add_device (c1); + circuit->add_device (c2); + + db::Net *nb = new db::Net ("nb"); + circuit->add_net (nb); + circuit->connect_pin (pin_bulk.id (), nb); + c1->connect_terminal (db::DeviceClassCapacitorWithBulk::terminal_id_W, nb); + + db::Net *n1 = new db::Net ("n1"); + circuit->add_net (n1); + circuit->connect_pin (pin_a.id (), n1); + c1->connect_terminal (db::DeviceClassCapacitorWithBulk::terminal_id_A, n1); + c2->connect_terminal (db::DeviceClassCapacitorWithBulk::terminal_id_A, n1); + + db::Net *n2 = new db::Net ("n2"); + circuit->add_net (n2); + circuit->connect_pin (pin_b.id (), n2); + c1->connect_terminal (db::DeviceClassCapacitorWithBulk::terminal_id_B, n2); + c2->connect_terminal (db::DeviceClassCapacitorWithBulk::terminal_id_B, n2); + c2->connect_terminal (db::DeviceClassCapacitorWithBulk::terminal_id_W, n2); + + EXPECT_EQ (nl.to_string (), + "circuit '' (A=n1,B=n2,BULK=nb);\n" + " device '' c1 (A=n1,B=n2,W=nb) (C=1,A=5,P=10);\n" + " device '' c2 (A=n1,B=n2,W=n2) (C=3,A=1,P=2);\n" + "end;\n" + ); + + nl.combine_devices (); + + // devices are not combined as the bulk terminals are connected differently + EXPECT_EQ (nl.to_string (), + "circuit '' (A=n1,B=n2,BULK=nb);\n" + " device '' c1 (A=n1,B=n2,W=nb) (C=1,A=5,P=10);\n" + " device '' c2 (A=n1,B=n2,W=n2) (C=3,A=1,P=2);\n" + "end;\n" + ); + + c2->connect_terminal (db::DeviceClassCapacitorWithBulk::terminal_id_W, nb); + + EXPECT_EQ (nl.to_string (), + "circuit '' (A=n1,B=n2,BULK=nb);\n" + " device '' c1 (A=n1,B=n2,W=nb) (C=1,A=5,P=10);\n" + " device '' c2 (A=n1,B=n2,W=nb) (C=3,A=1,P=2);\n" + "end;\n" + ); + + nl.combine_devices (); + + EXPECT_EQ (nl.to_string (), + "circuit '' (A=n1,B=n2,BULK=nb);\n" + " device '' c1 (A=n1,B=n2,W=nb) (C=4,A=6,P=12);\n" + "end;\n" + ); +} + +TEST(37_SerialResistorsWithBulk) +{ + db::DeviceClassResistorWithBulk *cap = new db::DeviceClassResistorWithBulk (); + + db::Netlist nl; + nl.add_device_class (cap); + + db::Device *r1 = new db::Device (cap, "r1"); + r1->set_parameter_value (db::DeviceClassResistorWithBulk::param_id_R, 2.0); + r1->set_parameter_value (db::DeviceClassResistor::param_id_A, 5.0); + r1->set_parameter_value (db::DeviceClassResistor::param_id_P, 10.0); + db::Device *r2 = new db::Device (cap, "r2"); + r2->set_parameter_value (db::DeviceClassResistorWithBulk::param_id_R, 0.5); + r2->set_parameter_value (db::DeviceClassResistor::param_id_A, 1.0); + r2->set_parameter_value (db::DeviceClassResistor::param_id_P, 2.0); + + db::Circuit *circuit = new db::Circuit (); + nl.add_circuit (circuit); + + db::Pin pin_a = circuit->add_pin ("A"); + db::Pin pin_b = circuit->add_pin ("B"); + db::Pin pin_bulk = circuit->add_pin ("BULK"); + + circuit->add_device (r1); + circuit->add_device (r2); + + db::Net *nb = new db::Net ("nb"); + circuit->add_net (nb); + circuit->connect_pin (pin_bulk.id (), nb); + r1->connect_terminal (db::DeviceClassResistorWithBulk::terminal_id_W, nb); + + db::Net *n1 = new db::Net ("n1"); + circuit->add_net (n1); + circuit->connect_pin (pin_a.id (), n1); + r1->connect_terminal (db::DeviceClassResistorWithBulk::terminal_id_A, n1); + + db::Net *n2 = new db::Net ("n2"); + circuit->add_net (n2); + r1->connect_terminal (db::DeviceClassResistorWithBulk::terminal_id_B, n2); + r2->connect_terminal (db::DeviceClassResistorWithBulk::terminal_id_A, n2); + r2->connect_terminal (db::DeviceClassResistorWithBulk::terminal_id_W, n2); + + db::Net *n3 = new db::Net ("n3"); + circuit->add_net (n3); + r2->connect_terminal (db::DeviceClassResistorWithBulk::terminal_id_B, n3); + circuit->connect_pin (pin_b.id (), n3); + + EXPECT_EQ (nl.to_string (), + "circuit '' (A=n1,B=n3,BULK=nb);\n" + " device '' r1 (A=n1,B=n2,W=nb) (R=2,A=5,P=10);\n" + " device '' r2 (A=n2,B=n3,W=n2) (R=0.5,A=1,P=2);\n" + "end;\n" + ); + + nl.combine_devices (); + + // no combination because bulk terminals are connected differently + EXPECT_EQ (nl.to_string (), + "circuit '' (A=n1,B=n3,BULK=nb);\n" + " device '' r1 (A=n1,B=n2,W=nb) (R=2,A=5,P=10);\n" + " device '' r2 (A=n2,B=n3,W=n2) (R=0.5,A=1,P=2);\n" + "end;\n" + ); + + r2->connect_terminal (db::DeviceClassResistorWithBulk::terminal_id_W, nb); + + EXPECT_EQ (nl.to_string (), + "circuit '' (A=n1,B=n3,BULK=nb);\n" + " device '' r1 (A=n1,B=n2,W=nb) (R=2,A=5,P=10);\n" + " device '' r2 (A=n2,B=n3,W=nb) (R=0.5,A=1,P=2);\n" + "end;\n" + ); + + nl.combine_devices (); + + EXPECT_EQ (nl.to_string (), + "circuit '' (A=n1,B=n3,BULK=nb);\n" + " device '' r1 (A=n1,B=n3,W=nb) (R=2.5,A=6,P=12);\n" + "end;\n" + ); +} + +TEST(38_ParallelResistorsWithBulk) +{ + db::DeviceClassResistorWithBulk *cap = new db::DeviceClassResistorWithBulk (); + + db::Netlist nl; + nl.add_device_class (cap); + + db::Device *r1 = new db::Device (cap, "r1"); + r1->set_parameter_value (db::DeviceClassResistorWithBulk::param_id_R, 2.0); + r1->set_parameter_value (db::DeviceClassResistor::param_id_A, 5.0); + r1->set_parameter_value (db::DeviceClassResistor::param_id_P, 10.0); + db::Device *r2 = new db::Device (cap, "r2"); + r2->set_parameter_value (db::DeviceClassResistorWithBulk::param_id_R, 0.5); + r2->set_parameter_value (db::DeviceClassResistor::param_id_A, 1.0); + r2->set_parameter_value (db::DeviceClassResistor::param_id_P, 2.0); + + db::Circuit *circuit = new db::Circuit (); + nl.add_circuit (circuit); + + db::Pin pin_a = circuit->add_pin ("A"); + db::Pin pin_b = circuit->add_pin ("B"); + db::Pin pin_bulk = circuit->add_pin ("BULK"); + + circuit->add_device (r1); + circuit->add_device (r2); + + db::Net *nb = new db::Net ("nb"); + circuit->add_net (nb); + circuit->connect_pin (pin_bulk.id (), nb); + r1->connect_terminal (db::DeviceClassResistorWithBulk::terminal_id_W, nb); + + db::Net *n1 = new db::Net ("n1"); + circuit->add_net (n1); + circuit->connect_pin (pin_a.id (), n1); + r1->connect_terminal (db::DeviceClassResistorWithBulk::terminal_id_A, n1); + r2->connect_terminal (db::DeviceClassResistorWithBulk::terminal_id_A, n1); + + db::Net *n2 = new db::Net ("n2"); + circuit->add_net (n2); + circuit->connect_pin (pin_b.id (), n2); + r1->connect_terminal (db::DeviceClassResistorWithBulk::terminal_id_B, n2); + r2->connect_terminal (db::DeviceClassResistorWithBulk::terminal_id_B, n2); + r2->connect_terminal (db::DeviceClassResistorWithBulk::terminal_id_W, n2); + + EXPECT_EQ (nl.to_string (), + "circuit '' (A=n1,B=n2,BULK=nb);\n" + " device '' r1 (A=n1,B=n2,W=nb) (R=2,A=5,P=10);\n" + " device '' r2 (A=n1,B=n2,W=n2) (R=0.5,A=1,P=2);\n" + "end;\n" + ); + + nl.combine_devices (); + + // devices are not combined as the bulk terminals are connected differently + EXPECT_EQ (nl.to_string (), + "circuit '' (A=n1,B=n2,BULK=nb);\n" + " device '' r1 (A=n1,B=n2,W=nb) (R=2,A=5,P=10);\n" + " device '' r2 (A=n1,B=n2,W=n2) (R=0.5,A=1,P=2);\n" + "end;\n" + ); + + r2->connect_terminal (db::DeviceClassResistorWithBulk::terminal_id_W, nb); + + EXPECT_EQ (nl.to_string (), + "circuit '' (A=n1,B=n2,BULK=nb);\n" + " device '' r1 (A=n1,B=n2,W=nb) (R=2,A=5,P=10);\n" + " device '' r2 (A=n1,B=n2,W=nb) (R=0.5,A=1,P=2);\n" + "end;\n" + ); + + nl.combine_devices (); + + EXPECT_EQ (nl.to_string (), + "circuit '' (A=n1,B=n2,BULK=nb);\n" + " device '' r1 (A=n1,B=n2,W=nb) (R=0.4,A=6,P=12);\n" + "end;\n" + ); +} + +TEST(39_ParallelBipolarTransistors) +{ + db::DeviceClassBipolarTransistor *cls = new db::DeviceClassBipolarTransistor (); + + db::Netlist nl; + nl.add_device_class (cls); + + db::Device *d1 = new db::Device (cls, "d1"); + d1->set_parameter_value (db::DeviceClassBipolarTransistor::param_id_AE, 2.0); + d1->set_parameter_value (db::DeviceClassBipolarTransistor::param_id_PE, 12.0); + db::Device *d2 = new db::Device (cls, "d2"); + d2->set_parameter_value (db::DeviceClassBipolarTransistor::param_id_AE, 3.0); + d2->set_parameter_value (db::DeviceClassBipolarTransistor::param_id_PE, 13.0); + + db::Circuit *circuit = new db::Circuit (); + nl.add_circuit (circuit); + + db::Pin pin_a = circuit->add_pin ("A"); + db::Pin pin_b = circuit->add_pin ("B"); + db::Pin pin_c = circuit->add_pin ("C"); + + circuit->add_device (d1); + circuit->add_device (d2); + + db::Net *n1 = new db::Net ("n1"); + circuit->add_net (n1); + circuit->connect_pin (pin_a.id (), n1); + d1->connect_terminal (db::DeviceClassBipolarTransistor::terminal_id_C, n1); + d2->connect_terminal (db::DeviceClassBipolarTransistor::terminal_id_C, n1); + + db::Net *n2 = new db::Net ("n2"); + circuit->add_net (n2); + circuit->connect_pin (pin_b.id (), n2); + d1->connect_terminal (db::DeviceClassBipolarTransistor::terminal_id_B, n2); + d2->connect_terminal (db::DeviceClassBipolarTransistor::terminal_id_B, n2); + d2->connect_terminal (db::DeviceClassBipolarTransistor::terminal_id_E, n2); + + db::Net *n3 = new db::Net ("n3"); + circuit->add_net (n3); + circuit->connect_pin (pin_c.id (), n3); + d1->connect_terminal (db::DeviceClassBipolarTransistor::terminal_id_E, n3); + + EXPECT_EQ (nl.to_string (), + "circuit '' (A=n1,B=n2,C=n3);\n" + " device '' d1 (C=n1,B=n2,E=n3) (AE=2,PE=12);\n" + " device '' d2 (C=n1,B=n2,E=n2) (AE=3,PE=13);\n" + "end;\n" + ); + + nl.combine_devices (); + + // no combination as emitters are connected differently + EXPECT_EQ (nl.to_string (), + "circuit '' (A=n1,B=n2,C=n3);\n" + " device '' d1 (C=n1,B=n2,E=n3) (AE=2,PE=12);\n" + " device '' d2 (C=n1,B=n2,E=n2) (AE=3,PE=13);\n" + "end;\n" + ); + + d2->connect_terminal (db::DeviceClassBipolarTransistor::terminal_id_E, n3); + + EXPECT_EQ (nl.to_string (), + "circuit '' (A=n1,B=n2,C=n3);\n" + " device '' d1 (C=n1,B=n2,E=n3) (AE=2,PE=12);\n" + " device '' d2 (C=n1,B=n2,E=n3) (AE=3,PE=13);\n" + "end;\n" + ); + + nl.combine_devices (); + + EXPECT_EQ (nl.to_string (), + "circuit '' (A=n1,B=n2,C=n3);\n" + " device '' d1 (C=n1,B=n2,E=n3) (AE=5,PE=25);\n" + "end;\n" + ); +} + diff --git a/src/laybasic/laybasic/images/icon_device_bjt_16.png b/src/laybasic/laybasic/images/icon_device_bjt_16.png new file mode 100644 index 0000000000000000000000000000000000000000..c6855dc75f7fed2a474685d28d4ed947633157da GIT binary patch literal 323 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4ylH!DNKB-T@99`VB78`!HiH2B?8H{8O?Y$&GFYEtTZYsJ5W182-D z-_P4qUgW3uN01@8hpD4O-1XwdmmA;zp4TD6@W?`}AuKUs#j7PRHyfsDDv8}t@w{~Q zYgk?2RZ)Z79<58v#}1q*y_FVdQ&MBb@02c9ioB#j- literal 0 HcmV?d00001 diff --git a/src/laybasic/laybasic/images/icon_device_bjt_24.png b/src/laybasic/laybasic/images/icon_device_bjt_24.png new file mode 100644 index 0000000000000000000000000000000000000000..b4521fb5c797ef6ce1859c7eff2ee29a95d49ad0 GIT binary patch literal 373 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjEX7WqAsj$Z!;#Vf2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4#;2r>91okwfvu2c_pVQ-f~Fcs-aid&R4&3c2Jd`UfWn9OB;4 zWw`I!r0Vy}4}`d^OYSNEowVgc8S9-ZlbAbBGs^(b7o@LTwRx69sD4B4xu5$af-CP|YWEhLxqOOUpP0$F zhj-4%WizU~7Te$c{qF>yF>}RogLeV?7yCcFZd$xz>gpr^^)G7tsJ3IA6z06*9oxbE QK;JWXy85}Sb4q9e0MJUF1ONa4 literal 0 HcmV?d00001 diff --git a/src/laybasic/laybasic/images/icon_device_bjt_32.png b/src/laybasic/laybasic/images/icon_device_bjt_32.png new file mode 100644 index 0000000000000000000000000000000000000000..c1250e00a85c83a4470e132621b738543e28514f GIT binary patch literal 485 zcmVWD z)>=x=n#P!?st@#fy{1y?;rG5Vh5#TaF6L;hheXr?a8Xr2Db)cmG{&5iod=eCiHICk z5$N~(hs+%0d49mmm$o=A+YH0-2EcZ^-L?rXg@|@VBqpML5gBN$&&%?a3XDdhS0cJ^ zG#Xp30wVHRShhsuJx$YWC4pIjgqinT1(>-g@EioeS!tXt0TCqtoCS&%5Rv03ir)St zFqus50JOT@?wX^6nmv9s9*+}SkX0Z}(@aEe!!X=&6xaapk!9KGq9CgP@ZAOxac#pU zfGCdR7iWR#bb1Y-<0!BWV6ZG`;Xj{`P|K)Zg-6WBy^Vzx_z!9qs6>U<{7`!Zynq+* b0=4r6*>G_7$nTQ#00000NkvXXu0mjfIh@F_ literal 0 HcmV?d00001 diff --git a/src/laybasic/laybasic/images/icon_device_bjt_48.png b/src/laybasic/laybasic/images/icon_device_bjt_48.png new file mode 100644 index 0000000000000000000000000000000000000000..c07b8829041d068c5297e8161ad16a3e18794275 GIT binary patch literal 689 zcmV;i0#5yjP)BdA3z?5;Qtj$IB81R((l+JqD~Nhv2{Cl+=|u88chW8tnWL7aJ$EJw)v zs#kp9-20d}vvYvM;cz${4#(An06g&m}rwEA;DaK!=fh^ zLI~DxTm$|j`JYHixdmVoKpVho>+TF7qIO-BB| zSOWm1)Q(0DAm0HU^?H48Hk%y*Sn_@UE`YbzUH$_p>RG62id>GaMynlt5C2=Q1aG7c~rjeY_+1o&5-4Mg-bj^pn-9d{Ipo1uzxQ07y! z+3cGLSpl*v+s@0?Znt}j-If_C5j~8eC^HeW0*uGw0{}k&kmq^#ZMrkyc^t=|O~u?1 zQc9`!d2!)mq?9@eg5V{`!@dqnU*&tPR_i*~f0i%|gVNfshQr}0$IlLsrs*z#UjS}2 z8jUrs|17@mujge}tJU6c{pGk=} z%Fhuq{`i~=-SfUo)o+^0aRC<1r4LXkQc6|z!N2r7-~ucf7huu20E@;2STrtx2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR47n|0Vhz-@oz-w8?&oE{u_#i7 zWDVK*k&#I#Blrm0=6e#C+G_5e*;jc+=Y#zDJP}vLM;7@nWqNH5?{CW-E{QY#tli)~`(ti|=2LG?d;ijT&&yrDFeN+_innc?8LW6j?0_B5 z;cD^6{|&TfRI(2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4XUo2kQK{Lb*?T~<5(FU z%=w-2Oj`3P&w;I5ziCbrblBsbCiXi2*bL{jUyU1HZkzKf_aOi5C#jKs&K&#<_mY0j z)iOFJBX}{EBa!jJyqW8hW~MZ5EnBuVj?p5_%XdcQyh*{Gr{!A((w#U~z5b>8bw$WQ r>xQM@?^!(Gcg=qLS9_yP^7|O4OUBHeolv+L7fAsLlSWWq0PAkC|D(VzF5M znFWJb5<w?z0%FLZgrQ%PDV`lv;1^{3%7;FK!b{yv^48y8v z{>%n?z21kE@+6Mq5)mCS^F_H_UimWv3GH_K-gVt|0I&Ic{(+gdv*_fq8UTPsqoDvC zGIJNeIWu=W&pU{sD78lB4vZtE?7FTS09cBm=*}dUl0(YP)l$lzOcOI-0Vquql2Q^d zHiG10iumWG$1n^Fj^mtZtyfd(0hrSWn0c3op0(C5p66|v&y#hmZ^#{l*L)TNY{Sqf)1;QRh95e?%w vUTd{l!&!=(Ld^Uogs5Ze`&uj(%dC6>6Crw;L|HAt00000NkvXXu0mjfk?Gd* literal 0 HcmV?d00001 diff --git a/src/laybasic/laybasic/images/icon_device_diode_48.png b/src/laybasic/laybasic/images/icon_device_diode_48.png new file mode 100644 index 0000000000000000000000000000000000000000..a1f1fc55033ee37d23d4706e138687e2c1e8d7cf GIT binary patch literal 752 zcmVB#o~JhHSLP7b|&ZZ`4Bh*oT}IB zi^iB6yP0pTO|7+QJ2kWwU<(IDeT5Ai1LcwL1|G=rZs(xBsT|Ey>HMA#}mzU?p$H$Ml^l8TV>Qt-M z4OJ}wBO^0_4-?5%vBfS`w;+unVFe|IF1K_3eYDa zk6q~gc9dx2s~D?lPph8R+6mw;a9}THs`{($ee1v$x^Qp~1L$tPX-?J(`FuXC)oR~c z9dC>|EFzD9%kB6!vu_W_mXW*NN+$@z!4;^amh>PDUi)otn08zPI{@|b{ ikH_Qjcsw3Yi~Im9p1jSxmEgw!0000 + inkscape:window-maximized="0" + inkscape:snap-global="true" + inkscape:snap-others="false"> + + icon_device_bjt_48.png + + + + + + + + + + + + + + + icon_device_bjt_32.png + icon_device_bjt_24.png + icon_device_bjt_16.png + + + + + + + + + + + + + + + + + + + icon_device_diode_48.png + + + + + + + + + icon_device_diode_32.png + icon_device_diode_24.png + icon_device_diode_16.png + + + + + + + + + + + diff --git a/src/laybasic/laybasic/layNetlistBrowserModel.cc b/src/laybasic/laybasic/layNetlistBrowserModel.cc index b9e1e2639..acf94560f 100644 --- a/src/laybasic/laybasic/layNetlistBrowserModel.cc +++ b/src/laybasic/laybasic/layNetlistBrowserModel.cc @@ -1510,17 +1510,33 @@ static QIcon icon_for_pin () static QIcon icon_for_device (const db::DeviceClass *dc) { QIcon icon; - // TODO: diode, inductor, generic device ... + // TODO: inductor, generic device ... if (dynamic_cast (dc)) { icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_res_48.png"))); icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_res_32.png"))); icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_res_24.png"))); icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_res_16.png"))); + } else if (dynamic_cast (dc)) { + // fake ... + icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_res_48.png"))); + icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_res_32.png"))); + icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_res_24.png"))); + icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_res_16.png"))); } else if (dynamic_cast (dc)) { icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_cap_48.png"))); icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_cap_32.png"))); icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_cap_24.png"))); icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_cap_16.png"))); + } else if (dynamic_cast (dc)) { + icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_diode_48.png"))); + icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_diode_32.png"))); + icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_diode_24.png"))); + icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_diode_16.png"))); + } else if (dynamic_cast (dc)) { + icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_bjt_48.png"))); + icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_bjt_32.png"))); + icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_bjt_24.png"))); + icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_bjt_16.png"))); } else { icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_mos_48.png"))); icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_mos_32.png"))); diff --git a/src/laybasic/laybasic/laybasicResources.qrc b/src/laybasic/laybasic/laybasicResources.qrc index 39169648c..a5ff51cce 100644 --- a/src/laybasic/laybasic/laybasicResources.qrc +++ b/src/laybasic/laybasic/laybasicResources.qrc @@ -36,5 +36,13 @@ images/icon_conn_light_24.png images/icon_conn_light_32.png images/icon_conn_light_48.png + images/icon_device_diode_16.png + images/icon_device_diode_24.png + images/icon_device_diode_32.png + images/icon_device_diode_48.png + images/icon_device_bjt_48.png + images/icon_device_bjt_32.png + images/icon_device_bjt_24.png + images/icon_device_bjt_16.png