diff --git a/src/db/db/dbDeviceClass.cc b/src/db/db/dbDeviceClass.cc index c51933143..4c27c7409 100644 --- a/src/db/db/dbDeviceClass.cc +++ b/src/db/db/dbDeviceClass.cc @@ -120,11 +120,6 @@ public: virtual bool less (const db::Device &a, const db::Device &b) const; - virtual DeviceParameterCompareDelegate *clone () const - { - return new PrimaryDeviceParametersAreEqual (*this); - } - private: double m_relative; }; @@ -159,13 +154,13 @@ bool PrimaryDeviceParametersAreEqual::less (const db::Device &a, const db::Devic // DeviceClass class implementation DeviceClass::DeviceClass () - : m_strict (false), mp_netlist (0) + : m_strict (false), mp_netlist (0), m_supports_parallel_combination (false), m_supports_serial_combination (false) { // .. nothing yet .. } DeviceClass::DeviceClass (const DeviceClass &other) - : gsi::ObjectBase (other), tl::Object (other), tl::UniqueId (other), m_strict (false), mp_netlist (0) + : gsi::ObjectBase (other), tl::Object (other), tl::UniqueId (other), m_strict (false), mp_netlist (0), m_supports_parallel_combination (false), m_supports_serial_combination (false) { operator= (other); } @@ -173,12 +168,18 @@ DeviceClass::DeviceClass (const DeviceClass &other) DeviceClass &DeviceClass::operator= (const DeviceClass &other) { if (this != &other) { + m_terminal_definitions = other.m_terminal_definitions; m_parameter_definitions = other.m_parameter_definitions; m_name = other.m_name; m_description = other.m_description; m_strict = other.m_strict; mp_pc_delegate.reset (const_cast (other.mp_pc_delegate.get ())); + mp_device_combiner.reset (const_cast (other.mp_device_combiner.get ())); + m_supports_serial_combination = other.m_supports_serial_combination; + m_supports_parallel_combination = other.m_supports_parallel_combination; + m_equivalent_terminal_ids = other.m_equivalent_terminal_ids; + } return *this; } diff --git a/src/db/db/dbDeviceClass.h b/src/db/db/dbDeviceClass.h index 01e8dc06e..a6306cdf8 100644 --- a/src/db/db/dbDeviceClass.h +++ b/src/db/db/dbDeviceClass.h @@ -295,7 +295,6 @@ public: DeviceParameterCompareDelegate () { } virtual ~DeviceParameterCompareDelegate () { } - virtual DeviceParameterCompareDelegate *clone () const = 0; virtual bool less (const db::Device &a, const db::Device &b) const = 0; }; @@ -315,11 +314,6 @@ public: virtual bool less (const db::Device &a, const db::Device &b) const; - virtual DeviceParameterCompareDelegate *clone () const - { - return new EqualDeviceParameters (*this); - } - EqualDeviceParameters &operator+= (const EqualDeviceParameters &other); EqualDeviceParameters operator+ (const EqualDeviceParameters &other) const @@ -344,15 +338,35 @@ public: virtual bool less (const db::Device &a, const db::Device &b) const; - virtual DeviceParameterCompareDelegate *clone () const - { - return new AllDeviceParametersAreEqual (*this); - } - private: double m_relative; }; +/** + * @brief A device combiner + * + * The device combiner is a delegate that combines devices + */ +class DB_PUBLIC DeviceCombiner + : public gsi::ObjectBase, public tl::Object +{ +public: + DeviceCombiner () { } + virtual ~DeviceCombiner () { } + + /** + * @brief Combines two devices + * + * This method shall test, whether the two devices can be combined. Both devices + * are guaranteed to share the same device class. + * If they cannot be combined, this method shall do nothing and return false. + * If they can be combined, this method shall reconnect the nets of the first + * device and entirely disconnect the nets of the second device. + * The second device will be deleted afterwards. + */ + virtual bool combine_devices (db::Device *a, db::Device *b) const = 0; +}; + /** * @brief A device class * @@ -553,25 +567,57 @@ public: * device and entirely disconnect the nets of the second device. * The second device will be deleted afterwards. */ - virtual bool combine_devices (db::Device * /*a*/, db::Device * /*b*/) const + bool combine_devices (db::Device *a, db::Device *b) const { - return false; + return mp_device_combiner.get () ? mp_device_combiner->combine_devices (a, b) : false; } /** * @brief Returns true if the device class supports device combination in parallel mode */ - virtual bool supports_parallel_combination () const + bool supports_parallel_combination () const { - return false; + return m_supports_parallel_combination; } /** * @brief Returns true if the device class supports device combination in serial mode */ - virtual bool supports_serial_combination () const + bool supports_serial_combination () const { - return false; + return m_supports_serial_combination; + } + + /** + * @brief Sets a value indicating that the class supports device combination in parallel mode + */ + void set_supports_parallel_combination (bool f) + { + m_supports_parallel_combination = f; + } + + /** + * @brief Sets a value indicating that the class supports device combination in serial mode + */ + void set_supports_serial_combination (bool f) + { + m_supports_serial_combination = f; + } + + /** + * @brief Marks two terminals as equivalent (swappable) + */ + void equivalent_terminal_id (size_t tid, size_t equiv_tid) + { + m_equivalent_terminal_ids.insert (std::make_pair (tid, equiv_tid)); + } + + /** + * @brief Clears all equivalent terminal ids + */ + void clear_equivalent_terminal_ids () + { + m_equivalent_terminal_ids.clear (); } /** @@ -580,9 +626,14 @@ public: * This method returns a "normalized" terminal ID. For example, for MOS * transistors where S and D can be exchanged, D will be mapped to S. */ - virtual size_t normalize_terminal_id (size_t tid) const + size_t normalize_terminal_id (size_t tid) const { - return tid; + std::map::const_iterator ntid = m_equivalent_terminal_ids.find (tid); + if (ntid != m_equivalent_terminal_ids.end ()) { + return ntid->second; + } else { + return tid; + } } /** @@ -643,6 +694,35 @@ public: return mp_pc_delegate.get (); } + /** + * @brief Registers a device combiner + * + * The device class takes ownership of the combiner. + */ + void set_device_combiner (db::DeviceCombiner *combiner) + { + if (combiner) { + combiner->keep (); // assume transfer of ownership for scripts + } + mp_device_combiner.reset (combiner); + } + + /** + * @brief Gets the device combiner or null if no such delegate is registered + */ + const db::DeviceCombiner *device_combiner () const + { + return mp_device_combiner.get (); + } + + /** + * @brief Gets the device combiner or null if no such delegate is registered (non-const version) + */ + db::DeviceCombiner *device_combiner () + { + return mp_device_combiner.get (); + } + /** * @brief Generate memory statistics */ @@ -667,6 +747,10 @@ private: bool m_strict; db::Netlist *mp_netlist; tl::shared_ptr mp_pc_delegate; + tl::shared_ptr mp_device_combiner; + bool m_supports_parallel_combination; + bool m_supports_serial_combination; + std::map m_equivalent_terminal_ids; void set_netlist (db::Netlist *nl) { diff --git a/src/db/db/dbNetlistDeviceClasses.cc b/src/db/db/dbNetlistDeviceClasses.cc index ad1fae98f..c9936e0e8 100644 --- a/src/db/db/dbNetlistDeviceClasses.cc +++ b/src/db/db/dbNetlistDeviceClasses.cc @@ -43,58 +43,424 @@ static tl::RegisteredClass dct_bjt4 (new db::device // ------------------------------------------------------------------------------------ // DeviceClassTwoTerminalDevice implementation -bool DeviceClassTwoTerminalDevice::combine_devices (Device *a, Device *b) const +namespace { - db::Net *na1 = a->net_for_terminal (0); - db::Net *na2 = a->net_for_terminal (1); - db::Net *nb1 = b->net_for_terminal (0); - db::Net *nb2 = b->net_for_terminal (1); - if ((na1 == nb1 && na2 == nb2) || (na1 == nb2 && na2 == nb1)) { +class TwoTerminalDeviceCombiner + : public db::DeviceCombiner +{ +public: + bool combine_devices(db::Device *a, db::Device *b) const + { + db::Net *na1 = a->net_for_terminal (0); + db::Net *na2 = a->net_for_terminal (1); + db::Net *nb1 = b->net_for_terminal (0); + db::Net *nb2 = b->net_for_terminal (1); - parallel (a, b); + if ((na1 == nb1 && na2 == nb2) || (na1 == nb2 && na2 == nb1)) { + parallel (a, b); + + if (na1 == nb1 && na2 == nb2) { + a->join_terminals (0, b, 0); + a->join_terminals (1, b, 1); + } else { + a->join_terminals (0, b, 1); + a->join_terminals (1, b, 0); + } + + return true; + + } else if ((na2 == nb1 || na2 == nb2) && na2->is_internal ()) { + + // serial a(B) to b(A or B) + serial (a, b); + + if (na2 == nb1) { + a->reroute_terminal (1, b, 0, 1); + } else { + a->reroute_terminal (1, b, 1, 0); + } + + return true; + + } else if ((na1 == nb1 || na1 == nb2) && na1->is_internal ()) { + + // serial a(A) to b(A or B) + serial (a, b); + + if (na1 == nb1) { + a->reroute_terminal (0, b, 0, 1); + } else { + a->reroute_terminal (0, b, 1, 0); + } + + return true; + + } else { + return false; + } + } + + virtual void parallel (Device *a, Device *b) const = 0; + virtual void serial (Device *a, Device *b) const = 0; +}; + +class ResistorDeviceCombiner + : public TwoTerminalDeviceCombiner +{ +public: + void parallel (Device *a, Device *b) const + { + double va = a->parameter_value (0); + double vb = b->parameter_value (0); + a->set_parameter_value (0, va + vb < 1e-10 ? 0.0 : va * vb / (va + vb)); + + // parallel width is sum of both, length is the one that gives the same value of resistance + // R = 1/(1/R1 + 1/R2) + // R = L/(W1+W2) + // R1 = L1/W1 + // R2 = L2/W2 + // -> L = (L1*L2*(W1+W2))/(L2*W1+L1*W2)) + double l1 = a->parameter_value (1); + double w1 = a->parameter_value (2); + double l2 = b->parameter_value (1); + double w2 = b->parameter_value (2); + double dnom = (l2 * w1 + l1 * w2); + if (fabs (dnom) > 1e-15) { + a->set_parameter_value (1, (l1 * l2 * (w1 + w2)) / dnom); + } + a->set_parameter_value (2, w1 + w2); + + // TODO: does this implementation make sense? (area) + double aa = a->parameter_value (3); + double ab = b->parameter_value (3); + a->set_parameter_value (3, aa + ab); + + // TODO: does this implementation make sense? (perimeter) + double pa = a->parameter_value (4); + double pb = b->parameter_value (4); + a->set_parameter_value (4, pa + pb); + } + + void serial (Device *a, Device *b) const + { + double va = a->parameter_value (0); + double vb = b->parameter_value (0); + a->set_parameter_value (0, va + vb); + + // parallel length is sum of both, width is the one that gives the same value of resistance + // assuming same sheet rho + // R = R1+R2 + // R = (L1+L2)/W + // R1 = L1/W1 + // R2 = L2/W2 + // -> W = ((L1+L2)*W1*W2)/(W1*L2+W2*L1) + double l1 = a->parameter_value (1); + double w1 = a->parameter_value (2); + double l2 = b->parameter_value (1); + double w2 = b->parameter_value (2); + a->set_parameter_value (1, l1 + l2); + double dnom = (l2 * w1 + l1 * w2); + if (fabs (dnom) > 1e-15) { + a->set_parameter_value (2, (w1 * w2 * (l1 + l2)) / dnom); + } + + double aa = a->parameter_value (3); + double ab = b->parameter_value (3); + a->set_parameter_value (3, aa + ab); + + double pa = a->parameter_value (4); + double pb = b->parameter_value (4); + a->set_parameter_value (4, pa + pb); + } +}; + +class ResistorWithBulkDeviceCombiner + : public ResistorDeviceCombiner +{ +public: + bool combine_devices (Device *a, Device *b) const + { + db::Net *nab = a->net_for_terminal (2); + db::Net *nbb = b->net_for_terminal (2); + + if (nab == nbb && ResistorDeviceCombiner::combine_devices (a, b)) { + a->join_terminals (2, b, 2); + return true; + } else { + return false; + } + } +}; + +class CapacitorDeviceCombiner + : public TwoTerminalDeviceCombiner +{ +public: + void serial (Device *a, Device *b) const + { + double va = a->parameter_value (0); + double vb = b->parameter_value (0); + a->set_parameter_value (0, va + vb < 1e-10 ? 0.0 : va * vb / (va + vb)); + + // TODO: does this implementation make sense? + double aa = a->parameter_value (1); + double ab = b->parameter_value (1); + a->set_parameter_value (1, aa + ab); + + // TODO: does this implementation make sense? + double pa = a->parameter_value (2); + double pb = b->parameter_value (2); + a->set_parameter_value (2, pa + pb); + } + + void parallel (Device *a, Device *b) const + { + double va = a->parameter_value (0); + double vb = b->parameter_value (0); + a->set_parameter_value (0, va + vb); + + double aa = a->parameter_value (1); + double ab = b->parameter_value (1); + a->set_parameter_value (1, aa + ab); + + double pa = a->parameter_value (2); + double pb = b->parameter_value (2); + a->set_parameter_value (2, pa + pb); + } +}; + +class CapacitorWithBulkDeviceCombiner + : public CapacitorDeviceCombiner +{ +public: + bool combine_devices (Device *a, Device *b) const + { + db::Net *nab = a->net_for_terminal (2); + db::Net *nbb = b->net_for_terminal (2); + + if (nab == nbb && CapacitorDeviceCombiner::combine_devices (a, b)) { + a->join_terminals (2, b, 2); + return true; + } else { + return false; + } + } +}; + +class InductorDeviceCombiner + : public TwoTerminalDeviceCombiner +{ +public: + void parallel (Device *a, Device *b) const + { + double va = a->parameter_value (0); + double vb = b->parameter_value (0); + a->set_parameter_value (0, va + vb < 1e-10 ? 0.0 : va * vb / (va + vb)); + } + + void serial (Device *a, Device *b) const + { + double va = a->parameter_value (0); + double vb = b->parameter_value (0); + a->set_parameter_value (0, va + vb); + } +}; + +class DiodeDeviceCombiner + : public db::DeviceCombiner +{ +public: + bool combine_devices (Device *a, Device *b) const + { + const db::Net *na1 = a->net_for_terminal (0); + const db::Net *na2 = a->net_for_terminal (1); + const db::Net *nb1 = b->net_for_terminal (0); + const db::Net *nb2 = b->net_for_terminal (1); + + // only parallel diodes can be combined and their areas will add 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); + + return true; + } else { - a->join_terminals (0, b, 1); - a->join_terminals (1, b, 0); + return false; + } + } +}; + +class MOS3DeviceCombiner + : public db::DeviceCombiner +{ +public: + bool combine_devices (Device *a, Device *b) const + { + const db::Net *nas = a->net_for_terminal (0); + const db::Net *nag = a->net_for_terminal (1); + const db::Net *nad = a->net_for_terminal (2); + const db::Net *nbs = b->net_for_terminal (0); + const db::Net *nbg = b->net_for_terminal (1); + const db::Net *nbd = b->net_for_terminal (2); + + // parallel transistors can be combined into one + if (((nas == nbs && nad == nbd) || (nas == nbd && nad == nbs)) && nag == nbg) { + + // for combination the gate length must be identical + if (fabs (a->parameter_value (0) - b->parameter_value (0)) < 1e-6) { + + combine_parameters (a, b); + + if (nas == nbs && nad == nbd) { + a->join_terminals (0, b, 0); + a->join_terminals (2, b, 2); + } else { + a->join_terminals (0, b, 2); + a->join_terminals (2, b, 0); + } + + a->join_terminals (1, b, 1); + + return true; + + } + } - return true; - - } else if ((na2 == nb1 || na2 == nb2) && na2->is_internal ()) { - - // serial a(B) to b(A or B) - serial (a, b); - - if (na2 == nb1) { - a->reroute_terminal (1, b, 0, 1); - } else { - a->reroute_terminal (1, b, 1, 0); - } - - return true; - - } else if ((na1 == nb1 || na1 == nb2) && na1->is_internal ()) { - - // serial a(A) to b(A or B) - serial (a, b); - - if (na1 == nb1) { - a->reroute_terminal (0, b, 0, 1); - } else { - a->reroute_terminal (0, b, 1, 0); - } - - return true; - - } else { return false; } -} + void combine_parameters (Device *a, Device *b) const + { + a->set_parameter_value (1, a->parameter_value (1) + b->parameter_value (1)); + a->set_parameter_value (2, a->parameter_value (2) + b->parameter_value (2)); + a->set_parameter_value (3, a->parameter_value (3) + b->parameter_value (3)); + a->set_parameter_value (4, a->parameter_value (4) + b->parameter_value (4)); + a->set_parameter_value (5, a->parameter_value (5) + b->parameter_value (5)); + } +}; + +class MOS4DeviceCombiner + : public MOS3DeviceCombiner +{ +public: + bool combine_devices (Device *a, Device *b) const + { + const db::Net *nas = a->net_for_terminal (0); + const db::Net *nag = a->net_for_terminal (1); + const db::Net *nad = a->net_for_terminal (2); + const db::Net *nab = a->net_for_terminal (3); + const db::Net *nbs = b->net_for_terminal (0); + const db::Net *nbg = b->net_for_terminal (1); + const db::Net *nbd = b->net_for_terminal (2); + const db::Net *nbb = b->net_for_terminal (3); + + // parallel transistors can be combined into one + if (((nas == nbs && nad == nbd) || (nas == nbd && nad == nbs)) && nag == nbg && nab == nbb) { + + // for combination the gate length must be identical + if (fabs (a->parameter_value (0) - b->parameter_value (0)) < 1e-6) { + + combine_parameters (a, b); + + if (nas == nbs && nad == nbd) { + a->join_terminals (0, b, 0); + a->join_terminals (2, b, 2); + } else { + a->join_terminals (0, b, 2); + a->join_terminals (2, b, 0); + } + + a->join_terminals (1, b, 1); + a->join_terminals (3, b, 3); + + return true; + + } + + } + + return false; + } +}; + +class BJT3DeviceCombiner + : public db::DeviceCombiner +{ +public: + bool combine_devices (Device *a, Device *b) const + { + const db::Net *nac = a->net_for_terminal (0); + const db::Net *nab = a->net_for_terminal (1); + const db::Net *nae = a->net_for_terminal (2); + const db::Net *nbc = b->net_for_terminal (0); + const db::Net *nbb = b->net_for_terminal (1); + const db::Net *nbe = b->net_for_terminal (2); + + // parallel transistors can be combined into one + if (nac == nbc && nae == nbe && nab == nbb) { + + combine_parameters (a, b); + + a->join_terminals (0, b, 0); + a->join_terminals (1, b, 1); + a->join_terminals (2, b, 2); + + return true; + + } + + return false; + } + + void combine_parameters (Device *a, Device *b) const + { + a->set_parameter_value (DeviceClassBJT3Transistor::param_id_AE, a->parameter_value (DeviceClassBJT3Transistor::param_id_AE) + b->parameter_value (DeviceClassBJT3Transistor::param_id_AE)); + a->set_parameter_value (DeviceClassBJT3Transistor::param_id_PE, a->parameter_value (DeviceClassBJT3Transistor::param_id_PE) + b->parameter_value (DeviceClassBJT3Transistor::param_id_PE)); + a->set_parameter_value (DeviceClassBJT3Transistor::param_id_NE, a->parameter_value (DeviceClassBJT3Transistor::param_id_NE) + b->parameter_value (DeviceClassBJT3Transistor::param_id_NE)); + } +}; + +class BJT4DeviceCombiner + : public BJT3DeviceCombiner +{ +public: + bool combine_devices (Device *a, Device *b) const + { + const db::Net *nac = a->net_for_terminal (0); + const db::Net *nab = a->net_for_terminal (1); + const db::Net *nae = a->net_for_terminal (2); + const db::Net *nas = a->net_for_terminal (3); + const db::Net *nbc = b->net_for_terminal (0); + const db::Net *nbb = b->net_for_terminal (1); + const db::Net *nbe = b->net_for_terminal (2); + const db::Net *nbs = b->net_for_terminal (3); + + // parallel transistors can be combined into one + if (nac == nbc && nae == nbe && nab == nbb && nas == nbs) { + + combine_parameters (a, b); + + a->join_terminals (0, b, 0); + a->join_terminals (1, b, 1); + a->join_terminals (2, b, 2); + a->join_terminals (3, b, 3); + + return true; + + } + + return false; + } +}; + +} // ------------------------------------------------------------------------------------ // DeviceClassResistor implementation @@ -110,8 +476,13 @@ DB_PUBLIC size_t DeviceClassResistor::terminal_id_B = 1; DeviceClassResistor::DeviceClassResistor () { + set_supports_serial_combination (true); + set_supports_parallel_combination (true); + set_device_combiner (new ResistorDeviceCombiner ()); + add_terminal_definition (db::DeviceTerminalDefinition ("A", "Terminal A")); add_terminal_definition (db::DeviceTerminalDefinition ("B", "Terminal B")); + equivalent_terminal_id (terminal_id_A, terminal_id_B); add_parameter_definition (db::DeviceParameterDefinition ("R", "Resistance (Ohm)", 0.0)); add_parameter_definition (db::DeviceParameterDefinition ("L", "Length (micrometer)", 0.0, false, 1e-6)); @@ -120,71 +491,6 @@ DeviceClassResistor::DeviceClassResistor () add_parameter_definition (db::DeviceParameterDefinition ("P", "Perimeter (micrometer)", 0.0, false, 1e-6)); } -void DeviceClassResistor::parallel (Device *a, Device *b) const -{ - double va = a->parameter_value (0); - double vb = b->parameter_value (0); - a->set_parameter_value (0, va + vb < 1e-10 ? 0.0 : va * vb / (va + vb)); - - // parallel width is sum of both, length is the one that gives the same value of resistance - // R = 1/(1/R1 + 1/R2) - // R = L/(W1+W2) - // R1 = L1/W1 - // R2 = L2/W2 - // -> L = (L1*L2*(W1+W2))/(L2*W1+L1*W2)) - double l1 = a->parameter_value (1); - double w1 = a->parameter_value (2); - double l2 = b->parameter_value (1); - double w2 = b->parameter_value (2); - double dnom = (l2 * w1 + l1 * w2); - if (fabs (dnom) > 1e-15) { - a->set_parameter_value (1, (l1 * l2 * (w1 + w2)) / dnom); - } - a->set_parameter_value (2, w1 + w2); - - // TODO: does this implementation make sense? (area) - double aa = a->parameter_value (3); - double ab = b->parameter_value (3); - a->set_parameter_value (3, aa + ab); - - // TODO: does this implementation make sense? (perimeter) - double pa = a->parameter_value (4); - double pb = b->parameter_value (4); - a->set_parameter_value (4, pa + pb); -} - -void DeviceClassResistor::serial (Device *a, Device *b) const -{ - double va = a->parameter_value (0); - double vb = b->parameter_value (0); - a->set_parameter_value (0, va + vb); - - // parallel length is sum of both, width is the one that gives the same value of resistance - // assuming same sheet rho - // R = R1+R2 - // R = (L1+L2)/W - // R1 = L1/W1 - // R2 = L2/W2 - // -> W = ((L1+L2)*W1*W2)/(W1*L2+W2*L1) - double l1 = a->parameter_value (1); - double w1 = a->parameter_value (2); - double l2 = b->parameter_value (1); - double w2 = b->parameter_value (2); - a->set_parameter_value (1, l1 + l2); - double dnom = (l2 * w1 + l1 * w2); - if (fabs (dnom) > 1e-15) { - a->set_parameter_value (2, (w1 * w2 * (l1 + l2)) / dnom); - } - - double aa = a->parameter_value (3); - double ab = b->parameter_value (3); - a->set_parameter_value (3, aa + ab); - - double pa = a->parameter_value (4); - double pb = b->parameter_value (4); - a->set_parameter_value (4, pa + pb); -} - // ------------------------------------------------------------------------------------ // DeviceClassResistorWithBulk implementation @@ -193,22 +499,10 @@ DB_PUBLIC size_t DeviceClassResistorWithBulk::terminal_id_W = 2; DeviceClassResistorWithBulk::DeviceClassResistorWithBulk () : DeviceClassResistor () { + set_device_combiner (new ResistorWithBulkDeviceCombiner ()); add_terminal_definition (db::DeviceTerminalDefinition ("W", "Terminal W (well, bulk)")); } -bool DeviceClassResistorWithBulk::combine_devices (Device *a, Device *b) const -{ - db::Net *nab = a->net_for_terminal (2); - db::Net *nbb = b->net_for_terminal (2); - - if (nab == nbb && DeviceClassResistor::combine_devices (a, b)) { - a->join_terminals (2, b, 2); - return true; - } else { - return false; - } -} - // ------------------------------------------------------------------------------------ // DeviceClassCapacitor implementation @@ -221,46 +515,19 @@ DB_PUBLIC size_t DeviceClassCapacitor::terminal_id_B = 1; DeviceClassCapacitor::DeviceClassCapacitor () { + set_supports_serial_combination (true); + set_supports_parallel_combination (true); + set_device_combiner (new CapacitorDeviceCombiner ()); + add_terminal_definition (db::DeviceTerminalDefinition ("A", "Terminal A")); add_terminal_definition (db::DeviceTerminalDefinition ("B", "Terminal B")); + equivalent_terminal_id (terminal_id_A, terminal_id_B); add_parameter_definition (db::DeviceParameterDefinition ("C", "Capacitance (Farad)", 0.0)); add_parameter_definition (db::DeviceParameterDefinition ("A", "Area (square micrometer)", 0.0, false, 1e-12)); add_parameter_definition (db::DeviceParameterDefinition ("P", "Perimeter (micrometer)", 0.0, false, 1e-6)); } -void DeviceClassCapacitor::serial (Device *a, Device *b) const -{ - double va = a->parameter_value (0); - double vb = b->parameter_value (0); - a->set_parameter_value (0, va + vb < 1e-10 ? 0.0 : va * vb / (va + vb)); - - // TODO: does this implementation make sense? - double aa = a->parameter_value (1); - double ab = b->parameter_value (1); - a->set_parameter_value (1, aa + ab); - - // TODO: does this implementation make sense? - double pa = a->parameter_value (2); - double pb = b->parameter_value (2); - a->set_parameter_value (2, pa + pb); -} - -void DeviceClassCapacitor::parallel (Device *a, Device *b) const -{ - double va = a->parameter_value (0); - double vb = b->parameter_value (0); - a->set_parameter_value (0, va + vb); - - double aa = a->parameter_value (1); - double ab = b->parameter_value (1); - a->set_parameter_value (1, aa + ab); - - double pa = a->parameter_value (2); - double pb = b->parameter_value (2); - a->set_parameter_value (2, pa + pb); -} - // ------------------------------------------------------------------------------------ // DeviceClassCapacitorWithBulk implementation @@ -269,22 +536,10 @@ DB_PUBLIC size_t DeviceClassCapacitorWithBulk::terminal_id_W = 2; DeviceClassCapacitorWithBulk::DeviceClassCapacitorWithBulk () : DeviceClassCapacitor () { + set_device_combiner (new CapacitorWithBulkDeviceCombiner ()); add_terminal_definition (db::DeviceTerminalDefinition ("W", "Terminal W (well, bulk)")); } -bool DeviceClassCapacitorWithBulk::combine_devices (Device *a, Device *b) const -{ - db::Net *nab = a->net_for_terminal (2); - db::Net *nbb = b->net_for_terminal (2); - - if (nab == nbb && DeviceClassCapacitor::combine_devices (a, b)) { - a->join_terminals (2, b, 2); - return true; - } else { - return false; - } -} - // ------------------------------------------------------------------------------------ // DeviceClassInductor implementation @@ -295,28 +550,19 @@ DB_PUBLIC size_t DeviceClassInductor::terminal_id_B = 1; DeviceClassInductor::DeviceClassInductor () { + set_supports_serial_combination (true); + set_supports_parallel_combination (true); + set_device_combiner (new InductorDeviceCombiner ()); + add_terminal_definition (db::DeviceTerminalDefinition ("A", "Terminal A")); add_terminal_definition (db::DeviceTerminalDefinition ("B", "Terminal B")); + equivalent_terminal_id (terminal_id_A, terminal_id_B); add_parameter_definition (db::DeviceParameterDefinition ("L", "Inductance (Henry)", 0.0)); } -void DeviceClassInductor::parallel (Device *a, Device *b) const -{ - double va = a->parameter_value (0); - double vb = b->parameter_value (0); - a->set_parameter_value (0, va + vb < 1e-10 ? 0.0 : va * vb / (va + vb)); -} - -void DeviceClassInductor::serial (Device *a, Device *b) const -{ - double va = a->parameter_value (0); - double vb = b->parameter_value (0); - a->set_parameter_value (0, va + vb); -} - // ------------------------------------------------------------------------------------ -// DeviceClassInductor implementation +// DeviceClassDiode implementation DB_PUBLIC size_t DeviceClassDiode::param_id_A = 0; DB_PUBLIC size_t DeviceClassDiode::param_id_P = 1; @@ -326,6 +572,9 @@ DB_PUBLIC size_t DeviceClassDiode::terminal_id_C = 1; DeviceClassDiode::DeviceClassDiode () { + set_supports_parallel_combination (true); + set_device_combiner (new DiodeDeviceCombiner ()); + add_terminal_definition (db::DeviceTerminalDefinition ("A", "Anode")); add_terminal_definition (db::DeviceTerminalDefinition ("C", "Cathode")); @@ -333,29 +582,6 @@ DeviceClassDiode::DeviceClassDiode () add_parameter_definition (db::DeviceParameterDefinition ("P", "Perimeter (micrometer)", 0.0, false, 1e-6)); } -bool DeviceClassDiode::combine_devices (Device *a, Device *b) const -{ - const db::Net *na1 = a->net_for_terminal (0); - const db::Net *na2 = a->net_for_terminal (1); - const db::Net *nb1 = b->net_for_terminal (0); - const db::Net *nb2 = b->net_for_terminal (1); - - // only parallel diodes can be combined and their areas will add - 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); - - return true; - - } else { - return false; - } -} - // ------------------------------------------------------------------------------------ // DeviceClassMOS3Transistor implementation @@ -372,9 +598,13 @@ DB_PUBLIC size_t DeviceClassMOS3Transistor::terminal_id_D = 2; DeviceClassMOS3Transistor::DeviceClassMOS3Transistor () { + set_supports_parallel_combination (true); + set_device_combiner (new MOS3DeviceCombiner ()); + add_terminal_definition (db::DeviceTerminalDefinition ("S", "Source")); add_terminal_definition (db::DeviceTerminalDefinition ("G", "Gate")); add_terminal_definition (db::DeviceTerminalDefinition ("D", "Drain")); + equivalent_terminal_id (terminal_id_D, terminal_id_S); add_parameter_definition (db::DeviceParameterDefinition ("L", "Gate length (micrometer)", 0.0, true, 1e-6)); add_parameter_definition (db::DeviceParameterDefinition ("W", "Gate width (micrometer)", 0.0, true, 1e-6)); @@ -384,51 +614,6 @@ DeviceClassMOS3Transistor::DeviceClassMOS3Transistor () add_parameter_definition (db::DeviceParameterDefinition ("PD", "Drain perimeter (micrometer)", 0.0, false, 1e-6)); } -bool DeviceClassMOS3Transistor::combine_devices (Device *a, Device *b) const -{ - const db::Net *nas = a->net_for_terminal (0); - const db::Net *nag = a->net_for_terminal (1); - const db::Net *nad = a->net_for_terminal (2); - const db::Net *nbs = b->net_for_terminal (0); - const db::Net *nbg = b->net_for_terminal (1); - const db::Net *nbd = b->net_for_terminal (2); - - // parallel transistors can be combined into one - if (((nas == nbs && nad == nbd) || (nas == nbd && nad == nbs)) && nag == nbg) { - - // for combination the gate length must be identical - if (fabs (a->parameter_value (0) - b->parameter_value (0)) < 1e-6) { - - combine_parameters (a, b); - - if (nas == nbs && nad == nbd) { - a->join_terminals (0, b, 0); - a->join_terminals (2, b, 2); - } else { - a->join_terminals (0, b, 2); - a->join_terminals (2, b, 0); - } - - a->join_terminals (1, b, 1); - - return true; - - } - - } - - return false; -} - -void DeviceClassMOS3Transistor::combine_parameters (Device *a, Device *b) const -{ - a->set_parameter_value (1, a->parameter_value (1) + b->parameter_value (1)); - a->set_parameter_value (2, a->parameter_value (2) + b->parameter_value (2)); - a->set_parameter_value (3, a->parameter_value (3) + b->parameter_value (3)); - a->set_parameter_value (4, a->parameter_value (4) + b->parameter_value (4)); - a->set_parameter_value (5, a->parameter_value (5) + b->parameter_value (5)); -} - // ------------------------------------------------------------------------------------ // DeviceClassMOS4Transistor implementation @@ -436,48 +621,10 @@ DB_PUBLIC size_t DeviceClassMOS4Transistor::terminal_id_B = 3; DeviceClassMOS4Transistor::DeviceClassMOS4Transistor () { + set_device_combiner (new MOS4DeviceCombiner ()); add_terminal_definition (db::DeviceTerminalDefinition ("B", "Bulk")); } -bool DeviceClassMOS4Transistor::combine_devices (Device *a, Device *b) const -{ - const db::Net *nas = a->net_for_terminal (0); - const db::Net *nag = a->net_for_terminal (1); - const db::Net *nad = a->net_for_terminal (2); - const db::Net *nab = a->net_for_terminal (3); - const db::Net *nbs = b->net_for_terminal (0); - const db::Net *nbg = b->net_for_terminal (1); - const db::Net *nbd = b->net_for_terminal (2); - const db::Net *nbb = b->net_for_terminal (3); - - // parallel transistors can be combined into one - if (((nas == nbs && nad == nbd) || (nas == nbd && nad == nbs)) && nag == nbg && nab == nbb) { - - // for combination the gate length must be identical - if (fabs (a->parameter_value (0) - b->parameter_value (0)) < 1e-6) { - - combine_parameters (a, b); - - if (nas == nbs && nad == nbd) { - a->join_terminals (0, b, 0); - a->join_terminals (2, b, 2); - } else { - a->join_terminals (0, b, 2); - a->join_terminals (2, b, 0); - } - - a->join_terminals (1, b, 1); - a->join_terminals (3, b, 3); - - return true; - - } - - } - - return false; -} - // ------------------------------------------------------------------------------------ // DeviceClassBJT3Transistor implementation @@ -495,6 +642,9 @@ DB_PUBLIC size_t DeviceClassBJT3Transistor::terminal_id_E = 2; DeviceClassBJT3Transistor::DeviceClassBJT3Transistor () { + set_supports_parallel_combination (true); + set_device_combiner (new BJT3DeviceCombiner ()); + add_terminal_definition (db::DeviceTerminalDefinition ("C", "Collector")); add_terminal_definition (db::DeviceTerminalDefinition ("B", "Base")); add_terminal_definition (db::DeviceTerminalDefinition ("E", "Emitter")); @@ -509,38 +659,6 @@ DeviceClassBJT3Transistor::DeviceClassBJT3Transistor () add_parameter_definition (db::DeviceParameterDefinition ("NE", "Emitter count", 1.0, true)); } -bool DeviceClassBJT3Transistor::combine_devices (Device *a, Device *b) const -{ - const db::Net *nac = a->net_for_terminal (0); - const db::Net *nab = a->net_for_terminal (1); - const db::Net *nae = a->net_for_terminal (2); - const db::Net *nbc = b->net_for_terminal (0); - const db::Net *nbb = b->net_for_terminal (1); - const db::Net *nbe = b->net_for_terminal (2); - - // parallel transistors can be combined into one - if (nac == nbc && nae == nbe && nab == nbb) { - - combine_parameters (a, b); - - a->join_terminals (0, b, 0); - a->join_terminals (1, b, 1); - a->join_terminals (2, b, 2); - - return true; - - } - - return false; -} - -void DeviceClassBJT3Transistor::combine_parameters (Device *a, Device *b) const -{ - a->set_parameter_value (param_id_AE, a->parameter_value (param_id_AE) + b->parameter_value (param_id_AE)); - a->set_parameter_value (param_id_PE, a->parameter_value (param_id_PE) + b->parameter_value (param_id_PE)); - a->set_parameter_value (param_id_NE, a->parameter_value (param_id_NE) + b->parameter_value (param_id_NE)); -} - // ------------------------------------------------------------------------------------ // DeviceClassBJT4Transistor implementation @@ -548,35 +666,8 @@ DB_PUBLIC size_t DeviceClassBJT4Transistor::terminal_id_S = 3; DeviceClassBJT4Transistor::DeviceClassBJT4Transistor () { + set_device_combiner (new BJT4DeviceCombiner ()); add_terminal_definition (db::DeviceTerminalDefinition ("S", "Substrate")); } -bool DeviceClassBJT4Transistor::combine_devices (Device *a, Device *b) const -{ - const db::Net *nac = a->net_for_terminal (0); - const db::Net *nab = a->net_for_terminal (1); - const db::Net *nae = a->net_for_terminal (2); - const db::Net *nas = a->net_for_terminal (3); - const db::Net *nbc = b->net_for_terminal (0); - const db::Net *nbb = b->net_for_terminal (1); - const db::Net *nbe = b->net_for_terminal (2); - const db::Net *nbs = b->net_for_terminal (3); - - // parallel transistors can be combined into one - if (nac == nbc && nae == nbe && nab == nbb && nas == nbs) { - - combine_parameters (a, b); - - a->join_terminals (0, b, 0); - a->join_terminals (1, b, 1); - a->join_terminals (2, b, 2); - a->join_terminals (3, b, 3); - - return true; - - } - - return false; -} - } diff --git a/src/db/db/dbNetlistDeviceClasses.h b/src/db/db/dbNetlistDeviceClasses.h index e54f518e5..385759f87 100644 --- a/src/db/db/dbNetlistDeviceClasses.h +++ b/src/db/db/dbNetlistDeviceClasses.h @@ -29,28 +29,13 @@ namespace db { -/** - * @brief A basic two-terminal device class - */ -class DB_PUBLIC DeviceClassTwoTerminalDevice - : public db::DeviceClass -{ -public: - virtual bool combine_devices (Device *a, Device *b) const; - - virtual void parallel (Device *a, Device *b) const = 0; - virtual void serial (Device *a, Device *b) const = 0; - virtual bool supports_parallel_combination () const { return true; } - virtual bool supports_serial_combination () const { return true; } -}; - /** * @brief A basic resistor device class * A resistor defines a single parameter, "R", which is the resistance in Ohm. * It defines two terminals, "A" and "B" for the two terminals. */ class DB_PUBLIC DeviceClassResistor - : public db::DeviceClassTwoTerminalDevice + : public db::DeviceClass { public: DeviceClassResistor (); @@ -68,14 +53,6 @@ public: static size_t terminal_id_A; static size_t terminal_id_B; - - virtual void parallel (Device *a, Device *b) const; - virtual void serial (Device *a, Device *b) const; - - virtual size_t normalize_terminal_id (size_t id) const - { - return id == terminal_id_B ? terminal_id_A : id; - } }; /** @@ -95,8 +72,6 @@ public: } static size_t terminal_id_W; - - virtual bool combine_devices (Device *a, Device *b) const; }; /** @@ -105,7 +80,7 @@ public: * It defines two terminals, "A" and "B" for the two terminals. */ class DB_PUBLIC DeviceClassCapacitor - : public db::DeviceClassTwoTerminalDevice + : public db::DeviceClass { public: DeviceClassCapacitor (); @@ -121,14 +96,6 @@ public: static size_t terminal_id_A; static size_t terminal_id_B; - - virtual void parallel (Device *a, Device *b) const; - virtual void serial (Device *a, Device *b) const; - - virtual size_t normalize_terminal_id (size_t id) const - { - return id == terminal_id_B ? terminal_id_A : id; - } }; /** @@ -148,8 +115,6 @@ public: } static size_t terminal_id_W; - - virtual bool combine_devices (Device *a, Device *b) const; }; /** @@ -158,7 +123,7 @@ public: * It defines two terminals, "A" and "B" for the two terminals. */ class DB_PUBLIC DeviceClassInductor - : public db::DeviceClassTwoTerminalDevice + : public db::DeviceClass { public: DeviceClassInductor (); @@ -172,14 +137,6 @@ public: static size_t terminal_id_A; static size_t terminal_id_B; - - virtual void parallel (Device *a, Device *b) const; - virtual void serial (Device *a, Device *b) const; - - virtual size_t normalize_terminal_id (size_t id) const - { - return id == terminal_id_B ? terminal_id_A : id; - } }; /** @@ -204,9 +161,6 @@ public: { return new DeviceClassDiode (*this); } - - virtual bool combine_devices (Device *a, Device *b) const; - virtual bool supports_parallel_combination () const { return true; } }; /** @@ -237,14 +191,6 @@ public: return new DeviceClassMOS3Transistor (*this); } - virtual bool combine_devices (Device *a, Device *b) const; - virtual bool supports_parallel_combination () const { return true; } - - virtual size_t normalize_terminal_id (size_t tid) const - { - return tid == terminal_id_D ? terminal_id_S : tid; - } - protected: void combine_parameters (Device *a, Device *b) const; }; @@ -266,13 +212,6 @@ public: { return new DeviceClassMOS4Transistor (*this); } - - virtual size_t normalize_terminal_id (size_t tid) const - { - return tid == terminal_id_D ? terminal_id_S : tid; - } - - virtual bool combine_devices (Device *a, Device *b) const; }; /** @@ -303,12 +242,6 @@ public: { return new DeviceClassBJT3Transistor (*this); } - - virtual bool combine_devices (Device *a, Device *b) const; - virtual bool supports_parallel_combination () const { return true; } - -protected: - void combine_parameters (Device *a, Device *b) const; }; /** @@ -328,8 +261,6 @@ public: { return new DeviceClassBJT4Transistor (*this); } - - virtual bool combine_devices (Device *a, Device *b) const; }; } diff --git a/src/db/db/gsiDeclDbNetlist.cc b/src/db/db/gsiDeclDbNetlist.cc index 0941d63c3..d095c936a 100644 --- a/src/db/db/gsiDeclDbNetlist.cc +++ b/src/db/db/gsiDeclDbNetlist.cc @@ -876,6 +876,31 @@ public: gsi::Callback cb_less; }; +/** + * @brief A DeviceCombiner implementation that allows reimplementation of the virtual methods + */ +class GenericDeviceCombiner + : public db::DeviceCombiner +{ +public: + GenericDeviceCombiner () + : db::DeviceCombiner () + { + // .. nothing yet .. + } + + virtual bool combine_devices (db::Device *a, db::Device *b) const + { + if (cb_combine.can_issue ()) { + return cb_combine.issue (&db::DeviceCombiner::combine_devices, a, b); + } else { + return false; + } + } + + gsi::Callback cb_combine; +}; + } db::EqualDeviceParameters *make_equal_dp (size_t param_id, double absolute, double relative) @@ -942,6 +967,29 @@ Class decl_GenericDeviceParameterCompare (decl_db "This class has been added in version 0.26. The 'equal' method has been dropped in 0.27.1 as it can be expressed as !less(a,b) && !less(b,a)." ); +Class decl_GenericDeviceCombiner ("db", "GenericDeviceCombiner", + gsi::callback ("combine_devices", &GenericDeviceCombiner::combine_devices, &GenericDeviceCombiner::cb_combine, gsi::arg ("device_a"), gsi::arg ("device_b"), + "@brief Combines two devices if possible.\n" + "This method needs to test, whether the two devices can be combined. Both devices " + "are guaranteed to share the same device class. " + "If they cannot be combined, this method shall do nothing and return false. " + "If they can be combined, this method shall reconnect the nets of the first " + "device and entirely disconnect the nets of the second device. " + "The second device will be deleted afterwards. " + ), + "@brief A class implementing the combination of two devices (parallel or serial mode).\n" + "Reimplement this class to provide a custom device combiner.\n" + "Device combination requires 'supports_paralell_combination' or 'supports_serial_combination' to be set " + "to true for the device class. In the netlist device combination step, the algorithm will try to identify " + "devices which can be combined into single devices and use the combiner object to implement the actual " + "joining of such devices.\n" + "\n" + "Attach this object to a device class with \\DeviceClass#combiner= to make the device " + "class use this combiner.\n" + "\n" + "This class has been added in version 0.27.3." +); + static tl::id_type id_of_device_class (const db::DeviceClass *cls) { return tl::id_of (cls); @@ -957,6 +1005,16 @@ static db::EqualDeviceParameters *get_equal_parameters (db::DeviceClass *cls) return dynamic_cast (cls->parameter_compare_delegate ()); } +static void set_combiner (db::DeviceClass *cls, GenericDeviceCombiner *combiner) +{ + cls->set_device_combiner (combiner); +} + +static GenericDeviceCombiner *get_combiner (db::DeviceClass *cls) +{ + return dynamic_cast (cls->device_combiner ()); +} + static void enable_parameter (db::DeviceClass *cls, size_t id, bool en) { db::DeviceParameterDefinition *pd = cls->parameter_definition_non_const (id); @@ -987,6 +1045,20 @@ static const db::DeviceParameterDefinition *parameter_definition2 (const db::Dev } } +static void dc_add_terminal_definition (db::DeviceClass *cls, db::DeviceTerminalDefinition *terminal_def) +{ + if (terminal_def) { + *terminal_def = cls->add_terminal_definition (*terminal_def); + } +} + +static void dc_add_parameter_definition (db::DeviceClass *cls, db::DeviceParameterDefinition *parameter_def) +{ + if (parameter_def) { + *parameter_def = cls->add_parameter_definition (*parameter_def); + } +} + Class decl_dbDeviceClass ("db", "DeviceClass", gsi::method ("name", &db::DeviceClass::name, "@brief Gets the name of the device class." @@ -1088,7 +1160,7 @@ Class decl_dbDeviceClass ("db", "DeviceClass", "@brief Gets the device parameter comparer for netlist verification or nil if no comparer is registered.\n" "See \\equal_parameters= for the setter.\n" "\n" - "This getter has been introduced in version 0.26.4.\n" + "This method has been moved from 'GenericDeviceClass' to 'DeviceClass' in version 0.27.3.\n" ) + gsi::method_ext ("equal_parameters=", &equal_parameters, gsi::arg ("comparer"), "@brief Specifies a device parameter comparer for netlist verification.\n" @@ -1099,7 +1171,85 @@ Class decl_dbDeviceClass ("db", "DeviceClass", "\n" "You can assign nil for the parameter comparer to remove it.\n" "\n" - "In special cases, you can even implement a custom compare scheme by deriving your own comparer from the \\GenericDeviceParameterCompare class." + "In special cases, you can even implement a custom compare scheme by deriving your own comparer from the \\GenericDeviceParameterCompare class.\n" + "\n" + "This method has been moved from 'GenericDeviceClass' to 'DeviceClass' in version 0.27.3.\n" + ) + + gsi::method_ext ("add_terminal", &gsi::dc_add_terminal_definition, gsi::arg ("terminal_def"), + "@brief Adds the given terminal definition to the device class\n" + "This method will define a new terminal. The new terminal is added at the end of existing terminals. " + "The terminal definition object passed as the argument is modified to contain the " + "new ID of the terminal.\n" + "\n" + "The terminal is copied into the device class. Modifying the terminal object later " + "does not have the effect of changing the terminal definition.\n" + "\n" + "This method has been moved from 'GenericDeviceClass' to 'DeviceClass' in version 0.27.3.\n" + ) + + gsi::method ("clear_terminals", &db::DeviceClass::clear_terminal_definitions, + "@brief Clears the list of terminals\n" + "\n" + "This method has been moved from 'GenericDeviceClass' to 'DeviceClass' in version 0.27.3.\n" + ) + + gsi::method_ext ("add_parameter", &gsi::dc_add_parameter_definition, gsi::arg ("parameter_def"), + "@brief Adds the given parameter definition to the device class\n" + "This method will define a new parameter. The new parameter is added at the end of existing parameters. " + "The parameter definition object passed as the argument is modified to contain the " + "new ID of the parameter." + "\n" + "The parameter is copied into the device class. Modifying the parameter object later " + "does not have the effect of changing the parameter definition.\n" + "\n" + "This method has been moved from 'GenericDeviceClass' to 'DeviceClass' in version 0.27.3.\n" + ) + + gsi::method ("clear_parameters", &db::DeviceClass::clear_parameter_definitions, + "@brief Clears the list of parameters\n" + "\n" + "This method has been added in version 0.27.3.\n" + ) + + gsi::method_ext ("combiner=", &set_combiner, gsi::arg ("combiner"), + "@brief Specifies a device combiner (parallel or serial device combination).\n" + "\n" + "You can assign nil for the combiner to remove it.\n" + "\n" + "In special cases, you can even implement a custom combiner by deriving your own comparer from the \\GenericDeviceCombiner class.\n" + "\n" + "This method has been added in version 0.27.3.\n" + ) + + gsi::method_ext ("combiner", &get_combiner, + "@brief Gets a device combiner or nil if none is registered.\n" + "\n" + "This method has been added in version 0.27.3.\n" + ) + + gsi::method ("supports_parallel_combination=", &db::DeviceClass::set_supports_parallel_combination, gsi::arg ("f"), + "@brief Specifies whether the device supports parallel device combination.\n" + "Parallel device combination means that all terminals of two combination candidates are connected to the same nets. " + "If the device does not support this combination mode, this predicate can be set to false. This will make the device " + "extractor skip the combination test in parallel mode and improve performance somewhat.\n" + "\n" + "This method has been moved from 'GenericDeviceClass' to 'DeviceClass' in version 0.27.3.\n" + ) + + gsi::method ("supports_serial_combination=", &db::DeviceClass::set_supports_serial_combination, gsi::arg ("f"), + "@brief Specifies whether the device supports serial device combination.\n" + "Serial device combination means that the devices are connected by internal nodes. " + "If the device does not support this combination mode, this predicate can be set to false. This will make the device " + "extractor skip the combination test in serial mode and improve performance somewhat.\n" + "\n" + "This method has been moved from 'GenericDeviceClass' to 'DeviceClass' in version 0.27.3.\n" + ) + + gsi::method ("equivalent_terminal_id", &db::DeviceClass::equivalent_terminal_id, gsi::arg ("original_id"), gsi::arg ("equivalent_id"), + "@brief Specifies a terminal to be equivalent to another.\n" + "Use this method to specify two terminals to be exchangeable. For example to make S and D of a MOS transistor equivalent, " + "call this method with S and D terminal IDs. In netlist matching, S will be translated to D and thus made equivalent to D.\n" + "\n" + "Note that terminal equivalence is not effective if the device class operates in strict mode (see \\DeviceClass#strict=).\n" + "\n" + "This method has been moved from 'GenericDeviceClass' to 'DeviceClass' in version 0.27.3.\n" + ) + + gsi::method ("clear_equivalent_terminal_ids", &db::DeviceClass::clear_equivalent_terminal_ids, + "@brief Clears all equivalent terminal ids\n" + "\n" + "This method has been added in version 0.27.3.\n" ), "@brief A class describing a specific type of device.\n" "Device class objects live in the context of a \\Netlist object. After a " @@ -1109,7 +1259,8 @@ Class decl_dbDeviceClass ("db", "DeviceClass", "\n" "The \\DeviceClass class is the base class for other device classes.\n" "\n" - "This class has been added in version 0.26." + "This class has been added in version 0.26. In version 0.27.3, the 'GenericDeviceClass' has been integrated with \\DeviceClass " + "and the device class was made writeable in most respects. This enables manipulating built-in device classes." ); namespace { @@ -1184,87 +1335,6 @@ private: } -static void gdc_add_terminal_definition (GenericDeviceClass *cls, db::DeviceTerminalDefinition *terminal_def) -{ - if (terminal_def) { - *terminal_def = cls->add_terminal_definition (*terminal_def); - } -} - -static void gdc_add_parameter_definition (GenericDeviceClass *cls, db::DeviceParameterDefinition *parameter_def) -{ - if (parameter_def) { - *parameter_def = cls->add_parameter_definition (*parameter_def); - } -} - -Class decl_GenericDeviceClass (decl_dbDeviceClass, "db", "GenericDeviceClass", - gsi::method_ext ("add_terminal", &gsi::gdc_add_terminal_definition, gsi::arg ("terminal_def"), - "@brief Adds the given terminal definition to the device class\n" - "This method will define a new terminal. The new terminal is added at the end of existing terminals. " - "The terminal definition object passed as the argument is modified to contain the " - "new ID of the terminal.\n" - "\n" - "The terminal is copied into the device class. Modifying the terminal object later " - "does not have the effect of changing the terminal definition." - ) + - gsi::method ("clear_terminals", &GenericDeviceClass::clear_terminal_definitions, - "@brief Clears the list of terminals\n" - ) + - gsi::method_ext ("add_parameter", &gsi::gdc_add_parameter_definition, gsi::arg ("parameter_def"), - "@brief Adds the given parameter definition to the device class\n" - "This method will define a new parameter. The new parameter is added at the end of existing parameters. " - "The parameter definition object passed as the argument is modified to contain the " - "new ID of the parameter." - "\n" - "The parameter is copied into the device class. Modifying the parameter object later " - "does not have the effect of changing the parameter definition." - ) + - gsi::method ("clear_parameters", &GenericDeviceClass::clear_parameter_definitions, - "@brief Clears the list of parameters\n" - ) + - gsi::callback ("combine_devices", &GenericDeviceClass::combine_devices, &GenericDeviceClass::cb_combine_devices, gsi::arg ("a"), gsi::arg ("b"), - "@brief Combines two devices.\n" - "This method shall test, whether the two devices can be combined. Both devices " - "are guaranteed to share the same device class (self). " - "If they cannot be combined, this method shall do nothing and return false. " - "If they can be combined, this method shall reconnect the nets of the first " - "device and entirely disconnect the nets of the second device. " - "It shall combine the parameters of both devices into the first. " - "The second device will be deleted afterwards.\n" - ) + - gsi::method ("supports_parallel_combination=", &GenericDeviceClass::set_supports_parallel_combination, gsi::arg ("f"), - "@brief Specifies whether the device supports parallel device combination.\n" - "Parallel device combination means that all terminals of two combination candidates are connected to the same nets. " - "If the device does not support this combination mode, this predicate can be set to false. This will make the device " - "extractor skip the combination test in parallel mode and improve performance somewhat." - ) + - gsi::method ("supports_serial_combination=", &GenericDeviceClass::set_supports_serial_combination, gsi::arg ("f"), - "@brief Specifies whether the device supports serial device combination.\n" - "Serial device combination means that the devices are connected by internal nodes. " - "If the device does not support this combination mode, this predicate can be set to false. This will make the device " - "extractor skip the combination test in serial mode and improve performance somewhat." - ) + - gsi::method ("equivalent_terminal_id", &GenericDeviceClass::equivalent_terminal_id, gsi::arg ("original_id"), gsi::arg ("equivalent_id"), - "@brief Specifies a terminal to be equivalent to another.\n" - "Use this method to specify two terminals to be exchangeable. For example to make S and D of a MOS transistor equivalent, " - "call this method with S and D terminal IDs. In netlist matching, S will be translated to D and thus made equivalent to D.\n" - "\n" - "Note that terminal equivalence is not effective if the device class operates in strict mode (see \\DeviceClass#strict=)." - ), - "@brief A generic device class\n" - "This class allows building generic device classes. Specifically, terminals can be defined " - "by adding terminal definitions. Terminal definitions should not be added dynamically. To create " - "your own device, instantiate the \\GenericDeviceClass object, set name and description and " - "specify the terminals. Then add this new device class to the \\Netlist object where it will live " - "and be used to define device instances (\\Device objects).\n" - "\n" - "In addition, parameters can be defined which correspond to values stored inside the " - "specific device instance (\\Device object)." - "\n" - "This class has been added in version 0.26." -); - static db::Net *create_net (db::Circuit *c, const std::string &name) { db::Net *n = new db::Net (); diff --git a/testdata/ruby/dbNetlist.rb b/testdata/ruby/dbNetlist.rb index dc09d7f4b..9f0081795 100644 --- a/testdata/ruby/dbNetlist.rb +++ b/testdata/ruby/dbNetlist.rb @@ -124,13 +124,13 @@ class DBNetlist_TestClass < TestBase def test_2_NetlistBasicDeviceClass nl = RBA::Netlist::new - c = RBA::GenericDeviceClass::new + c = RBA::DeviceClass::new nl.add(c) c.name = "XYZ" assert_equal(c.name, "XYZ") - cc = RBA::GenericDeviceClass::new + cc = RBA::DeviceClass::new begin nl.remove(cc) # not in netlist yet @@ -158,7 +158,7 @@ class DBNetlist_TestClass < TestBase nl.each_device_class { |i| names << i.name } assert_equal(names, [ c.name ]) - cc = RBA::GenericDeviceClass::new + cc = RBA::DeviceClass::new nl.add(cc) cc.name = "UVW" @@ -239,7 +239,7 @@ class DBNetlist_TestClass < TestBase nl = RBA::Netlist::new - dc = RBA::GenericDeviceClass::new + dc = RBA::DeviceClass::new nl.add(dc) assert_equal(dc.netlist.object_id, nl.object_id) dc.name = "DC" @@ -576,11 +576,11 @@ class DBNetlist_TestClass < TestBase end - def test_7_GenericDeviceClass + def test_7_DeviceClass nl = RBA::Netlist::new - dc = RBA::GenericDeviceClass::new + dc = RBA::DeviceClass::new nl.add(dc) dc.name = "DC" assert_equal(dc.name, "DC") @@ -758,7 +758,7 @@ class DBNetlist_TestClass < TestBase nl = RBA::Netlist::new - dc = RBA::GenericDeviceClass::new + dc = RBA::DeviceClass::new dc.name = "DC" nl.add(dc)