mirror of https://github.com/KLayout/klayout.git
Merge branch 'wip-lvs'
This commit is contained in:
commit
4e54715d64
|
|
@ -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);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 ()) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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", ¶meter_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 ();
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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*/
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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%
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -386,6 +386,9 @@ gate = nactive & poly # gate area
|
|||
|
||||
extract_devices(mos4("NMOS4"), { :SD => nsd, :G => gate, :P => poly, :W => 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"/>
|
||||
|
|
|
|||
|
|
@ -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 < 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>
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
.include "nreader14a.cir"
|
||||
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
.subckt INVX1 1 2 3 4 5 6
|
||||
.include nreader14x.cir
|
||||
.ends
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
.SUBCKT Rre
|
||||
RR0 vdd! gnd! 10 RR1 W=600n L=6u M=1
|
||||
.ENDS
|
||||
|
||||
Binary file not shown.
|
|
@ -0,0 +1,4 @@
|
|||
.SUBCKT Rre
|
||||
RR0 vdd! gnd! 10 RR1 W=600n L=7u M=1
|
||||
.ENDS
|
||||
|
||||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
Loading…
Reference in New Issue