Merge branch 'wip-lvs'

This commit is contained in:
Matthias Koefferlein 2021-07-06 23:40:44 +02:00
commit 4e54715d64
49 changed files with 2372 additions and 781 deletions

View File

@ -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<db::DeviceParameterDefinition> &pd = a.device_class ()->parameter_definitions ();
for (std::vector<db::DeviceParameterDefinition>::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<DeviceParameterCompareDelegate *> (other.mp_pc_delegate.get ()));
mp_device_combiner.reset (const_cast<DeviceCombiner *> (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<db::DeviceParameterDefinition> &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<db::DeviceParameterDefinition> &pd = a.device_class ()->parameter_definitions ();
for (std::vector<db::DeviceParameterDefinition>::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<db::DeviceParameterDefinition> &pd = a.device_class ()->parameter_definitions ();
for (std::vector<db::DeviceParameterDefinition>::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);
}
// --------------------------------------------------------------------------------

View File

@ -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<size_t, size_t>::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<db::DeviceParameterCompareDelegate> mp_pc_delegate;
tl::shared_ptr<db::DeviceCombiner> mp_device_combiner;
bool m_supports_parallel_combination;
bool m_supports_serial_combination;
std::map<size_t, size_t> m_equivalent_terminal_ids;
void set_netlist (db::Netlist *nl)
{

View File

@ -58,7 +58,7 @@ namespace db
* - connects the shapes of the layer with the given global
* nets [short key: G]
* circuit(<name> [circuit-def]) - circuit (cell) [short key: X]
* class(<name> <template>) - a device class definition (template: RES,CAP,...) [short key: K]
* class(<name> <template> [template-def]) - a device class definition (template: RES,CAP,...) [short key: K]
* device(<name> <class> [device-abstract-def])
* - device abstract [short key: D]
*
@ -127,8 +127,18 @@ namespace db
* (<x> <y>) - relative coordinates (reference is reset to 0,0
* for each net or terminal in device abstract)
*
* [template-def]:
*
* param(<name> <primary>? <default-value>*) - defines a template parameter [short key: E]
* ('primary' is a value: 0 or 1)
* terminal(<name>) - defines a terminal [short key: T]
*
* [device-abstract-def]:
*
* [device-abstract-terminal-def]*
*
* [device-abstract-terminal-def]:
*
* terminal(<terminal-name> [geometry-def]*)
* - specifies the terminal geometry [short key: T]
*

View File

@ -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);

View File

@ -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<Keys>::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 <class Keys>
void std_writer_impl<Keys>::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<DeviceParameterDefinition> &pd = cls->parameter_definitions ();
for (std::vector<DeviceParameterDefinition>::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<DeviceTerminalDefinition> &td = cls->terminal_definitions ();
for (std::vector<DeviceTerminalDefinition>::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 <class Keys>
void std_writer_impl<Keys>::write (bool nested, std::map<const db::Circuit *, std::map<const db::Net *, unsigned int> > *net2id_per_circuit)
{
@ -203,9 +245,13 @@ void std_writer_impl<Keys>::write (bool nested, std::map<const db::Circuit *, st
for (db::Netlist::const_device_class_iterator c = mp_netlist->begin_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<db::DeviceClass> 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 ()) {

View File

@ -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

View File

@ -30,7 +30,9 @@ namespace db
// The built-in device class templates
static tl::RegisteredClass<db::DeviceClassTemplateBase> dct_cap (new db::device_class_template<db::DeviceClassCapacitor> ("CAP"));
static tl::RegisteredClass<db::DeviceClassTemplateBase> dct_cap_with_bulk (new db::device_class_template<db::DeviceClassCapacitorWithBulk> ("CAP3"));
static tl::RegisteredClass<db::DeviceClassTemplateBase> dct_res (new db::device_class_template<db::DeviceClassResistor> ("RES"));
static tl::RegisteredClass<db::DeviceClassTemplateBase> dct_res_with_bulk (new db::device_class_template<db::DeviceClassResistorWithBulk> ("RES3"));
static tl::RegisteredClass<db::DeviceClassTemplateBase> dct_ind (new db::device_class_template<db::DeviceClassInductor> ("IND"));
static tl::RegisteredClass<db::DeviceClassTemplateBase> dct_diode (new db::device_class_template<db::DeviceClassDiode> ("DIODE"));
static tl::RegisteredClass<db::DeviceClassTemplateBase> dct_mos3 (new db::device_class_template<db::DeviceClassMOS3Transistor> ("MOS3"));
@ -41,58 +43,424 @@ static tl::RegisteredClass<db::DeviceClassTemplateBase> 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;
}
}

View File

@ -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;
};
}

View File

@ -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;
}

View File

@ -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<db::cell_index_type> *mp_breakout_cells;
double m_device_scaling;
db::Circuit *mp_circuit;
db::DeviceClass *mp_device_class;
tl::weak_ptr<db::DeviceClass> mp_device_class;
std::string m_name;
layer_definitions m_layer_definitions;
std::vector<unsigned int> 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<unsigned int> &layers, double device_scaling, const std::set<cell_index_type> *breakout_cells);
void push_new_devices (const Vector &disp_cache);
void push_cached_devices (const tl::vector<Device *> &cached_devices, const db::Vector &disp_cache, const db::Vector &new_disp);

View File

@ -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<DeviceClassMOS3Transistor> ()),
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<db
// ---------------------------------------------------------------------------------
// NetlistDeviceExtractorMOS4Transistor implementation
NetlistDeviceExtractorMOS4Transistor::NetlistDeviceExtractorMOS4Transistor (const std::string &name, bool strict)
: NetlistDeviceExtractorMOS3Transistor (name, strict)
NetlistDeviceExtractorMOS4Transistor::NetlistDeviceExtractorMOS4Transistor (const std::string &name, bool strict, db::DeviceClassFactory *factory)
: NetlistDeviceExtractorMOS3Transistor (name, strict, factory ? factory : new db::device_class_factory<db::DeviceClassMOS4Transistor> ())
{
// .. 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<db::DeviceClassResistor> ()), 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<unsigned int> &layers) const
@ -454,17 +454,17 @@ void NetlistDeviceExtractorResistor::extract_devices (const std::vector<db::Regi
db::Edges eperp = rres.edges ();
eperp &= contacts_per_res.edges ();
db::Coord length = eparallel.length ();
db::Coord width = eperp.length ();
db::Coord length2 = eparallel.length ();
db::Coord width2 = eperp.length ();
if (width < 1) {
if (width2 < 1) {
error (tl::to_string (tr ("Invalid contact geometry - resistor shape ignored")), *p);
continue;
}
device->set_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<db::Regi
// ---------------------------------------------------------------------------------
// NetlistDeviceExtractorResistorWithBulk implementation
NetlistDeviceExtractorResistorWithBulk::NetlistDeviceExtractorResistorWithBulk (const std::string &name, double sheet_rho)
: NetlistDeviceExtractorResistor (name, sheet_rho)
NetlistDeviceExtractorResistorWithBulk::NetlistDeviceExtractorResistorWithBulk (const std::string &name, double sheet_rho, db::DeviceClassFactory *factory)
: NetlistDeviceExtractorResistor (name, sheet_rho, factory ? factory : new db::device_class_factory<db::DeviceClassResistorWithBulk> ())
{
// .. 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<db::Region> & /*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<db::DeviceClassCapacitor> ()), 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<unsigned int> &layers) const
@ -596,8 +596,8 @@ void NetlistDeviceExtractorCapacitor::extract_devices (const std::vector<db::Reg
// ---------------------------------------------------------------------------------
// NetlistDeviceExtractorCapacitorWithBulk implementation
NetlistDeviceExtractorCapacitorWithBulk::NetlistDeviceExtractorCapacitorWithBulk (const std::string &name, double area_cap)
: NetlistDeviceExtractorCapacitor (name, area_cap)
NetlistDeviceExtractorCapacitorWithBulk::NetlistDeviceExtractorCapacitorWithBulk (const std::string &name, double area_cap, db::DeviceClassFactory *factory)
: NetlistDeviceExtractorCapacitor (name, area_cap, factory ? factory : new db::device_class_factory<db::DeviceClassCapacitorWithBulk> ())
{
// .. 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<db::Region> & /*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<db::DeviceClassBJT3Transistor> ())
{
// .. 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<unsigned int> &layers) const
@ -750,8 +750,8 @@ void NetlistDeviceExtractorBJT3Transistor::extract_devices (const std::vector<db
// ---------------------------------------------------------------------------------
// NetlistDeviceExtractorBJT4Transistor implementation
NetlistDeviceExtractorBJT4Transistor::NetlistDeviceExtractorBJT4Transistor (const std::string &name)
: NetlistDeviceExtractorBJT3Transistor (name)
NetlistDeviceExtractorBJT4Transistor::NetlistDeviceExtractorBJT4Transistor (const std::string &name, db::DeviceClassFactory *factory)
: NetlistDeviceExtractorBJT3Transistor (name, factory ? factory : new db::device_class_factory<db::DeviceClassBJT4Transistor> ())
{
// .. 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<db::Region> & /*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<db::DeviceClassDiode> ())
{
// .. 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<unsigned int> &layers) const

View File

@ -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 C>
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<DeviceClassFactory> 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<unsigned int> &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<unsigned int> &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<db::Region> & /*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<unsigned int> &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<db::Region> & /*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<unsigned int> &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<unsigned int> &layers) const;

View File

@ -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<std::string, bool>
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<std::string, bool> 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;
}

View File

@ -31,6 +31,7 @@
#include <set>
#include <map>
#include <memory>
#include <list>
namespace db
{
@ -168,14 +169,48 @@ public:
virtual void read (tl::InputStream &stream, db::Netlist &netlist);
private:
class SpiceReaderStream
{
public:
SpiceReaderStream ();
~SpiceReaderStream ();
void set_stream (tl::InputStream &stream);
void set_stream (tl::InputStream *stream);
void close ();
std::pair<std::string, bool> get_line();
int line_number () const;
std::string source () const;
bool at_end () const;
void swap (SpiceReaderStream &other)
{
std::swap (mp_stream, other.mp_stream);
std::swap (m_owns_stream, other.m_owns_stream);
std::swap (mp_text_stream, other.mp_text_stream);
std::swap (m_line_number, other.m_line_number);
std::swap (m_stored_line, other.m_stored_line);
std::swap (m_has_stored_line, other.m_has_stored_line);
}
private:
tl::InputStream *mp_stream;
bool m_owns_stream;
tl::TextInputStream *mp_text_stream;
int m_line_number;
std::string m_stored_line;
bool m_has_stored_line;
};
db::Netlist *mp_netlist;
db::Circuit *mp_circuit;
db::Circuit *mp_anonymous_top_circuit;
std::unique_ptr<tl::TextInputStream> mp_stream;
tl::weak_ptr<NetlistSpiceReaderDelegate> mp_delegate;
std::vector<std::pair<tl::InputStream *, tl::TextInputStream *> > m_streams;
std::list<SpiceReaderStream> m_streams;
SpiceReaderStream m_stream;
std::unique_ptr<std::map<std::string, db::Net *> > mp_nets_by_name;
std::string m_stored_line;
std::map<std::string, bool> m_captured;
std::vector<std::string> m_global_nets;
std::set<std::string> m_global_net_names;
@ -191,7 +226,6 @@ private:
bool read_card ();
std::string read_name (tl::Extractor &ex);
std::string get_line ();
void unget_line (const std::string &l);
void error (const std::string &msg);
void warn (const std::string &msg);
void finish ();

View File

@ -117,6 +117,7 @@ void NetlistSpiceWriterDelegate::write_device (const db::Device &dev) const
os << " ";
os << format_name (dev.device_class ()->name ());
}
os << format_params (dev, db::DeviceClassCapacitor::param_id_C, true);
} else if (ind) {
@ -129,6 +130,7 @@ void NetlistSpiceWriterDelegate::write_device (const db::Device &dev) const
os << " ";
os << format_name (dev.device_class ()->name ());
}
os << format_params (dev, db::DeviceClassInductor::param_id_L, true);
} else if (res || res3) {
@ -141,6 +143,7 @@ void NetlistSpiceWriterDelegate::write_device (const db::Device &dev) const
os << " ";
os << format_name (dev.device_class ()->name ());
}
os << format_params (dev, db::DeviceClassResistor::param_id_R, true);
} else if (diode) {
@ -209,13 +212,13 @@ std::string NetlistSpiceWriterDelegate::format_terminals (const db::Device &dev,
return os.str ();
}
std::string NetlistSpiceWriterDelegate::format_params (const db::Device &dev, size_t without_id) const
std::string NetlistSpiceWriterDelegate::format_params (const db::Device &dev, size_t without_id, bool only_primary) const
{
std::ostringstream os;
const std::vector<db::DeviceParameterDefinition> &pd = dev.device_class ()->parameter_definitions ();
for (std::vector<db::DeviceParameterDefinition>::const_iterator i = pd.begin (); i != pd.end (); ++i) {
if (i->id () != without_id) {
if (i->id () != without_id && (! only_primary || i->is_primary ())) {
double sis = i->si_scaling ();
os << " " << i->name () << "=";
// for compatibility

View File

@ -63,7 +63,7 @@ public:
void emit_comment (const std::string &comment) const;
std::string format_name (const std::string &s) const;
std::string format_terminals (const db::Device &dev, size_t max_terminals = std::numeric_limits<size_t>::max ()) const;
std::string format_params (const db::Device &dev, size_t without_id = std::numeric_limits<size_t>::max ()) const;
std::string format_params (const db::Device &dev, size_t without_id = std::numeric_limits<size_t>::max (), bool only_primary = false) const;
private:
friend class NetlistSpiceWriter;

View File

@ -251,6 +251,24 @@ static void add_other_abstracts (db::Device *device, const db::DeviceAbstractRef
device->other_abstracts ().push_back (ref);
}
static const db::Net *net_for_terminal_by_name_const (const db::Device *device, const std::string &name)
{
if (! device->device_class () || ! device->device_class ()->has_terminal_with_name (name)) {
return 0;
} else {
return device->net_for_terminal (device->device_class ()->terminal_id_for_name (name));
}
}
static const db::Net *net_for_terminal_by_name (db::Device *device, const std::string &name)
{
if (! device->device_class () || ! device->device_class ()->has_terminal_with_name (name)) {
return 0;
} else {
return device->net_for_terminal (device->device_class ()->terminal_id_for_name (name));
}
}
Class<db::Device> decl_dbDevice (decl_dbNetlistObject, "db", "Device",
gsi::method ("device_class", &db::Device::device_class,
"@brief Gets the device class the device belongs to.\n"
@ -337,6 +355,18 @@ Class<db::Device> decl_dbDevice (decl_dbNetlistObject, "db", "Device",
"\n\n"
"This constness variant has been introduced in version 0.26.8"
) +
gsi::method_ext ("net_for_terminal", net_for_terminal_by_name_const, gsi::arg ("terminal_name"),
"@brief Gets the net connected to the specified terminal.\n"
"If the terminal is not connected, nil is returned for the net."
"\n\n"
"This convenience method has been introduced in version 0.27.3.\n"
) +
gsi::method_ext ("net_for_terminal", net_for_terminal_by_name, gsi::arg ("terminal_name"),
"@brief Gets the net connected to the specified terminal (non-const version).\n"
"If the terminal is not connected, nil is returned for the net."
"\n\n"
"This convenience method has been introduced in version 0.27.3.\n"
) +
gsi::method ("connect_terminal", &db::Device::connect_terminal, gsi::arg ("terminal_id"), gsi::arg ("net"),
"@brief Connects the given terminal to the specified net.\n"
) +
@ -843,7 +873,32 @@ public:
}
}
gsi::Callback cb_less, cb_equal;
gsi::Callback cb_less;
};
/**
* @brief A DeviceCombiner implementation that allows reimplementation of the virtual methods
*/
class GenericDeviceCombiner
: public db::DeviceCombiner
{
public:
GenericDeviceCombiner ()
: db::DeviceCombiner ()
{
// .. nothing yet ..
}
virtual bool combine_devices (db::Device *a, db::Device *b) const
{
if (cb_combine.can_issue ()) {
return cb_combine.issue<db::DeviceCombiner, bool, db::Device *, db::Device *> (&db::DeviceCombiner::combine_devices, a, b);
} else {
return false;
}
}
gsi::Callback cb_combine;
};
}
@ -912,6 +967,29 @@ Class<GenericDeviceParameterCompare> decl_GenericDeviceParameterCompare (decl_db
"This class has been added in version 0.26. The 'equal' method has been dropped in 0.27.1 as it can be expressed as !less(a,b) && !less(b,a)."
);
Class<GenericDeviceCombiner> decl_GenericDeviceCombiner ("db", "GenericDeviceCombiner",
gsi::callback ("combine_devices", &GenericDeviceCombiner::combine_devices, &GenericDeviceCombiner::cb_combine, gsi::arg ("device_a"), gsi::arg ("device_b"),
"@brief Combines two devices if possible.\n"
"This method needs to test, whether the two devices can be combined. Both devices "
"are guaranteed to share the same device class. "
"If they cannot be combined, this method shall do nothing and return false. "
"If they can be combined, this method shall reconnect the nets of the first "
"device and entirely disconnect the nets of the second device. "
"The second device will be deleted afterwards. "
),
"@brief A class implementing the combination of two devices (parallel or serial mode).\n"
"Reimplement this class to provide a custom device combiner.\n"
"Device combination requires 'supports_paralell_combination' or 'supports_serial_combination' to be set "
"to true for the device class. In the netlist device combination step, the algorithm will try to identify "
"devices which can be combined into single devices and use the combiner object to implement the actual "
"joining of such devices.\n"
"\n"
"Attach this object to a device class with \\DeviceClass#combiner= to make the device "
"class use this combiner.\n"
"\n"
"This class has been added in version 0.27.3."
);
static tl::id_type id_of_device_class (const db::DeviceClass *cls)
{
return tl::id_of (cls);
@ -927,6 +1005,60 @@ static db::EqualDeviceParameters *get_equal_parameters (db::DeviceClass *cls)
return dynamic_cast<db::EqualDeviceParameters *> (cls->parameter_compare_delegate ());
}
static void set_combiner (db::DeviceClass *cls, GenericDeviceCombiner *combiner)
{
cls->set_device_combiner (combiner);
}
static GenericDeviceCombiner *get_combiner (db::DeviceClass *cls)
{
return dynamic_cast<GenericDeviceCombiner *> (cls->device_combiner ());
}
static void enable_parameter (db::DeviceClass *cls, size_t id, bool en)
{
db::DeviceParameterDefinition *pd = cls->parameter_definition_non_const (id);
if (pd) {
pd->set_is_primary (en);
}
}
static void enable_parameter2 (db::DeviceClass *cls, const std::string &name, bool en)
{
if (! cls->has_parameter_with_name (name)) {
return;
}
size_t id = cls->parameter_id_for_name (name);
db::DeviceParameterDefinition *pd = cls->parameter_definition_non_const (id);
if (pd) {
pd->set_is_primary (en);
}
}
static const db::DeviceParameterDefinition *parameter_definition2 (const db::DeviceClass *cls, const std::string &name)
{
if (! cls->has_parameter_with_name (name)) {
return 0;
} else {
return cls->parameter_definition (cls->parameter_id_for_name (name));
}
}
static void dc_add_terminal_definition (db::DeviceClass *cls, db::DeviceTerminalDefinition *terminal_def)
{
if (terminal_def) {
*terminal_def = cls->add_terminal_definition (*terminal_def);
}
}
static void dc_add_parameter_definition (db::DeviceClass *cls, db::DeviceParameterDefinition *parameter_def)
{
if (parameter_def) {
*parameter_def = cls->add_parameter_definition (*parameter_def);
}
}
Class<db::DeviceClass> decl_dbDeviceClass ("db", "DeviceClass",
gsi::method ("name", &db::DeviceClass::name,
"@brief Gets the name of the device class."
@ -981,6 +1113,33 @@ Class<db::DeviceClass> decl_dbDeviceClass ("db", "DeviceClass",
"Parameter definition IDs are used in some places to reference a specific parameter of a device. "
"This method obtains the corresponding definition object."
) +
gsi::method_ext ("parameter_definition", &parameter_definition2, gsi::arg ("parameter_name"),
"@brief Gets the parameter definition object for a given ID.\n"
"Parameter definition IDs are used in some places to reference a specific parameter of a device. "
"This method obtains the corresponding definition object."
"\n"
"This version accepts a parameter name.\n"
"\n"
"This method has been introduced in version 0.27.3.\n"
) +
gsi::method_ext ("enable_parameter", &enable_parameter, gsi::arg ("parameter_id"), gsi::arg ("enable"),
"@brief Enables or disables a parameter.\n"
"Some parameters are 'secondary' parameters which are extracted but not handled in device compare and are not shown in the netlist browser. "
"For example, the 'W' parameter of the resistor is such a secondary parameter. This method allows turning a parameter in a primary one ('enable') or "
"into a secondary one ('disable').\n"
"\n"
"This method has been introduced in version 0.27.3.\n"
) +
gsi::method_ext ("enable_parameter", &enable_parameter2, gsi::arg ("parameter_name"), gsi::arg ("enable"),
"@brief Enables or disables a parameter.\n"
"Some parameters are 'secondary' parameters which are extracted but not handled in device compare and are not shown in the netlist browser. "
"For example, the 'W' parameter of the resistor is such a secondary parameter. This method allows turning a parameter in a primary one ('enable') or "
"into a secondary one ('disable').\n"
"\n"
"This version accepts a parameter name.\n"
"\n"
"This method has been introduced in version 0.27.3.\n"
) +
gsi::method ("has_parameter?", &db::DeviceClass::has_parameter_with_name, gsi::arg ("name"),
"@brief Returns true, if the device class has a parameter with the given name.\n"
) +
@ -1001,7 +1160,7 @@ Class<db::DeviceClass> decl_dbDeviceClass ("db", "DeviceClass",
"@brief Gets the device parameter comparer for netlist verification or nil if no comparer is registered.\n"
"See \\equal_parameters= for the setter.\n"
"\n"
"This getter has been introduced in version 0.26.4.\n"
"This method has been moved from 'GenericDeviceClass' to 'DeviceClass' in version 0.27.3.\n"
) +
gsi::method_ext ("equal_parameters=", &equal_parameters, gsi::arg ("comparer"),
"@brief Specifies a device parameter comparer for netlist verification.\n"
@ -1012,7 +1171,85 @@ Class<db::DeviceClass> decl_dbDeviceClass ("db", "DeviceClass",
"\n"
"You can assign nil for the parameter comparer to remove it.\n"
"\n"
"In special cases, you can even implement a custom compare scheme by deriving your own comparer from the \\GenericDeviceParameterCompare class."
"In special cases, you can even implement a custom compare scheme by deriving your own comparer from the \\GenericDeviceParameterCompare class.\n"
"\n"
"This method has been moved from 'GenericDeviceClass' to 'DeviceClass' in version 0.27.3.\n"
) +
gsi::method_ext ("add_terminal", &gsi::dc_add_terminal_definition, gsi::arg ("terminal_def"),
"@brief Adds the given terminal definition to the device class\n"
"This method will define a new terminal. The new terminal is added at the end of existing terminals. "
"The terminal definition object passed as the argument is modified to contain the "
"new ID of the terminal.\n"
"\n"
"The terminal is copied into the device class. Modifying the terminal object later "
"does not have the effect of changing the terminal definition.\n"
"\n"
"This method has been moved from 'GenericDeviceClass' to 'DeviceClass' in version 0.27.3.\n"
) +
gsi::method ("clear_terminals", &db::DeviceClass::clear_terminal_definitions,
"@brief Clears the list of terminals\n"
"\n"
"This method has been moved from 'GenericDeviceClass' to 'DeviceClass' in version 0.27.3.\n"
) +
gsi::method_ext ("add_parameter", &gsi::dc_add_parameter_definition, gsi::arg ("parameter_def"),
"@brief Adds the given parameter definition to the device class\n"
"This method will define a new parameter. The new parameter is added at the end of existing parameters. "
"The parameter definition object passed as the argument is modified to contain the "
"new ID of the parameter."
"\n"
"The parameter is copied into the device class. Modifying the parameter object later "
"does not have the effect of changing the parameter definition.\n"
"\n"
"This method has been moved from 'GenericDeviceClass' to 'DeviceClass' in version 0.27.3.\n"
) +
gsi::method ("clear_parameters", &db::DeviceClass::clear_parameter_definitions,
"@brief Clears the list of parameters\n"
"\n"
"This method has been added in version 0.27.3.\n"
) +
gsi::method_ext ("combiner=", &set_combiner, gsi::arg ("combiner"),
"@brief Specifies a device combiner (parallel or serial device combination).\n"
"\n"
"You can assign nil for the combiner to remove it.\n"
"\n"
"In special cases, you can even implement a custom combiner by deriving your own comparer from the \\GenericDeviceCombiner class.\n"
"\n"
"This method has been added in version 0.27.3.\n"
) +
gsi::method_ext ("combiner", &get_combiner,
"@brief Gets a device combiner or nil if none is registered.\n"
"\n"
"This method has been added in version 0.27.3.\n"
) +
gsi::method ("supports_parallel_combination=", &db::DeviceClass::set_supports_parallel_combination, gsi::arg ("f"),
"@brief Specifies whether the device supports parallel device combination.\n"
"Parallel device combination means that all terminals of two combination candidates are connected to the same nets. "
"If the device does not support this combination mode, this predicate can be set to false. This will make the device "
"extractor skip the combination test in parallel mode and improve performance somewhat.\n"
"\n"
"This method has been moved from 'GenericDeviceClass' to 'DeviceClass' in version 0.27.3.\n"
) +
gsi::method ("supports_serial_combination=", &db::DeviceClass::set_supports_serial_combination, gsi::arg ("f"),
"@brief Specifies whether the device supports serial device combination.\n"
"Serial device combination means that the devices are connected by internal nodes. "
"If the device does not support this combination mode, this predicate can be set to false. This will make the device "
"extractor skip the combination test in serial mode and improve performance somewhat.\n"
"\n"
"This method has been moved from 'GenericDeviceClass' to 'DeviceClass' in version 0.27.3.\n"
) +
gsi::method ("equivalent_terminal_id", &db::DeviceClass::equivalent_terminal_id, gsi::arg ("original_id"), gsi::arg ("equivalent_id"),
"@brief Specifies a terminal to be equivalent to another.\n"
"Use this method to specify two terminals to be exchangeable. For example to make S and D of a MOS transistor equivalent, "
"call this method with S and D terminal IDs. In netlist matching, S will be translated to D and thus made equivalent to D.\n"
"\n"
"Note that terminal equivalence is not effective if the device class operates in strict mode (see \\DeviceClass#strict=).\n"
"\n"
"This method has been moved from 'GenericDeviceClass' to 'DeviceClass' in version 0.27.3.\n"
) +
gsi::method ("clear_equivalent_terminal_ids", &db::DeviceClass::clear_equivalent_terminal_ids,
"@brief Clears all equivalent terminal ids\n"
"\n"
"This method has been added in version 0.27.3.\n"
),
"@brief A class describing a specific type of device.\n"
"Device class objects live in the context of a \\Netlist object. After a "
@ -1022,7 +1259,8 @@ Class<db::DeviceClass> decl_dbDeviceClass ("db", "DeviceClass",
"\n"
"The \\DeviceClass class is the base class for other device classes.\n"
"\n"
"This class has been added in version 0.26."
"This class has been added in version 0.26. In version 0.27.3, the 'GenericDeviceClass' has been integrated with \\DeviceClass "
"and the device class was made writeable in most respects. This enables manipulating built-in device classes."
);
namespace {
@ -1097,87 +1335,6 @@ private:
}
static void gdc_add_terminal_definition (GenericDeviceClass *cls, db::DeviceTerminalDefinition *terminal_def)
{
if (terminal_def) {
*terminal_def = cls->add_terminal_definition (*terminal_def);
}
}
static void gdc_add_parameter_definition (GenericDeviceClass *cls, db::DeviceParameterDefinition *parameter_def)
{
if (parameter_def) {
*parameter_def = cls->add_parameter_definition (*parameter_def);
}
}
Class<GenericDeviceClass> decl_GenericDeviceClass (decl_dbDeviceClass, "db", "GenericDeviceClass",
gsi::method_ext ("add_terminal", &gsi::gdc_add_terminal_definition, gsi::arg ("terminal_def"),
"@brief Adds the given terminal definition to the device class\n"
"This method will define a new terminal. The new terminal is added at the end of existing terminals. "
"The terminal definition object passed as the argument is modified to contain the "
"new ID of the terminal.\n"
"\n"
"The terminal is copied into the device class. Modifying the terminal object later "
"does not have the effect of changing the terminal definition."
) +
gsi::method ("clear_terminals", &GenericDeviceClass::clear_terminal_definitions,
"@brief Clears the list of terminals\n"
) +
gsi::method_ext ("add_parameter", &gsi::gdc_add_parameter_definition, gsi::arg ("parameter_def"),
"@brief Adds the given parameter definition to the device class\n"
"This method will define a new parameter. The new parameter is added at the end of existing parameters. "
"The parameter definition object passed as the argument is modified to contain the "
"new ID of the parameter."
"\n"
"The parameter is copied into the device class. Modifying the parameter object later "
"does not have the effect of changing the parameter definition."
) +
gsi::method ("clear_parameters", &GenericDeviceClass::clear_parameter_definitions,
"@brief Clears the list of parameters\n"
) +
gsi::callback ("combine_devices", &GenericDeviceClass::combine_devices, &GenericDeviceClass::cb_combine_devices, gsi::arg ("a"), gsi::arg ("b"),
"@brief Combines two devices.\n"
"This method shall test, whether the two devices can be combined. Both devices "
"are guaranteed to share the same device class (self). "
"If they cannot be combined, this method shall do nothing and return false. "
"If they can be combined, this method shall reconnect the nets of the first "
"device and entirely disconnect the nets of the second device. "
"It shall combine the parameters of both devices into the first. "
"The second device will be deleted afterwards.\n"
) +
gsi::method ("supports_parallel_combination=", &GenericDeviceClass::set_supports_parallel_combination, gsi::arg ("f"),
"@brief Specifies whether the device supports parallel device combination.\n"
"Parallel device combination means that all terminals of two combination candidates are connected to the same nets. "
"If the device does not support this combination mode, this predicate can be set to false. This will make the device "
"extractor skip the combination test in parallel mode and improve performance somewhat."
) +
gsi::method ("supports_serial_combination=", &GenericDeviceClass::set_supports_serial_combination, gsi::arg ("f"),
"@brief Specifies whether the device supports serial device combination.\n"
"Serial device combination means that the devices are connected by internal nodes. "
"If the device does not support this combination mode, this predicate can be set to false. This will make the device "
"extractor skip the combination test in serial mode and improve performance somewhat."
) +
gsi::method ("equivalent_terminal_id", &GenericDeviceClass::equivalent_terminal_id, gsi::arg ("original_id"), gsi::arg ("equivalent_id"),
"@brief Specifies a terminal to be equivalent to another.\n"
"Use this method to specify two terminals to be exchangeable. For example to make S and D of a MOS transistor equivalent, "
"call this method with S and D terminal IDs. In netlist matching, S will be translated to D and thus made equivalent to D.\n"
"\n"
"Note that terminal equivalence is not effective if the device class operates in strict mode (see \\DeviceClass#strict=)."
),
"@brief A generic device class\n"
"This class allows building generic device classes. Specifically, terminals can be defined "
"by adding terminal definitions. Terminal definitions should not be added dynamically. To create "
"your own device, instantiate the \\GenericDeviceClass object, set name and description and "
"specify the terminals. Then add this new device class to the \\Netlist object where it will live "
"and be used to define device instances (\\Device objects).\n"
"\n"
"In addition, parameters can be defined which correspond to values stored inside the "
"specific device instance (\\Device object)."
"\n"
"This class has been added in version 0.26."
);
static db::Net *create_net (db::Circuit *c, const std::string &name)
{
db::Net *n = new db::Net ();

View File

@ -27,7 +27,7 @@
namespace {
/**
* @brief A NetlistDeviceExtractor implementation that allows reimplementation of the virtual methods
* @brief A NetlistDeviceExtractor implementation that allows reimplementing the virtual methods
*/
class GenericDeviceExtractor
: public db::NetlistDeviceExtractor
@ -110,6 +110,69 @@ template<> struct type_traits<GenericDeviceExtractor> : public tl::type_traits<v
namespace gsi
{
namespace
{
/**
* @brief A DeviceClassFactory implementation that allows reimplementation of the virtual methods
*/
class DeviceClassFactoryImpl
: public db::DeviceClassFactory
{
public:
DeviceClassFactoryImpl ()
: db::DeviceClassFactory ()
{
// .. nothing yet ..
}
virtual db::DeviceClass *create_class () const
{
if (cb_create_class.can_issue ()) {
return cb_create_class.issue<db::DeviceClassFactory, db::DeviceClass *> (&db::DeviceClassFactory::create_class);
} else {
return 0;
}
}
gsi::Callback cb_create_class;
};
}
Class<DeviceClassFactoryImpl> decl_dbDeviceClassFactoryBase ("db", "DeviceClassFactory",
gsi::factory_callback ("create_class", &DeviceClassFactoryImpl::create_class, &DeviceClassFactoryImpl::cb_create_class,
"@brief Creates the DeviceClass object\n"
"Reimplement this method to create the desired device class."
),
"@brief A factory for creating specific device classes for the standard device extractors\n"
"Use a reimplementation of this class to provide a device class generator for built-in device extractors "
"such as \\DeviceExtractorMOS3Transistor. The constructor of this extractor has a 'factory' parameter "
"which takes an object of \\DeviceClassFactory type.\n"
"\n"
"If such an object is provided, this factory is used "
"to create the actual device class. The following code shows an example:\n"
"\n"
"@code\n"
"class MyClass < RBA::DeviceClassMOS3Transistor\n"
" ... overrides some methods ...\n"
"end\n"
"\n"
"class MyFactory < RBA::DeviceClassFactory\n"
" def create_class\n"
" MyClass.new\n"
" end\n"
"end\n"
"\n"
"extractor = RBA::DeviceExtractorMOS3Transistor::new(\"NMOS\", false, MyFactory.new)\n"
"@/code\n"
"\n"
"When using a factory with a device extractor, make sure it creates a corresponding device class, e.g. "
"for the \\DeviceExtractorMOS3Transistor extractor create a device class derived from \\DeviceClassMOS3Transistor.\n"
"\n"
"This class has been introduced in version 0.27.3.\n"
);
Class<db::NetlistDeviceExtractorError> decl_dbNetlistDeviceExtractorError ("db", "NetlistDeviceExtractorError",
gsi::method ("message", &db::NetlistDeviceExtractorError::message,
"@brief Gets the message text.\n"
@ -210,10 +273,24 @@ Class<db::NetlistDeviceExtractorLayerDefinition> decl_dbNetlistDeviceExtractorLa
"This class has been introduced in version 0.26."
);
// for test only
static void test_initialize (db::NetlistDeviceExtractor *ex, db::Netlist *nl)
{
ex->initialize (nl);
}
Class<db::NetlistDeviceExtractor> decl_dbNetlistDeviceExtractor ("db", "DeviceExtractorBase",
gsi::method ("name", &db::NetlistDeviceExtractor::name,
"@brief Gets the name of the device extractor and the device class."
) +
gsi::method ("device_class", &db::NetlistDeviceExtractor::device_class,
"@brief Gets the device class used during extraction\n"
"The attribute will hold the actual device class used in the device extraction. It "
"is valid only after 'extract_devices'.\n"
"\n"
"This method has been added in version 0.27.3.\n"
) +
gsi::method_ext ("test_initialize", &test_initialize, gsi::arg ("netlist"), "@hide") + // for test only
gsi::iterator ("each_layer_definition", &db::NetlistDeviceExtractor::begin_layer_definitions, &db::NetlistDeviceExtractor::end_layer_definitions,
"@brief Iterates over all layer definitions."
) +
@ -251,9 +328,13 @@ Class<GenericDeviceExtractor> decl_GenericDeviceExtractor (decl_dbNetlistDeviceE
"This method shall raise an error, if the input layer are not properly defined (e.g.\n"
"too few etc.)\n"
"\n"
"This is not a connectivity definition in the electrical sense, but defines the cluster of shapes "
"which generates a specific device. In this case, 'connectivity' means 'definition of shapes that need to touch to form the device'.\n"
"\n"
"The 'layers' argument specifies the actual layer layouts for the logical device layers (see \\define_layer). "
"The list of layers corresponds to the number of layers defined. Use the layer indexes from this list "
"to build the connectivity with \\Connectivity#connect."
"to build the connectivity with \\Connectivity#connect. Note, that in order to capture a connected cluster of shapes on the "
"same layer you'll need to include a self-connection like 'connectivity.connect(layers[0], layers[0])'."
) +
gsi::callback ("extract_devices", &GenericDeviceExtractor::extract_devices, &GenericDeviceExtractor::cb_extract_devices,
gsi::arg ("layer_geometry"),
@ -397,16 +478,18 @@ Class<GenericDeviceExtractor> decl_GenericDeviceExtractor (decl_dbNetlistDeviceE
"This class has been introduced in version 0.26."
);
static db::NetlistDeviceExtractorMOS3Transistor *make_mos3_extractor (const std::string &name, bool strict)
static db::NetlistDeviceExtractorMOS3Transistor *make_mos3_extractor (const std::string &name, bool strict, DeviceClassFactoryImpl *factory)
{
return new db::NetlistDeviceExtractorMOS3Transistor (name, strict);
return new db::NetlistDeviceExtractorMOS3Transistor (name, strict, factory);
}
Class<db::NetlistDeviceExtractorMOS3Transistor> decl_NetlistDeviceExtractorMOS3Transistor (decl_dbNetlistDeviceExtractor, "db", "DeviceExtractorMOS3Transistor",
gsi::constructor ("new", &make_mos3_extractor, gsi::arg ("name"), gsi::arg ("strict", false),
gsi::constructor ("new", &make_mos3_extractor, gsi::arg ("name"), gsi::arg ("strict", false), gsi::arg ("factory", (DeviceClassFactoryImpl *)0, "none"),
"@brief Creates a new device extractor with the given name.\n"
"If \\strict is true, the MOS device extraction will happen in strict mode. That is, source and drain "
"are not interchangeable."
"are not interchangeable.\n"
"\n"
"For the 'factory' parameter see \\DeviceClassFactory. It has been added in version 0.27.3.\n"
) +
gsi::method ("strict?", &db::NetlistDeviceExtractorMOS3Transistor::is_strict,
"@brief Returns a value indicating whether extraction happens in strict mode."
@ -454,14 +537,15 @@ Class<db::NetlistDeviceExtractorMOS3Transistor> decl_NetlistDeviceExtractorMOS3T
"This class has been introduced in version 0.26."
);
static db::NetlistDeviceExtractorMOS4Transistor *make_mos4_extractor (const std::string &name, bool strict)
static db::NetlistDeviceExtractorMOS4Transistor *make_mos4_extractor (const std::string &name, bool strict, DeviceClassFactoryImpl *factory)
{
return new db::NetlistDeviceExtractorMOS4Transistor (name, strict);
return new db::NetlistDeviceExtractorMOS4Transistor (name, strict, factory);
}
Class<db::NetlistDeviceExtractorMOS4Transistor> decl_NetlistDeviceExtractorMOS4Transistor (decl_dbNetlistDeviceExtractor, "db", "DeviceExtractorMOS4Transistor",
gsi::constructor ("new", &make_mos4_extractor, gsi::arg ("name"), gsi::arg ("strict", false),
"@brief Creates a new device extractor with the given name."
gsi::constructor ("new", &make_mos4_extractor, gsi::arg ("name"), gsi::arg ("strict", false), gsi::arg ("factory", (DeviceClassFactoryImpl *)0, "none"),
"@brief Creates a new device extractor with the given name\n"
"For the 'factory' parameter see \\DeviceClassFactory. It has been added in version 0.27.3.\n"
),
"@brief A device extractor for a four-terminal MOS transistor\n"
"\n"
@ -492,14 +576,15 @@ Class<db::NetlistDeviceExtractorMOS4Transistor> decl_NetlistDeviceExtractorMOS4T
"This class has been introduced in version 0.26."
);
db::NetlistDeviceExtractorResistor *make_res_extractor (const std::string &name, double sheet_rho)
db::NetlistDeviceExtractorResistor *make_res_extractor (const std::string &name, double sheet_rho, DeviceClassFactoryImpl *factory)
{
return new db::NetlistDeviceExtractorResistor (name, sheet_rho);
return new db::NetlistDeviceExtractorResistor (name, sheet_rho, factory);
}
Class<db::NetlistDeviceExtractorResistor> decl_NetlistDeviceExtractorResistor (decl_dbNetlistDeviceExtractor, "db", "DeviceExtractorResistor",
gsi::constructor ("new", &make_res_extractor, gsi::arg ("name"), gsi::arg ("sheet_rho"),
"@brief Creates a new device extractor with the given name."
gsi::constructor ("new", &make_res_extractor, gsi::arg ("name"), gsi::arg ("sheet_rho"), gsi::arg ("factory", (DeviceClassFactoryImpl *)0, "none"),
"@brief Creates a new device extractor with the given name\n"
"For the 'factory' parameter see \\DeviceClassFactory. It has been added in version 0.27.3.\n"
),
"@brief A device extractor for a two-terminal resistor\n"
"\n"
@ -542,14 +627,15 @@ Class<db::NetlistDeviceExtractorResistor> decl_NetlistDeviceExtractorResistor (d
"This class has been introduced in version 0.26."
);
db::NetlistDeviceExtractorResistorWithBulk *make_res_with_bulk_extractor (const std::string &name, double sheet_rho)
db::NetlistDeviceExtractorResistorWithBulk *make_res_with_bulk_extractor (const std::string &name, double sheet_rho, DeviceClassFactoryImpl *factory)
{
return new db::NetlistDeviceExtractorResistorWithBulk (name, sheet_rho);
return new db::NetlistDeviceExtractorResistorWithBulk (name, sheet_rho, factory);
}
Class<db::NetlistDeviceExtractorResistorWithBulk> decl_NetlistDeviceExtractorResistorWithBulk (decl_dbNetlistDeviceExtractor, "db", "DeviceExtractorResistorWithBulk",
gsi::constructor ("new", &make_res_with_bulk_extractor, gsi::arg ("name"), gsi::arg ("sheet_rho"),
"@brief Creates a new device extractor with the given name."
gsi::constructor ("new", &make_res_with_bulk_extractor, gsi::arg ("name"), gsi::arg ("sheet_rho"), gsi::arg ("factory", (DeviceClassFactoryImpl *)0, "none"),
"@brief Creates a new device extractor with the given name\n"
"For the 'factory' parameter see \\DeviceClassFactory. It has been added in version 0.27.3.\n"
),
"@brief A device extractor for a resistor with a bulk terminal\n"
"\n"
@ -587,14 +673,15 @@ Class<db::NetlistDeviceExtractorResistorWithBulk> decl_NetlistDeviceExtractorRes
"This class has been introduced in version 0.26."
);
db::NetlistDeviceExtractorCapacitor *make_cap_extractor (const std::string &name, double area_cap)
db::NetlistDeviceExtractorCapacitor *make_cap_extractor (const std::string &name, double area_cap, DeviceClassFactoryImpl *factory)
{
return new db::NetlistDeviceExtractorCapacitor (name, area_cap);
return new db::NetlistDeviceExtractorCapacitor (name, area_cap, factory);
}
Class<db::NetlistDeviceExtractorCapacitor> decl_NetlistDeviceExtractorCapacitor (decl_dbNetlistDeviceExtractor, "db", "DeviceExtractorCapacitor",
gsi::constructor ("new", &make_cap_extractor, gsi::arg ("name"), gsi::arg ("area_cap"),
"@brief Creates a new device extractor with the given name."
gsi::constructor ("new", &make_cap_extractor, gsi::arg ("name"), gsi::arg ("area_cap"), gsi::arg ("factory", (DeviceClassFactoryImpl *)0, "none"),
"@brief Creates a new device extractor with the given name\n"
"For the 'factory' parameter see \\DeviceClassFactory. It has been added in version 0.27.3.\n"
),
"@brief A device extractor for a two-terminal capacitor\n"
"\n"
@ -632,14 +719,15 @@ Class<db::NetlistDeviceExtractorCapacitor> decl_NetlistDeviceExtractorCapacitor
"This class has been introduced in version 0.26."
);
db::NetlistDeviceExtractorCapacitorWithBulk *make_cap_with_bulk_extractor (const std::string &name, double area_cap)
db::NetlistDeviceExtractorCapacitorWithBulk *make_cap_with_bulk_extractor (const std::string &name, double area_cap, DeviceClassFactoryImpl *factory)
{
return new db::NetlistDeviceExtractorCapacitorWithBulk (name, area_cap);
return new db::NetlistDeviceExtractorCapacitorWithBulk (name, area_cap, factory);
}
Class<db::NetlistDeviceExtractorCapacitorWithBulk> decl_NetlistDeviceExtractorCapacitorWithBulk (decl_dbNetlistDeviceExtractor, "db", "DeviceExtractorCapacitorWithBulk",
gsi::constructor ("new", &make_cap_with_bulk_extractor, gsi::arg ("name"), gsi::arg ("sheet_rho"),
"@brief Creates a new device extractor with the given name."
gsi::constructor ("new", &make_cap_with_bulk_extractor, gsi::arg ("name"), gsi::arg ("sheet_rho"), gsi::arg ("factory", (DeviceClassFactoryImpl *)0, "none"),
"@brief Creates a new device extractor with the given name\n"
"For the 'factory' parameter see \\DeviceClassFactory. It has been added in version 0.27.3.\n"
),
"@brief A device extractor for a capacitor with a bulk terminal\n"
"\n"
@ -676,14 +764,15 @@ Class<db::NetlistDeviceExtractorCapacitorWithBulk> decl_NetlistDeviceExtractorCa
"This class has been introduced in version 0.26."
);
db::NetlistDeviceExtractorBJT3Transistor *make_bjt3_extractor (const std::string &name)
db::NetlistDeviceExtractorBJT3Transistor *make_bjt3_extractor (const std::string &name, DeviceClassFactoryImpl *factory)
{
return new db::NetlistDeviceExtractorBJT3Transistor (name);
return new db::NetlistDeviceExtractorBJT3Transistor (name, factory);
}
Class<db::NetlistDeviceExtractorBJT3Transistor> decl_dbNetlistDeviceExtractorBJT3Transistor (decl_dbNetlistDeviceExtractor, "db", "DeviceExtractorBJT3Transistor",
gsi::constructor ("new", &make_bjt3_extractor, gsi::arg ("name"),
"@brief Creates a new device extractor with the given name."
gsi::constructor ("new", &make_bjt3_extractor, gsi::arg ("name"), gsi::arg ("factory", (DeviceClassFactoryImpl *)0, "none"),
"@brief Creates a new device extractor with the given name\n"
"For the 'factory' parameter see \\DeviceClassFactory. It has been added in version 0.27.3.\n"
),
"@brief A device extractor for a bipolar transistor (BJT)\n"
"\n"
@ -729,14 +818,15 @@ Class<db::NetlistDeviceExtractorBJT3Transistor> decl_dbNetlistDeviceExtractorBJT
"This class has been introduced in version 0.26."
);
db::NetlistDeviceExtractorBJT4Transistor *make_bjt4_extractor (const std::string &name)
db::NetlistDeviceExtractorBJT4Transistor *make_bjt4_extractor (const std::string &name, DeviceClassFactoryImpl *factory)
{
return new db::NetlistDeviceExtractorBJT4Transistor (name);
return new db::NetlistDeviceExtractorBJT4Transistor (name, factory);
}
Class<db::NetlistDeviceExtractorBJT4Transistor> decl_NetlistDeviceExtractorBJT4Transistor (decl_dbNetlistDeviceExtractorBJT3Transistor, "db", "DeviceExtractorBJT4Transistor",
gsi::constructor ("new", &make_bjt4_extractor, gsi::arg ("name"),
"@brief Creates a new device extractor with the given name."
gsi::constructor ("new", &make_bjt4_extractor, gsi::arg ("name"), gsi::arg ("factory", (DeviceClassFactoryImpl *)0, "none"),
"@brief Creates a new device extractor with the given name\n"
"For the 'factory' parameter see \\DeviceClassFactory. It has been added in version 0.27.3.\n"
),
"@brief A device extractor for a four-terminal bipolar transistor (BJT)\n"
"\n"
@ -763,14 +853,15 @@ Class<db::NetlistDeviceExtractorBJT4Transistor> decl_NetlistDeviceExtractorBJT4T
"This class has been introduced in version 0.26."
);
db::NetlistDeviceExtractorDiode *make_diode_extractor (const std::string &name)
db::NetlistDeviceExtractorDiode *make_diode_extractor (const std::string &name, DeviceClassFactoryImpl *factory)
{
return new db::NetlistDeviceExtractorDiode (name);
return new db::NetlistDeviceExtractorDiode (name, factory);
}
Class<db::NetlistDeviceExtractorDiode> decl_NetlistDeviceExtractorDiode (decl_dbNetlistDeviceExtractor, "db", "DeviceExtractorDiode",
gsi::constructor ("new", &make_diode_extractor, gsi::arg ("name"),
"@brief Creates a new device extractor with the given name."
gsi::constructor ("new", &make_diode_extractor, gsi::arg ("name"), gsi::arg ("factory", (DeviceClassFactoryImpl *)0, "none"),
"@brief Creates a new device extractor with the given name\n"
"For the 'factory' parameter see \\DeviceClassFactory. It has been added in version 0.27.3.\n"
),
"@brief A device extractor for a planar diode\n"
"\n"

View File

@ -25,6 +25,7 @@
#include "dbReader.h"
#include "dbRecursiveShapeIterator.h"
#include "dbNetlistDeviceExtractorClasses.h"
#include "dbNetlistDeviceClasses.h"
#include "tlUnitTest.h"
#include "tlFileUtils.h"
@ -90,6 +91,67 @@ TEST(2_NetlistDeviceExtractorErrors)
EXPECT_EQ (error2string (errors [3]), ":cat1:desc1:(10,11;10,13;12,13;12,11):msg3");
}
namespace {
class MyDeviceClass
: public db::DeviceClassMOS3Transistor
{
public:
MyDeviceClass () : db::DeviceClassMOS3Transistor () { }
};
}
TEST(3_ClassFactoryTest)
{
db::Layout ly;
{
db::LoadLayoutOptions options;
std::string fn (tl::testdata ());
fn = tl::combine_path (fn, "algo");
fn = tl::combine_path (fn, "mos3_1.gds");
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (ly, options);
}
db::Cell &tc = ly.cell (*ly.begin_top_down ());
db::DeepShapeStore dss;
dss.set_text_enlargement (1);
dss.set_text_property_name (tl::Variant ("LABEL"));
// original layers
db::Region l1 (db::RecursiveShapeIterator (ly, tc, ly.get_layer (db::LayerProperties(1, 0))), dss);
db::Region l2 (db::RecursiveShapeIterator (ly, tc, ly.get_layer (db::LayerProperties(2, 0))), dss);
db::Region o1 (dss);
db::Region o2 (dss);
db::Region o3 (dss);
// perform the extraction
db::Netlist nl;
db::hier_clusters<db::NetShape> cl;
db::NetlistDeviceExtractorMOS3Transistor ex ("MOS3", false, new db::device_class_factory<MyDeviceClass> ());
db::NetlistDeviceExtractor::input_layers dl;
dl["SD"] = &l1;
dl["G"] = &l2;
dl["tS"] = &o1;
dl["tD"] = &o2;
dl["tG"] = &o3;
ex.extract (dss, 0, dl, nl, cl);
// the generated objects are of MyDeviceClassType
EXPECT_EQ (dynamic_cast<const MyDeviceClass *> (ex.device_class ()) != 0, true);
EXPECT_EQ (dynamic_cast<const MyDeviceClass *> (nl.device_class_by_name ("MOS3")) != 0, true);
}
TEST(10_MOS3DeviceExtractorTest)
{
db::Layout ly;

View File

@ -1301,8 +1301,8 @@ TEST(4_ResAndCapExtraction)
" device PMOS $2 (S=VDD,G=IN,D=$3) (L=0.4,W=2.3,AS=1.38,AD=1.38,PS=5.8,PD=5.8);\n"
" device NMOS $3 (S=VSS,G=$4,D=OUT) (L=0.4,W=4.6,AS=2.185,AD=2.185,PS=8.8,PD=8.8);\n"
" device MIM_CAP $5 (A=$4,B=VSS) (C=2.622e-14,A=26.22,P=29.8);\n"
" device POLY_RES $7 (A=$3,B=$4) (R=750,L=12,W=0.8,A=2.4,P=13.6);\n"
" device POLY_RES $9 (A=$4,B=VSS) (R=1825,L=29.2,W=0.8,A=5.84,P=30);\n"
" device POLY_RES $7 (A=$3,B=$4) (R=750,L=6,W=0.4,A=2.4,P=13.6);\n"
" device POLY_RES $9 (A=$4,B=VSS) (R=1825,L=14.6,W=0.4,A=5.84,P=30);\n"
" device NMOS $10 (S=VSS,G=IN,D=$3) (L=0.4,W=3.1,AS=1.86,AD=1.86,PS=7.4,PD=7.4);\n"
"end;\n",
true /*exact parameter compare*/
@ -1576,8 +1576,8 @@ TEST(5_ResAndCapWithBulkExtraction)
" device NMOS $3 (S=VSS,G=$4,D=OUT,B=BULK) (L=0.4,W=4.6,AS=2.185,AD=2.185,PS=8.8,PD=8.8);\n"
" device MIM_CAP_SUBSTRATE $5 (A=$4,B=VSS,W=BULK) (C=1.334e-14,A=13.34,P=15);\n"
" device MIM_CAP_NWELL $6 (A=$4,B=VSS,W=NWELL) (C=1.288e-14,A=12.88,P=14.8);\n"
" device POLY_RES_NWELL $7 (A=$3,B=$4,W=NWELL) (R=750,L=12,W=0.8,A=2.4,P=13.6);\n"
" device POLY_RES_SUBSTRATE $9 (A=$4,B=VSS,W=BULK) (R=1825,L=29.2,W=0.8,A=5.84,P=30);\n"
" device POLY_RES_NWELL $7 (A=$3,B=$4,W=NWELL) (R=750,L=6,W=0.4,A=2.4,P=13.6);\n"
" device POLY_RES_SUBSTRATE $9 (A=$4,B=VSS,W=BULK) (R=1825,L=14.6,W=0.4,A=5.84,P=30);\n"
" device NMOS $10 (S=VSS,G=IN,D=$3,B=BULK) (L=0.4,W=3.1,AS=1.86,AD=1.86,PS=7.4,PD=7.4);\n"
"end;\n",
true /*exact parameter compare*/

View File

@ -550,3 +550,43 @@ TEST(13_NoGlobalNetsIfNotUsed)
);
}
TEST(14_IncludeWithError)
{
db::Netlist nl;
std::string path = tl::combine_path (tl::combine_path (tl::testdata (), "algo"), "nreader14.cir");
try {
db::NetlistSpiceReader reader;
tl::InputStream is (path);
reader.read (is, nl);
EXPECT_EQ (true, false); // must not happen
} catch (tl::Exception &ex) {
EXPECT_EQ (ex.msg (), "'M' element must have four nodes in " + std::string (tl::combine_path (tl::combine_path (tl::testdata (), "algo"), "nreader14x.cir")) + ", line 3");
}
}
TEST(15_ContinuationWithBlanks)
{
db::Netlist nl;
std::string path = tl::combine_path (tl::combine_path (tl::testdata (), "algo"), "nreader15.cir");
db::NetlistSpiceReader reader;
tl::InputStream is (path);
reader.read (is, nl);
EXPECT_EQ (nl.to_string (),
"circuit SUBCKT ($1=$1,'A[5]<1>'='A[5]<1>','V42(%)'='V42(%)',Z=Z,GND=GND,GND$1=GND$1);\n"
" subcircuit HVPMOS D_$1 ($1='V42(%)',$2=$3,$3=Z,$4=$1);\n"
" subcircuit HVPMOS D_$2 ($1='V42(%)',$2='A[5]<1>',$3=$3,$4=$1);\n"
" subcircuit HVNMOS D_$3 ($1=GND,$2=$3,$3=GND,$4=GND$1);\n"
" subcircuit HVNMOS D_$4 ($1=GND,$2=$3,$3=Z,$4=GND$1);\n"
" subcircuit HVNMOS D_$5 ($1=GND,$2='A[5]<1>',$3=$3,$4=GND$1);\n"
"end;\n"
"circuit HVPMOS ($1=(null),$2=(null),$3=(null),$4=(null));\n"
"end;\n"
"circuit HVNMOS ($1=(null),$2=(null),$3=(null),$4=(null));\n"
"end;\n"
);
}

View File

@ -4,6 +4,15 @@ require 'pathname'
module DRC
class CustomDeviceClassFactory < RBA::DeviceClassFactory
def initialize(cls)
@cls = cls
end
def create_class
@cls.new
end
end
# The DRC engine
# %DRC%
@ -308,22 +317,57 @@ module DRC
# @brief Defines SPICE output format (with options)
# @name write_spice
# @synopsis write_spice([ use_net_names [, with_comments ] ])
# @synopsis write_spice(writer_delegate [, use_net_names [, with_comments ] ])
# Use this option in \target_netlist for the format parameter to
# 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.
def write_spice(*args)
def write_spice(use_net_names = nil, with_comments = nil)
self._context("write_spice") do
writer = RBA::NetlistSpiceWriter::new
delegate = nil
use_net_names = nil
with_comments = nil
args.each do |a|
if (a == false || a == true) && (use_net_names == nil || with_comments == nil)
if use_net_names == nil
use_net_names = a
else
with_comments = a
end
elsif a.is_a?(RBA::NetlistSpiceWriterDelegate)
delegate = a
else
raise("Too many arguments specified or argument is of wrong type: " + a.inspect)
end
end
writer = RBA::NetlistSpiceWriter::new(delegate)
if use_net_names != nil
writer.use_net_names = use_net_names
end
if with_comments != nil
writer.with_comments = with_comments
end
writer
end
end
def _make_factory(cls)
if !cls
return nil
elsif !cls.is_a?(Class)
raise("Expected a class object for the 'class' argument of device extractors")
else
CustomDeviceClassFactory::new(cls)
end
end
@ -331,15 +375,16 @@ module DRC
# @brief Supplies the MOS3 transistor extractor class
# @name mos3
# @synopsis mos3(name)
# @synopsis mos3(name, class)
# Use this class with \extract_devices to specify extraction of a
# three-terminal MOS transistor.
#
# See RBA::DeviceExtractorMOS3Transistor for more details
# about this extractor (non-strict mode applies for 'mos3').
def mos3(name)
def mos3(name, cls = nil)
self._context("mos3") do
RBA::DeviceExtractorMOS3Transistor::new(name)
RBA::DeviceExtractorMOS3Transistor::new(name, false, _make_factory(cls))
end
end
@ -347,15 +392,16 @@ module DRC
# @brief Supplies the MOS4 transistor extractor class
# @name mos4
# @synopsis mos4(name)
# @synopsis mos4(name, class)
# Use this class with \extract_devices to specify extraction of a
# four-terminal MOS transistor.
#
# See RBA::DeviceExtractorMOS4Transistor for more details
# about this extractor (non-strict mode applies for 'mos4').
def mos4(name)
def mos4(name, cls = nil)
self._context("mos4") do
RBA::DeviceExtractorMOS4Transistor::new(name)
RBA::DeviceExtractorMOS4Transistor::new(name, false, _make_factory(cls))
end
end
@ -363,6 +409,7 @@ module DRC
# @brief Supplies the DMOS3 transistor extractor class
# @name dmos3
# @synopsis dmos3(name)
# @synopsis dmos3(name, class)
# Use this class with \extract_devices to specify extraction of a
# three-terminal DMOS transistor. A DMOS transistor is essentially
# the same than a MOS transistor, but source and drain are
@ -371,9 +418,9 @@ module DRC
# See RBA::DeviceExtractorMOS3Transistor for more details
# about this extractor (strict mode applies for 'dmos3').
def dmos3(name)
def dmos3(name, cls = nil)
self._context("dmos3") do
RBA::DeviceExtractorMOS3Transistor::new(name, true)
RBA::DeviceExtractorMOS3Transistor::new(name, true, _make_factory(cls))
end
end
@ -381,6 +428,7 @@ module DRC
# @brief Supplies the MOS4 transistor extractor class
# @name dmos4
# @synopsis dmos4(name)
# @synopsis dmos4(name, class)
# Use this class with \extract_devices to specify extraction of a
# four-terminal DMOS transistor. A DMOS transistor is essentially
# the same than a MOS transistor, but source and drain are
@ -389,9 +437,9 @@ module DRC
# See RBA::DeviceExtractorMOS4Transistor for more details
# about this extractor (strict mode applies for 'dmos4').
def dmos4(name)
def dmos4(name, cls = nil)
self._context("dmos4") do
RBA::DeviceExtractorMOS4Transistor::new(name, true)
RBA::DeviceExtractorMOS4Transistor::new(name, true, _make_factory(cls))
end
end
@ -399,15 +447,16 @@ module DRC
# @brief Supplies the BJT3 transistor extractor class
# @name bjt3
# @synopsis bjt3(name)
# @synopsis bjt3(name, class)
# Use this class with \extract_devices to specify extraction of a
# bipolar junction transistor
#
# See RBA::DeviceExtractorBJT3Transistor for more details
# about this extractor.
def bjt3(name)
def bjt3(name, cls = nil)
self._context("bjt3") do
RBA::DeviceExtractorBJT3Transistor::new(name)
RBA::DeviceExtractorBJT3Transistor::new(name, _make_factory(cls))
end
end
@ -415,15 +464,16 @@ module DRC
# @brief Supplies the BJT4 transistor extractor class
# @name bjt4
# @synopsis bjt4(name)
# @synopsis bjt4(name, class)
# Use this class with \extract_devices to specify extraction of a
# bipolar junction transistor with a substrate terminal
#
# See RBA::DeviceExtractorBJT4Transistor for more details
# about this extractor.
def bjt4(name)
def bjt4(name, cls = nil)
self._context("bjt4") do
RBA::DeviceExtractorBJT4Transistor::new(name)
RBA::DeviceExtractorBJT4Transistor::new(name, _make_factory(cls))
end
end
@ -431,15 +481,16 @@ module DRC
# @brief Supplies the diode extractor class
# @name diode
# @synopsis diode(name)
# @synopsis diode(name, class)
# Use this class with \extract_devices to specify extraction of a
# planar diode
#
# See RBA::DeviceExtractorDiode for more details
# about this extractor.
def diode(name)
def diode(name, cls = nil)
self._context("diode") do
RBA::DeviceExtractorDiode::new(name)
RBA::DeviceExtractorDiode::new(name, _make_factory(cls))
end
end
@ -447,6 +498,7 @@ module DRC
# @brief Supplies the resistor extractor class
# @name resistor
# @synopsis resistor(name, sheet_rho)
# @synopsis resistor(name, sheet_rho, class)
# Use this class with \extract_devices to specify extraction of a resistor.
#
# The sheet_rho value is the sheet resistance in ohms/square. It is used
@ -455,9 +507,9 @@ module DRC
# See RBA::DeviceExtractorResistor for more details
# about this extractor.
def resistor(name, sheet_rho)
def resistor(name, sheet_rho, cls = nil)
self._context("resistor") do
RBA::DeviceExtractorResistor::new(name, sheet_rho)
RBA::DeviceExtractorResistor::new(name, sheet_rho, _make_factory(cls))
end
end
@ -465,6 +517,7 @@ module DRC
# @brief Supplies the resistor extractor class that includes a bulk terminal
# @name resistor_with_bulk
# @synopsis resistor_with_bulk(name, sheet_rho)
# @synopsis resistor_with_bulk(name, sheet_rho, class)
# Use this class with \extract_devices to specify extraction of a resistor
# with a bulk terminal.
# The sheet_rho value is the sheet resistance in ohms/square.
@ -472,9 +525,9 @@ module DRC
# See RBA::DeviceExtractorResistorWithBulk for more details
# about this extractor.
def resistor_with_bulk(name, sheet_rho)
def resistor_with_bulk(name, sheet_rho, cls = nil)
self._context("resistor_with_bulk") do
RBA::DeviceExtractorResistorWithBulk::new(name, sheet_rho)
RBA::DeviceExtractorResistorWithBulk::new(name, sheet_rho, _make_factory(cls))
end
end
@ -482,15 +535,16 @@ module DRC
# @brief Supplies the capacitor extractor class
# @name capacitor
# @synopsis capacitor(name, area_cap)
# @synopsis capacitor(name, area_cap, class)
# Use this class with \extract_devices to specify extraction of a capacitor.
# The area_cap argument is the capacitance in Farad per square micrometer.
#
# See RBA::DeviceExtractorCapacitor for more details
# about this extractor.
def capacitor(name, area_cap)
def capacitor(name, area_cap, cls = nil)
self._context("capacitor") do
RBA::DeviceExtractorCapacitor::new(name, area_cap)
RBA::DeviceExtractorCapacitor::new(name, area_cap, _make_factory(cls))
end
end
@ -498,6 +552,7 @@ module DRC
# @brief Supplies the capacitor extractor class that includes a bulk terminal
# @name capacitor_with_bulk
# @synopsis capacitor_with_bulk(name, area_cap)
# @synopsis capacitor_with_bulk(name, area_cap, class)
# Use this class with \extract_devices to specify extraction of a capacitor
# with a bulk terminal.
# The area_cap argument is the capacitance in Farad per square micrometer.
@ -505,9 +560,9 @@ module DRC
# See RBA::DeviceExtractorCapacitorWithBulk for more details
# about this extractor.
def capacitor_with_bulk(name, area_cap)
def capacitor_with_bulk(name, area_cap, cls = nil)
self._context("capacitor_with_bulk") do
RBA::DeviceExtractorCapacitorWithBulk::new(name, area_cap)
RBA::DeviceExtractorCapacitorWithBulk::new(name, area_cap, _make_factory(cls))
end
end

View File

@ -190,6 +190,9 @@ module DRC
#
# extract_devices(mos4("NMOS4"), { :SD => nsd, :G => gate, :P => poly, :W => bulk })
# @/code
#
# The return value of this method will be the device class of the devices
# generated in the extraction step (see \DeviceClass).
def extract_devices(devex, layer_selection)
@ -213,6 +216,8 @@ module DRC
end
devex.device_class
end
# %DRC%

View File

@ -107,6 +107,7 @@ See <a href="/about/drc_ref_layer.xml#drc">Layer#drc</a>, <a href="#bbox_height"
<p>Usage:</p>
<ul>
<li><tt>bjt3(name)</tt></li>
<li><tt>bjt3(name, class)</tt></li>
</ul>
<p>
Use this class with <a href="#extract_devices">extract_devices</a> to specify extraction of a
@ -120,6 +121,7 @@ about this extractor.
<p>Usage:</p>
<ul>
<li><tt>bjt4(name)</tt></li>
<li><tt>bjt4(name, class)</tt></li>
</ul>
<p>
Use this class with <a href="#extract_devices">extract_devices</a> to specify extraction of a
@ -143,6 +145,7 @@ This function creates a box object. The arguments are the same than for the
<p>Usage:</p>
<ul>
<li><tt>capacitor(name, area_cap)</tt></li>
<li><tt>capacitor(name, area_cap, class)</tt></li>
</ul>
<p>
Use this class with <a href="#extract_devices">extract_devices</a> to specify extraction of a capacitor.
@ -156,6 +159,7 @@ about this extractor.
<p>Usage:</p>
<ul>
<li><tt>capacitor_with_bulk(name, area_cap)</tt></li>
<li><tt>capacitor_with_bulk(name, area_cap, class)</tt></li>
</ul>
<p>
Use this class with <a href="#extract_devices">extract_devices</a> to specify extraction of a capacitor
@ -442,6 +446,7 @@ See <a href="/about/drc_ref_netter.xml#device_scaling">Netter#device_scaling</a>
<p>Usage:</p>
<ul>
<li><tt>diode(name)</tt></li>
<li><tt>diode(name, class)</tt></li>
</ul>
<p>
Use this class with <a href="#extract_devices">extract_devices</a> to specify extraction of a
@ -455,6 +460,7 @@ about this extractor.
<p>Usage:</p>
<ul>
<li><tt>dmos3(name)</tt></li>
<li><tt>dmos3(name, class)</tt></li>
</ul>
<p>
Use this class with <a href="#extract_devices">extract_devices</a> to specify extraction of a
@ -470,6 +476,7 @@ about this extractor (strict mode applies for 'dmos3').
<p>Usage:</p>
<ul>
<li><tt>dmos4(name)</tt></li>
<li><tt>dmos4(name, class)</tt></li>
</ul>
<p>
Use this class with <a href="#extract_devices">extract_devices</a> to specify extraction of a
@ -1054,6 +1061,7 @@ argument, "middle" represents the bounding box center marker generator on primar
<p>Usage:</p>
<ul>
<li><tt>mos3(name)</tt></li>
<li><tt>mos3(name, class)</tt></li>
</ul>
<p>
Use this class with <a href="#extract_devices">extract_devices</a> to specify extraction of a
@ -1067,6 +1075,7 @@ about this extractor (non-strict mode applies for 'mos3').
<p>Usage:</p>
<ul>
<li><tt>mos4(name)</tt></li>
<li><tt>mos4(name, class)</tt></li>
</ul>
<p>
Use this class with <a href="#extract_devices">extract_devices</a> to specify extraction of a
@ -1402,6 +1411,7 @@ version of the L2N DB format will be used.
<p>Usage:</p>
<ul>
<li><tt>resistor(name, sheet_rho)</tt></li>
<li><tt>resistor(name, sheet_rho, class)</tt></li>
</ul>
<p>
Use this class with <a href="#extract_devices">extract_devices</a> to specify extraction of a resistor.
@ -1417,6 +1427,7 @@ about this extractor.
<p>Usage:</p>
<ul>
<li><tt>resistor_with_bulk(name, sheet_rho)</tt></li>
<li><tt>resistor_with_bulk(name, sheet_rho, class)</tt></li>
</ul>
<p>
Use this class with <a href="#extract_devices">extract_devices</a> to specify extraction of a resistor
@ -1922,6 +1933,7 @@ shape.
<p>Usage:</p>
<ul>
<li><tt>write_spice([ use_net_names [, with_comments ] ])</tt></li>
<li><tt>write_spice(writer_delegate [, use_net_names [, with_comments ] ])</tt></li>
</ul>
<p>
Use this option in <a href="#target_netlist">target_netlist</a> 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.
</p><p>
"writer_delegate" allows using a <a href="#NetlistSpiceWriterDelegate">NetlistSpiceWriterDelegate</a> object to
control the actual writing.
</p>
</doc>

View File

@ -386,6 +386,9 @@ gate = nactive &amp; poly # gate area
extract_devices(mos4("NMOS4"), { :SD =&gt; nsd, :G =&gt; gate, :P =&gt; poly, :W =&gt; bulk })
</pre>
</p><p>
The return value of this method will be the device class of the devices
generated in the extraction step (see <a href="#DeviceClass">DeviceClass</a>).
</p>
<a name="l2n_data"/><h2>"l2n_data" - Gets the internal <class_doc href="LayoutToNetlist">LayoutToNetlist</class_doc> object</h2>
<keyword name="l2n_data"/>

View File

@ -3,9 +3,9 @@
<doc>
<title>LVS Devices Extractors</title>
<title>LVS Device Extractors</title>
<keyword name="LVS"/>
<keyword name="LVS Devices Extractors"/>
<keyword name="LVS Device Extractors"/>
<h2-index/>
@ -345,5 +345,64 @@ extract_devices(bjt3(model_name), { "C" => collector, "B" => base, "E" => emitte
<img src="/manual/bjtlat_ex_ts.png"/>
</p>
<h2>Device extractors and device classes</h2>
<p>
"extract_devices" will return the <class_doc href="DeviceClass">DeviceClass</class_doc> 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.
</p>
<p>
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.
</p>
<p>
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:
</p>
<pre>dc = extract_devices(resistor("RES", 1), ...)
dc.enable_parameter("W", true)
dc.enable_parameter("L", true)
</pre>
<p>
This will modify the parameters of the generated device class such that "W" and "L" are
fully enabled parameters.
</p>
<p>
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".
</p>
<pre>class MyResistor &lt; RBA::DeviceClassResistor
def initialize
super
enable_parameter("W", true)
enable_parameter("L", true)
end
end
...
extract_devices(resistor("RES", 1, MyResistor), ...)
</pre>
<p>
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.
</p>
</doc>

View File

@ -25,6 +25,7 @@
#include "layIndexedNetlistModel.h"
#include "layNetlistCrossReferenceModel.h"
#include "dbNetlistDeviceClasses.h"
#include "tlMath.h"
#include <QPainter>
#include <QIcon>
@ -324,7 +325,8 @@ std::string device_parameter_string (const db::Device *device)
bool first = true;
const std::vector<db::DeviceParameterDefinition> &pd = device->device_class ()->parameter_definitions ();
for (std::vector<db::DeviceParameterDefinition>::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) {

View File

@ -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);

View File

@ -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");
}

View File

@ -35,7 +35,7 @@ namespace tl
* @brief A generic less operator
*/
template <class T>
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 <class T>
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 <class T>
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 <class T>
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 <class T>
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);
}

3
testdata/algo/nreader14.cir vendored Normal file
View File

@ -0,0 +1,3 @@
.include "nreader14a.cir"

4
testdata/algo/nreader14a.cir vendored Normal file
View File

@ -0,0 +1,4 @@
.subckt INVX1 1 2 3 4 5 6
.include nreader14x.cir
.ends

4
testdata/algo/nreader14x.cir vendored Normal file
View File

@ -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

18
testdata/algo/nreader15.cir vendored Normal file
View File

@ -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

View File

@ -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)

11
testdata/lvs/enable_wl1.cir vendored Normal file
View File

@ -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

52
testdata/lvs/enable_wl1.lvs vendored Normal file
View File

@ -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

118
testdata/lvs/enable_wl1.lvsdb vendored Normal file
View File

@ -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)
)
)
)

11
testdata/lvs/enable_wl2.cir vendored Normal file
View File

@ -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

33
testdata/lvs/enable_wl2.lvs vendored Normal file
View File

@ -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

118
testdata/lvs/enable_wl2.lvsdb vendored Normal file
View File

@ -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)
)
)
)

11
testdata/lvs/enable_wl3.cir vendored Normal file
View File

@ -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

33
testdata/lvs/enable_wl3.lvs vendored Normal file
View File

@ -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

121
testdata/lvs/enable_wl3.lvsdb vendored Normal file
View File

@ -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)
)
)
)

4
testdata/lvs/resistor.cir vendored Normal file
View File

@ -0,0 +1,4 @@
.SUBCKT Rre
RR0 vdd! gnd! 10 RR1 W=600n L=6u M=1
.ENDS

BIN
testdata/lvs/resistor.gds vendored Normal file

Binary file not shown.

4
testdata/lvs/resistor2.cir vendored Normal file
View File

@ -0,0 +1,4 @@
.SUBCKT Rre
RR0 vdd! gnd! 10 RR1 W=600n L=7u M=1
.ENDS

View File

@ -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)

View File

@ -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")