Fixed DeviceClass assignment operator

This commit is contained in:
Matthias Koefferlein 2021-07-06 07:56:27 +02:00
parent 4e0d8d92ef
commit 8f65ab099f
6 changed files with 710 additions and 533 deletions

View File

@ -120,11 +120,6 @@ public:
virtual bool less (const db::Device &a, const db::Device &b) const;
virtual DeviceParameterCompareDelegate *clone () const
{
return new PrimaryDeviceParametersAreEqual (*this);
}
private:
double m_relative;
};
@ -159,13 +154,13 @@ bool PrimaryDeviceParametersAreEqual::less (const db::Device &a, const db::Devic
// DeviceClass class implementation
DeviceClass::DeviceClass ()
: m_strict (false), mp_netlist (0)
: m_strict (false), mp_netlist (0), m_supports_parallel_combination (false), m_supports_serial_combination (false)
{
// .. nothing yet ..
}
DeviceClass::DeviceClass (const DeviceClass &other)
: gsi::ObjectBase (other), tl::Object (other), tl::UniqueId (other), m_strict (false), mp_netlist (0)
: gsi::ObjectBase (other), tl::Object (other), tl::UniqueId (other), m_strict (false), mp_netlist (0), m_supports_parallel_combination (false), m_supports_serial_combination (false)
{
operator= (other);
}
@ -173,12 +168,18 @@ DeviceClass::DeviceClass (const DeviceClass &other)
DeviceClass &DeviceClass::operator= (const DeviceClass &other)
{
if (this != &other) {
m_terminal_definitions = other.m_terminal_definitions;
m_parameter_definitions = other.m_parameter_definitions;
m_name = other.m_name;
m_description = other.m_description;
m_strict = other.m_strict;
mp_pc_delegate.reset (const_cast<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;
}

View File

@ -295,7 +295,6 @@ public:
DeviceParameterCompareDelegate () { }
virtual ~DeviceParameterCompareDelegate () { }
virtual DeviceParameterCompareDelegate *clone () const = 0;
virtual bool less (const db::Device &a, const db::Device &b) const = 0;
};
@ -315,11 +314,6 @@ public:
virtual bool less (const db::Device &a, const db::Device &b) const;
virtual DeviceParameterCompareDelegate *clone () const
{
return new EqualDeviceParameters (*this);
}
EqualDeviceParameters &operator+= (const EqualDeviceParameters &other);
EqualDeviceParameters operator+ (const EqualDeviceParameters &other) const
@ -344,15 +338,35 @@ public:
virtual bool less (const db::Device &a, const db::Device &b) const;
virtual DeviceParameterCompareDelegate *clone () const
{
return new AllDeviceParametersAreEqual (*this);
}
private:
double m_relative;
};
/**
* @brief A device combiner
*
* The device combiner is a delegate that combines devices
*/
class DB_PUBLIC DeviceCombiner
: public gsi::ObjectBase, public tl::Object
{
public:
DeviceCombiner () { }
virtual ~DeviceCombiner () { }
/**
* @brief Combines two devices
*
* This method shall test, whether the two devices can be combined. Both devices
* are guaranteed to share the same device class.
* If they cannot be combined, this method shall do nothing and return false.
* If they can be combined, this method shall reconnect the nets of the first
* device and entirely disconnect the nets of the second device.
* The second device will be deleted afterwards.
*/
virtual bool combine_devices (db::Device *a, db::Device *b) const = 0;
};
/**
* @brief A device class
*
@ -553,25 +567,57 @@ public:
* device and entirely disconnect the nets of the second device.
* The second device will be deleted afterwards.
*/
virtual bool combine_devices (db::Device * /*a*/, db::Device * /*b*/) const
bool combine_devices (db::Device *a, db::Device *b) const
{
return false;
return mp_device_combiner.get () ? mp_device_combiner->combine_devices (a, b) : false;
}
/**
* @brief Returns true if the device class supports device combination in parallel mode
*/
virtual bool supports_parallel_combination () const
bool supports_parallel_combination () const
{
return false;
return m_supports_parallel_combination;
}
/**
* @brief Returns true if the device class supports device combination in serial mode
*/
virtual bool supports_serial_combination () const
bool supports_serial_combination () const
{
return false;
return m_supports_serial_combination;
}
/**
* @brief Sets a value indicating that the class supports device combination in parallel mode
*/
void set_supports_parallel_combination (bool f)
{
m_supports_parallel_combination = f;
}
/**
* @brief Sets a value indicating that the class supports device combination in serial mode
*/
void set_supports_serial_combination (bool f)
{
m_supports_serial_combination = f;
}
/**
* @brief Marks two terminals as equivalent (swappable)
*/
void equivalent_terminal_id (size_t tid, size_t equiv_tid)
{
m_equivalent_terminal_ids.insert (std::make_pair (tid, equiv_tid));
}
/**
* @brief Clears all equivalent terminal ids
*/
void clear_equivalent_terminal_ids ()
{
m_equivalent_terminal_ids.clear ();
}
/**
@ -580,9 +626,14 @@ public:
* This method returns a "normalized" terminal ID. For example, for MOS
* transistors where S and D can be exchanged, D will be mapped to S.
*/
virtual size_t normalize_terminal_id (size_t tid) const
size_t normalize_terminal_id (size_t tid) const
{
return tid;
std::map<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;
}
}
/**
@ -643,6 +694,35 @@ public:
return mp_pc_delegate.get ();
}
/**
* @brief Registers a device combiner
*
* The device class takes ownership of the combiner.
*/
void set_device_combiner (db::DeviceCombiner *combiner)
{
if (combiner) {
combiner->keep (); // assume transfer of ownership for scripts
}
mp_device_combiner.reset (combiner);
}
/**
* @brief Gets the device combiner or null if no such delegate is registered
*/
const db::DeviceCombiner *device_combiner () const
{
return mp_device_combiner.get ();
}
/**
* @brief Gets the device combiner or null if no such delegate is registered (non-const version)
*/
db::DeviceCombiner *device_combiner ()
{
return mp_device_combiner.get ();
}
/**
* @brief Generate memory statistics
*/
@ -667,6 +747,10 @@ private:
bool m_strict;
db::Netlist *mp_netlist;
tl::shared_ptr<db::DeviceParameterCompareDelegate> mp_pc_delegate;
tl::shared_ptr<db::DeviceCombiner> mp_device_combiner;
bool m_supports_parallel_combination;
bool m_supports_serial_combination;
std::map<size_t, size_t> m_equivalent_terminal_ids;
void set_netlist (db::Netlist *nl)
{

View File

@ -43,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
@ -110,8 +476,13 @@ DB_PUBLIC size_t DeviceClassResistor::terminal_id_B = 1;
DeviceClassResistor::DeviceClassResistor ()
{
set_supports_serial_combination (true);
set_supports_parallel_combination (true);
set_device_combiner (new ResistorDeviceCombiner ());
add_terminal_definition (db::DeviceTerminalDefinition ("A", "Terminal A"));
add_terminal_definition (db::DeviceTerminalDefinition ("B", "Terminal B"));
equivalent_terminal_id (terminal_id_A, terminal_id_B);
add_parameter_definition (db::DeviceParameterDefinition ("R", "Resistance (Ohm)", 0.0));
add_parameter_definition (db::DeviceParameterDefinition ("L", "Length (micrometer)", 0.0, false, 1e-6));
@ -120,71 +491,6 @@ DeviceClassResistor::DeviceClassResistor ()
add_parameter_definition (db::DeviceParameterDefinition ("P", "Perimeter (micrometer)", 0.0, false, 1e-6));
}
void DeviceClassResistor::parallel (Device *a, Device *b) const
{
double va = a->parameter_value (0);
double vb = b->parameter_value (0);
a->set_parameter_value (0, va + vb < 1e-10 ? 0.0 : va * vb / (va + vb));
// parallel width is sum of both, length is the one that gives the same value of resistance
// R = 1/(1/R1 + 1/R2)
// R = L/(W1+W2)
// R1 = L1/W1
// R2 = L2/W2
// -> L = (L1*L2*(W1+W2))/(L2*W1+L1*W2))
double l1 = a->parameter_value (1);
double w1 = a->parameter_value (2);
double l2 = b->parameter_value (1);
double w2 = b->parameter_value (2);
double dnom = (l2 * w1 + l1 * w2);
if (fabs (dnom) > 1e-15) {
a->set_parameter_value (1, (l1 * l2 * (w1 + w2)) / dnom);
}
a->set_parameter_value (2, w1 + w2);
// TODO: does this implementation make sense? (area)
double aa = a->parameter_value (3);
double ab = b->parameter_value (3);
a->set_parameter_value (3, aa + ab);
// TODO: does this implementation make sense? (perimeter)
double pa = a->parameter_value (4);
double pb = b->parameter_value (4);
a->set_parameter_value (4, pa + pb);
}
void DeviceClassResistor::serial (Device *a, Device *b) const
{
double va = a->parameter_value (0);
double vb = b->parameter_value (0);
a->set_parameter_value (0, va + vb);
// parallel length is sum of both, width is the one that gives the same value of resistance
// assuming same sheet rho
// R = R1+R2
// R = (L1+L2)/W
// R1 = L1/W1
// R2 = L2/W2
// -> W = ((L1+L2)*W1*W2)/(W1*L2+W2*L1)
double l1 = a->parameter_value (1);
double w1 = a->parameter_value (2);
double l2 = b->parameter_value (1);
double w2 = b->parameter_value (2);
a->set_parameter_value (1, l1 + l2);
double dnom = (l2 * w1 + l1 * w2);
if (fabs (dnom) > 1e-15) {
a->set_parameter_value (2, (w1 * w2 * (l1 + l2)) / dnom);
}
double aa = a->parameter_value (3);
double ab = b->parameter_value (3);
a->set_parameter_value (3, aa + ab);
double pa = a->parameter_value (4);
double pb = b->parameter_value (4);
a->set_parameter_value (4, pa + pb);
}
// ------------------------------------------------------------------------------------
// DeviceClassResistorWithBulk implementation
@ -193,22 +499,10 @@ DB_PUBLIC size_t DeviceClassResistorWithBulk::terminal_id_W = 2;
DeviceClassResistorWithBulk::DeviceClassResistorWithBulk ()
: DeviceClassResistor ()
{
set_device_combiner (new ResistorWithBulkDeviceCombiner ());
add_terminal_definition (db::DeviceTerminalDefinition ("W", "Terminal W (well, bulk)"));
}
bool DeviceClassResistorWithBulk::combine_devices (Device *a, Device *b) const
{
db::Net *nab = a->net_for_terminal (2);
db::Net *nbb = b->net_for_terminal (2);
if (nab == nbb && DeviceClassResistor::combine_devices (a, b)) {
a->join_terminals (2, b, 2);
return true;
} else {
return false;
}
}
// ------------------------------------------------------------------------------------
// DeviceClassCapacitor implementation
@ -221,46 +515,19 @@ DB_PUBLIC size_t DeviceClassCapacitor::terminal_id_B = 1;
DeviceClassCapacitor::DeviceClassCapacitor ()
{
set_supports_serial_combination (true);
set_supports_parallel_combination (true);
set_device_combiner (new CapacitorDeviceCombiner ());
add_terminal_definition (db::DeviceTerminalDefinition ("A", "Terminal A"));
add_terminal_definition (db::DeviceTerminalDefinition ("B", "Terminal B"));
equivalent_terminal_id (terminal_id_A, terminal_id_B);
add_parameter_definition (db::DeviceParameterDefinition ("C", "Capacitance (Farad)", 0.0));
add_parameter_definition (db::DeviceParameterDefinition ("A", "Area (square micrometer)", 0.0, false, 1e-12));
add_parameter_definition (db::DeviceParameterDefinition ("P", "Perimeter (micrometer)", 0.0, false, 1e-6));
}
void DeviceClassCapacitor::serial (Device *a, Device *b) const
{
double va = a->parameter_value (0);
double vb = b->parameter_value (0);
a->set_parameter_value (0, va + vb < 1e-10 ? 0.0 : va * vb / (va + vb));
// TODO: does this implementation make sense?
double aa = a->parameter_value (1);
double ab = b->parameter_value (1);
a->set_parameter_value (1, aa + ab);
// TODO: does this implementation make sense?
double pa = a->parameter_value (2);
double pb = b->parameter_value (2);
a->set_parameter_value (2, pa + pb);
}
void DeviceClassCapacitor::parallel (Device *a, Device *b) const
{
double va = a->parameter_value (0);
double vb = b->parameter_value (0);
a->set_parameter_value (0, va + vb);
double aa = a->parameter_value (1);
double ab = b->parameter_value (1);
a->set_parameter_value (1, aa + ab);
double pa = a->parameter_value (2);
double pb = b->parameter_value (2);
a->set_parameter_value (2, pa + pb);
}
// ------------------------------------------------------------------------------------
// DeviceClassCapacitorWithBulk implementation
@ -269,22 +536,10 @@ DB_PUBLIC size_t DeviceClassCapacitorWithBulk::terminal_id_W = 2;
DeviceClassCapacitorWithBulk::DeviceClassCapacitorWithBulk ()
: DeviceClassCapacitor ()
{
set_device_combiner (new CapacitorWithBulkDeviceCombiner ());
add_terminal_definition (db::DeviceTerminalDefinition ("W", "Terminal W (well, bulk)"));
}
bool DeviceClassCapacitorWithBulk::combine_devices (Device *a, Device *b) const
{
db::Net *nab = a->net_for_terminal (2);
db::Net *nbb = b->net_for_terminal (2);
if (nab == nbb && DeviceClassCapacitor::combine_devices (a, b)) {
a->join_terminals (2, b, 2);
return true;
} else {
return false;
}
}
// ------------------------------------------------------------------------------------
// DeviceClassInductor implementation
@ -295,28 +550,19 @@ DB_PUBLIC size_t DeviceClassInductor::terminal_id_B = 1;
DeviceClassInductor::DeviceClassInductor ()
{
set_supports_serial_combination (true);
set_supports_parallel_combination (true);
set_device_combiner (new InductorDeviceCombiner ());
add_terminal_definition (db::DeviceTerminalDefinition ("A", "Terminal A"));
add_terminal_definition (db::DeviceTerminalDefinition ("B", "Terminal B"));
equivalent_terminal_id (terminal_id_A, terminal_id_B);
add_parameter_definition (db::DeviceParameterDefinition ("L", "Inductance (Henry)", 0.0));
}
void DeviceClassInductor::parallel (Device *a, Device *b) const
{
double va = a->parameter_value (0);
double vb = b->parameter_value (0);
a->set_parameter_value (0, va + vb < 1e-10 ? 0.0 : va * vb / (va + vb));
}
void DeviceClassInductor::serial (Device *a, Device *b) const
{
double va = a->parameter_value (0);
double vb = b->parameter_value (0);
a->set_parameter_value (0, va + vb);
}
// ------------------------------------------------------------------------------------
// DeviceClassInductor implementation
// DeviceClassDiode implementation
DB_PUBLIC size_t DeviceClassDiode::param_id_A = 0;
DB_PUBLIC size_t DeviceClassDiode::param_id_P = 1;
@ -326,6 +572,9 @@ DB_PUBLIC size_t DeviceClassDiode::terminal_id_C = 1;
DeviceClassDiode::DeviceClassDiode ()
{
set_supports_parallel_combination (true);
set_device_combiner (new DiodeDeviceCombiner ());
add_terminal_definition (db::DeviceTerminalDefinition ("A", "Anode"));
add_terminal_definition (db::DeviceTerminalDefinition ("C", "Cathode"));
@ -333,29 +582,6 @@ DeviceClassDiode::DeviceClassDiode ()
add_parameter_definition (db::DeviceParameterDefinition ("P", "Perimeter (micrometer)", 0.0, false, 1e-6));
}
bool DeviceClassDiode::combine_devices (Device *a, Device *b) const
{
const db::Net *na1 = a->net_for_terminal (0);
const db::Net *na2 = a->net_for_terminal (1);
const db::Net *nb1 = b->net_for_terminal (0);
const db::Net *nb2 = b->net_for_terminal (1);
// only parallel diodes can be combined and their areas will add
if (na1 == nb1 && na2 == nb2) {
a->set_parameter_value (0, a->parameter_value (0) + b->parameter_value (0));
a->set_parameter_value (1, a->parameter_value (1) + b->parameter_value (1));
a->join_terminals (0, b, 0);
a->join_terminals (1, b, 1);
return true;
} else {
return false;
}
}
// ------------------------------------------------------------------------------------
// DeviceClassMOS3Transistor implementation
@ -372,9 +598,13 @@ DB_PUBLIC size_t DeviceClassMOS3Transistor::terminal_id_D = 2;
DeviceClassMOS3Transistor::DeviceClassMOS3Transistor ()
{
set_supports_parallel_combination (true);
set_device_combiner (new MOS3DeviceCombiner ());
add_terminal_definition (db::DeviceTerminalDefinition ("S", "Source"));
add_terminal_definition (db::DeviceTerminalDefinition ("G", "Gate"));
add_terminal_definition (db::DeviceTerminalDefinition ("D", "Drain"));
equivalent_terminal_id (terminal_id_D, terminal_id_S);
add_parameter_definition (db::DeviceParameterDefinition ("L", "Gate length (micrometer)", 0.0, true, 1e-6));
add_parameter_definition (db::DeviceParameterDefinition ("W", "Gate width (micrometer)", 0.0, true, 1e-6));
@ -384,51 +614,6 @@ DeviceClassMOS3Transistor::DeviceClassMOS3Transistor ()
add_parameter_definition (db::DeviceParameterDefinition ("PD", "Drain perimeter (micrometer)", 0.0, false, 1e-6));
}
bool DeviceClassMOS3Transistor::combine_devices (Device *a, Device *b) const
{
const db::Net *nas = a->net_for_terminal (0);
const db::Net *nag = a->net_for_terminal (1);
const db::Net *nad = a->net_for_terminal (2);
const db::Net *nbs = b->net_for_terminal (0);
const db::Net *nbg = b->net_for_terminal (1);
const db::Net *nbd = b->net_for_terminal (2);
// parallel transistors can be combined into one
if (((nas == nbs && nad == nbd) || (nas == nbd && nad == nbs)) && nag == nbg) {
// for combination the gate length must be identical
if (fabs (a->parameter_value (0) - b->parameter_value (0)) < 1e-6) {
combine_parameters (a, b);
if (nas == nbs && nad == nbd) {
a->join_terminals (0, b, 0);
a->join_terminals (2, b, 2);
} else {
a->join_terminals (0, b, 2);
a->join_terminals (2, b, 0);
}
a->join_terminals (1, b, 1);
return true;
}
}
return false;
}
void DeviceClassMOS3Transistor::combine_parameters (Device *a, Device *b) const
{
a->set_parameter_value (1, a->parameter_value (1) + b->parameter_value (1));
a->set_parameter_value (2, a->parameter_value (2) + b->parameter_value (2));
a->set_parameter_value (3, a->parameter_value (3) + b->parameter_value (3));
a->set_parameter_value (4, a->parameter_value (4) + b->parameter_value (4));
a->set_parameter_value (5, a->parameter_value (5) + b->parameter_value (5));
}
// ------------------------------------------------------------------------------------
// DeviceClassMOS4Transistor implementation
@ -436,48 +621,10 @@ DB_PUBLIC size_t DeviceClassMOS4Transistor::terminal_id_B = 3;
DeviceClassMOS4Transistor::DeviceClassMOS4Transistor ()
{
set_device_combiner (new MOS4DeviceCombiner ());
add_terminal_definition (db::DeviceTerminalDefinition ("B", "Bulk"));
}
bool DeviceClassMOS4Transistor::combine_devices (Device *a, Device *b) const
{
const db::Net *nas = a->net_for_terminal (0);
const db::Net *nag = a->net_for_terminal (1);
const db::Net *nad = a->net_for_terminal (2);
const db::Net *nab = a->net_for_terminal (3);
const db::Net *nbs = b->net_for_terminal (0);
const db::Net *nbg = b->net_for_terminal (1);
const db::Net *nbd = b->net_for_terminal (2);
const db::Net *nbb = b->net_for_terminal (3);
// parallel transistors can be combined into one
if (((nas == nbs && nad == nbd) || (nas == nbd && nad == nbs)) && nag == nbg && nab == nbb) {
// for combination the gate length must be identical
if (fabs (a->parameter_value (0) - b->parameter_value (0)) < 1e-6) {
combine_parameters (a, b);
if (nas == nbs && nad == nbd) {
a->join_terminals (0, b, 0);
a->join_terminals (2, b, 2);
} else {
a->join_terminals (0, b, 2);
a->join_terminals (2, b, 0);
}
a->join_terminals (1, b, 1);
a->join_terminals (3, b, 3);
return true;
}
}
return false;
}
// ------------------------------------------------------------------------------------
// DeviceClassBJT3Transistor implementation
@ -495,6 +642,9 @@ DB_PUBLIC size_t DeviceClassBJT3Transistor::terminal_id_E = 2;
DeviceClassBJT3Transistor::DeviceClassBJT3Transistor ()
{
set_supports_parallel_combination (true);
set_device_combiner (new BJT3DeviceCombiner ());
add_terminal_definition (db::DeviceTerminalDefinition ("C", "Collector"));
add_terminal_definition (db::DeviceTerminalDefinition ("B", "Base"));
add_terminal_definition (db::DeviceTerminalDefinition ("E", "Emitter"));
@ -509,38 +659,6 @@ DeviceClassBJT3Transistor::DeviceClassBJT3Transistor ()
add_parameter_definition (db::DeviceParameterDefinition ("NE", "Emitter count", 1.0, true));
}
bool DeviceClassBJT3Transistor::combine_devices (Device *a, Device *b) const
{
const db::Net *nac = a->net_for_terminal (0);
const db::Net *nab = a->net_for_terminal (1);
const db::Net *nae = a->net_for_terminal (2);
const db::Net *nbc = b->net_for_terminal (0);
const db::Net *nbb = b->net_for_terminal (1);
const db::Net *nbe = b->net_for_terminal (2);
// parallel transistors can be combined into one
if (nac == nbc && nae == nbe && nab == nbb) {
combine_parameters (a, b);
a->join_terminals (0, b, 0);
a->join_terminals (1, b, 1);
a->join_terminals (2, b, 2);
return true;
}
return false;
}
void DeviceClassBJT3Transistor::combine_parameters (Device *a, Device *b) const
{
a->set_parameter_value (param_id_AE, a->parameter_value (param_id_AE) + b->parameter_value (param_id_AE));
a->set_parameter_value (param_id_PE, a->parameter_value (param_id_PE) + b->parameter_value (param_id_PE));
a->set_parameter_value (param_id_NE, a->parameter_value (param_id_NE) + b->parameter_value (param_id_NE));
}
// ------------------------------------------------------------------------------------
// DeviceClassBJT4Transistor implementation
@ -548,35 +666,8 @@ DB_PUBLIC size_t DeviceClassBJT4Transistor::terminal_id_S = 3;
DeviceClassBJT4Transistor::DeviceClassBJT4Transistor ()
{
set_device_combiner (new BJT4DeviceCombiner ());
add_terminal_definition (db::DeviceTerminalDefinition ("S", "Substrate"));
}
bool DeviceClassBJT4Transistor::combine_devices (Device *a, Device *b) const
{
const db::Net *nac = a->net_for_terminal (0);
const db::Net *nab = a->net_for_terminal (1);
const db::Net *nae = a->net_for_terminal (2);
const db::Net *nas = a->net_for_terminal (3);
const db::Net *nbc = b->net_for_terminal (0);
const db::Net *nbb = b->net_for_terminal (1);
const db::Net *nbe = b->net_for_terminal (2);
const db::Net *nbs = b->net_for_terminal (3);
// parallel transistors can be combined into one
if (nac == nbc && nae == nbe && nab == nbb && nas == nbs) {
combine_parameters (a, b);
a->join_terminals (0, b, 0);
a->join_terminals (1, b, 1);
a->join_terminals (2, b, 2);
a->join_terminals (3, b, 3);
return true;
}
return false;
}
}

