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( ) - a device class definition (template: RES,CAP,...) [short key: K]
+ * class( [template-def]) - a device class definition (template: RES,CAP,...) [short key: K]
* device( [device-abstract-def])
* - device abstract [short key: D]
*
@@ -127,8 +127,18 @@ namespace db
* ( ) - relative coordinates (reference is reset to 0,0
* for each net or terminal in device abstract)
*
+ * [template-def]:
+ *
+ * param( ? *) - defines a template parameter [short key: E]
+ * ('primary' is a value: 0 or 1)
+ * terminal() - defines a terminal [short key: T]
+ *
* [device-abstract-def]:
*
+ * [device-abstract-terminal-def]*
+ *
+ * [device-abstract-terminal-def]:
+ *
* terminal( [geometry-def]*)
* - specifies the terminal geometry [short key: T]
*
diff --git a/src/db/db/dbLayoutToNetlistReader.cc b/src/db/db/dbLayoutToNetlistReader.cc
index d809398d1..4300c0a43 100644
--- a/src/db/db/dbLayoutToNetlistReader.cc
+++ b/src/db/db/dbLayoutToNetlistReader.cc
@@ -236,10 +236,9 @@ void LayoutToNetlistStandardReader::read_netlist (db::Netlist *netlist, db::Layo
std::string class_name, templ_name;
read_word_or_quoted (class_name);
read_word_or_quoted (templ_name);
- br.done ();
if (netlist->device_class_by_name (class_name) != 0) {
- throw tl::Exception (tl::to_string (tr ("Device class must be defined before being used in device")));
+ throw tl::Exception (tl::to_string (tr ("Duplicate definition of device class: ")) + class_name);
}
db::DeviceClassTemplateBase *dct = db::DeviceClassTemplateBase::template_by_name (templ_name);
@@ -251,6 +250,52 @@ void LayoutToNetlistStandardReader::read_netlist (db::Netlist *netlist, db::Layo
dc->set_name (class_name);
netlist->add_device_class (dc);
+ while (br) {
+
+ if (test (skeys::terminal_key) || test (lkeys::terminal_key)) {
+
+ Brace br (this);
+
+ std::string terminal_name;
+ read_word_or_quoted (terminal_name);
+ if (! dc->has_terminal_with_name (terminal_name)) {
+ db::DeviceTerminalDefinition td;
+ td.set_name (terminal_name);
+ dc->add_terminal_definition (td);
+ }
+
+ br.done ();
+
+ } else if (test (skeys::param_key) || test (lkeys::param_key)) {
+
+ Brace br (this);
+
+ std::string param_name;
+ read_word_or_quoted (param_name);
+ int primary = read_int ();
+ int default_value = read_double ();
+ if (! dc->has_parameter_with_name (param_name)) {
+ db::DeviceParameterDefinition pd;
+ pd.set_name (param_name);
+ pd.set_is_primary (primary);
+ pd.set_default_value (default_value);
+ dc->add_parameter_definition (pd);
+ } else {
+ db::DeviceParameterDefinition *pd = dc->parameter_definition_non_const (dc->parameter_id_for_name (param_name));
+ pd->set_default_value (default_value);
+ pd->set_is_primary (primary);
+ }
+
+ br.done ();
+
+ } else {
+ throw tl::Exception (tl::to_string (tr ("Invalid keyword")));
+ }
+
+ }
+
+ br.done ();
+
} else if (l2n && (test (skeys::connect_key) || test (lkeys::connect_key))) {
Brace br (this);
diff --git a/src/db/db/dbLayoutToNetlistWriter.cc b/src/db/db/dbLayoutToNetlistWriter.cc
index 4dc227ae4..d7956761d 100644
--- a/src/db/db/dbLayoutToNetlistWriter.cc
+++ b/src/db/db/dbLayoutToNetlistWriter.cc
@@ -24,6 +24,7 @@
#include "dbLayoutToNetlist.h"
#include "dbLayoutToNetlistFormatDefs.h"
#include "dbPolygonTools.h"
+#include "tlMath.h"
namespace db
{
@@ -113,6 +114,47 @@ void std_writer_impl::write (const db::Netlist *netlist, const db::LayoutT
}
}
+static bool same_parameter (const DeviceParameterDefinition &a, const DeviceParameterDefinition &b)
+{
+ if (a.is_primary () != b.is_primary ()) {
+ return false;
+ }
+ if (! tl::equal (a.default_value (), b.default_value ())) {
+ return false;
+ }
+ return true;
+}
+
+template
+void std_writer_impl::write_device_class (const std::string &indent, const db::DeviceClass *cls, const std::string &temp_name, const db::DeviceClass *temp_class)
+{
+ *mp_stream << indent << Keys::class_key << "(" << tl::to_word_or_quoted_string (cls->name ()) << " " << tl::to_word_or_quoted_string (temp_name);
+
+ bool any_def = false;
+
+ const std::vector &pd = cls->parameter_definitions ();
+ for (std::vector::const_iterator p = pd.begin (); p != pd.end (); ++p) {
+ if (! temp_class->has_parameter_with_name (p->name ()) || !same_parameter (*p, *temp_class->parameter_definition (temp_class->parameter_id_for_name (p->name ())))) {
+ *mp_stream << endl << indent << indent1 << Keys::param_key << "(" << tl::to_word_or_quoted_string (p->name ()) << " " << tl::to_string (p->is_primary () ? 1 : 0) << " " << tl::to_string (p->default_value ()) << ")";
+ any_def = true;
+ }
+ }
+
+ const std::vector &td = cls->terminal_definitions ();
+ for (std::vector::const_iterator t = td.begin (); t != td.end (); ++t) {
+ if (! temp_class->has_terminal_with_name (t->name ())) {
+ *mp_stream << endl << indent << indent1 << Keys::terminal_key << "(" << tl::to_word_or_quoted_string (t->name ()) << ")";
+ any_def = true;
+ }
+ }
+
+ if (any_def) {
+ *mp_stream << endl << indent << ")" << endl;
+ } else {
+ *mp_stream << ")" << endl;
+ }
+}
+
template
void std_writer_impl::write (bool nested, std::map > *net2id_per_circuit)
{
@@ -203,9 +245,13 @@ void std_writer_impl::write (bool nested, std::mapbegin_device_classes (); c != mp_netlist->end_device_classes (); ++c) {
db::DeviceClassTemplateBase *temp = db::DeviceClassTemplateBase::is_a (c.operator-> ());
if (temp) {
- *mp_stream << indent << Keys::class_key << "(" << tl::to_word_or_quoted_string (c->name ()) << " " << tl::to_word_or_quoted_string (temp->name ()) << ")" << endl;
- m_progress.set (mp_stream->pos ());
+ std::unique_ptr temp_class (temp->create ());
+ write_device_class (indent, c.operator-> (), temp->name (), temp_class.get ());
+ } else {
+ db::DeviceClass empty;
+ write_device_class (indent, c.operator-> (), std::string (), &empty);
}
+ m_progress.set (mp_stream->pos ());
}
if (mp_netlist->begin_device_abstracts () != mp_netlist->end_device_abstracts () && ! Keys::is_short ()) {
diff --git a/src/db/db/dbLayoutToNetlistWriter.h b/src/db/db/dbLayoutToNetlistWriter.h
index 72d9b14f8..67d2b0366 100644
--- a/src/db/db/dbLayoutToNetlistWriter.h
+++ b/src/db/db/dbLayoutToNetlistWriter.h
@@ -37,6 +37,7 @@ namespace db
class Circuit;
class SubCircuit;
class Device;
+class DeviceClass;
class DeviceAbstract;
class Net;
class Netlist;
@@ -78,6 +79,7 @@ private:
void write (const db::DeviceAbstract &device_abstract, const std::string &indent);
void write (const db::NetShape *s, const db::ICplxTrans &tr, const std::string &lname, bool relative);
void write (const db::DCplxTrans &trans);
+ void write_device_class (const std::string &indent, const db::DeviceClass *cls, const std::string &name, const db::DeviceClass *temp_class);
void reset_geometry_ref ();
// implementation of CircuitCallback
diff --git a/src/db/db/dbNetlistDeviceClasses.cc b/src/db/db/dbNetlistDeviceClasses.cc
index 915f03f27..c9936e0e8 100644
--- a/src/db/db/dbNetlistDeviceClasses.cc
+++ b/src/db/db/dbNetlistDeviceClasses.cc
@@ -30,7 +30,9 @@ namespace db
// The built-in device class templates
static tl::RegisteredClass dct_cap (new db::device_class_template ("CAP"));
+static tl::RegisteredClass dct_cap_with_bulk (new db::device_class_template ("CAP3"));
static tl::RegisteredClass dct_res (new db::device_class_template ("RES"));
+static tl::RegisteredClass dct_res_with_bulk (new db::device_class_template ("RES3"));
static tl::RegisteredClass dct_ind (new db::device_class_template ("IND"));
static tl::RegisteredClass dct_diode (new db::device_class_template ("DIODE"));
static tl::RegisteredClass dct_mos3 (new db::device_class_template ("MOS3"));
@@ -41,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
@@ -108,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));
@@ -118,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
@@ -191,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
@@ -219,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
@@ -267,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
@@ -293,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;
@@ -324,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"));
@@ -331,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
@@ -370,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));
@@ -382,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
@@ -434,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
@@ -493,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"));
@@ -507,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
@@ -546,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 0c7153889..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) const
- {
- return terminal_id_A;
- }
};
/**
@@ -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/dbNetlistDeviceExtractor.cc b/src/db/db/dbNetlistDeviceExtractor.cc
index 7c97d1782..03129ea62 100644
--- a/src/db/db/dbNetlistDeviceExtractor.cc
+++ b/src/db/db/dbNetlistDeviceExtractor.cc
@@ -391,7 +391,7 @@ void NetlistDeviceExtractor::push_new_devices (const db::Vector &disp_cache)
std::string cell_name = "D$" + mp_device_class->name ();
db::Cell &device_cell = mp_layout->cell (mp_layout->add_cell (cell_name.c_str ()));
- db::DeviceAbstract *dm = new db::DeviceAbstract (mp_device_class, mp_layout->cell_name (device_cell.cell_index ()));
+ db::DeviceAbstract *dm = new db::DeviceAbstract (mp_device_class.get (), mp_layout->cell_name (device_cell.cell_index ()));
m_netlist->add_device_abstract (dm);
dm->set_cell_index (device_cell.cell_index ());
@@ -487,7 +487,7 @@ void NetlistDeviceExtractor::register_device_class (DeviceClass *device_class)
tl_assert (device_class != 0);
tl_assert (m_netlist.get () != 0);
- if (mp_device_class != 0) {
+ if (mp_device_class.get () != 0) {
throw tl::Exception (tl::to_string (tr ("Device class already set")));
}
if (m_name.empty ()) {
@@ -526,12 +526,12 @@ const db::NetlistDeviceExtractorLayerDefinition &NetlistDeviceExtractor::define_
Device *NetlistDeviceExtractor::create_device ()
{
- if (mp_device_class == 0) {
+ if (mp_device_class.get () == 0) {
throw tl::Exception (tl::to_string (tr ("No device class registered")));
}
tl_assert (mp_circuit != 0);
- Device *device = new Device (mp_device_class);
+ Device *device = new Device (mp_device_class.get ());
mp_circuit->add_device (device);
return device;
}
diff --git a/src/db/db/dbNetlistDeviceExtractor.h b/src/db/db/dbNetlistDeviceExtractor.h
index c6cab89ae..9300586ea 100644
--- a/src/db/db/dbNetlistDeviceExtractor.h
+++ b/src/db/db/dbNetlistDeviceExtractor.h
@@ -387,6 +387,16 @@ public:
*/
Device *create_device ();
+ /**
+ * @brief Gets the device class used during extraction
+ *
+ * This member is set in 'extract_devices' and holds the device class object used during extraction.
+ */
+ DeviceClass *device_class ()
+ {
+ return mp_device_class.get ();
+ }
+
/**
* @brief Defines a device terminal in the layout (a region)
*/
@@ -493,6 +503,13 @@ public:
*/
std::string cell_name () const;
+ /**
+ * @brief Initializes the extractor
+ * This method will produce the device classes required for the device extraction.
+ * It is mainly provided for test purposes. Don't call it directly.
+ */
+ void initialize (db::Netlist *nl);
+
private:
struct DeviceCellKey
{
@@ -535,7 +552,7 @@ private:
const std::set *mp_breakout_cells;
double m_device_scaling;
db::Circuit *mp_circuit;
- db::DeviceClass *mp_device_class;
+ tl::weak_ptr mp_device_class;
std::string m_name;
layer_definitions m_layer_definitions;
std::vector m_layers;
@@ -547,12 +564,6 @@ private:
NetlistDeviceExtractor (const NetlistDeviceExtractor &);
NetlistDeviceExtractor &operator= (const NetlistDeviceExtractor &);
- /**
- * @brief Initializes the extractor
- * This method will produce the device classes required for the device extraction.
- */
- void initialize (db::Netlist *nl);
-
void extract_without_initialize (db::Layout &layout, db::Cell &cell, hier_clusters_type &clusters, const std::vector &layers, double device_scaling, const std::set *breakout_cells);
void push_new_devices (const Vector &disp_cache);
void push_cached_devices (const tl::vector &cached_devices, const db::Vector &disp_cache, const db::Vector &new_disp);
diff --git a/src/db/db/dbNetlistDeviceExtractorClasses.cc b/src/db/db/dbNetlistDeviceExtractorClasses.cc
index 2eb1d5c2a..957c9e8bb 100644
--- a/src/db/db/dbNetlistDeviceExtractorClasses.cc
+++ b/src/db/db/dbNetlistDeviceExtractorClasses.cc
@@ -30,8 +30,8 @@ namespace db
// ---------------------------------------------------------------------------------
// NetlistDeviceExtractorMOS3Transistor implementation
-NetlistDeviceExtractorMOS3Transistor::NetlistDeviceExtractorMOS3Transistor (const std::string &name, bool strict)
- : db::NetlistDeviceExtractor (name),
+NetlistDeviceExtractorMOS3Transistor::NetlistDeviceExtractorMOS3Transistor (const std::string &name, bool strict, db::DeviceClassFactory *factory)
+ : db::NetlistDeviceExtractorImplBase (name, factory ? factory : new db::device_class_factory ()),
m_strict (strict)
{
// .. nothing yet ..
@@ -66,7 +66,7 @@ void NetlistDeviceExtractorMOS3Transistor::setup ()
}
- db::DeviceClass *cls = new db::DeviceClassMOS3Transistor ();
+ db::DeviceClass *cls = make_class ();
cls->set_strict (m_strict);
register_device_class (cls);
}
@@ -322,8 +322,8 @@ void NetlistDeviceExtractorMOS3Transistor::extract_devices (const std::vector ())
{
// .. nothing yet ..
}
@@ -367,7 +367,7 @@ void NetlistDeviceExtractorMOS4Transistor::setup ()
}
- db::DeviceClass *cls = new db::DeviceClassMOS4Transistor ();
+ db::DeviceClass *cls = make_class ();
cls->set_strict (is_strict ());
register_device_class (cls);
}
@@ -383,8 +383,8 @@ void NetlistDeviceExtractorMOS4Transistor::modify_device (const db::Polygon &rga
// ---------------------------------------------------------------------------------
// NetlistDeviceExtractorResistor implementation
-NetlistDeviceExtractorResistor::NetlistDeviceExtractorResistor (const std::string &name, double sheet_rho)
- : db::NetlistDeviceExtractor (name), m_sheet_rho (sheet_rho)
+NetlistDeviceExtractorResistor::NetlistDeviceExtractorResistor (const std::string &name, double sheet_rho, db::DeviceClassFactory *factory)
+ : db::NetlistDeviceExtractorImplBase (name, factory ? factory : new db::device_class_factory ()), m_sheet_rho (sheet_rho)
{
// .. nothing yet ..
}
@@ -396,7 +396,7 @@ void NetlistDeviceExtractorResistor::setup ()
define_layer ("tA", 1, "A terminal output"); // #2 -> C
define_layer ("tB", 1, "B terminal output"); // #3 -> C
- register_device_class (new db::DeviceClassResistor ());
+ register_device_class (make_class ());
}
db::Connectivity NetlistDeviceExtractorResistor::get_connectivity (const db::Layout & /*layout*/, const std::vector &layers) const
@@ -454,17 +454,17 @@ void NetlistDeviceExtractorResistor::extract_devices (const std::vectorset_parameter_value (db::DeviceClassResistor::param_id_R, m_sheet_rho * double (length) / double (width));
- device->set_parameter_value (db::DeviceClassResistor::param_id_L, sdbu () * length);
- device->set_parameter_value (db::DeviceClassResistor::param_id_W, sdbu () * width);
+ device->set_parameter_value (db::DeviceClassResistor::param_id_R, m_sheet_rho * double (length2) / double (width2));
+ device->set_parameter_value (db::DeviceClassResistor::param_id_L, sdbu () * 0.5 * length2);
+ device->set_parameter_value (db::DeviceClassResistor::param_id_W, sdbu () * 0.5 * width2);
device->set_parameter_value (db::DeviceClassResistor::param_id_A, sdbu () * sdbu () * p->area ());
device->set_parameter_value (db::DeviceClassResistor::param_id_P, sdbu () * p->perimeter ());
@@ -494,8 +494,8 @@ void NetlistDeviceExtractorResistor::extract_devices (const std::vector ())
{
// .. nothing yet ..
}
@@ -509,7 +509,7 @@ void NetlistDeviceExtractorResistorWithBulk::setup ()
define_layer ("W", "Well/Bulk"); // #4
define_layer ("tW", 4, "W terminal output"); // #5 -> W
- register_device_class (new db::DeviceClassResistorWithBulk ());
+ register_device_class (make_class ());
}
void NetlistDeviceExtractorResistorWithBulk::modify_device (const db::Polygon &res, const std::vector & /*layer_geometry*/, db::Device *device)
@@ -521,8 +521,8 @@ void NetlistDeviceExtractorResistorWithBulk::modify_device (const db::Polygon &r
// ---------------------------------------------------------------------------------
// NetlistDeviceExtractorCapacitor implementation
-NetlistDeviceExtractorCapacitor::NetlistDeviceExtractorCapacitor (const std::string &name, double area_cap)
- : db::NetlistDeviceExtractor (name), m_area_cap (area_cap)
+NetlistDeviceExtractorCapacitor::NetlistDeviceExtractorCapacitor (const std::string &name, double area_cap, db::DeviceClassFactory *factory)
+ : db::NetlistDeviceExtractorImplBase (name, factory ? factory : new db::device_class_factory ()), m_area_cap (area_cap)
{
// .. nothing yet ..
}
@@ -534,7 +534,7 @@ void NetlistDeviceExtractorCapacitor::setup ()
define_layer ("tA", 0, "A terminal output"); // #2 -> P1
define_layer ("tB", 1, "B terminal output"); // #3 -> P2
- register_device_class (new db::DeviceClassCapacitor ());
+ register_device_class (make_class ());
}
db::Connectivity NetlistDeviceExtractorCapacitor::get_connectivity (const db::Layout & /*layout*/, const std::vector &layers) const
@@ -596,8 +596,8 @@ void NetlistDeviceExtractorCapacitor::extract_devices (const std::vector ())
{
// .. nothing yet ..
}
@@ -611,7 +611,7 @@ void NetlistDeviceExtractorCapacitorWithBulk::setup ()
define_layer ("W", "Well/Bulk"); // #4
define_layer ("tW", 4, "W terminal output"); // #5 -> W
- register_device_class (new db::DeviceClassCapacitorWithBulk ());
+ register_device_class (make_class ());
}
void NetlistDeviceExtractorCapacitorWithBulk::modify_device (const db::Polygon &cap, const std::vector & /*layer_geometry*/, db::Device *device)
@@ -623,8 +623,8 @@ void NetlistDeviceExtractorCapacitorWithBulk::modify_device (const db::Polygon &
// ---------------------------------------------------------------------------------
// NetlistDeviceExtractorBJT3Transistor implementation
-NetlistDeviceExtractorBJT3Transistor::NetlistDeviceExtractorBJT3Transistor (const std::string &name)
- : db::NetlistDeviceExtractor (name)
+NetlistDeviceExtractorBJT3Transistor::NetlistDeviceExtractorBJT3Transistor (const std::string &name, db::DeviceClassFactory *factory)
+ : db::NetlistDeviceExtractorImplBase (name, factory ? factory : new db::device_class_factory ())
{
// .. nothing yet ..
}
@@ -640,7 +640,7 @@ void NetlistDeviceExtractorBJT3Transistor::setup ()
define_layer ("tB", 1, "Base terminal output"); // #4 -> B
define_layer ("tE", 2, "Emitter terminal output"); // #5 -> E
- register_device_class (new db::DeviceClassBJT3Transistor ());
+ register_device_class (make_class ());
}
db::Connectivity NetlistDeviceExtractorBJT3Transistor::get_connectivity (const db::Layout & /*layout*/, const std::vector &layers) const
@@ -750,8 +750,8 @@ void NetlistDeviceExtractorBJT3Transistor::extract_devices (const std::vector ())
{
// .. nothing yet ..
}
@@ -772,7 +772,7 @@ void NetlistDeviceExtractorBJT4Transistor::setup ()
define_layer ("tS", 6, "Substrate (bulk) terminal output"); // #7 -> S
- register_device_class (new db::DeviceClassBJT4Transistor ());
+ register_device_class (make_class ());
}
void NetlistDeviceExtractorBJT4Transistor::modify_device (const db::Polygon &emitter, const std::vector & /*layer_geometry*/, db::Device *device)
@@ -784,8 +784,8 @@ void NetlistDeviceExtractorBJT4Transistor::modify_device (const db::Polygon &emi
// ---------------------------------------------------------------------------------
// NetlistDeviceExtractorDiode implementation
-NetlistDeviceExtractorDiode::NetlistDeviceExtractorDiode (const std::string &name)
- : db::NetlistDeviceExtractor (name)
+NetlistDeviceExtractorDiode::NetlistDeviceExtractorDiode (const std::string &name, db::DeviceClassFactory *factory)
+ : db::NetlistDeviceExtractorImplBase (name, factory ? factory : new db::device_class_factory ())
{
// .. nothing yet ..
}
@@ -797,7 +797,7 @@ void NetlistDeviceExtractorDiode::setup ()
define_layer ("tA", 0, "A terminal output"); // #2 -> P
define_layer ("tC", 1, "C terminal output"); // #3 -> N
- register_device_class (new db::DeviceClassDiode ());
+ register_device_class (make_class ());
}
db::Connectivity NetlistDeviceExtractorDiode::get_connectivity (const db::Layout & /*layout*/, const std::vector &layers) const
diff --git a/src/db/db/dbNetlistDeviceExtractorClasses.h b/src/db/db/dbNetlistDeviceExtractorClasses.h
index 3a157b7aa..1f1f07429 100644
--- a/src/db/db/dbNetlistDeviceExtractorClasses.h
+++ b/src/db/db/dbNetlistDeviceExtractorClasses.h
@@ -24,10 +24,64 @@
#define _HDR_dbNetlistDeviceExtractorClasses
#include "dbNetlistDeviceExtractor.h"
+#include "gsiObject.h"
namespace db
{
+/**
+ * @brief A device class factory base class
+ */
+class DB_PUBLIC DeviceClassFactory
+ : public gsi::ObjectBase
+{
+public:
+ DeviceClassFactory () { }
+ ~DeviceClassFactory () { }
+ virtual db::DeviceClass *create_class () const = 0;
+};
+
+/**
+ * @brief A specific factory
+ */
+template
+class DB_PUBLIC device_class_factory
+ : public DeviceClassFactory
+{
+public:
+ virtual db::DeviceClass *create_class () const { return new C (); }
+};
+
+/**
+ * @brief A base class for the specialized device extractors
+ *
+ * The main feature of this class is to supply a device class factory
+ * which actually creates the device class object.
+ *
+ * The NetlistDeviceExtractorImplBase object will own the factory object.
+ */
+class DB_PUBLIC NetlistDeviceExtractorImplBase
+ : public db::NetlistDeviceExtractor
+{
+public:
+ NetlistDeviceExtractorImplBase (const std::string &name, DeviceClassFactory *factory)
+ : db::NetlistDeviceExtractor (name), mp_factory (factory)
+ {
+ mp_factory->keep ();
+ }
+
+ /**
+ * @brief Creates the device class object
+ */
+ db::DeviceClass *make_class ()
+ {
+ return mp_factory->create_class ();
+ }
+
+private:
+ std::unique_ptr mp_factory;
+};
+
/**
* @brief A device extractor for a three-terminal MOS transistor
*
@@ -45,10 +99,10 @@ namespace db
* the particular source or drain area.
*/
class DB_PUBLIC NetlistDeviceExtractorMOS3Transistor
- : public db::NetlistDeviceExtractor
+ : public db::NetlistDeviceExtractorImplBase
{
public:
- NetlistDeviceExtractorMOS3Transistor (const std::string &name, bool strict = false);
+ NetlistDeviceExtractorMOS3Transistor (const std::string &name, bool strict = false, DeviceClassFactory *factory = 0);
virtual void setup ();
virtual db::Connectivity get_connectivity (const db::Layout &layout, const std::vector &layers) const;
@@ -94,7 +148,7 @@ class DB_PUBLIC NetlistDeviceExtractorMOS4Transistor
: public NetlistDeviceExtractorMOS3Transistor
{
public:
- NetlistDeviceExtractorMOS4Transistor (const std::string &name, bool strict = false);
+ NetlistDeviceExtractorMOS4Transistor (const std::string &name, bool strict = false, DeviceClassFactory *factory = 0);
virtual void setup ();
@@ -121,10 +175,10 @@ private:
* terminals are produced.
*/
class DB_PUBLIC NetlistDeviceExtractorResistor
- : public db::NetlistDeviceExtractor
+ : public db::NetlistDeviceExtractorImplBase
{
public:
- NetlistDeviceExtractorResistor (const std::string &name, double sheet_rho);
+ NetlistDeviceExtractorResistor (const std::string &name, double sheet_rho, DeviceClassFactory *factory = 0);
virtual void setup ();
virtual db::Connectivity get_connectivity (const db::Layout &layout, const std::vector &layers) const;
@@ -162,7 +216,7 @@ class DB_PUBLIC NetlistDeviceExtractorResistorWithBulk
: public db::NetlistDeviceExtractorResistor
{
public:
- NetlistDeviceExtractorResistorWithBulk (const std::string &name, double sheet_rho);
+ NetlistDeviceExtractorResistorWithBulk (const std::string &name, double sheet_rho, DeviceClassFactory *factory = 0);
virtual void setup ();
virtual void modify_device (const db::Polygon &res, const std::vector & /*layer_geometry*/, db::Device *device);
@@ -186,10 +240,10 @@ public:
* the terminals for A and B are produced respectively.
*/
class DB_PUBLIC NetlistDeviceExtractorCapacitor
- : public db::NetlistDeviceExtractor
+ : public db::NetlistDeviceExtractorImplBase
{
public:
- NetlistDeviceExtractorCapacitor (const std::string &name, double area_cap);
+ NetlistDeviceExtractorCapacitor (const std::string &name, double area_cap, DeviceClassFactory *factory = 0);
virtual void setup ();
virtual db::Connectivity get_connectivity (const db::Layout &layout, const std::vector &layers) const;
@@ -227,7 +281,7 @@ class DB_PUBLIC NetlistDeviceExtractorCapacitorWithBulk
: public db::NetlistDeviceExtractorCapacitor
{
public:
- NetlistDeviceExtractorCapacitorWithBulk (const std::string &name, double cap_area);
+ NetlistDeviceExtractorCapacitorWithBulk (const std::string &name, double cap_area, DeviceClassFactory *factory = 0);
virtual void setup ();
virtual void modify_device (const db::Polygon &cap, const std::vector & /*layer_geometry*/, db::Device *device);
@@ -256,10 +310,10 @@ public:
* The terminal output layer names are 'tC' (collector), 'tB' (base) and 'tE' (emitter).
*/
class DB_PUBLIC NetlistDeviceExtractorBJT3Transistor
- : public db::NetlistDeviceExtractor
+ : public db::NetlistDeviceExtractorImplBase
{
public:
- NetlistDeviceExtractorBJT3Transistor (const std::string &name);
+ NetlistDeviceExtractorBJT3Transistor (const std::string &name, DeviceClassFactory *factory = 0);
virtual void setup ();
virtual db::Connectivity get_connectivity (const db::Layout &layout, const std::vector &layers) const;
@@ -296,7 +350,7 @@ class DB_PUBLIC NetlistDeviceExtractorBJT4Transistor
: public NetlistDeviceExtractorBJT3Transistor
{
public:
- NetlistDeviceExtractorBJT4Transistor (const std::string &name);
+ NetlistDeviceExtractorBJT4Transistor (const std::string &name, DeviceClassFactory *factory = 0);
virtual void setup ();
@@ -321,10 +375,10 @@ private:
* cathode respectively.
*/
class DB_PUBLIC NetlistDeviceExtractorDiode
- : public db::NetlistDeviceExtractor
+ : public db::NetlistDeviceExtractorImplBase
{
public:
- NetlistDeviceExtractorDiode (const std::string &name);
+ NetlistDeviceExtractorDiode (const std::string &name, DeviceClassFactory *factory = 0);
virtual void setup ();
virtual db::Connectivity get_connectivity (const db::Layout &layout, const std::vector &layers) const;
diff --git a/src/db/db/dbNetlistSpiceReader.cc b/src/db/db/dbNetlistSpiceReader.cc
index bfa207d13..0f0fe8312 100644
--- a/src/db/db/dbNetlistSpiceReader.cc
+++ b/src/db/db/dbNetlistSpiceReader.cc
@@ -635,8 +635,108 @@ bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::strin
// ------------------------------------------------------------------------------------------------------
+NetlistSpiceReader::SpiceReaderStream::SpiceReaderStream ()
+ : mp_stream (0), m_owns_stream (false), mp_text_stream (0), m_line_number (0), m_stored_line (), m_has_stored_line (false)
+{
+ // .. nothing yet ..
+}
+
+NetlistSpiceReader::SpiceReaderStream::~SpiceReaderStream ()
+{
+ close ();
+}
+
+void
+NetlistSpiceReader::SpiceReaderStream::close ()
+{
+ delete mp_text_stream;
+ mp_text_stream = 0;
+
+ if (m_owns_stream) {
+ delete mp_stream;
+ mp_stream = 0;
+ m_owns_stream = false;
+ }
+}
+
+std::pair
+NetlistSpiceReader::SpiceReaderStream::get_line ()
+{
+ if (mp_text_stream->at_end ()) {
+ return std::make_pair (std::string (), false);
+ }
+
+ ++m_line_number;
+
+ std::string l = m_has_stored_line ? m_stored_line : mp_text_stream->get_line ();
+
+ m_has_stored_line = false;
+ m_stored_line.clear ();
+
+ while (! mp_text_stream->at_end ()) {
+
+ std::string ll = mp_text_stream->get_line ();
+
+ tl::Extractor ex (ll.c_str ());
+ if (! ex.test ("+")) {
+ m_stored_line = ll;
+ m_has_stored_line = true;
+ break;
+ } else {
+ ++m_line_number;
+ l += " ";
+ l += ex.get ();
+ }
+
+ }
+
+ return std::make_pair (l, true);
+}
+
+int
+NetlistSpiceReader::SpiceReaderStream::line_number () const
+{
+ return m_line_number;
+}
+
+std::string
+NetlistSpiceReader::SpiceReaderStream::source () const
+{
+ return mp_stream->source ();
+}
+
+bool
+NetlistSpiceReader::SpiceReaderStream::at_end () const
+{
+ return mp_text_stream->at_end ();
+}
+
+void
+NetlistSpiceReader::SpiceReaderStream::set_stream (tl::InputStream &stream)
+{
+ close ();
+ mp_stream = &stream;
+ mp_text_stream = new tl::TextInputStream (stream);
+ m_owns_stream = false;
+ m_has_stored_line = false;
+ m_line_number = 0;
+}
+
+void
+NetlistSpiceReader::SpiceReaderStream::set_stream (tl::InputStream *stream)
+{
+ close ();
+ mp_stream = stream;
+ mp_text_stream = new tl::TextInputStream (*stream);
+ m_owns_stream = true;
+ m_has_stored_line = false;
+ m_line_number = 0;
+}
+
+// ------------------------------------------------------------------------------------------------------
+
NetlistSpiceReader::NetlistSpiceReader (NetlistSpiceReaderDelegate *delegate)
- : mp_netlist (0), mp_stream (), mp_delegate (delegate)
+ : mp_netlist (0), mp_delegate (delegate), m_stream ()
{
static NetlistSpiceReaderDelegate std_delegate;
if (! delegate) {
@@ -653,7 +753,8 @@ void NetlistSpiceReader::read (tl::InputStream &stream, db::Netlist &netlist)
{
tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("Reading netlist ")) + stream.source ());
- mp_stream.reset (new tl::TextInputStream (stream));
+ m_stream.set_stream (stream);
+
mp_netlist = &netlist;
mp_circuit = 0;
mp_anonymous_top_circuit = 0;
@@ -681,7 +782,7 @@ void NetlistSpiceReader::read (tl::InputStream &stream, db::Netlist &netlist)
// NOTE: because we do a peek to capture the "+" line continuation character, we're
// one line ahead.
- std::string fmt_msg = tl::sprintf ("%s in %s, line %d", ex.msg (), mp_stream->source (), mp_stream->line_number () - 1);
+ std::string fmt_msg = tl::sprintf ("%s in %s, line %d", ex.msg (), m_stream.source (), m_stream.line_number ());
finish ();
throw tl::Exception (fmt_msg);
@@ -737,11 +838,9 @@ void NetlistSpiceReader::build_global_nets ()
void NetlistSpiceReader::finish ()
{
- while (! m_streams.empty ()) {
- pop_stream ();
- }
+ m_streams.clear ();
+ m_stream.close ();
- mp_stream.reset (0);
mp_netlist = 0;
mp_circuit = 0;
mp_nets_by_name.reset (0);
@@ -749,7 +848,7 @@ void NetlistSpiceReader::finish ()
void NetlistSpiceReader::push_stream (const std::string &path)
{
- tl::URI current_uri (mp_stream->source ());
+ tl::URI current_uri (m_stream.source ());
tl::URI new_uri (path);
tl::InputStream *istream;
@@ -757,80 +856,68 @@ void NetlistSpiceReader::push_stream (const std::string &path)
if (tl::is_absolute (path)) {
istream = new tl::InputStream (path);
} else {
- istream = new tl::InputStream (tl::combine_path (tl::dirname (mp_stream->source ()), path));
+ istream = new tl::InputStream (tl::combine_path (tl::dirname (m_stream.source ()), path));
}
} else {
istream = new tl::InputStream (current_uri.resolved (new_uri).to_abstract_path ());
}
- m_streams.push_back (std::make_pair (istream, mp_stream.release ()));
- mp_stream.reset (new tl::TextInputStream (*istream));
+ m_streams.push_back (SpiceReaderStream ());
+ m_streams.back ().swap (m_stream);
+ m_stream.set_stream (istream);
}
void NetlistSpiceReader::pop_stream ()
{
if (! m_streams.empty ()) {
-
- mp_stream.reset (m_streams.back ().second);
- delete m_streams.back ().first;
-
+ m_stream.swap (m_streams.back ());
m_streams.pop_back ();
-
}
}
bool NetlistSpiceReader::at_end ()
{
- return mp_stream->at_end () && m_streams.empty ();
+ return m_stream.at_end () && m_streams.empty ();
}
std::string NetlistSpiceReader::get_line ()
{
- if (! m_stored_line.empty ()) {
- std::string l;
- l.swap (m_stored_line);
- return l;
+ std::pair lp;
+
+ while (true) {
+
+ lp = m_stream.get_line ();
+ if (! lp.second) {
+
+ if (m_streams.empty ()) {
+ break;
+ } else {
+ pop_stream ();
+ }
+
+ } else {
+
+ tl::Extractor ex (lp.first.c_str ());
+ if (ex.test_without_case (".include") || ex.test_without_case (".inc")) {
+
+ std::string path;
+ ex.read_word_or_quoted (path, allowed_name_chars);
+
+ push_stream (path);
+
+ } else if (ex.at_end () || ex.test ("*")) {
+
+ // skip empty and comment lines
+
+ } else {
+ break;
+ }
+
+ }
+
}
- std::string l;
-
- do {
-
- while (mp_stream->at_end ()) {
- if (m_streams.empty ()) {
- return std::string ();
- }
- pop_stream ();
- }
-
- l = mp_stream->get_line ();
- while (! mp_stream->at_end () && mp_stream->peek_char () == '+') {
- mp_stream->get_char ();
- l += mp_stream->get_line ();
- }
-
- tl::Extractor ex (l.c_str ());
- if (ex.test_without_case (".include") || ex.test_without_case (".inc")) {
-
- std::string path;
- ex.read_word_or_quoted (path, allowed_name_chars);
-
- push_stream (path);
-
- l.clear ();
-
- } else if (ex.at_end () || ex.test ("*")) {
- l.clear ();
- }
-
- } while (l.empty ());
-
- return l;
-}
-
-void NetlistSpiceReader::unget_line (const std::string &l)
-{
- m_stored_line = l;
+ return lp.first;
}
bool NetlistSpiceReader::subcircuit_captured (const std::string &nc_name)
@@ -928,7 +1015,7 @@ void NetlistSpiceReader::error (const std::string &msg)
void NetlistSpiceReader::warn (const std::string &msg)
{
- std::string fmt_msg = tl::sprintf ("%s in %s, line %d", msg, mp_stream->source (), mp_stream->line_number () - 1);
+ std::string fmt_msg = tl::sprintf ("%s in %s, line %d", msg, m_stream.source (), m_stream.line_number ());
tl::warn << fmt_msg;
}
diff --git a/src/db/db/dbNetlistSpiceReader.h b/src/db/db/dbNetlistSpiceReader.h
index 24dd6f111..394b45a69 100644
--- a/src/db/db/dbNetlistSpiceReader.h
+++ b/src/db/db/dbNetlistSpiceReader.h
@@ -31,6 +31,7 @@
#include
#include
- bjt3(name)
+- bjt3(name, class)
Use this class with extract_devices to specify extraction of a
@@ -120,6 +121,7 @@ about this extractor.
Usage:
- bjt4(name)
+- bjt4(name, class)
Use this class with extract_devices to specify extraction of a
@@ -143,6 +145,7 @@ This function creates a box object. The arguments are the same than for the
Usage:
- capacitor(name, area_cap)
+- capacitor(name, area_cap, class)
Use this class with extract_devices to specify extraction of a capacitor.
@@ -156,6 +159,7 @@ about this extractor.
Usage:
- capacitor_with_bulk(name, area_cap)
+- capacitor_with_bulk(name, area_cap, class)
Use this class with extract_devices to specify extraction of a capacitor
@@ -442,6 +446,7 @@ See Netter#device_scaling
Usage:
- diode(name)
+- diode(name, class)
Use this class with extract_devices to specify extraction of a
@@ -455,6 +460,7 @@ about this extractor.
Usage:
- dmos3(name)
+- dmos3(name, class)
Use this class with extract_devices to specify extraction of a
@@ -470,6 +476,7 @@ about this extractor (strict mode applies for 'dmos3').
Usage:
- dmos4(name)
+- dmos4(name, class)
Use this class with extract_devices to specify extraction of a
@@ -1054,6 +1061,7 @@ argument, "middle" represents the bounding box center marker generator on primar
Usage:
- mos3(name)
+- mos3(name, class)
Use this class with extract_devices to specify extraction of a
@@ -1067,6 +1075,7 @@ about this extractor (non-strict mode applies for 'mos3').
Usage:
- mos4(name)
+- mos4(name, class)
Use this class with extract_devices to specify extraction of a
@@ -1402,6 +1411,7 @@ version of the L2N DB format will be used.
Usage:
- resistor(name, sheet_rho)
+- resistor(name, sheet_rho, class)
Use this class with extract_devices to specify extraction of a resistor.
@@ -1417,6 +1427,7 @@ about this extractor.
Usage:
- resistor_with_bulk(name, sheet_rho)
+- resistor_with_bulk(name, sheet_rho, class)
Use this class with extract_devices to specify extraction of a resistor
@@ -1922,6 +1933,7 @@ shape.
Usage:
- write_spice([ use_net_names [, with_comments ] ])
+- write_spice(writer_delegate [, use_net_names [, with_comments ] ])
Use this option in target_netlist for the format parameter to
@@ -1929,5 +1941,8 @@ specify SPICE format.
"use_net_names" and "with_comments" are boolean parameters indicating
whether to use named nets (numbers if false) and whether to add
information comments such as instance coordinates or pin names.
+
+"writer_delegate" allows using a NetlistSpiceWriterDelegate object to
+control the actual writing.
diff --git a/src/lay/lay/doc/about/drc_ref_netter.xml b/src/lay/lay/doc/about/drc_ref_netter.xml
index 8e8cf429d..999473569 100644
--- a/src/lay/lay/doc/about/drc_ref_netter.xml
+++ b/src/lay/lay/doc/about/drc_ref_netter.xml
@@ -386,6 +386,9 @@ gate = nactive & poly # gate area
extract_devices(mos4("NMOS4"), { :SD => nsd, :G => gate, :P => poly, :W => bulk })
+
+The return value of this method will be the device class of the devices
+generated in the extraction step (see DeviceClass).
"l2n_data" - Gets the internal LayoutToNetlist object
diff --git a/src/lay/lay/doc/manual/lvs_device_extractors.xml b/src/lay/lay/doc/manual/lvs_device_extractors.xml
index b6fdbe30a..7cf6449e2 100644
--- a/src/lay/lay/doc/manual/lvs_device_extractors.xml
+++ b/src/lay/lay/doc/manual/lvs_device_extractors.xml
@@ -3,9 +3,9 @@
- LVS Devices Extractors
+ LVS Device Extractors
-
+
@@ -345,5 +345,64 @@ extract_devices(bjt3(model_name), { "C" => collector, "B" => base, "E" => emitte
+ Device extractors and device classes
+
+
+ "extract_devices" will return the DeviceClass object of the devices generated.
+ This object can be useful to apply some basic modifications.
+ The most important of them is enabling or disabling certain parameters.
+
+
+
+ Most device extractors extract more parameters than they give you by default.
+ For example, the resistor extractor will not just extract the resistance, but also the length (L)
+ and width (W) of the resistor stripe and its area (A) and perimeter (P).
+ By default these additional parameters are declared "secondary" - i.e. they will not
+ participate in the device compare and will not be netlisted.
+
+
+
+ Parameters can be fully enabled by using "enable_parameter" on the device class.
+ Hence it is possible to enable "W" and "L" on a resistor type using the following code:
+
+
+ dc = extract_devices(resistor("RES", 1), ...)
+dc.enable_parameter("W", true)
+dc.enable_parameter("L", true)
+
+
+
+ This will modify the parameters of the generated device class such that "W" and "L" are
+ fully enabled parameters.
+
+
+
+ Another way of customizing the built-in device extractors is to
+ supply a custom device class. The following code creates a new
+ resistor class which changes the preconfigured device parameter definitions
+ to enable "W" and "L".
+
+
+ class MyResistor < RBA::DeviceClassResistor
+ def initialize
+ super
+ enable_parameter("W", true)
+ enable_parameter("L", true)
+ end
+end
+
+...
+
+extract_devices(resistor("RES", 1, MyResistor), ...)
+
+
+
+ The effect of this code is the same than the first one, but using a custom
+ device class opens the option to supply additional parameters for example
+ or to implement some entirely new device while using the extraction
+ mechanics of the resistor extractor. The only requirement is compatibility of
+ the parameter and terminal definitions.
+
+
diff --git a/src/laybasic/laybasic/layNetlistBrowserModel.cc b/src/laybasic/laybasic/layNetlistBrowserModel.cc
index 5def404a6..e5e8daf3d 100644
--- a/src/laybasic/laybasic/layNetlistBrowserModel.cc
+++ b/src/laybasic/laybasic/layNetlistBrowserModel.cc
@@ -25,6 +25,7 @@
#include "layIndexedNetlistModel.h"
#include "layNetlistCrossReferenceModel.h"
#include "dbNetlistDeviceClasses.h"
+#include "tlMath.h"
#include
#include
@@ -324,7 +325,8 @@ std::string device_parameter_string (const db::Device *device)
bool first = true;
const std::vector &pd = device->device_class ()->parameter_definitions ();
for (std::vector::const_iterator p = pd.begin (); p != pd.end (); ++p) {
- if (p->is_primary ()) {
+ double v = device->parameter_value (p->id ());
+ if (! tl::equal (v, p->default_value ())) {
if (first) {
s += " [";
first = false;
@@ -333,7 +335,7 @@ std::string device_parameter_string (const db::Device *device)
}
s += p->name ();
s += "=";
- s += formatted_value (device->parameter_value (p->id ()));
+ s += formatted_value (v);
}
}
if (! first) {
diff --git a/src/laybasic/unit_tests/layNetlistBrowserModelTests.cc b/src/laybasic/unit_tests/layNetlistBrowserModelTests.cc
index 57599b8af..f155df235 100644
--- a/src/laybasic/unit_tests/layNetlistBrowserModelTests.cc
+++ b/src/laybasic/unit_tests/layNetlistBrowserModelTests.cc
@@ -320,7 +320,7 @@ TEST (2)
// INV2, net 1 has one pin and one terminal at BULK
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2Net0Index), Qt::UserRole).toString ()), "B|B|PMOS|PMOS|$1|$1");
- EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2Net0Index), Qt::DisplayRole).toString ()), "B / PMOS [L=0.25, W=3.5]");
+ EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2Net0Index), Qt::DisplayRole).toString ()), "B / PMOS [L=0.25, W=3.5, AS=1.4, AD=1.4, PS=6.85, PD=6.85]");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, inv2Net0Index), Qt::DisplayRole).toString ()), "$1");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 3, inv2Net0Index), Qt::DisplayRole).toString ()), "$1");
@@ -356,8 +356,8 @@ TEST (2)
// first of devices in INV2 circuit
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_devices), Qt::UserRole).toString ()), "$1|$1|PMOS|PMOS");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_devices), Qt::DisplayRole).toString ()), "PMOS");
- EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, sn_devices), Qt::DisplayRole).toString ()), "$1 / PMOS [L=0.25, W=3.5]");
- EXPECT_EQ (tl::to_string (model->data (model->index (0, 3, sn_devices), Qt::DisplayRole).toString ()), "$1 / PMOS [L=0.25, W=3.5]");
+ EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, sn_devices), Qt::DisplayRole).toString ()), "$1 / PMOS [L=0.25, W=3.5, AS=1.4, AD=1.4, PS=6.85, PD=6.85]");
+ EXPECT_EQ (tl::to_string (model->data (model->index (0, 3, sn_devices), Qt::DisplayRole).toString ()), "$1 / PMOS [L=0.25, W=3.5, AS=1.4, AD=1.4, PS=6.85, PD=6.85]");
QModelIndex inv2PairIndex = model->index (2, 0, QModelIndex ());
EXPECT_EQ (model->parent (inv2PairIndex).isValid (), false);
diff --git a/src/lvs/unit_tests/lvsSimpleTests.cc b/src/lvs/unit_tests/lvsSimpleTests.cc
index d6fdec334..c3dbe3ef1 100644
--- a/src/lvs/unit_tests/lvsSimpleTests.cc
+++ b/src/lvs/unit_tests/lvsSimpleTests.cc
@@ -221,7 +221,6 @@ TEST(23_issue709)
run_test (_this, "empty_subcells", "empty_subcells.gds");
}
-// empty gds
TEST(24_issue806)
{
run_test (_this, "custom_compare", "custom_compare.gds");
@@ -234,4 +233,10 @@ TEST(25_blackbox)
run_test (_this, "blackbox3", "blackbox_open.gds");
run_test (_this, "blackbox4", "blackbox_short.gds");
run_test (_this, "blackbox5", "blackbox_short_and_open.gds");
+
+TEST(26_enableWandL)
+{
+ run_test (_this, "enable_wl1", "resistor.gds");
+ run_test (_this, "enable_wl2", "resistor.gds");
+ run_test (_this, "enable_wl3", "resistor.gds");
}
diff --git a/src/tl/tl/tlMath.h b/src/tl/tl/tlMath.h
index 0b174fc35..7a93726ba 100644
--- a/src/tl/tl/tlMath.h
+++ b/src/tl/tl/tlMath.h
@@ -35,7 +35,7 @@ namespace tl
* @brief A generic less operator
*/
template
-bool less (T a, T b)
+inline bool less (T a, T b)
{
return a < b;
}
@@ -44,7 +44,7 @@ bool less (T a, T b)
* @brief A generic equal operator
*/
template
-bool equal (T a, T b)
+inline bool equal (T a, T b)
{
return a == b;
}
@@ -53,7 +53,7 @@ bool equal (T a, T b)
* @brief A generalization of the modulo operator
*/
template
-T modulo (T a, T b)
+inline T modulo (T a, T b)
{
return a % b;
}
@@ -68,7 +68,7 @@ const double epsilon = 1e-10;
/**
* @brief A specialization for double values
*/
-bool less (double a, double b)
+inline bool less (double a, double b)
{
return a < b - tl::epsilon;
}
@@ -76,7 +76,7 @@ bool less (double a, double b)
/**
* @brief A specialization for double values
*/
-bool equal (double a, double b)
+inline bool equal (double a, double b)
{
return fabs (a - b) < tl::epsilon;
}
@@ -85,7 +85,7 @@ bool equal (double a, double b)
* @brief A specialization of the modulo operator for doubles
* a % b == a - b * floor (a / b)
*/
-double modulo (double a, double b)
+inline double modulo (double a, double b)
{
return a - b * floor (a / b + tl::epsilon);
}
@@ -94,6 +94,7 @@ double modulo (double a, double b)
* @brief Compute the greatest common divider of two numbers using the euclidian method
*/
template
+inline
T gcd (T a, T b)
{
while (! equal (b, T (0))) {
@@ -108,6 +109,7 @@ T gcd (T a, T b)
* @brief Compute the lowest common multiple of two numbers using the euclidian method
*/
template
+inline
T lcm (T a, T b)
{
return a * (b / gcd (a, b));
@@ -116,7 +118,7 @@ T lcm (T a, T b)
/**
* @brief Rounding down to the closest multiple of g
*/
-double round_down (double x, double g)
+inline double round_down (double x, double g)
{
return g * floor (x / g + tl::epsilon);
}
@@ -124,7 +126,7 @@ double round_down (double x, double g)
/**
* @brief Rounding up to the closest multiple of g
*/
-double round_up (double x, double g)
+inline double round_up (double x, double g)
{
return g * ceil (x / g - tl::epsilon);
}
@@ -133,7 +135,7 @@ double round_up (double x, double g)
* @brief Rounding to the closest multiple of g
* A value of (n+1/2)*g is rounded down.
*/
-double round (double x, double g)
+inline double round (double x, double g)
{
return g * floor (0.5 + x / g - tl::epsilon);
}
diff --git a/testdata/algo/nreader14.cir b/testdata/algo/nreader14.cir
new file mode 100644
index 000000000..20a308b46
--- /dev/null
+++ b/testdata/algo/nreader14.cir
@@ -0,0 +1,3 @@
+
+.include "nreader14a.cir"
+
diff --git a/testdata/algo/nreader14a.cir b/testdata/algo/nreader14a.cir
new file mode 100644
index 000000000..08414862b
--- /dev/null
+++ b/testdata/algo/nreader14a.cir
@@ -0,0 +1,4 @@
+.subckt INVX1 1 2 3 4 5 6
+ .include nreader14x.cir
+.ends
+
diff --git a/testdata/algo/nreader14x.cir b/testdata/algo/nreader14x.cir
new file mode 100644
index 000000000..74e02ef7f
--- /dev/null
+++ b/testdata/algo/nreader14x.cir
@@ -0,0 +1,4 @@
+m$1 1 5 2 4 mlvpmos w=1.5um l=0.25um
+m$2 3 5 2 6 mlvnmos w=0.95um l=0.25um
+m1 1 *an error
+
diff --git a/testdata/algo/nreader15.cir b/testdata/algo/nreader15.cir
new file mode 100644
index 000000000..3ff574f5e
--- /dev/null
+++ b/testdata/algo/nreader15.cir
@@ -0,0 +1,18 @@
+.SUBCKT SUBCKT
+ + \$1 A[5]<1> V42\x28\x25\x29 Z gnd gnd$1
+* device instance $1 r0 *1 0,0 HVPMOS
+XD_$1 V42\x28\x25\x29 \$3 Z \$1
+ + HVPMOS PARAMS: L=0.2 W=1 AS=0.18 AD=0.18
+ + PS=2.16 PD=2.16
+XD_$2
+ + V42\x28\x25\x29 A[5]<1> \$3 \$1
+ + HVPMOS PARAMS: L=0.2 W=1 AS=0.18 AD=0.18
+ + PS=2.16 PD=2.16
+XD_$3 gnd \$3 gnd gnd$1 HVNMOS PARAMS: L=1.13 W=2.12 PS=6 PD=6 AS=0 AD=0
+ +
+
+XD_$4 gnd \$3 Z gnd$1 HVNMOS PARAMS: L=0.4 W=0.4 PS=1.16 PD=1.16 AS=0.19 AD=0.19
+XD_$5 gnd A[5]<1> \$3 gnd$1 HVNMOS
+ + PARAMS: L=0.4 W=0.4 PS=1.76 PD=1.76 AS=0.19 AD=0.19
+
+.ENDS SUBCKT
diff --git a/testdata/lvs/custom_compare.lvsdb b/testdata/lvs/custom_compare.lvsdb
index c54b0fb98..69358e767 100644
--- a/testdata/lvs/custom_compare.lvsdb
+++ b/testdata/lvs/custom_compare.lvsdb
@@ -53,8 +53,8 @@ layout(
device(1 D$RES
location(7520 4175)
param(R 51)
- param(L 25.5)
- param(W 0.5)
+ param(L 12.75)
+ param(W 0.25)
param(A 3.1875)
param(P 26)
terminal(A 2)
diff --git a/testdata/lvs/enable_wl1.cir b/testdata/lvs/enable_wl1.cir
new file mode 100644
index 000000000..2dbc8c321
--- /dev/null
+++ b/testdata/lvs/enable_wl1.cir
@@ -0,0 +1,11 @@
+* Extracted by KLayout
+
+* cell Rre
+* pin gnd!
+* pin vdd!
+.SUBCKT Rre 1 2
+* net 1 gnd!
+* net 2 vdd!
+* device instance $1 r0 *1 8.43,1.51 RR1
+R$1 1 2 RR1 10 W=0.6 L=6
+.ENDS Rre
diff --git a/testdata/lvs/enable_wl1.lvs b/testdata/lvs/enable_wl1.lvs
new file mode 100644
index 000000000..a58903723
--- /dev/null
+++ b/testdata/lvs/enable_wl1.lvs
@@ -0,0 +1,52 @@
+
+# test spice writer delegate on this occasion
+class MyWriterDelegate < RBA::NetlistSpiceWriterDelegate
+ def write_device(device)
+ if device.device_class.name == "RR1"
+ line = "R"
+ line += format_name(device.expanded_name)
+ line += " "
+ line += net_to_string(device.net_for_terminal("A"))
+ line += " "
+ line += net_to_string(device.net_for_terminal("B"))
+ line += " "
+ line += format_name(device.device_class.name)
+ line += " "
+ line += "%.12g" % device.parameter("R")
+ line += " W="
+ line += "%.12g" % device.parameter("W")
+ line += " L="
+ line += "%.12g" % device.parameter("L")
+ emit_line(line)
+ else
+ super
+ end
+ end
+end
+
+source($lvs_test_source)
+report_lvs($lvs_test_target_lvsdb, true)
+target_netlist($lvs_test_target_cir, write_spice(MyWriterDelegate::new), "Extracted by KLayout")
+
+schematic("resistor.cir")
+
+deep
+
+contact = input(15, 0)
+metal1 = input(16, 0)
+metal1_ver = input(16, 5)
+metal1_lbl = labels(16, 3)
+res = metal1 & metal1_ver
+metal1_not_res = metal1 - metal1_ver
+
+dc = extract_devices(resistor("RR1", 1), { "R" => res , "C" => metal1_not_res})
+dc.enable_parameter("W", true)
+dc.enable_parameter("L", true)
+
+connect(contact, metal1_not_res)
+connect(metal1_not_res, metal1_lbl)
+
+align
+netlist.simplify
+compare
+
diff --git a/testdata/lvs/enable_wl1.lvsdb b/testdata/lvs/enable_wl1.lvsdb
new file mode 100644
index 000000000..67695b612
--- /dev/null
+++ b/testdata/lvs/enable_wl1.lvsdb
@@ -0,0 +1,118 @@
+#%lvsdb-klayout
+
+# Layout
+layout(
+ top(Rre)
+ unit(0.001)
+
+ # Layer section
+ # This section lists the mask layers (drawing or derived) and their connections.
+
+ # Mask layers
+ layer(l3 '15/0')
+ layer(l4 '16/3')
+ layer(l1)
+
+ # Mask layer connectivity
+ connect(l3 l3 l1)
+ connect(l4 l1)
+ connect(l1 l3 l4 l1)
+
+ # Device class section
+ class(RR1 RES
+ param(L 1 0)
+ param(W 1 0)
+ )
+
+ # Device abstracts section
+ # Device abstracts list the pin shapes of the devices.
+ device(D$RR1 RR1
+ terminal(A
+ rect(l1 (-3160 -300) (160 600))
+ )
+ terminal(B
+ rect(l1 (3000 -300) (160 600))
+ )
+ )
+
+ # Circuit section
+ # Circuits are the hierarchical building blocks of the netlist.
+ circuit(Rre
+
+ # Circuit boundary
+ rect((5270 1210) (6320 600))
+
+ # Nets with their geometries
+ net(1 name('gnd!')
+ rect(l3 (5295 1230) (120 560))
+ text(l4 'gnd!' (-60 -60))
+ rect(l1 (-70 -505) (125 570))
+ rect(l1 (-140 -585) (160 600))
+ )
+ net(2 name('vdd!')
+ rect(l3 (11455 1240) (120 540))
+ text(l4 'vdd!' (-65 -60))
+ rect(l1 (-65 -495) (125 560))
+ rect(l1 (-140 -575) (160 600))
+ )
+
+ # Outgoing pins and their connections to nets
+ pin(1 name('gnd!'))
+ pin(2 name('vdd!'))
+
+ # Devices and their connections
+ device(1 D$RR1
+ location(8430 1510)
+ param(R 10)
+ param(L 6)
+ param(W 0.6)
+ param(A 3.6)
+ param(P 13.2)
+ terminal(A 1)
+ terminal(B 2)
+ )
+
+ )
+)
+
+# Reference netlist
+reference(
+
+ # Device class section
+ class(RR1 RES)
+
+ # Circuit section
+ # Circuits are the hierarchical building blocks of the netlist.
+ circuit(RRE
+
+ # Nets
+ net(1 name('VDD!'))
+ net(2 name('GND!'))
+
+ # Devices and their connections
+ device(1 RR1
+ name(R0)
+ param(R 10)
+ param(L 6)
+ param(W 0.6)
+ param(A 0)
+ param(P 0)
+ terminal(A 1)
+ terminal(B 2)
+ )
+
+ )
+)
+
+# Cross reference
+xref(
+ circuit(Rre RRE match
+ xref(
+ net(1 2 match)
+ net(2 1 match)
+ pin(0 () match)
+ pin(1 () match)
+ device(1 1 match)
+ )
+ )
+)
diff --git a/testdata/lvs/enable_wl2.cir b/testdata/lvs/enable_wl2.cir
new file mode 100644
index 000000000..d668c488e
--- /dev/null
+++ b/testdata/lvs/enable_wl2.cir
@@ -0,0 +1,11 @@
+* Extracted by KLayout
+
+* cell Rre
+* pin gnd!
+* pin vdd!
+.SUBCKT Rre 1 2
+* net 1 gnd!
+* net 2 vdd!
+* device instance $1 r0 *1 8.43,1.51 RR1
+R$1 1 2 10 RR1 L=6U W=0.6U
+.ENDS Rre
diff --git a/testdata/lvs/enable_wl2.lvs b/testdata/lvs/enable_wl2.lvs
new file mode 100644
index 000000000..945a89294
--- /dev/null
+++ b/testdata/lvs/enable_wl2.lvs
@@ -0,0 +1,33 @@
+
+source($lvs_test_source)
+report_lvs($lvs_test_target_lvsdb, true)
+target_netlist($lvs_test_target_cir, write_spice, "Extracted by KLayout")
+
+schematic("resistor.cir")
+
+deep
+
+contact = input(15, 0)
+metal1 = input(16, 0)
+metal1_ver = input(16, 5)
+metal1_lbl = labels(16, 3)
+res = metal1 & metal1_ver
+metal1_not_res = metal1 - metal1_ver
+
+class MyResistorClass < RBA::DeviceClassResistor
+ def initialize
+ super
+ enable_parameter("W", true)
+ enable_parameter("L", true)
+ end
+end
+
+extract_devices(resistor("RR1", 1, MyResistorClass), { "R" => res , "C" => metal1_not_res})
+
+connect(contact, metal1_not_res)
+connect(metal1_not_res, metal1_lbl)
+
+align
+netlist.simplify
+compare
+
diff --git a/testdata/lvs/enable_wl2.lvsdb b/testdata/lvs/enable_wl2.lvsdb
new file mode 100644
index 000000000..67695b612
--- /dev/null
+++ b/testdata/lvs/enable_wl2.lvsdb
@@ -0,0 +1,118 @@
+#%lvsdb-klayout
+
+# Layout
+layout(
+ top(Rre)
+ unit(0.001)
+
+ # Layer section
+ # This section lists the mask layers (drawing or derived) and their connections.
+
+ # Mask layers
+ layer(l3 '15/0')
+ layer(l4 '16/3')
+ layer(l1)
+
+ # Mask layer connectivity
+ connect(l3 l3 l1)
+ connect(l4 l1)
+ connect(l1 l3 l4 l1)
+
+ # Device class section
+ class(RR1 RES
+ param(L 1 0)
+ param(W 1 0)
+ )
+
+ # Device abstracts section
+ # Device abstracts list the pin shapes of the devices.
+ device(D$RR1 RR1
+ terminal(A
+ rect(l1 (-3160 -300) (160 600))
+ )
+ terminal(B
+ rect(l1 (3000 -300) (160 600))
+ )
+ )
+
+ # Circuit section
+ # Circuits are the hierarchical building blocks of the netlist.
+ circuit(Rre
+
+ # Circuit boundary
+ rect((5270 1210) (6320 600))
+
+ # Nets with their geometries
+ net(1 name('gnd!')
+ rect(l3 (5295 1230) (120 560))
+ text(l4 'gnd!' (-60 -60))
+ rect(l1 (-70 -505) (125 570))
+ rect(l1 (-140 -585) (160 600))
+ )
+ net(2 name('vdd!')
+ rect(l3 (11455 1240) (120 540))
+ text(l4 'vdd!' (-65 -60))
+ rect(l1 (-65 -495) (125 560))
+ rect(l1 (-140 -575) (160 600))
+ )
+
+ # Outgoing pins and their connections to nets
+ pin(1 name('gnd!'))
+ pin(2 name('vdd!'))
+
+ # Devices and their connections
+ device(1 D$RR1
+ location(8430 1510)
+ param(R 10)
+ param(L 6)
+ param(W 0.6)
+ param(A 3.6)
+ param(P 13.2)
+ terminal(A 1)
+ terminal(B 2)
+ )
+
+ )
+)
+
+# Reference netlist
+reference(
+
+ # Device class section
+ class(RR1 RES)
+
+ # Circuit section
+ # Circuits are the hierarchical building blocks of the netlist.
+ circuit(RRE
+
+ # Nets
+ net(1 name('VDD!'))
+ net(2 name('GND!'))
+
+ # Devices and their connections
+ device(1 RR1
+ name(R0)
+ param(R 10)
+ param(L 6)
+ param(W 0.6)
+ param(A 0)
+ param(P 0)
+ terminal(A 1)
+ terminal(B 2)
+ )
+
+ )
+)
+
+# Cross reference
+xref(
+ circuit(Rre RRE match
+ xref(
+ net(1 2 match)
+ net(2 1 match)
+ pin(0 () match)
+ pin(1 () match)
+ device(1 1 match)
+ )
+ )
+)
diff --git a/testdata/lvs/enable_wl3.cir b/testdata/lvs/enable_wl3.cir
new file mode 100644
index 000000000..d668c488e
--- /dev/null
+++ b/testdata/lvs/enable_wl3.cir
@@ -0,0 +1,11 @@
+* Extracted by KLayout
+
+* cell Rre
+* pin gnd!
+* pin vdd!
+.SUBCKT Rre 1 2
+* net 1 gnd!
+* net 2 vdd!
+* device instance $1 r0 *1 8.43,1.51 RR1
+R$1 1 2 10 RR1 L=6U W=0.6U
+.ENDS Rre
diff --git a/testdata/lvs/enable_wl3.lvs b/testdata/lvs/enable_wl3.lvs
new file mode 100644
index 000000000..8f5405307
--- /dev/null
+++ b/testdata/lvs/enable_wl3.lvs
@@ -0,0 +1,33 @@
+
+source($lvs_test_source)
+report_lvs($lvs_test_target_lvsdb, true)
+target_netlist($lvs_test_target_cir, write_spice, "Extracted by KLayout")
+
+schematic("resistor2.cir")
+
+deep
+
+contact = input(15, 0)
+metal1 = input(16, 0)
+metal1_ver = input(16, 5)
+metal1_lbl = labels(16, 3)
+res = metal1 & metal1_ver
+metal1_not_res = metal1 - metal1_ver
+
+class MyResistorClass < RBA::DeviceClassResistor
+ def initialize
+ super
+ enable_parameter("W", true)
+ enable_parameter("L", true)
+ end
+end
+
+extract_devices(resistor("RR1", 1, MyResistorClass), { "R" => res , "C" => metal1_not_res})
+
+connect(contact, metal1_not_res)
+connect(metal1_not_res, metal1_lbl)
+
+align
+netlist.simplify
+compare
+
diff --git a/testdata/lvs/enable_wl3.lvsdb b/testdata/lvs/enable_wl3.lvsdb
new file mode 100644
index 000000000..947fc54ac
--- /dev/null
+++ b/testdata/lvs/enable_wl3.lvsdb
@@ -0,0 +1,121 @@
+#%lvsdb-klayout
+
+# Layout
+layout(
+ top(Rre)
+ unit(0.001)
+
+ # Layer section
+ # This section lists the mask layers (drawing or derived) and their connections.
+
+ # Mask layers
+ layer(l3 '15/0')
+ layer(l4 '16/3')
+ layer(l1)
+
+ # Mask layer connectivity
+ connect(l3 l3 l1)
+ connect(l4 l1)
+ connect(l1 l3 l4 l1)
+
+ # Device class section
+ class(RR1 RES
+ param(L 1 0)
+ param(W 1 0)
+ )
+
+ # Device abstracts section
+ # Device abstracts list the pin shapes of the devices.
+ device(D$RR1 RR1
+ terminal(A
+ rect(l1 (-3160 -300) (160 600))
+ )
+ terminal(B
+ rect(l1 (3000 -300) (160 600))
+ )
+ )
+
+ # Circuit section
+ # Circuits are the hierarchical building blocks of the netlist.
+ circuit(Rre
+
+ # Circuit boundary
+ rect((5270 1210) (6320 600))
+
+ # Nets with their geometries
+ net(1 name('gnd!')
+ rect(l3 (5295 1230) (120 560))
+ text(l4 'gnd!' (-60 -60))
+ rect(l1 (-70 -505) (125 570))
+ rect(l1 (-140 -585) (160 600))
+ )
+ net(2 name('vdd!')
+ rect(l3 (11455 1240) (120 540))
+ text(l4 'vdd!' (-65 -60))
+ rect(l1 (-65 -495) (125 560))
+ rect(l1 (-140 -575) (160 600))
+ )
+
+ # Outgoing pins and their connections to nets
+ pin(1 name('gnd!'))
+ pin(2 name('vdd!'))
+
+ # Devices and their connections
+ device(1 D$RR1
+ location(8430 1510)
+ param(R 10)
+ param(L 6)
+ param(W 0.6)
+ param(A 3.6)
+ param(P 13.2)
+ terminal(A 1)
+ terminal(B 2)
+ )
+
+ )
+)
+
+# Reference netlist
+reference(
+
+ # Device class section
+ class(RR1 RES)
+
+ # Circuit section
+ # Circuits are the hierarchical building blocks of the netlist.
+ circuit(RRE
+
+ # Nets
+ net(1 name('VDD!'))
+ net(2 name('GND!'))
+
+ # Devices and their connections
+ device(1 RR1
+ name(R0)
+ param(R 10)
+ param(L 7)
+ param(W 0.6)
+ param(A 0)
+ param(P 0)
+ terminal(A 1)
+ terminal(B 2)
+ )
+
+ )
+)
+
+# Cross reference
+xref(
+ circuit(Rre RRE nomatch
+ xref(
+ net(() 2 mismatch)
+ net(() 1 mismatch)
+ net(1 () mismatch)
+ net(2 () mismatch)
+ pin(0 () match)
+ pin(1 () match)
+ device(() 1 mismatch)
+ device(1 () mismatch)
+ )
+ )
+)
diff --git a/testdata/lvs/resistor.cir b/testdata/lvs/resistor.cir
new file mode 100644
index 000000000..c210ac37c
--- /dev/null
+++ b/testdata/lvs/resistor.cir
@@ -0,0 +1,4 @@
+.SUBCKT Rre
+RR0 vdd! gnd! 10 RR1 W=600n L=6u M=1
+.ENDS
+
diff --git a/testdata/lvs/resistor.gds b/testdata/lvs/resistor.gds
new file mode 100644
index 000000000..aa2b5869b
Binary files /dev/null and b/testdata/lvs/resistor.gds differ
diff --git a/testdata/lvs/resistor2.cir b/testdata/lvs/resistor2.cir
new file mode 100644
index 000000000..38882671e
--- /dev/null
+++ b/testdata/lvs/resistor2.cir
@@ -0,0 +1,4 @@
+.SUBCKT Rre
+RR0 vdd! gnd! 10 RR1 W=600n L=7u M=1
+.ENDS
+
diff --git a/testdata/ruby/dbNetlist.rb b/testdata/ruby/dbNetlist.rb
index 392c9a3e8..d5820f71f 100644
--- a/testdata/ruby/dbNetlist.rb
+++ b/testdata/ruby/dbNetlist.rb
@@ -136,13 +136,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
@@ -170,7 +170,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"
@@ -251,7 +251,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"
@@ -343,6 +343,8 @@ class DBNetlist_TestClass < TestBase
assert_equal(net.terminal_count, 1)
assert_equal(d1.net_for_terminal(1).name, "NET")
+ assert_equal(d1.net_for_terminal("B").name, "NET")
+ assert_equal(d1.net_for_terminal("X").inspect, "nil")
assert_equal(d1.net_for_terminal(0).inspect, "nil")
d1.disconnect_terminal("B")
@@ -586,11 +588,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")
@@ -781,7 +783,7 @@ class DBNetlist_TestClass < TestBase
nl = RBA::Netlist::new
- dc = RBA::GenericDeviceClass::new
+ dc = RBA::DeviceClass::new
dc.name = "DC"
nl.add(dc)
diff --git a/testdata/ruby/dbNetlistDeviceExtractors.rb b/testdata/ruby/dbNetlistDeviceExtractors.rb
index aed9b395d..74c372263 100644
--- a/testdata/ruby/dbNetlistDeviceExtractors.rb
+++ b/testdata/ruby/dbNetlistDeviceExtractors.rb
@@ -74,6 +74,118 @@ class DBNetlistExtractorTests_TestClass < TestBase
end
+ class MyClass < RBA::DeviceClass
+ end
+
+ class MyFactory < RBA::DeviceClassFactory
+ def create_class
+ MyClass.new
+ end
+ end
+
+ def test_3_Factory
+
+ ex = RBA::DeviceExtractorMOS3Transistor::new("myclass")
+ ex.test_initialize(RBA::Netlist::new)
+ assert_equal(ex.device_class.name, "myclass")
+ assert_equal(ex.device_class.class == MyClass, false)
+ assert_equal(ex.device_class.class == RBA::DeviceClassMOS3Transistor, true)
+
+ ex = RBA::DeviceExtractorMOS3Transistor::new("myclass", false, MyFactory.new)
+ ex.test_initialize(RBA::Netlist::new)
+ assert_equal(ex.device_class.name, "myclass")
+ assert_equal(ex.device_class.class == MyClass, true)
+
+ ex = RBA::DeviceExtractorMOS4Transistor::new("myclass")
+ ex.test_initialize(RBA::Netlist::new)
+ assert_equal(ex.device_class.name, "myclass")
+ assert_equal(ex.device_class.class == MyClass, false)
+ assert_equal(ex.device_class.class == RBA::DeviceClassMOS4Transistor, true)
+
+ ex = RBA::DeviceExtractorMOS4Transistor::new("myclass", false, MyFactory.new)
+ ex.test_initialize(RBA::Netlist::new)
+ assert_equal(ex.device_class.name, "myclass")
+ assert_equal(ex.device_class.class == MyClass, true)
+
+ ex = RBA::DeviceExtractorBJT3Transistor::new("myclass")
+ ex.test_initialize(RBA::Netlist::new)
+ assert_equal(ex.device_class.name, "myclass")
+ assert_equal(ex.device_class.class == MyClass, false)
+ assert_equal(ex.device_class.class == RBA::DeviceClassBJT3Transistor, true)
+
+ ex = RBA::DeviceExtractorBJT3Transistor::new("myclass", MyFactory.new)
+ ex.test_initialize(RBA::Netlist::new)
+ assert_equal(ex.device_class.name, "myclass")
+ assert_equal(ex.device_class.class == MyClass, true)
+
+ ex = RBA::DeviceExtractorBJT4Transistor::new("myclass")
+ ex.test_initialize(RBA::Netlist::new)
+ assert_equal(ex.device_class.name, "myclass")
+ assert_equal(ex.device_class.class == MyClass, false)
+ assert_equal(ex.device_class.class == RBA::DeviceClassBJT4Transistor, true)
+
+ ex = RBA::DeviceExtractorBJT4Transistor::new("myclass", MyFactory.new)
+ ex.test_initialize(RBA::Netlist::new)
+ assert_equal(ex.device_class.name, "myclass")
+ assert_equal(ex.device_class.class == MyClass, true)
+
+ ex = RBA::DeviceExtractorDiode::new("myclass")
+ ex.test_initialize(RBA::Netlist::new)
+ assert_equal(ex.device_class.name, "myclass")
+ assert_equal(ex.device_class.class == MyClass, false)
+ assert_equal(ex.device_class.class == RBA::DeviceClassDiode, true)
+
+ ex = RBA::DeviceExtractorDiode::new("myclass", MyFactory.new)
+ ex.test_initialize(RBA::Netlist::new)
+ assert_equal(ex.device_class.name, "myclass")
+ assert_equal(ex.device_class.class == MyClass, true)
+
+ ex = RBA::DeviceExtractorResistor::new("myclass", 1.0)
+ ex.test_initialize(RBA::Netlist::new)
+ assert_equal(ex.device_class.name, "myclass")
+ assert_equal(ex.device_class.class == MyClass, false)
+ assert_equal(ex.device_class.class == RBA::DeviceClassResistor, true)
+
+ ex = RBA::DeviceExtractorResistor::new("myclass", 1.0, MyFactory.new)
+ ex.test_initialize(RBA::Netlist::new)
+ assert_equal(ex.device_class.name, "myclass")
+ assert_equal(ex.device_class.class == MyClass, true)
+
+ ex = RBA::DeviceExtractorResistorWithBulk::new("myclass", 1.0)
+ ex.test_initialize(RBA::Netlist::new)
+ assert_equal(ex.device_class.name, "myclass")
+ assert_equal(ex.device_class.class == MyClass, false)
+ assert_equal(ex.device_class.class == RBA::DeviceClassResistorWithBulk, true)
+
+ ex = RBA::DeviceExtractorResistorWithBulk::new("myclass", 1.0, MyFactory.new)
+ ex.test_initialize(RBA::Netlist::new)
+ assert_equal(ex.device_class.name, "myclass")
+ assert_equal(ex.device_class.class == MyClass, true)
+
+ ex = RBA::DeviceExtractorCapacitor::new("myclass", 1.0)
+ ex.test_initialize(RBA::Netlist::new)
+ assert_equal(ex.device_class.name, "myclass")
+ assert_equal(ex.device_class.class == MyClass, false)
+ assert_equal(ex.device_class.class == RBA::DeviceClassCapacitor, true)
+
+ ex = RBA::DeviceExtractorCapacitor::new("myclass", 1.0, MyFactory.new)
+ ex.test_initialize(RBA::Netlist::new)
+ assert_equal(ex.device_class.name, "myclass")
+ assert_equal(ex.device_class.class == MyClass, true)
+
+ ex = RBA::DeviceExtractorCapacitorWithBulk::new("myclass", 1.0)
+ ex.test_initialize(RBA::Netlist::new)
+ assert_equal(ex.device_class.name, "myclass")
+ assert_equal(ex.device_class.class == MyClass, false)
+ assert_equal(ex.device_class.class == RBA::DeviceClassCapacitorWithBulk, true)
+
+ ex = RBA::DeviceExtractorCapacitorWithBulk::new("myclass", 1.0, MyFactory.new)
+ ex.test_initialize(RBA::Netlist::new)
+ assert_equal(ex.device_class.name, "myclass")
+ assert_equal(ex.device_class.class == MyClass, true)
+
+ end
+
end
load("test_epilogue.rb")