diff --git a/src/db/db/dbDeviceClass.cc b/src/db/db/dbDeviceClass.cc index 389e81677..4c27c7409 100644 --- a/src/db/db/dbDeviceClass.cc +++ b/src/db/db/dbDeviceClass.cc @@ -109,17 +109,58 @@ bool AllDeviceParametersAreEqual::less (const db::Device &a, const db::Device &b return false; } +// -------------------------------------------------------------------------------- +// PrimaryDeviceParametersAreEqual class implementation + +class DB_PUBLIC PrimaryDeviceParametersAreEqual + : public DeviceParameterCompareDelegate +{ +public: + PrimaryDeviceParametersAreEqual (double relative); + + virtual bool less (const db::Device &a, const db::Device &b) const; + +private: + double m_relative; +}; + +PrimaryDeviceParametersAreEqual::PrimaryDeviceParametersAreEqual (double relative) + : m_relative (relative) +{ + // .. nothing yet .. +} + +bool PrimaryDeviceParametersAreEqual::less (const db::Device &a, const db::Device &b) const +{ + const std::vector &pd = a.device_class ()->parameter_definitions (); + for (std::vector::const_iterator p = pd.begin (); p != pd.end (); ++p) { + const db::DeviceParameterDefinition *pdb = b.device_class ()->parameter_definition (p->id ()); + if (! pdb) { + continue; + } + if (! pdb->is_primary () && ! p->is_primary ()) { + continue; + } + int cmp = compare_parameters (a.parameter_value (p->id ()), b.parameter_value (p->id ()), 0.0, m_relative); + if (cmp != 0) { + return cmp < 0; + } + } + + return false; +} + // -------------------------------------------------------------------------------- // 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); } @@ -127,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; } @@ -179,6 +226,15 @@ const DeviceParameterDefinition *DeviceClass::parameter_definition (size_t id) c } } +DeviceParameterDefinition *DeviceClass::parameter_definition_non_const (size_t id) +{ + if (id < m_parameter_definitions.size ()) { + return & m_parameter_definitions [id]; + } else { + return 0; + } +} + bool DeviceClass::has_parameter_with_name (const std::string &name) const { const std::vector &pd = parameter_definitions (); @@ -227,6 +283,9 @@ size_t DeviceClass::terminal_id_for_name (const std::string &name) const // a default relative tolerance. const double relative_tolerance = 1e-6; +// The default compare delegate +static PrimaryDeviceParametersAreEqual default_compare (relative_tolerance); + bool DeviceClass::less (const db::Device &a, const db::Device &b) { tl_assert (a.device_class () != 0); @@ -236,25 +295,11 @@ bool DeviceClass::less (const db::Device &a, const db::Device &b) if (! pcd) { pcd = b.device_class ()->mp_pc_delegate.get (); } - - if (pcd != 0) { - return pcd->less (a, b); - } else { - - const std::vector &pd = a.device_class ()->parameter_definitions (); - for (std::vector::const_iterator p = pd.begin (); p != pd.end (); ++p) { - if (! p->is_primary ()) { - continue; - } - int cmp = compare_parameters (a.parameter_value (p->id ()), b.parameter_value (p->id ()), 0.0, relative_tolerance); - if (cmp != 0) { - return cmp < 0; - } - } - - return false; - + if (! pcd) { + pcd = &default_compare; } + + return pcd->less (a, b); } bool DeviceClass::equal (const db::Device &a, const db::Device &b) @@ -266,25 +311,11 @@ bool DeviceClass::equal (const db::Device &a, const db::Device &b) if (! pcd) { pcd = b.device_class ()->mp_pc_delegate.get (); } - - if (pcd != 0) { - return ! pcd->less (a, b) && ! pcd->less (b, a); - } else { - - const std::vector &pd = a.device_class ()->parameter_definitions (); - for (std::vector::const_iterator p = pd.begin (); p != pd.end (); ++p) { - if (! p->is_primary ()) { - continue; - } - int cmp = compare_parameters (a.parameter_value (p->id ()), b.parameter_value (p->id ()), 0.0, relative_tolerance); - if (cmp != 0) { - return false; - } - } - - return true; - + if (! pcd) { + pcd = &default_compare; } + + return ! pcd->less (a, b) && ! pcd->less (b, a); } // -------------------------------------------------------------------------------- diff --git a/src/db/db/dbDeviceClass.h b/src/db/db/dbDeviceClass.h index 396a03fe4..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 * @@ -508,6 +522,11 @@ public: */ const DeviceParameterDefinition *parameter_definition (size_t id) const; + /** + * @brief Gets the parameter definition from the ID (non-const version) + */ + DeviceParameterDefinition *parameter_definition_non_const (size_t id); + /** * @brief Returns true, if the device has a parameter with the given name */ @@ -548,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 (); } /** @@ -575,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; + } } /** @@ -638,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 */ @@ -662,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/dbLayoutToNetlistFormatDefs.h b/src/db/db/dbLayoutToNetlistFormatDefs.h index 66cc393e1..5f261e467 100644 --- a/src/db/db/dbLayoutToNetlistFormatDefs.h +++ b/src/db/db/dbLayoutToNetlistFormatDefs.h @@ -58,7 +58,7 @@ namespace db * - connects the shapes of the layer with the given global * nets [short key: G] * circuit( [circuit-def]) - circuit (cell) [short key: X] - * class(