View File

@ -29,28 +29,13 @@
namespace db
{
/**
* @brief A basic two-terminal device class
*/
class DB_PUBLIC DeviceClassTwoTerminalDevice
: public db::DeviceClass
{
public:
virtual bool combine_devices (Device *a, Device *b) const;
virtual void parallel (Device *a, Device *b) const = 0;
virtual void serial (Device *a, Device *b) const = 0;
virtual bool supports_parallel_combination () const { return true; }
virtual bool supports_serial_combination () const { return true; }
};
/**
* @brief A basic resistor device class
* A resistor defines a single parameter, "R", which is the resistance in Ohm.
* It defines two terminals, "A" and "B" for the two terminals.
*/
class DB_PUBLIC DeviceClassResistor
: public db::DeviceClassTwoTerminalDevice
: public db::DeviceClass
{
public:
DeviceClassResistor ();
@ -68,14 +53,6 @@ public:
static size_t terminal_id_A;
static size_t terminal_id_B;
virtual void parallel (Device *a, Device *b) const;
virtual void serial (Device *a, Device *b) const;
virtual size_t normalize_terminal_id (size_t id) const
{
return id == terminal_id_B ? terminal_id_A : id;
}
};
/**
@ -95,8 +72,6 @@ public:
}
static size_t terminal_id_W;
virtual bool combine_devices (Device *a, Device *b) const;
};
/**
@ -105,7 +80,7 @@ public:
* It defines two terminals, "A" and "B" for the two terminals.
*/
class DB_PUBLIC DeviceClassCapacitor
: public db::DeviceClassTwoTerminalDevice
: public db::DeviceClass
{
public:
DeviceClassCapacitor ();
@ -121,14 +96,6 @@ public:
static size_t terminal_id_A;
static size_t terminal_id_B;
virtual void parallel (Device *a, Device *b) const;
virtual void serial (Device *a, Device *b) const;
virtual size_t normalize_terminal_id (size_t id) const
{
return id == terminal_id_B ? terminal_id_A : id;
}
};
/**
@ -148,8 +115,6 @@ public:
}
static size_t terminal_id_W;
virtual bool combine_devices (Device *a, Device *b) const;
};
/**
@ -158,7 +123,7 @@ public:
* It defines two terminals, "A" and "B" for the two terminals.
*/
class DB_PUBLIC DeviceClassInductor
: public db::DeviceClassTwoTerminalDevice
: public db::DeviceClass
{
public:
DeviceClassInductor ();
@ -172,14 +137,6 @@ public:
static size_t terminal_id_A;
static size_t terminal_id_B;
virtual void parallel (Device *a, Device *b) const;
virtual void serial (Device *a, Device *b) const;
virtual size_t normalize_terminal_id (size_t id) const
{
return id == terminal_id_B ? terminal_id_A : id;
}
};
/**
@ -204,9 +161,6 @@ public:
{
return new DeviceClassDiode (*this);
}
virtual bool combine_devices (Device *a, Device *b) const;
virtual bool supports_parallel_combination () const { return true; }
};
/**
@ -237,14 +191,6 @@ public:
return new DeviceClassMOS3Transistor (*this);
}
virtual bool combine_devices (Device *a, Device *b) const;
virtual bool supports_parallel_combination () const { return true; }
virtual size_t normalize_terminal_id (size_t tid) const
{
return tid == terminal_id_D ? terminal_id_S : tid;
}
protected:
void combine_parameters (Device *a, Device *b) const;
};
@ -266,13 +212,6 @@ public:
{
return new DeviceClassMOS4Transistor (*this);
}
virtual size_t normalize_terminal_id (size_t tid) const
{
return tid == terminal_id_D ? terminal_id_S : tid;
}
virtual bool combine_devices (Device *a, Device *b) const;
};
/**
@ -303,12 +242,6 @@ public:
{
return new DeviceClassBJT3Transistor (*this);
}
virtual bool combine_devices (Device *a, Device *b) const;
virtual bool supports_parallel_combination () const { return true; }
protected:
void combine_parameters (Device *a, Device *b) const;
};
/**
@ -328,8 +261,6 @@ public:
{
return new DeviceClassBJT4Transistor (*this);
}
virtual bool combine_devices (Device *a, Device *b) const;
};
}

View File

@ -876,6 +876,31 @@ public:
gsi::Callback cb_less;
};
/**
* @brief A DeviceCombiner implementation that allows reimplementation of the virtual methods
*/
class GenericDeviceCombiner
: public db::DeviceCombiner
{
public:
GenericDeviceCombiner ()
: db::DeviceCombiner ()
{
// .. nothing yet ..
}
virtual bool combine_devices (db::Device *a, db::Device *b) const
{
if (cb_combine.can_issue ()) {
return cb_combine.issue<db::DeviceCombiner, bool, db::Device *, db::Device *> (&db::DeviceCombiner::combine_devices, a, b);
} else {
return false;
}
}
gsi::Callback cb_combine;
};
}
db::EqualDeviceParameters *make_equal_dp (size_t param_id, double absolute, double relative)
@ -942,6 +967,29 @@ Class<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);
@ -957,6 +1005,16 @@ 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);
@ -987,6 +1045,20 @@ static const db::DeviceParameterDefinition *parameter_definition2 (const db::Dev
}
}
static void dc_add_terminal_definition (db::DeviceClass *cls, db::DeviceTerminalDefinition *terminal_def)
{
if (terminal_def) {
*terminal_def = cls->add_terminal_definition (*terminal_def);
}
}
static void dc_add_parameter_definition (db::DeviceClass *cls, db::DeviceParameterDefinition *parameter_def)
{
if (parameter_def) {
*parameter_def = cls->add_parameter_definition (*parameter_def);
}
}
Class<db::DeviceClass> decl_dbDeviceClass ("db", "DeviceClass",
gsi::method ("name", &db::DeviceClass::name,
"@brief Gets the name of the device class."
@ -1088,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"
@ -1099,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 "
@ -1109,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 {
@ -1184,87 +1335,6 @@ private:
}
static void gdc_add_terminal_definition (GenericDeviceClass *cls, db::DeviceTerminalDefinition *terminal_def)
{
if (terminal_def) {
*terminal_def = cls->add_terminal_definition (*terminal_def);
}
}
static void gdc_add_parameter_definition (GenericDeviceClass *cls, db::DeviceParameterDefinition *parameter_def)
{
if (parameter_def) {
*parameter_def = cls->add_parameter_definition (*parameter_def);
}
}
Class<GenericDeviceClass> decl_GenericDeviceClass (decl_dbDeviceClass, "db", "GenericDeviceClass",
gsi::method_ext ("add_terminal", &gsi::gdc_add_terminal_definition, gsi::arg ("terminal_def"),
"@brief Adds the given terminal definition to the device class\n"
"This method will define a new terminal. The new terminal is added at the end of existing terminals. "
"The terminal definition object passed as the argument is modified to contain the "
"new ID of the terminal.\n"
"\n"
"The terminal is copied into the device class. Modifying the terminal object later "
"does not have the effect of changing the terminal definition."
) +
gsi::method ("clear_terminals", &GenericDeviceClass::clear_terminal_definitions,
"@brief Clears the list of terminals\n"
) +
gsi::method_ext ("add_parameter", &gsi::gdc_add_parameter_definition, gsi::arg ("parameter_def"),
"@brief Adds the given parameter definition to the device class\n"
"This method will define a new parameter. The new parameter is added at the end of existing parameters. "
"The parameter definition object passed as the argument is modified to contain the "
"new ID of the parameter."
"\n"
"The parameter is copied into the device class. Modifying the parameter object later "
"does not have the effect of changing the parameter definition."
) +
gsi::method ("clear_parameters", &GenericDeviceClass::clear_parameter_definitions,
"@brief Clears the list of parameters\n"
) +
gsi::callback ("combine_devices", &GenericDeviceClass::combine_devices, &GenericDeviceClass::cb_combine_devices, gsi::arg ("a"), gsi::arg ("b"),
"@brief Combines two devices.\n"
"This method shall test, whether the two devices can be combined. Both devices "
"are guaranteed to share the same device class (self). "
"If they cannot be combined, this method shall do nothing and return false. "
"If they can be combined, this method shall reconnect the nets of the first "
"device and entirely disconnect the nets of the second device. "
"It shall combine the parameters of both devices into the first. "
"The second device will be deleted afterwards.\n"
) +
gsi::method ("supports_parallel_combination=", &GenericDeviceClass::set_supports_parallel_combination, gsi::arg ("f"),
"@brief Specifies whether the device supports parallel device combination.\n"
"Parallel device combination means that all terminals of two combination candidates are connected to the same nets. "
"If the device does not support this combination mode, this predicate can be set to false. This will make the device "
"extractor skip the combination test in parallel mode and improve performance somewhat."
) +
gsi::method ("supports_serial_combination=", &GenericDeviceClass::set_supports_serial_combination, gsi::arg ("f"),
"@brief Specifies whether the device supports serial device combination.\n"
"Serial device combination means that the devices are connected by internal nodes. "
"If the device does not support this combination mode, this predicate can be set to false. This will make the device "
"extractor skip the combination test in serial mode and improve performance somewhat."
) +
gsi::method ("equivalent_terminal_id", &GenericDeviceClass::equivalent_terminal_id, gsi::arg ("original_id"), gsi::arg ("equivalent_id"),
"@brief Specifies a terminal to be equivalent to another.\n"
"Use this method to specify two terminals to be exchangeable. For example to make S and D of a MOS transistor equivalent, "
"call this method with S and D terminal IDs. In netlist matching, S will be translated to D and thus made equivalent to D.\n"
"\n"
"Note that terminal equivalence is not effective if the device class operates in strict mode (see \\DeviceClass#strict=)."
),
"@brief A generic device class\n"
"This class allows building generic device classes. Specifically, terminals can be defined "
"by adding terminal definitions. Terminal definitions should not be added dynamically. To create "
"your own device, instantiate the \\GenericDeviceClass object, set name and description and "
"specify the terminals. Then add this new device class to the \\Netlist object where it will live "
"and be used to define device instances (\\Device objects).\n"
"\n"
"In addition, parameters can be defined which correspond to values stored inside the "
"specific device instance (\\Device object)."
"\n"
"This class has been added in version 0.26."
);
static db::Net *create_net (db::Circuit *c, const std::string &name)
{
db::Net *n = new db::Net ();

View File

@ -124,13 +124,13 @@ class DBNetlist_TestClass < TestBase
def test_2_NetlistBasicDeviceClass
nl = RBA::Netlist::new
c = RBA::GenericDeviceClass::new
c = RBA::DeviceClass::new
nl.add(c)
c.name = "XYZ"
assert_equal(c.name, "XYZ")
cc = RBA::GenericDeviceClass::new
cc = RBA::DeviceClass::new
begin
nl.remove(cc) # not in netlist yet
@ -158,7 +158,7 @@ class DBNetlist_TestClass < TestBase
nl.each_device_class { |i| names << i.name }
assert_equal(names, [ c.name ])
cc = RBA::GenericDeviceClass::new
cc = RBA::DeviceClass::new
nl.add(cc)
cc.name = "UVW"
@ -239,7 +239,7 @@ class DBNetlist_TestClass < TestBase
nl = RBA::Netlist::new
dc = RBA::GenericDeviceClass::new
dc = RBA::DeviceClass::new
nl.add(dc)
assert_equal(dc.netlist.object_id, nl.object_id)
dc.name = "DC"
@ -576,11 +576,11 @@ class DBNetlist_TestClass < TestBase
end
def test_7_GenericDeviceClass
def test_7_DeviceClass
nl = RBA::Netlist::new
dc = RBA::GenericDeviceClass::new
dc = RBA::DeviceClass::new
nl.add(dc)
dc.name = "DC"
assert_equal(dc.name, "DC")
@ -758,7 +758,7 @@ class DBNetlist_TestClass < TestBase
nl = RBA::Netlist::new
dc = RBA::GenericDeviceClass::new
dc = RBA::DeviceClass::new
dc.name = "DC"
nl.add(dc)