mirror of https://github.com/KLayout/klayout.git
Merge remote-tracking branch 'origin/dvb'
This commit is contained in:
commit
3de4a8408e
|
|
@ -172,7 +172,11 @@ SOURCES = \
|
|||
dbDeepEdgePairs.cc \
|
||||
dbRegionUtils.cc \
|
||||
dbEdgesUtils.cc \
|
||||
dbRegionProcessors.cc
|
||||
dbRegionProcessors.cc \
|
||||
dbNetlistCompare.cc \
|
||||
dbNetlistReader.cc \
|
||||
dbNetlistSpiceReader.cc \
|
||||
gsiDeclDbNetlistCompare.cc
|
||||
|
||||
HEADERS = \
|
||||
dbArray.h \
|
||||
|
|
@ -310,7 +314,10 @@ HEADERS = \
|
|||
dbRegionUtils.h \
|
||||
dbEdgesUtils.h \
|
||||
dbRegionProcessors.h \
|
||||
gsiDeclDbHelpers.h
|
||||
gsiDeclDbHelpers.h \
|
||||
dbNetlistCompare.h \
|
||||
dbNetlistReader.h \
|
||||
dbNetlistSpiceReader.h
|
||||
|
||||
!equals(HAVE_QT, "0") {
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ namespace db
|
|||
// Circuit class implementation
|
||||
|
||||
Circuit::Circuit ()
|
||||
: mp_netlist (0),
|
||||
: m_cell_index (0), mp_netlist (0),
|
||||
m_device_by_id (this, &Circuit::begin_devices, &Circuit::end_devices),
|
||||
m_subcircuit_by_id (this, &Circuit::begin_subcircuits, &Circuit::end_subcircuits),
|
||||
m_net_by_cluster_id (this, &Circuit::begin_nets, &Circuit::end_nets),
|
||||
|
|
@ -45,7 +45,7 @@ Circuit::Circuit ()
|
|||
}
|
||||
|
||||
Circuit::Circuit (const Circuit &other)
|
||||
: gsi::ObjectBase (other), tl::Object (other), mp_netlist (0),
|
||||
: gsi::ObjectBase (other), tl::Object (other), m_cell_index (0), mp_netlist (0),
|
||||
m_device_by_id (this, &Circuit::begin_devices, &Circuit::end_devices),
|
||||
m_subcircuit_by_id (this, &Circuit::begin_subcircuits, &Circuit::end_subcircuits),
|
||||
m_net_by_cluster_id (this, &Circuit::begin_nets, &Circuit::end_nets),
|
||||
|
|
@ -80,6 +80,7 @@ Circuit &Circuit::operator= (const Circuit &other)
|
|||
clear ();
|
||||
|
||||
m_name = other.m_name;
|
||||
m_cell_index = other.m_cell_index;
|
||||
m_pins = other.m_pins;
|
||||
|
||||
std::map<const Device *, Device *> device_table;
|
||||
|
|
@ -246,6 +247,11 @@ Circuit::const_child_circuit_iterator Circuit::end_parents () const
|
|||
return reinterpret_cast<const tl::vector<const Circuit *> &> (mp_netlist->parent_circuits (const_cast <Circuit *> (this))).end ();
|
||||
}
|
||||
|
||||
void Circuit::clear_pins ()
|
||||
{
|
||||
m_pins.clear ();
|
||||
}
|
||||
|
||||
const Pin &Circuit::add_pin (const std::string &name)
|
||||
{
|
||||
m_pins.push_back (Pin (name));
|
||||
|
|
@ -312,6 +318,89 @@ void Circuit::unregister_ref (SubCircuit *r)
|
|||
m_refs.erase (r);
|
||||
}
|
||||
|
||||
void Circuit::flatten_subcircuit (SubCircuit *subcircuit)
|
||||
{
|
||||
tl_assert (subcircuit != 0);
|
||||
|
||||
const db::Circuit *c = subcircuit->circuit_ref ();
|
||||
|
||||
// copy the nets, produce a net map
|
||||
|
||||
std::map<const db::Net *, db::Net *> net2net;
|
||||
|
||||
for (db::Circuit::const_net_iterator n = c->begin_nets (); n != c->end_nets (); ++n) {
|
||||
|
||||
// TODO: cannot join pins through subcircuits currently
|
||||
tl_assert (n->pin_count () <= 1);
|
||||
|
||||
db::Net *outside_net = 0;
|
||||
|
||||
if (n->pin_count () > 0) {
|
||||
size_t pin_id = n->begin_pins ()->pin_id ();
|
||||
outside_net = subcircuit->net_for_pin (pin_id);
|
||||
} else {
|
||||
outside_net = new db::Net ();
|
||||
if (! n->name ().empty ()) {
|
||||
outside_net->set_name (subcircuit->expanded_name () + "." + n->name ());
|
||||
}
|
||||
add_net (outside_net);
|
||||
}
|
||||
|
||||
net2net.insert (std::make_pair (n.operator-> (), outside_net));
|
||||
|
||||
}
|
||||
|
||||
// copy the devices
|
||||
|
||||
for (db::Circuit::const_device_iterator d = c->begin_devices (); d != c->end_devices (); ++d) {
|
||||
|
||||
db::Device *device = new db::Device (*d);
|
||||
if (! d->name ().empty ()) {
|
||||
device->set_name (subcircuit->expanded_name () + "." + d->name ());
|
||||
}
|
||||
add_device (device);
|
||||
|
||||
const std::vector<db::DeviceTerminalDefinition> &td = d->device_class ()->terminal_definitions ();
|
||||
for (std::vector<db::DeviceTerminalDefinition>::const_iterator t = td.begin (); t != td.end (); ++t) {
|
||||
|
||||
const db::Net *tnet = d->net_for_terminal (t->id ());
|
||||
if (tnet) {
|
||||
std::map<const db::Net *, db::Net *>::const_iterator n2n = net2net.find (tnet);
|
||||
tl_assert (n2n != net2net.end ());
|
||||
device->connect_terminal (t->id (), n2n->second);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// copy the subcircuits
|
||||
|
||||
for (db::Circuit::const_subcircuit_iterator sc = c->begin_subcircuits (); sc != c->end_subcircuits (); ++sc) {
|
||||
|
||||
db::SubCircuit *new_subcircuit = new db::SubCircuit (*sc);
|
||||
if (! new_subcircuit->name ().empty ()) {
|
||||
new_subcircuit->set_name (subcircuit->expanded_name () + "." + new_subcircuit->name ());
|
||||
}
|
||||
add_subcircuit (new_subcircuit);
|
||||
|
||||
const db::Circuit *cr = sc->circuit_ref ();
|
||||
for (db::Circuit::const_pin_iterator p = cr->begin_pins (); p != cr->end_pins (); ++p) {
|
||||
|
||||
const db::Net *pnet = sc->net_for_pin (p->id ());
|
||||
if (pnet) {
|
||||
std::map<const db::Net *, db::Net *>::const_iterator n2n = net2net.find (pnet);
|
||||
tl_assert (n2n != net2net.end ());
|
||||
new_subcircuit->connect_pin (p->id (), n2n->second);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
delete subcircuit;
|
||||
}
|
||||
|
||||
void Circuit::translate_circuits (const std::map<const Circuit *, Circuit *> &map)
|
||||
{
|
||||
for (subcircuit_iterator i = m_subcircuits.begin (); i != m_subcircuits.end (); ++i) {
|
||||
|
|
|
|||
|
|
@ -235,10 +235,14 @@ public:
|
|||
}
|
||||
|
||||
/**
|
||||
* @brief Adds a pin to this circuit
|
||||
* The circuit takes over ownership of the object.
|
||||
* @brief Clears the pins
|
||||
*/
|
||||
const Pin &add_pin(const std::string &name);
|
||||
void clear_pins ();
|
||||
|
||||
/**
|
||||
* @brief Adds a pin to this circuit
|
||||
*/
|
||||
const Pin &add_pin (const std::string &name);
|
||||
|
||||
/**
|
||||
* @brief Begin iterator for the pins of the circuit (non-const version)
|
||||
|
|
@ -585,6 +589,15 @@ public:
|
|||
*/
|
||||
void combine_devices ();
|
||||
|
||||
/**
|
||||
* @brief Flattens the given subcircuit
|
||||
*
|
||||
* The subcircuit is resolved into the parent circuit and finally removed.
|
||||
* Net, device and subcircuit names are decorated with the subcircuit's name
|
||||
* if required.
|
||||
*/
|
||||
void flatten_subcircuit (SubCircuit *subcircuit);
|
||||
|
||||
private:
|
||||
friend class Netlist;
|
||||
friend class Net;
|
||||
|
|
|
|||
|
|
@ -21,10 +21,81 @@
|
|||
*/
|
||||
|
||||
#include "dbDeviceClass.h"
|
||||
#include "dbDevice.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// EqualDeviceParameters implementation
|
||||
|
||||
static int compare_parameters (double pa, double pb, double absolute, double relative)
|
||||
{
|
||||
double pa_min = pa - absolute;
|
||||
double pa_max = pa + absolute;
|
||||
|
||||
double mean = 0.5 * (fabs (pa) + fabs (pb));
|
||||
pa_min -= mean * relative;
|
||||
pa_max += mean * relative;
|
||||
|
||||
// NOTE: parameter values may be small (e.g. pF for caps) -> no epsilon
|
||||
|
||||
if (pa_max < pb) {
|
||||
return -1;
|
||||
} else if (pa_min > pb) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
EqualDeviceParameters::EqualDeviceParameters ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
EqualDeviceParameters::EqualDeviceParameters (size_t parameter_id)
|
||||
{
|
||||
m_compare_set.push_back (std::make_pair (parameter_id, std::make_pair (0.0, 0.0)));
|
||||
}
|
||||
|
||||
EqualDeviceParameters::EqualDeviceParameters (size_t parameter_id, double relative, double absolute)
|
||||
{
|
||||
m_compare_set.push_back (std::make_pair (parameter_id, std::make_pair (relative, absolute)));
|
||||
}
|
||||
|
||||
bool EqualDeviceParameters::less (const db::Device &a, const db::Device &b) const
|
||||
{
|
||||
for (std::vector<std::pair<size_t, std::pair<double, double> > >::const_iterator c = m_compare_set.begin (); c != m_compare_set.end (); ++c) {
|
||||
int cmp = compare_parameters (a.parameter_value (c->first), b.parameter_value (c->first), c->second.first, c->second.second);
|
||||
if (cmp != 0) {
|
||||
return cmp < 0;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool EqualDeviceParameters::equal (const db::Device &a, const db::Device &b) const
|
||||
{
|
||||
for (std::vector<std::pair<size_t, std::pair<double, double> > >::const_iterator c = m_compare_set.begin (); c != m_compare_set.end (); ++c) {
|
||||
int cmp = compare_parameters (a.parameter_value (c->first), b.parameter_value (c->first), c->second.first, c->second.second);
|
||||
if (cmp != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
EqualDeviceParameters &EqualDeviceParameters::operator+= (const EqualDeviceParameters &other)
|
||||
{
|
||||
for (std::vector<std::pair<size_t, std::pair<double, double> > >::const_iterator c = other.m_compare_set.begin (); c != other.m_compare_set.end (); ++c) {
|
||||
m_compare_set.push_back (*c);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// DeviceClass class implementation
|
||||
|
||||
|
|
@ -44,8 +115,10 @@ 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;
|
||||
mp_pc_delegate.reset (const_cast<DeviceParameterCompareDelegate *> (other.mp_pc_delegate.get ()));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
|
@ -136,4 +209,68 @@ size_t DeviceClass::terminal_id_for_name (const std::string &name) const
|
|||
throw tl::Exception (tl::to_string (tr ("Invalid terminal name")) + ": '" + name + "'");
|
||||
}
|
||||
|
||||
// NOTE: to allow rounding errors for parameter comparison, we use
|
||||
// a default relative tolerance.
|
||||
const double relative_tolerance = 1e-6;
|
||||
|
||||
bool DeviceClass::less (const db::Device &a, const db::Device &b)
|
||||
{
|
||||
tl_assert (a.device_class () != 0);
|
||||
tl_assert (b.device_class () != 0);
|
||||
|
||||
const db::DeviceParameterCompareDelegate *pcd = a.device_class ()->mp_pc_delegate.get ();
|
||||
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;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
bool DeviceClass::equal (const db::Device &a, const db::Device &b)
|
||||
{
|
||||
tl_assert (a.device_class () != 0);
|
||||
tl_assert (b.device_class () != 0);
|
||||
|
||||
const db::DeviceParameterCompareDelegate *pcd = a.device_class ()->mp_pc_delegate.get ();
|
||||
if (! pcd) {
|
||||
pcd = b.device_class ()->mp_pc_delegate.get ();
|
||||
}
|
||||
|
||||
if (pcd != 0) {
|
||||
return pcd->equal (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 false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ public:
|
|||
* @brief Creates an empty device parameter definition
|
||||
*/
|
||||
DeviceParameterDefinition ()
|
||||
: m_name (), m_description (), m_default_value (0.0), m_id (0)
|
||||
: m_name (), m_description (), m_default_value (0.0), m_id (0), m_is_primary (true)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -132,8 +132,8 @@ public:
|
|||
/**
|
||||
* @brief Creates a device parameter definition with the given name and description
|
||||
*/
|
||||
DeviceParameterDefinition (const std::string &name, const std::string &description, double default_value = 0.0)
|
||||
: m_name (name), m_description (description), m_default_value (default_value), m_id (0)
|
||||
DeviceParameterDefinition (const std::string &name, const std::string &description, double default_value = 0.0, bool is_primary = true)
|
||||
: m_name (name), m_description (description), m_default_value (default_value), m_id (0), m_is_primary (is_primary)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -186,6 +186,25 @@ public:
|
|||
m_default_value = d;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets a value indicating whether the parameter is a primary parameter
|
||||
*
|
||||
* If this flag is set to true (the default), the parameter is considered a primary parameter.
|
||||
* Only primary parameters are compared by default.
|
||||
*/
|
||||
void set_is_primary (bool p)
|
||||
{
|
||||
m_is_primary = p;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether the parameter is a primary parameter
|
||||
*/
|
||||
bool is_primary () const
|
||||
{
|
||||
return m_is_primary;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the parameter ID
|
||||
*/
|
||||
|
|
@ -200,6 +219,7 @@ private:
|
|||
std::string m_name, m_description;
|
||||
double m_default_value;
|
||||
size_t m_id;
|
||||
bool m_is_primary;
|
||||
|
||||
void set_id (size_t id)
|
||||
{
|
||||
|
|
@ -207,6 +227,53 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A device parameter compare delegate
|
||||
*
|
||||
* Device parameter compare delegates are used to establish
|
||||
* device equivalence in the context of netlist comparison.
|
||||
*/
|
||||
class DB_PUBLIC DeviceParameterCompareDelegate
|
||||
: public gsi::ObjectBase, public tl::Object
|
||||
{
|
||||
public:
|
||||
DeviceParameterCompareDelegate () { }
|
||||
virtual ~DeviceParameterCompareDelegate () { }
|
||||
|
||||
virtual bool less (const db::Device &a, const db::Device &b) const = 0;
|
||||
virtual bool equal (const db::Device &a, const db::Device &b) const = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A parameter compare delegate that compares several parameters either relative or absolute (or both)
|
||||
*
|
||||
* The reasoning behind this class is to supply a chainable compare delegate: ab = a + b
|
||||
* where a and b are compare delegates for two different parameters and ab is the combined compare delegate.
|
||||
*/
|
||||
class DB_PUBLIC EqualDeviceParameters
|
||||
: public DeviceParameterCompareDelegate
|
||||
{
|
||||
public:
|
||||
EqualDeviceParameters ();
|
||||
EqualDeviceParameters (size_t parameter_id);
|
||||
EqualDeviceParameters (size_t parameter_id, double relative, double absolute);
|
||||
|
||||
virtual bool less (const db::Device &a, const db::Device &b) const;
|
||||
virtual bool equal (const db::Device &a, const db::Device &b) const;
|
||||
|
||||
EqualDeviceParameters &operator+= (const EqualDeviceParameters &other);
|
||||
|
||||
EqualDeviceParameters operator+ (const EqualDeviceParameters &other) const
|
||||
{
|
||||
EqualDeviceParameters pc (*this);
|
||||
pc += other;
|
||||
return pc;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::pair<size_t, std::pair<double, double> > > m_compare_set;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A device class
|
||||
*
|
||||
|
|
@ -228,14 +295,14 @@ public:
|
|||
/**
|
||||
* @brief Copy constructor
|
||||
* NOTE: do not use this copy constructor as the device class
|
||||
* is intended to subclassing.
|
||||
* is intended for subclassing.
|
||||
*/
|
||||
DeviceClass (const DeviceClass &other);
|
||||
|
||||
/**
|
||||
* @brief Assignment
|
||||
* NOTE: do not use this copy constructor as the device class
|
||||
* is intended to subclassing.
|
||||
* is intended for subclassing.
|
||||
*/
|
||||
DeviceClass &operator= (const DeviceClass &other);
|
||||
|
||||
|
|
@ -365,7 +432,7 @@ public:
|
|||
size_t terminal_id_for_name (const std::string &name) const;
|
||||
|
||||
/**
|
||||
* @brief Clears the circuit
|
||||
* @brief Clones the device class
|
||||
*/
|
||||
virtual DeviceClass *clone () const
|
||||
{
|
||||
|
|
@ -403,6 +470,57 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Normalizes the terminal IDs to indicate terminal swapping
|
||||
*
|
||||
* 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
|
||||
{
|
||||
return tid;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares the parameters of the devices a and b
|
||||
*
|
||||
* a and b are expected to originate from this or an equivalent device class having
|
||||
* the same parameters.
|
||||
* This is the "less" operation. If a parameter compare delegate is registered, this
|
||||
* compare request will be forwarded to the delegate.
|
||||
*
|
||||
* If two devices with different device classes are compared and only one of
|
||||
* the classes features a delegate, the one with the delegate is employed.
|
||||
*/
|
||||
static bool less (const db::Device &a, const db::Device &b);
|
||||
|
||||
/**
|
||||
* @brief Compares the parameters of the devices a and b
|
||||
*
|
||||
* a and b are expected to originate from this or an equivalent device class having
|
||||
* the same parameters.
|
||||
* This is the "equal" operation. If a parameter compare delegate is registered, this
|
||||
* compare request will be forwarded to the delegate.
|
||||
*
|
||||
* If two devices with different device classes are compared and only one of
|
||||
* the classes features a delegate, the one with the delegate is employed.
|
||||
*/
|
||||
static bool equal (const db::Device &a, const db::Device &b);
|
||||
|
||||
/**
|
||||
* @brief Registers a compare delegate
|
||||
*
|
||||
* The reasoning behind chosing a delegate is that a delegate is efficient
|
||||
* also in scripts if one of the standard delegates is taken.
|
||||
*
|
||||
* The device class takes ownership of the delegate.
|
||||
*/
|
||||
virtual void set_parameter_compare_delegate (db::DeviceParameterCompareDelegate *delegate)
|
||||
{
|
||||
delegate->keep (); // assume transfer of ownership for scripts
|
||||
mp_pc_delegate.reset (delegate);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class Netlist;
|
||||
|
||||
|
|
@ -410,6 +528,7 @@ private:
|
|||
std::vector<DeviceTerminalDefinition> m_terminal_definitions;
|
||||
std::vector<DeviceParameterDefinition> m_parameter_definitions;
|
||||
db::Netlist *mp_netlist;
|
||||
tl::shared_ptr<db::DeviceParameterCompareDelegate> mp_pc_delegate;
|
||||
|
||||
void set_netlist (db::Netlist *nl)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -267,6 +267,13 @@ local_cluster<T>::clear ()
|
|||
m_global_nets.clear ();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool
|
||||
local_cluster<T>::empty () const
|
||||
{
|
||||
return m_global_nets.empty () && m_shapes.empty ();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void
|
||||
local_cluster<T>::set_global_nets (const global_nets &gn)
|
||||
|
|
@ -1762,7 +1769,7 @@ hier_clusters<T>::do_build (cell_clusters_box_converter<T> &cbc, const db::Layou
|
|||
tl::RelativeProgress progress (tl::to_string (tr ("Computing local clusters")), called.size (), 1);
|
||||
|
||||
for (std::set<db::cell_index_type>::const_iterator c = called.begin (); c != called.end (); ++c) {
|
||||
build_local_cluster (layout, layout.cell (*c), shape_flags, conn, attr_equivalence);
|
||||
build_local_cluster (layout, layout.cell (*c), shape_flags, conn, *c == cell.cell_index () ? attr_equivalence : 0);
|
||||
++progress;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -218,6 +218,11 @@ public:
|
|||
*/
|
||||
void clear ();
|
||||
|
||||
/**
|
||||
* @brief Returns true if the cluster is empty
|
||||
*/
|
||||
bool empty () const;
|
||||
|
||||
/**
|
||||
* @brief Adds a shape with the given layer to the cluster
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -245,7 +245,7 @@ size_t LayoutToNetlist::global_net_id (const std::string &name)
|
|||
return m_conn.global_net_id (name);
|
||||
}
|
||||
|
||||
void LayoutToNetlist::extract_netlist (bool join_nets_by_label)
|
||||
void LayoutToNetlist::extract_netlist (const std::string &joined_net_names)
|
||||
{
|
||||
if (m_netlist_extracted) {
|
||||
throw tl::Exception (tl::to_string (tr ("The netlist has already been extracted")));
|
||||
|
|
@ -255,7 +255,7 @@ void LayoutToNetlist::extract_netlist (bool join_nets_by_label)
|
|||
}
|
||||
|
||||
db::NetlistExtractor netex;
|
||||
netex.extract_nets (dss (), m_layout_index, m_conn, *mp_netlist, m_net_clusters, join_nets_by_label);
|
||||
netex.extract_nets (dss (), m_layout_index, m_conn, *mp_netlist, m_net_clusters, joined_net_names);
|
||||
|
||||
m_netlist_extracted = true;
|
||||
}
|
||||
|
|
@ -323,7 +323,7 @@ void LayoutToNetlist::register_layer (const db::Region ®ion, const std::strin
|
|||
if (region.empty ()) {
|
||||
dl = dss ().empty_layer (m_layout_index);
|
||||
} else {
|
||||
throw tl::Exception (tl::to_string (tr ("Layer is not a deep region and cannot be registered with name: ")) + n);
|
||||
dl = dss ().create_from_flat (region, true);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -296,7 +296,7 @@ public:
|
|||
* @brief Runs the netlist extraction
|
||||
* See the class description for more details.
|
||||
*/
|
||||
void extract_netlist (bool join_nets_by_label = true);
|
||||
void extract_netlist (const std::string &joined_net_names = std::string ());
|
||||
|
||||
/**
|
||||
* @brief Marks the netlist as extracted
|
||||
|
|
|
|||
|
|
@ -369,6 +369,32 @@ void Netlist::remove_circuit (Circuit *circuit)
|
|||
m_circuits.erase (circuit);
|
||||
}
|
||||
|
||||
void Netlist::flatten_circuit (Circuit *circuit)
|
||||
{
|
||||
tl_assert (circuit != 0);
|
||||
|
||||
std::vector<db::SubCircuit *> refs;
|
||||
for (db::Circuit::refs_iterator sc = circuit->begin_refs (); sc != circuit->end_refs (); ++sc) {
|
||||
refs.push_back (sc.operator-> ());
|
||||
}
|
||||
|
||||
for (std::vector<db::SubCircuit *>::const_iterator r = refs.begin (); r != refs.end (); ++r) {
|
||||
(*r)->circuit ()->flatten_subcircuit (*r);
|
||||
}
|
||||
|
||||
delete circuit;
|
||||
}
|
||||
|
||||
DeviceClass *Netlist::device_class_by_name (const std::string &name)
|
||||
{
|
||||
for (device_class_iterator d = begin_device_classes (); d != end_device_classes (); ++d) {
|
||||
if (d->name () == name) {
|
||||
return d.operator-> ();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Netlist::add_device_class (DeviceClass *device_class)
|
||||
{
|
||||
m_device_classes.push_back (device_class);
|
||||
|
|
@ -499,13 +525,7 @@ std::string Netlist::to_string () const
|
|||
ps += pin2string (*p) + "=" + net2string (c->net_for_pin (p->id ()));
|
||||
}
|
||||
|
||||
res += std::string ("Circuit ") + c->name () + " (" + ps + "):\n";
|
||||
|
||||
#if 0 // for debugging
|
||||
for (db::Circuit::const_net_iterator n = c->begin_nets (); n != c->end_nets (); ++n) {
|
||||
res += " N" + net_name (n.operator-> ()) + " pins=" + tl::to_string (n->pin_count ()) + " sc_pins=" + tl::to_string (n->subcircuit_pin_count ()) + " terminals=" + tl::to_string (n->terminal_count ()) + "\n";
|
||||
}
|
||||
#endif
|
||||
res += std::string ("circuit ") + tl::to_word_or_quoted_string (c->name ()) + " (" + ps + ");\n";
|
||||
|
||||
for (db::Circuit::const_device_iterator d = c->begin_devices (); d != c->end_devices (); ++d) {
|
||||
std::string ts;
|
||||
|
|
@ -524,7 +544,7 @@ std::string Netlist::to_string () const
|
|||
}
|
||||
ps += p->name () + "=" + tl::to_string (d->parameter_value (p->id ()));
|
||||
}
|
||||
res += std::string (" D") + d->device_class ()->name () + " " + device2string (*d) + " (" + ts + ") [" + ps + "]\n";
|
||||
res += std::string (" device ") + tl::to_word_or_quoted_string (d->device_class ()->name ()) + " " + device2string (*d) + " (" + ts + ") (" + ps + ");\n";
|
||||
}
|
||||
|
||||
for (db::Circuit::const_subcircuit_iterator sc = c->begin_subcircuits (); sc != c->end_subcircuits (); ++sc) {
|
||||
|
|
@ -535,15 +555,354 @@ std::string Netlist::to_string () const
|
|||
if (p != circuit->begin_pins ()) {
|
||||
ps += ",";
|
||||
}
|
||||
const db::Pin &pin = *p;
|
||||
ps += pin2string (pin) + "=" + net2string (subcircuit.net_for_pin (pin.id ()));
|
||||
ps += pin2string (*p) + "=" + net2string (subcircuit.net_for_pin (p->id ()));
|
||||
}
|
||||
res += std::string (" X") + circuit->name () + " " + subcircuit2string (*sc) + " (" + ps + ")\n";
|
||||
res += std::string (" subcircuit ") + tl::to_word_or_quoted_string (circuit->name ()) + " " + subcircuit2string (*sc) + " (" + ps + ");\n";
|
||||
}
|
||||
|
||||
res += std::string ("end;\n");
|
||||
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static db::Net *read_net (tl::Extractor &ex, db::Circuit *circuit, std::map<std::string, db::Net *> &n2n)
|
||||
{
|
||||
std::string nn;
|
||||
bool has_name = false;
|
||||
size_t cluster_id = 0;
|
||||
|
||||
if (ex.test ("(")) {
|
||||
|
||||
ex.expect ("null");
|
||||
ex.expect (")");
|
||||
|
||||
return 0;
|
||||
|
||||
} else if (ex.test ("$")) {
|
||||
|
||||
bool has_i = ex.test ("I");
|
||||
ex.read (cluster_id);
|
||||
|
||||
nn = (has_i ? "$I" : "$") + tl::to_string (cluster_id);
|
||||
|
||||
if (has_i) {
|
||||
cluster_id = (std::numeric_limits<size_t>::max () - cluster_id) + 1;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
ex.read_word_or_quoted (nn);
|
||||
|
||||
has_name = true;
|
||||
|
||||
}
|
||||
|
||||
std::map<std::string, db::Net *>::const_iterator i = n2n.find (nn);
|
||||
if (i == n2n.end ()) {
|
||||
|
||||
db::Net *net = new db::Net ();
|
||||
circuit->add_net (net);
|
||||
if (has_name) {
|
||||
net->set_name (nn);
|
||||
} else {
|
||||
net->set_cluster_id (cluster_id);
|
||||
}
|
||||
|
||||
n2n.insert (std::make_pair (nn, net));
|
||||
return net;
|
||||
|
||||
} else {
|
||||
|
||||
return i->second;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static void read_pins (tl::Extractor &ex, db::Circuit *circuit, std::map<std::string, db::Net *> &n2n)
|
||||
{
|
||||
std::vector<std::string> org_pins;
|
||||
for (db::Circuit::const_pin_iterator p = circuit->begin_pins (); p != circuit->end_pins (); ++p) {
|
||||
org_pins.push_back (p->name ());
|
||||
}
|
||||
|
||||
circuit->clear_pins ();
|
||||
|
||||
ex.expect ("(");
|
||||
while (! ex.test (")")) {
|
||||
|
||||
ex.expect_more ();
|
||||
|
||||
std::string pn;
|
||||
if (ex.test ("$")) {
|
||||
size_t i;
|
||||
ex.read (i);
|
||||
} else {
|
||||
ex.read_word_or_quoted (pn);
|
||||
}
|
||||
|
||||
ex.expect ("=");
|
||||
|
||||
db::Net *net = read_net (ex, circuit, n2n);
|
||||
|
||||
if (circuit->pin_count () < org_pins.size () && pn != org_pins [circuit->pin_count ()]) {
|
||||
ex.error (tl::sprintf (tl::to_string (tr ("Circuit defines different name for pin than subcircuit: %s (circuit) vs. %s (subcircuit)")), pn, org_pins [circuit->pin_count ()]));
|
||||
}
|
||||
|
||||
const db::Pin &pin = circuit->add_pin (pn);
|
||||
if (net) {
|
||||
net->add_pin (db::NetPinRef (pin.id ()));
|
||||
}
|
||||
|
||||
ex.test (",");
|
||||
|
||||
}
|
||||
|
||||
if (circuit->pin_count () < org_pins.size ()) {
|
||||
ex.error (tl::to_string (tr ("Circuit defines less pins that subcircuit")));
|
||||
} else if (org_pins.size () > 0 && circuit->pin_count () > org_pins.size ()) {
|
||||
ex.error (tl::to_string (tr ("Circuit defines more pins that subcircuit")));
|
||||
}
|
||||
}
|
||||
|
||||
static void read_device_terminals (tl::Extractor &ex, db::Device *device, std::map<std::string, db::Net *> &n2n)
|
||||
{
|
||||
ex.expect ("(");
|
||||
while (! ex.test (")")) {
|
||||
|
||||
ex.expect_more ();
|
||||
|
||||
std::string tn;
|
||||
ex.read_word_or_quoted (tn);
|
||||
|
||||
size_t tid = std::numeric_limits<size_t>::max ();
|
||||
const std::vector<DeviceTerminalDefinition> &td = device->device_class ()->terminal_definitions ();
|
||||
for (std::vector<DeviceTerminalDefinition>::const_iterator i = td.begin (); i != td.end (); ++i) {
|
||||
if (i->name () == tn) {
|
||||
tid = i->id ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (tid == std::numeric_limits<size_t>::max ()) {
|
||||
ex.error (tl::to_string (tr ("Not a valid terminal name: ")) + tn);
|
||||
}
|
||||
|
||||
ex.expect ("=");
|
||||
|
||||
db::Net *net = read_net (ex, device->circuit (), n2n);
|
||||
if (net) {
|
||||
device->connect_terminal (tid, net);
|
||||
}
|
||||
|
||||
ex.test (",");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static void read_device_parameters (tl::Extractor &ex, db::Device *device)
|
||||
{
|
||||
if (! ex.test ("(")) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (! ex.test (")")) {
|
||||
|
||||
ex.expect_more ();
|
||||
|
||||
std::string pn;
|
||||
ex.read_word_or_quoted (pn);
|
||||
|
||||
size_t pid = std::numeric_limits<size_t>::max ();
|
||||
const std::vector<DeviceParameterDefinition> &pd = device->device_class ()->parameter_definitions ();
|
||||
for (std::vector<DeviceParameterDefinition>::const_iterator i = pd.begin (); i != pd.end (); ++i) {
|
||||
if (i->name () == pn) {
|
||||
pid = i->id ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pid == std::numeric_limits<size_t>::max ()) {
|
||||
ex.error (tl::to_string (tr ("Not a valid parameter name: ")) + pn);
|
||||
}
|
||||
|
||||
ex.expect ("=");
|
||||
|
||||
double value = 0;
|
||||
ex.read (value);
|
||||
device->set_parameter_value (pid, value);
|
||||
|
||||
ex.test (",");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static void read_device (tl::Extractor &ex, db::Circuit *circuit, std::map<std::string, db::Net *> &n2n)
|
||||
{
|
||||
db::Netlist *netlist = circuit->netlist ();
|
||||
|
||||
std::string dcn;
|
||||
ex.read_word_or_quoted (dcn);
|
||||
db::DeviceClass *dc = 0;
|
||||
for (db::Netlist::device_class_iterator i = netlist->begin_device_classes (); i != netlist->end_device_classes (); ++i) {
|
||||
if (i->name () == dcn) {
|
||||
dc = i.operator-> ();
|
||||
}
|
||||
}
|
||||
if (! dc) {
|
||||
ex.error (tl::to_string (tr ("Not a valid device class name: ")) + dcn);
|
||||
}
|
||||
|
||||
std::string dn;
|
||||
if (ex.test ("$")) {
|
||||
size_t i;
|
||||
ex.read (i);
|
||||
} else {
|
||||
ex.read_word_or_quoted (dn);
|
||||
}
|
||||
|
||||
db::Device *device = new db::Device (dc, dn);
|
||||
circuit->add_device (device);
|
||||
|
||||
read_device_terminals (ex, device, n2n);
|
||||
read_device_parameters (ex, device);
|
||||
}
|
||||
|
||||
static void read_subcircuit_pins (tl::Extractor &ex, db::Circuit *circuit, db::SubCircuit *subcircuit, std::map<std::string, db::Net *> &n2n)
|
||||
{
|
||||
db::Circuit *circuit_ref = subcircuit->circuit_ref ();
|
||||
db::Circuit::pin_iterator pi = circuit_ref->begin_pins ();
|
||||
|
||||
ex.expect ("(");
|
||||
while (! ex.test (")")) {
|
||||
|
||||
std::string pn;
|
||||
if (ex.test ("$")) {
|
||||
size_t i;
|
||||
ex.read (i);
|
||||
} else {
|
||||
ex.read_word_or_quoted (pn);
|
||||
}
|
||||
|
||||
ex.expect ("=");
|
||||
|
||||
if (pi == circuit_ref->end_pins ()) {
|
||||
// add a dummy pin
|
||||
circuit_ref->add_pin (pn);
|
||||
pi = circuit_ref->end_pins ();
|
||||
--pi;
|
||||
} else if (! pi->name ().empty () && pi->name () != pn) {
|
||||
ex.error (tl::to_string (tr ("Expected pin with name: ")) + pi->name ());
|
||||
}
|
||||
|
||||
ex.expect_more ();
|
||||
|
||||
db::Net *net = read_net (ex, circuit, n2n);
|
||||
if (net) {
|
||||
subcircuit->connect_pin (pi->id (), net);
|
||||
}
|
||||
|
||||
ex.test (",");
|
||||
|
||||
++pi;
|
||||
|
||||
}
|
||||
|
||||
if (pi != circuit_ref->end_pins ()) {
|
||||
ex.error (tl::to_string (tr ("Too few pins in subcircuit call")));
|
||||
}
|
||||
}
|
||||
|
||||
static void read_subcircuit (tl::Extractor &ex, db::Circuit *circuit, std::map<std::string, db::Net *> &n2n, std::map<std::string, db::Circuit *> &c2n)
|
||||
{
|
||||
std::string cn;
|
||||
ex.read_word_or_quoted (cn);
|
||||
|
||||
db::Circuit *cc = 0;
|
||||
std::map<std::string, db::Circuit *>::const_iterator ic = c2n.find (cn);
|
||||
if (ic == c2n.end ()) {
|
||||
|
||||
cc = new db::Circuit ();
|
||||
circuit->netlist ()->add_circuit (cc);
|
||||
cc->set_name (cn);
|
||||
|
||||
c2n.insert (std::make_pair (cn, cc));
|
||||
|
||||
} else {
|
||||
cc = ic->second;
|
||||
}
|
||||
|
||||
std::string scn;
|
||||
if (ex.test ("$")) {
|
||||
size_t i;
|
||||
ex.read (i);
|
||||
} else {
|
||||
ex.read_word_or_quoted (scn);
|
||||
}
|
||||
|
||||
db::SubCircuit *subcircuit = new db::SubCircuit (cc, scn);
|
||||
circuit->add_subcircuit (subcircuit);
|
||||
|
||||
read_subcircuit_pins (ex, circuit, subcircuit, n2n);
|
||||
}
|
||||
|
||||
void Netlist::from_string (const std::string &s)
|
||||
{
|
||||
tl::Extractor ex (s.c_str ());
|
||||
|
||||
std::map<std::string, db::Circuit *> c2n;
|
||||
|
||||
while (ex.test ("circuit")) {
|
||||
|
||||
std::string n;
|
||||
ex.read_word_or_quoted (n);
|
||||
|
||||
db::Circuit *circuit = 0;
|
||||
|
||||
std::map<std::string, db::Circuit *>::const_iterator ic = c2n.find (n);
|
||||
if (ic == c2n.end ()) {
|
||||
|
||||
circuit = new db::Circuit ();
|
||||
add_circuit (circuit);
|
||||
circuit->set_name (n);
|
||||
|
||||
c2n.insert (std::make_pair (n, circuit));
|
||||
|
||||
} else {
|
||||
circuit = ic->second;
|
||||
}
|
||||
|
||||
std::map<std::string, db::Net *> n2n;
|
||||
read_pins (ex, circuit, n2n);
|
||||
|
||||
ex.expect (";");
|
||||
|
||||
while (! ex.test ("end")) {
|
||||
|
||||
ex.expect_more ();
|
||||
|
||||
if (ex.test ("device")) {
|
||||
|
||||
read_device (ex, circuit, n2n);
|
||||
ex.expect (";");
|
||||
|
||||
} else if (ex.test ("subcircuit")) {
|
||||
|
||||
read_subcircuit (ex, circuit, n2n, c2n);
|
||||
ex.expect (";");
|
||||
|
||||
} else {
|
||||
ex.error (tl::to_string (tr ("device or subcircuit expected")));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ex.expect (";");
|
||||
|
||||
}
|
||||
|
||||
ex.expect_end ();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,12 +88,20 @@ public:
|
|||
void clear ();
|
||||
|
||||
/**
|
||||
* @brief Returns a string representation of the netlist
|
||||
* @brief Returns a parsable string representation of the netlist
|
||||
*
|
||||
* This method is basically intended to testing.
|
||||
* This method returns a string suitable for being put into from_string.
|
||||
*/
|
||||
std::string to_string () const;
|
||||
|
||||
/**
|
||||
* @brief Reads a netlist from the string generated by to_parsable_string
|
||||
*
|
||||
* The device classes have to be installed so it's possible to identify the devices
|
||||
* by their class.
|
||||
*/
|
||||
void from_string (const std::string &s);
|
||||
|
||||
/**
|
||||
* @brief Starts a sequence of operations during which topology updates are not desired
|
||||
*
|
||||
|
|
@ -130,6 +138,12 @@ public:
|
|||
*/
|
||||
void remove_circuit (Circuit *circuit);
|
||||
|
||||
/**
|
||||
* @brief Flattens the given circuit
|
||||
* All subcircuit references are replaced by the content of this circuit.
|
||||
*/
|
||||
void flatten_circuit (Circuit *circuit);
|
||||
|
||||
/**
|
||||
* @brief Begin iterator for the circuits of the netlist (non-const version)
|
||||
*/
|
||||
|
|
@ -273,6 +287,23 @@ public:
|
|||
*/
|
||||
void remove_device_class (DeviceClass *device_class);
|
||||
|
||||
/**
|
||||
* @brief Gets a device class by it's name (const version)
|
||||
*
|
||||
* This method returns 0 if there is no class with this name.
|
||||
*/
|
||||
const DeviceClass *device_class_by_name (const std::string &name) const
|
||||
{
|
||||
return const_cast<Netlist *> (this)->device_class_by_name (name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets a device class by it's name (non-const version)
|
||||
*
|
||||
* This method returns 0 if there is no class with this name.
|
||||
*/
|
||||
DeviceClass *device_class_by_name (const std::string &name);
|
||||
|
||||
/**
|
||||
* @brief Begin iterator for the device classes of the netlist (non-const version)
|
||||
*/
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,291 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2019 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#ifndef _HDR_dbNetlistCompare
|
||||
#define _HDR_dbNetlistCompare
|
||||
|
||||
#include "dbCommon.h"
|
||||
#include "dbNetlist.h"
|
||||
|
||||
#include <set>
|
||||
#include <map>
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
class CircuitPinMapper;
|
||||
class DeviceCategorizer;
|
||||
class CircuitCategorizer;
|
||||
class CircuitMapper;
|
||||
|
||||
/**
|
||||
* @brief A receiver for netlist compare events
|
||||
*/
|
||||
class DB_PUBLIC NetlistCompareLogger
|
||||
{
|
||||
public:
|
||||
NetlistCompareLogger () { }
|
||||
virtual ~NetlistCompareLogger () { }
|
||||
|
||||
/**
|
||||
* @brief Begin logging for netlist a and b
|
||||
*/
|
||||
virtual void begin_netlist (const db::Netlist * /*a*/, const db::Netlist * /*b*/) { }
|
||||
|
||||
/**
|
||||
* @brief End logging for netlist a and b
|
||||
*/
|
||||
virtual void end_netlist (const db::Netlist * /*a*/, const db::Netlist * /*b*/) { }
|
||||
|
||||
/**
|
||||
* @brief There is a device class mismatch
|
||||
* "a" is null if there is no match for b and vice versa.
|
||||
*/
|
||||
virtual void device_class_mismatch (const db::DeviceClass * /*a*/, const db::DeviceClass * /*b*/) { }
|
||||
|
||||
/**
|
||||
* @brief Begin logging for circuit a and b
|
||||
*/
|
||||
virtual void begin_circuit (const db::Circuit * /*a*/, const db::Circuit * /*b*/) { }
|
||||
|
||||
/**
|
||||
* @brief End logging for circuit a and b
|
||||
*/
|
||||
virtual void end_circuit (const db::Circuit * /*a*/, const db::Circuit * /*b*/, bool /*matching*/) { }
|
||||
|
||||
/**
|
||||
* @brief Circuits are skipped
|
||||
* Circuits are skipped if their subcircuits could not be matched.
|
||||
*/
|
||||
virtual void circuit_skipped (const db::Circuit * /*a*/, const db::Circuit * /*b*/) { }
|
||||
|
||||
/**
|
||||
* @brief There is a circuit mismatch
|
||||
* "a" is null if there is no match for b and vice versa.
|
||||
*/
|
||||
virtual void circuit_mismatch (const db::Circuit * /*a*/, const db::Circuit * /*b*/) { }
|
||||
|
||||
/**
|
||||
* @brief Nets a and b match exactly
|
||||
*/
|
||||
virtual void match_nets (const db::Net * /*a*/, const db::Net * /*b*/) { }
|
||||
|
||||
/**
|
||||
* @brief Nets a and b are matched, but are ambiguous
|
||||
* Other nets might also match with a and also with b. Matching this a and b is
|
||||
* an arbitrary decision.
|
||||
*/
|
||||
virtual void match_ambiguous_nets (const db::Net * /*a*/, const db::Net * /*b*/) { }
|
||||
|
||||
/**
|
||||
* @brief Net a or b doesn't match
|
||||
* "a" is null if there is no match for b and vice versa.
|
||||
*/
|
||||
virtual void net_mismatch (const db::Net * /*a*/, const db::Net * /*b*/) { }
|
||||
|
||||
/**
|
||||
* @brief Devices a and b match exactly
|
||||
*/
|
||||
virtual void match_devices (const db::Device * /*a*/, const db::Device * /*b*/) { }
|
||||
|
||||
/**
|
||||
* @brief Devices a and b are matched but have different parameters
|
||||
*/
|
||||
virtual void match_devices_with_different_parameters (const db::Device * /*a*/, const db::Device * /*b*/) { }
|
||||
|
||||
/**
|
||||
* @brief Devices a and b are matched but have different device classes
|
||||
*/
|
||||
virtual void match_devices_with_different_device_classes (const db::Device * /*a*/, const db::Device * /*b*/) { }
|
||||
|
||||
/**
|
||||
* @brief Device a or b doesn't match
|
||||
* "a" is null if there is no match for b and vice versa.
|
||||
*/
|
||||
virtual void device_mismatch (const db::Device * /*a*/, const db::Device * /*b*/) { }
|
||||
|
||||
/**
|
||||
* @brief Pins a and b of the current circuit are matched
|
||||
*/
|
||||
virtual void match_pins (const db::Pin * /*a*/, const db::Pin * /*b*/) { }
|
||||
|
||||
/**
|
||||
* @brief Pin a or b doesn't match
|
||||
* "a" is null if there is no match for b and vice versa.
|
||||
*/
|
||||
virtual void pin_mismatch (const db::Pin * /*a*/, const db::Pin * /*b*/) { }
|
||||
|
||||
/**
|
||||
* @brief Subcircuits a and b match exactly
|
||||
*/
|
||||
virtual void match_subcircuits (const db::SubCircuit * /*a*/, const db::SubCircuit * /*b*/) { }
|
||||
|
||||
/**
|
||||
* @brief SubCircuit a or b doesn't match
|
||||
* "a" is null if there is no match for b and vice versa.
|
||||
*/
|
||||
virtual void subcircuit_mismatch (const db::SubCircuit * /*a*/, const db::SubCircuit * /*b*/) { }
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The netlist comparer
|
||||
*/
|
||||
class DB_PUBLIC NetlistComparer
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor
|
||||
*/
|
||||
NetlistComparer (NetlistCompareLogger *logger);
|
||||
|
||||
/**
|
||||
* @brief Mark two nets as identical
|
||||
*
|
||||
* This makes a net na in netlist a identical to the corresponding
|
||||
* net nb in netlist b.
|
||||
* By default nets are not identical expect through their topology.
|
||||
*/
|
||||
void same_nets (const db::Net *na, const db::Net *nb);
|
||||
|
||||
/**
|
||||
* @brief Mark two pins as equivalent (i.e. can be swapped)
|
||||
*
|
||||
* Only circuits from the *second* input can be given swappable pins.
|
||||
* This will imply the same swappable pins on the equivalent circuit of the first input.
|
||||
* To mark multiple pins as swappable, use the version that takes a list of pins.
|
||||
*/
|
||||
void equivalent_pins (const db::Circuit *cb, size_t pin1_id, size_t pin2_id);
|
||||
|
||||
/**
|
||||
* @brief Mark multiple pins as equivalent (i.e. can be swapped)
|
||||
*
|
||||
* Only circuits from the *second* input can be given swappable pins.
|
||||
* This will imply the same swappable pins on the equivalent circuit of the first input.
|
||||
*/
|
||||
void equivalent_pins (const db::Circuit *cb, const std::vector<size_t> &pin_ids);
|
||||
|
||||
/**
|
||||
* @brief Mark two device classes as identical
|
||||
*
|
||||
* This makes a device class ca in netlist a identical to the corresponding
|
||||
* device class cb in netlist b.
|
||||
* By default device classes with the same name are identical.
|
||||
*/
|
||||
void same_device_classes (const db::DeviceClass *ca, const db::DeviceClass *cb);
|
||||
|
||||
/**
|
||||
* @brief Mark two circuits as identical
|
||||
*
|
||||
* This makes a circuit ca in netlist a identical to the corresponding
|
||||
* circuit cb in netlist b.
|
||||
* By default circuits with the same name are identical.
|
||||
*/
|
||||
void same_circuits (const db::Circuit *ca, const db::Circuit *cb);
|
||||
|
||||
/**
|
||||
* @brief Exclude caps with less than the given capacity value
|
||||
*/
|
||||
void exclude_caps (double threshold);
|
||||
|
||||
/**
|
||||
* @brief Exclude resistors with more than the given resistance value
|
||||
*/
|
||||
void exclude_resistors (double threshold);
|
||||
|
||||
/**
|
||||
* @brief Sets the maximum seach depth
|
||||
*
|
||||
* This value limits the search depth of the backtracking algorithm to the
|
||||
* given number of jumps.
|
||||
*/
|
||||
void set_max_depth (size_t n)
|
||||
{
|
||||
m_max_depth = n;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the maximum search depth
|
||||
*/
|
||||
size_t max_depth () const
|
||||
{
|
||||
return m_max_depth;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the maximum branch complexity
|
||||
*
|
||||
* This value limits the maximum branch complexity of the backtracking algorithm.
|
||||
* The complexity is the accumulated number of branch options with ambiguous
|
||||
* net matches. Backtracking will stop when the maximum number of options
|
||||
* has been exceeded.
|
||||
* As the computational complexity is the square of the branch count,
|
||||
* this value should be adjusted carefully.
|
||||
*/
|
||||
void set_max_branch_complexity (size_t n)
|
||||
{
|
||||
m_max_n_branch = n;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the maximum branch complexity
|
||||
*/
|
||||
size_t max_branch_complexity () const
|
||||
{
|
||||
return m_max_n_branch;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Actually compares the two netlists
|
||||
*/
|
||||
bool compare (const db::Netlist *a, const db::Netlist *b) const;
|
||||
|
||||
protected:
|
||||
bool compare_circuits (const db::Circuit *c1, const db::Circuit *c2, db::DeviceCategorizer &device_categorizer, db::CircuitCategorizer &circuit_categorizer, db::CircuitPinMapper &circuit_pin_mapper, const std::vector<std::pair<const Net *, const Net *> > &net_identity, bool &pin_mismatch, std::map<const db::Circuit *, CircuitMapper> &c12_circuit_and_pin_mapping, std::map<const db::Circuit *, CircuitMapper> &c22_circuit_and_pin_mapping) const;
|
||||
bool all_subcircuits_verified (const db::Circuit *c, const std::set<const db::Circuit *> &verified_circuits) const;
|
||||
static void derive_pin_equivalence (const db::Circuit *ca, const db::Circuit *cb, CircuitPinMapper *circuit_pin_mapper);
|
||||
|
||||
NetlistCompareLogger *mp_logger;
|
||||
std::map<std::pair<const db::Circuit *, const db::Circuit *>, std::vector<std::pair<const Net *, const Net *> > > m_same_nets;
|
||||
std::auto_ptr<CircuitPinMapper> mp_circuit_pin_mapper;
|
||||
std::auto_ptr<DeviceCategorizer> mp_device_categorizer;
|
||||
std::auto_ptr<CircuitCategorizer> mp_circuit_categorizer;
|
||||
double m_cap_threshold;
|
||||
double m_res_threshold;
|
||||
size_t m_max_n_branch;
|
||||
size_t m_max_depth;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace tl
|
||||
{
|
||||
|
||||
template<> struct type_traits<db::NetlistComparer> : public tl::type_traits<void>
|
||||
{
|
||||
// mark "NetlistDeviceExtractor" as having a default ctor and no copy ctor
|
||||
typedef tl::false_tag has_copy_constructor;
|
||||
typedef tl::false_tag has_default_constructor;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -214,10 +214,10 @@ DeviceClassMOS3Transistor::DeviceClassMOS3Transistor ()
|
|||
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("L", "Gate length (micrometer)", 0.0));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("W", "Gate width (micrometer)", 0.0));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("AS", "Source area (square micrometer)", 0.0));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("AD", "Drain area (square micrometer)", 0.0));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("PS", "Source perimeter (micrometer)", 0.0));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("PD", "Drain perimeter (micrometer)", 0.0));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("AS", "Source area (square micrometer)", 0.0, false));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("AD", "Drain area (square micrometer)", 0.0, false));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("PS", "Source perimeter (micrometer)", 0.0, false));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("PD", "Drain perimeter (micrometer)", 0.0, false));
|
||||
}
|
||||
|
||||
bool DeviceClassMOS3Transistor::combine_devices (Device *a, Device *b) const
|
||||
|
|
|
|||
|
|
@ -67,6 +67,11 @@ public:
|
|||
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -92,6 +97,11 @@ public:
|
|||
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -117,6 +127,11 @@ public:
|
|||
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -176,6 +191,11 @@ public:
|
|||
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;
|
||||
};
|
||||
|
|
@ -198,6 +218,11 @@ 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;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
#include "dbNetlistExtractor.h"
|
||||
#include "dbDeepShapeStore.h"
|
||||
#include "dbNetlistDeviceExtractor.h"
|
||||
#include "tlGlobPattern.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
|
@ -34,15 +35,18 @@ NetlistExtractor::NetlistExtractor ()
|
|||
}
|
||||
|
||||
static void
|
||||
build_net_name_equivalence (const db::Layout *layout, db::property_names_id_type net_name_id, tl::equivalence_clusters<unsigned int> &eq)
|
||||
build_net_name_equivalence (const db::Layout *layout, db::property_names_id_type net_name_id, const std::string &joined_net_names, tl::equivalence_clusters<unsigned int> &eq)
|
||||
{
|
||||
std::map<std::string, std::set<unsigned int> > prop_by_name;
|
||||
tl::GlobPattern jn_pattern (joined_net_names);
|
||||
|
||||
for (db::PropertiesRepository::iterator i = layout->properties_repository ().begin (); i != layout->properties_repository ().end (); ++i) {
|
||||
for (db::PropertiesRepository::properties_set::const_iterator p = i->second.begin (); p != i->second.end (); ++p) {
|
||||
if (p->first == net_name_id) {
|
||||
std::string nn = p->second.to_string ();
|
||||
prop_by_name [nn].insert (i->first);
|
||||
if (jn_pattern.match (nn)) {
|
||||
prop_by_name [nn].insert (i->first);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -58,7 +62,7 @@ build_net_name_equivalence (const db::Layout *layout, db::property_names_id_type
|
|||
}
|
||||
|
||||
void
|
||||
NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, unsigned int layout_index, const db::Connectivity &conn, db::Netlist &nl, hier_clusters_type &clusters, bool join_nets_by_label)
|
||||
NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, unsigned int layout_index, const db::Connectivity &conn, db::Netlist &nl, hier_clusters_type &clusters, const std::string &joined_net_names)
|
||||
{
|
||||
mp_clusters = &clusters;
|
||||
mp_layout = &dss.const_layout (layout_index);
|
||||
|
|
@ -77,8 +81,8 @@ NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, unsigned int layo
|
|||
// the big part: actually extract the nets
|
||||
|
||||
tl::equivalence_clusters<unsigned int> net_name_equivalence;
|
||||
if (m_text_annot_name_id.first && join_nets_by_label) {
|
||||
build_net_name_equivalence (mp_layout, m_text_annot_name_id.second, net_name_equivalence);
|
||||
if (m_text_annot_name_id.first && ! joined_net_names.empty ()) {
|
||||
build_net_name_equivalence (mp_layout, m_text_annot_name_id.second, joined_net_names, net_name_equivalence);
|
||||
}
|
||||
mp_clusters->build (*mp_layout, *mp_cell, db::ShapeIterator::Polygons, conn, &net_name_equivalence);
|
||||
|
||||
|
|
@ -127,11 +131,18 @@ NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, unsigned int layo
|
|||
|
||||
for (connected_clusters_type::all_iterator c = clusters.begin_all (); ! c.at_end (); ++c) {
|
||||
|
||||
const db::local_cluster<db::PolygonRef> &lc = clusters.cluster_by_id (*c);
|
||||
if (clusters.connections_for_cluster (*c).empty () && lc.empty ()) {
|
||||
// this is an entirely empty cluster so we skip it.
|
||||
// Such clusters are left over when joining clusters.
|
||||
continue;
|
||||
}
|
||||
|
||||
db::Net *net = new db::Net ();
|
||||
net->set_cluster_id (*c);
|
||||
circuit->add_net (net);
|
||||
|
||||
const db::local_cluster<db::PolygonRef>::global_nets &gn = clusters.cluster_by_id (*c).get_global_nets ();
|
||||
const db::local_cluster<db::PolygonRef>::global_nets &gn = lc.get_global_nets ();
|
||||
for (db::local_cluster<db::PolygonRef>::global_nets::const_iterator g = gn.begin (); g != gn.end (); ++g) {
|
||||
assign_net_name (conn.global_net_name (*g), net);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ public:
|
|||
* @brief Extract the nets
|
||||
* See the class description for more details.
|
||||
*/
|
||||
void extract_nets (const db::DeepShapeStore &dss, unsigned int layout_index, const db::Connectivity &conn, db::Netlist &nl, hier_clusters_type &clusters, bool join_nets_by_label = true);
|
||||
void extract_nets (const db::DeepShapeStore &dss, unsigned int layout_index, const db::Connectivity &conn, db::Netlist &nl, hier_clusters_type &clusters, const std::string &joined_net_names = std::string ());
|
||||
|
||||
private:
|
||||
hier_clusters_type *mp_clusters;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2019 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include "dbNetlistReader.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
// .. nothing yet ..
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2019 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#ifndef HDR_dbNetlistReader
|
||||
#define HDR_dbNetlistReader
|
||||
|
||||
#include "dbCommon.h"
|
||||
#include "tlTypeTraits.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace tl
|
||||
{
|
||||
class InputStream;
|
||||
}
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
class Netlist;
|
||||
|
||||
/**
|
||||
* @brief A common base class for netlist writers
|
||||
*/
|
||||
class DB_PUBLIC NetlistReader
|
||||
{
|
||||
public:
|
||||
NetlistReader () { }
|
||||
virtual ~NetlistReader () { }
|
||||
|
||||
virtual void read (tl::InputStream &stream, db::Netlist &netlist) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace tl
|
||||
{
|
||||
|
||||
template <>
|
||||
struct type_traits<db::NetlistReader>
|
||||
: public tl::type_traits<void>
|
||||
{
|
||||
typedef tl::false_tag has_default_constructor;
|
||||
typedef tl::false_tag has_copy_constructor;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,617 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2019 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include "dbNetlistSpiceReader.h"
|
||||
#include "dbNetlist.h"
|
||||
#include "dbNetlistDeviceClasses.h"
|
||||
|
||||
#include "tlStream.h"
|
||||
#include "tlLog.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <cctype>
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
static const char *allowed_name_chars = "_.:,!+$/&\\#[]|";
|
||||
|
||||
NetlistSpiceReader::NetlistSpiceReader ()
|
||||
: mp_netlist (0), mp_stream (0)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
NetlistSpiceReader::~NetlistSpiceReader ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void NetlistSpiceReader::read (tl::InputStream &stream, db::Netlist &netlist)
|
||||
{
|
||||
mp_stream.reset (new tl::TextInputStream (stream));
|
||||
mp_netlist = &netlist;
|
||||
mp_circuit = 0;
|
||||
mp_nets_by_name.reset (0);
|
||||
|
||||
try {
|
||||
|
||||
while (! at_end ()) {
|
||||
read_element ();
|
||||
}
|
||||
|
||||
finish ();
|
||||
|
||||
} catch (tl::Exception &ex) {
|
||||
|
||||
// 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);
|
||||
finish ();
|
||||
throw tl::Exception (fmt_msg);
|
||||
|
||||
} catch (...) {
|
||||
|
||||
finish ();
|
||||
throw;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void NetlistSpiceReader::finish ()
|
||||
{
|
||||
while (! m_streams.empty ()) {
|
||||
pop_stream ();
|
||||
}
|
||||
|
||||
mp_stream.reset (0);
|
||||
mp_netlist = 0;
|
||||
mp_circuit = 0;
|
||||
mp_nets_by_name.reset (0);
|
||||
}
|
||||
|
||||
void NetlistSpiceReader::push_stream (const std::string &path)
|
||||
{
|
||||
tl::InputStream *istream = new tl::InputStream (path);
|
||||
m_streams.push_back (std::make_pair (istream, mp_stream.release ()));
|
||||
mp_stream.reset (new tl::TextInputStream (*istream));
|
||||
}
|
||||
|
||||
void NetlistSpiceReader::pop_stream ()
|
||||
{
|
||||
if (! m_streams.empty ()) {
|
||||
|
||||
mp_stream.reset (m_streams.back ().second);
|
||||
delete m_streams.back ().first;
|
||||
|
||||
m_streams.pop_back ();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
bool NetlistSpiceReader::at_end ()
|
||||
{
|
||||
return mp_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::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")) {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
bool NetlistSpiceReader::read_element ()
|
||||
{
|
||||
std::string l = get_line ();
|
||||
if (l.empty ()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
tl::Extractor ex (l.c_str ());
|
||||
|
||||
const char *res_device_class_name = "RES";
|
||||
const char *cap_device_class_name = "CAP";
|
||||
const char *ind_device_class_name = "IND";
|
||||
|
||||
if (ex.test_without_case (".")) {
|
||||
|
||||
// control statement
|
||||
if (ex.test_without_case ("model")) {
|
||||
|
||||
// ignore model statements
|
||||
|
||||
} else if (ex.test_without_case ("subckt")) {
|
||||
|
||||
read_circuit (ex);
|
||||
|
||||
} else if (ex.test_without_case ("ends")) {
|
||||
|
||||
return true;
|
||||
|
||||
} else if (ex.test_without_case ("end")) {
|
||||
|
||||
// ignore end statements
|
||||
|
||||
} else {
|
||||
|
||||
std::string s;
|
||||
ex.read_word (s);
|
||||
s = tl::to_lower_case (s);
|
||||
warn (tl::to_string (tr ("Control statement ignored: ")) + s);
|
||||
|
||||
}
|
||||
|
||||
} else if (ex.test_without_case ("r")) {
|
||||
|
||||
db::DeviceClass *dev_cls = mp_netlist->device_class_by_name (res_device_class_name);
|
||||
if (! dev_cls) {
|
||||
dev_cls = new db::DeviceClassResistor ();
|
||||
dev_cls->set_name (res_device_class_name);
|
||||
mp_netlist->add_device_class (dev_cls);
|
||||
}
|
||||
|
||||
ensure_circuit ();
|
||||
read_device (dev_cls, db::DeviceClassResistor::param_id_R, ex);
|
||||
|
||||
} else if (ex.test_without_case ("c")) {
|
||||
|
||||
db::DeviceClass *dev_cls = mp_netlist->device_class_by_name (cap_device_class_name);
|
||||
if (! dev_cls) {
|
||||
dev_cls = new db::DeviceClassCapacitor ();
|
||||
dev_cls->set_name (cap_device_class_name);
|
||||
mp_netlist->add_device_class (dev_cls);
|
||||
}
|
||||
|
||||
ensure_circuit ();
|
||||
read_device (dev_cls, db::DeviceClassCapacitor::param_id_C, ex);
|
||||
|
||||
} else if (ex.test_without_case ("l")) {
|
||||
|
||||
db::DeviceClass *dev_cls = mp_netlist->device_class_by_name (ind_device_class_name);
|
||||
if (! dev_cls) {
|
||||
dev_cls = new db::DeviceClassInductor ();
|
||||
dev_cls->set_name (ind_device_class_name);
|
||||
mp_netlist->add_device_class (dev_cls);
|
||||
}
|
||||
|
||||
ensure_circuit ();
|
||||
read_device (dev_cls, db::DeviceClassInductor::param_id_L, ex);
|
||||
|
||||
} else if (ex.test_without_case ("m")) {
|
||||
|
||||
ensure_circuit ();
|
||||
read_mos4_device (ex);
|
||||
|
||||
} else if (ex.test_without_case ("x")) {
|
||||
|
||||
ensure_circuit ();
|
||||
read_subcircuit (ex);
|
||||
|
||||
} else {
|
||||
|
||||
char c = *ex.skip ();
|
||||
if (c) {
|
||||
warn (tl::sprintf (tl::to_string (tr ("Element type '%c' ignored")), c));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void NetlistSpiceReader::error (const std::string &msg)
|
||||
{
|
||||
throw tl::Exception (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 ());
|
||||
tl::warn << fmt_msg;
|
||||
}
|
||||
|
||||
double NetlistSpiceReader::read_atomic_value (tl::Extractor &ex)
|
||||
{
|
||||
if (ex.test ("(")) {
|
||||
|
||||
double v = read_dot_expr (ex);
|
||||
ex.expect (")");
|
||||
return v;
|
||||
|
||||
} else {
|
||||
|
||||
double v = 0.0;
|
||||
ex.read (v);
|
||||
|
||||
double f = 1.0;
|
||||
if (*ex == 't' || *ex == 'T') {
|
||||
f = 1e12;
|
||||
} else if (*ex == 'g' || *ex == 'G') {
|
||||
f = 1e9;
|
||||
} else if (*ex == 'k' || *ex == 'K') {
|
||||
f = 1e3;
|
||||
} else if (*ex == 'm' || *ex == 'M') {
|
||||
f = 1e-3;
|
||||
if (ex.test_without_case ("meg")) {
|
||||
f = 1e6;
|
||||
}
|
||||
} else if (*ex == 'u' || *ex == 'U') {
|
||||
f = 1e-6;
|
||||
} else if (*ex == 'n' || *ex == 'N') {
|
||||
f = 1e-9;
|
||||
} else if (*ex == 'p' || *ex == 'P') {
|
||||
f = 1e-12;
|
||||
} else if (*ex == 'f' || *ex == 'F') {
|
||||
f = 1e-15;
|
||||
} else if (*ex == 'a' || *ex == 'A') {
|
||||
f = 1e-18;
|
||||
}
|
||||
while (*ex && isalpha (*ex)) {
|
||||
++ex;
|
||||
}
|
||||
|
||||
v *= f;
|
||||
return v;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
double NetlistSpiceReader::read_bar_expr (tl::Extractor &ex)
|
||||
{
|
||||
double v = read_atomic_value (ex);
|
||||
while (true) {
|
||||
if (ex.test ("+")) {
|
||||
double vv = read_atomic_value (ex);
|
||||
v += vv;
|
||||
} else if (ex.test ("+")) {
|
||||
double vv = read_atomic_value (ex);
|
||||
v -= vv;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
double NetlistSpiceReader::read_dot_expr (tl::Extractor &ex)
|
||||
{
|
||||
double v = read_atomic_value (ex);
|
||||
while (true) {
|
||||
if (ex.test ("*")) {
|
||||
double vv = read_atomic_value (ex);
|
||||
v *= vv;
|
||||
} else if (ex.test ("/")) {
|
||||
double vv = read_atomic_value (ex);
|
||||
v /= vv;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
double NetlistSpiceReader::read_value (tl::Extractor &ex)
|
||||
{
|
||||
return read_dot_expr (ex);
|
||||
}
|
||||
|
||||
void NetlistSpiceReader::ensure_circuit ()
|
||||
{
|
||||
if (! mp_circuit) {
|
||||
|
||||
mp_circuit = new db::Circuit ();
|
||||
// TODO: make top name configurable
|
||||
mp_circuit->set_name (".TOP");
|
||||
mp_netlist->add_circuit (mp_circuit);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
db::Net *NetlistSpiceReader::make_net (const std::string &name)
|
||||
{
|
||||
if (! mp_nets_by_name.get ()) {
|
||||
mp_nets_by_name.reset (new std::map<std::string, db::Net *> ());
|
||||
}
|
||||
|
||||
std::map<std::string, db::Net *>::const_iterator n2n = mp_nets_by_name->find (name);
|
||||
|
||||
db::Net *net = 0;
|
||||
if (n2n == mp_nets_by_name->end ()) {
|
||||
|
||||
net = new db::Net ();
|
||||
net->set_name (name);
|
||||
mp_circuit->add_net (net);
|
||||
|
||||
mp_nets_by_name->insert (std::make_pair (name, net));
|
||||
|
||||
} else {
|
||||
net = n2n->second;
|
||||
}
|
||||
|
||||
return net;
|
||||
}
|
||||
|
||||
void NetlistSpiceReader::read_subcircuit (tl::Extractor &ex)
|
||||
{
|
||||
std::string sc_name;
|
||||
ex.read_word_or_quoted (sc_name, allowed_name_chars);
|
||||
|
||||
std::vector<std::string> nn;
|
||||
std::map<std::string, double> pv;
|
||||
|
||||
while (! ex.at_end ()) {
|
||||
|
||||
std::string n;
|
||||
ex.read_word_or_quoted (n, allowed_name_chars);
|
||||
|
||||
if (ex.test ("=")) {
|
||||
// a parameter
|
||||
pv.insert (std::make_pair (tl::to_upper_case (n), read_value (ex)));
|
||||
} else {
|
||||
nn.push_back (n);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (nn.empty ()) {
|
||||
error (tl::to_string (tr ("No circuit name given for subcircuit call")));
|
||||
}
|
||||
if (! pv.empty ()) {
|
||||
warn (tl::to_string (tr ("Circuit parameters are not allowed currently")));
|
||||
}
|
||||
|
||||
std::string nc = nn.back ();
|
||||
nn.pop_back ();
|
||||
|
||||
if (nn.empty ()) {
|
||||
error (tl::to_string (tr ("A circuit call needs at least one net")));
|
||||
}
|
||||
|
||||
db::Circuit *cc = mp_netlist->circuit_by_name (nc);
|
||||
if (! cc) {
|
||||
cc = new db::Circuit ();
|
||||
mp_netlist->add_circuit (cc);
|
||||
cc->set_name (nc);
|
||||
for (std::vector<std::string>::const_iterator i = nn.begin (); i != nn.end (); ++i) {
|
||||
cc->add_pin (std::string ());
|
||||
}
|
||||
} else {
|
||||
if (cc->pin_count () != nn.size ()) {
|
||||
error (tl::sprintf (tl::to_string (tr ("Pin count mismatch between circuit definition and circuit call: %d expected, got %d")), int (cc->pin_count ()), int (nn.size ())));
|
||||
}
|
||||
}
|
||||
|
||||
db::SubCircuit *sc = new db::SubCircuit (cc, sc_name);
|
||||
mp_circuit->add_subcircuit (sc);
|
||||
|
||||
for (std::vector<std::string>::const_iterator i = nn.begin (); i != nn.end (); ++i) {
|
||||
db::Net *net = make_net (*i);
|
||||
sc->connect_pin (i - nn.begin (), net);
|
||||
}
|
||||
|
||||
ex.expect_end ();
|
||||
}
|
||||
|
||||
void NetlistSpiceReader::read_circuit (tl::Extractor &ex)
|
||||
{
|
||||
std::string nc;
|
||||
ex.read_word_or_quoted (nc, allowed_name_chars);
|
||||
|
||||
std::vector<std::string> nn;
|
||||
std::map<std::string, double> pv;
|
||||
|
||||
while (! ex.at_end ()) {
|
||||
|
||||
std::string n;
|
||||
ex.read_word_or_quoted (n, allowed_name_chars);
|
||||
|
||||
if (ex.test ("=")) {
|
||||
// a parameter
|
||||
pv.insert (std::make_pair (tl::to_upper_case (n), read_value (ex)));
|
||||
} else {
|
||||
nn.push_back (n);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (! pv.empty ()) {
|
||||
warn (tl::to_string (tr ("Circuit parameters are not allowed currently")));
|
||||
}
|
||||
|
||||
db::Circuit *cc = mp_netlist->circuit_by_name (nc);
|
||||
if (! cc) {
|
||||
cc = new db::Circuit ();
|
||||
mp_netlist->add_circuit (cc);
|
||||
cc->set_name (nc);
|
||||
for (std::vector<std::string>::const_iterator i = nn.begin (); i != nn.end (); ++i) {
|
||||
cc->add_pin (std::string ());
|
||||
}
|
||||
} else {
|
||||
if (cc->pin_count () != nn.size ()) {
|
||||
error (tl::sprintf (tl::to_string (tr ("Pin count mismatch between implicit (through call) and explicit circuit definition: %d expected, got %d")), int (cc->pin_count ()), int (nn.size ())));
|
||||
}
|
||||
}
|
||||
|
||||
std::auto_ptr<std::map<std::string, db::Net *> > n2n (mp_nets_by_name.release ());
|
||||
mp_nets_by_name.reset (0);
|
||||
|
||||
std::swap (cc, mp_circuit);
|
||||
|
||||
for (std::vector<std::string>::const_iterator i = nn.begin (); i != nn.end (); ++i) {
|
||||
db::Net *net = make_net (*i);
|
||||
mp_circuit->connect_pin (i - nn.begin (), net);
|
||||
}
|
||||
|
||||
while (! at_end ()) {
|
||||
if (read_element ()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mp_nets_by_name.reset (n2n.release ());
|
||||
std::swap (cc, mp_circuit);
|
||||
|
||||
ex.expect_end ();
|
||||
}
|
||||
|
||||
void NetlistSpiceReader::read_device (db::DeviceClass *dev_cls, size_t param_id, tl::Extractor &ex)
|
||||
{
|
||||
std::string dn;
|
||||
ex.read_word_or_quoted (dn, allowed_name_chars);
|
||||
|
||||
std::vector<std::string> nn;
|
||||
|
||||
while (! ex.at_end () && nn.size () < 2) {
|
||||
nn.push_back (std::string ());
|
||||
ex.read_word_or_quoted (nn.back (), allowed_name_chars);
|
||||
}
|
||||
|
||||
if (nn.size () != 2) {
|
||||
error (tl::to_string (tr ("Two-terminal device needs two nets")));
|
||||
}
|
||||
|
||||
double v = read_value (ex);
|
||||
|
||||
db::Device *dev = new db::Device (dev_cls, dn);
|
||||
mp_circuit->add_device (dev);
|
||||
|
||||
for (std::vector<std::string>::const_iterator i = nn.begin (); i != nn.end (); ++i) {
|
||||
db::Net *net = make_net (*i);
|
||||
dev->connect_terminal (i - nn.begin (), net);
|
||||
}
|
||||
|
||||
dev->set_parameter_value (param_id, v);
|
||||
|
||||
ex.expect_end ();
|
||||
}
|
||||
|
||||
void NetlistSpiceReader::read_mos4_device (tl::Extractor &ex)
|
||||
{
|
||||
std::string dn;
|
||||
ex.read_word_or_quoted (dn, allowed_name_chars);
|
||||
|
||||
std::vector<std::string> nn;
|
||||
std::map<std::string, double> pv;
|
||||
|
||||
while (! ex.at_end ()) {
|
||||
|
||||
std::string n;
|
||||
ex.read_word_or_quoted (n, allowed_name_chars);
|
||||
|
||||
if (ex.test ("=")) {
|
||||
// a parameter
|
||||
pv.insert (std::make_pair (tl::to_upper_case (n), read_value (ex)));
|
||||
} else {
|
||||
nn.push_back (n);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (nn.empty ()) {
|
||||
error (tl::to_string (tr ("No model name given for MOS transistor element")));
|
||||
}
|
||||
|
||||
std::string mn = nn.back ();
|
||||
nn.pop_back ();
|
||||
|
||||
if (nn.size () != 4) {
|
||||
error (tl::to_string (tr ("A MOS transistor needs four nets")));
|
||||
}
|
||||
|
||||
db::DeviceClass *dev_cls = mp_netlist->device_class_by_name (mn);
|
||||
if (! dev_cls) {
|
||||
dev_cls = new db::DeviceClassMOS4Transistor ();
|
||||
dev_cls->set_name (mn);
|
||||
mp_netlist->add_device_class (dev_cls);
|
||||
}
|
||||
|
||||
db::Device *dev = new db::Device (dev_cls, dn);
|
||||
mp_circuit->add_device (dev);
|
||||
|
||||
for (std::vector<std::string>::const_iterator i = nn.begin (); i != nn.end (); ++i) {
|
||||
db::Net *net = make_net (*i);
|
||||
dev->connect_terminal (i - nn.begin (), net);
|
||||
}
|
||||
|
||||
const std::vector<db::DeviceParameterDefinition> &pd = dev_cls->parameter_definitions ();
|
||||
for (std::vector<db::DeviceParameterDefinition>::const_iterator i = pd.begin (); i != pd.end (); ++i) {
|
||||
std::map<std::string, double>::const_iterator v = pv.find (i->name ());
|
||||
if (v != pv.end ()) {
|
||||
// by conventions, dimensions are in micrometer
|
||||
if (i->id () == db::DeviceClassMOS4Transistor::param_id_AD || i->id () == db::DeviceClassMOS4Transistor::param_id_AS) {
|
||||
dev->set_parameter_value (i->id (), v->second * 1e12);
|
||||
} else if (i->id () == db::DeviceClassMOS4Transistor::param_id_W
|
||||
|| i->id () == db::DeviceClassMOS4Transistor::param_id_L
|
||||
|| i->id () == db::DeviceClassMOS4Transistor::param_id_PD
|
||||
|| i->id () == db::DeviceClassMOS4Transistor::param_id_PS) {
|
||||
dev->set_parameter_value (i->id (), v->second * 1e6);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ex.expect_end ();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2019 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#ifndef HDR_dbNetlistSpiceReader
|
||||
#define HDR_dbNetlistSpiceReader
|
||||
|
||||
#include "dbCommon.h"
|
||||
#include "dbNetlistReader.h"
|
||||
#include "tlStream.h"
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
class Netlist;
|
||||
class Net;
|
||||
class Circuit;
|
||||
class DeviceClass;
|
||||
|
||||
/**
|
||||
* @brief A SPICE format reader for netlists
|
||||
*/
|
||||
class DB_PUBLIC NetlistSpiceReader
|
||||
: public NetlistReader
|
||||
{
|
||||
public:
|
||||
NetlistSpiceReader ();
|
||||
virtual ~NetlistSpiceReader ();
|
||||
|
||||
virtual void read (tl::InputStream &stream, db::Netlist &netlist);
|
||||
|
||||
private:
|
||||
db::Netlist *mp_netlist;
|
||||
db::Circuit *mp_circuit;
|
||||
std::auto_ptr<tl::TextInputStream> mp_stream;
|
||||
std::vector<std::pair<tl::InputStream *, tl::TextInputStream *> > m_streams;
|
||||
std::auto_ptr<std::map<std::string, db::Net *> > mp_nets_by_name;
|
||||
std::string m_stored_line;
|
||||
|
||||
void push_stream (const std::string &path);
|
||||
void pop_stream ();
|
||||
bool at_end ();
|
||||
void read_subcircuit (tl::Extractor &ex);
|
||||
void read_circuit (tl::Extractor &ex);
|
||||
void read_device (db::DeviceClass *dev_cls, size_t param_id, tl::Extractor &ex);
|
||||
void read_mos4_device (tl::Extractor &ex);
|
||||
bool read_element ();
|
||||
double read_value (tl::Extractor &ex);
|
||||
double read_atomic_value (tl::Extractor &ex);
|
||||
double read_dot_expr (tl::Extractor &ex);
|
||||
double read_bar_expr (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 ();
|
||||
db::Net *make_net (const std::string &name);
|
||||
void ensure_circuit ();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace tl
|
||||
{
|
||||
|
||||
template <>
|
||||
struct type_traits<db::NetlistSpiceReader>
|
||||
: public tl::type_traits<void>
|
||||
{
|
||||
typedef tl::false_tag has_default_constructor;
|
||||
typedef tl::false_tag has_copy_constructor;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -31,6 +31,8 @@
|
|||
namespace db
|
||||
{
|
||||
|
||||
static const char *allowed_name_chars = "_.:,!+$/&\\#[]";
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
|
||||
NetlistSpiceWriterDelegate::NetlistSpiceWriterDelegate ()
|
||||
|
|
@ -141,8 +143,8 @@ void NetlistSpiceWriterDelegate::write_device (const db::Device &dev) const
|
|||
os << net_to_string (dev.net_for_terminal (db::DeviceClassMOS3Transistor::terminal_id_S));
|
||||
}
|
||||
|
||||
// Use "M" + device class name for the model
|
||||
os << " M";
|
||||
// Use device class name for the model
|
||||
os << " ";
|
||||
os << format_name (dev.device_class ()->name ());
|
||||
|
||||
os << " L=" << tl::sprintf ("%.12gU", dev.parameter_value (db::DeviceClassMOS3Transistor::param_id_L));
|
||||
|
|
@ -257,7 +259,7 @@ std::string NetlistSpiceWriter::net_to_string (const db::Net *net) const
|
|||
nn += "\\";
|
||||
}
|
||||
for (const char *cp = n.c_str (); *cp; ++cp) {
|
||||
if (! isalnum (*cp) && strchr (".$!&\\#+:,", *cp) == 0) {
|
||||
if (! isalnum (*cp) && strchr (allowed_name_chars, *cp) == 0) {
|
||||
nn += tl::sprintf ("\\x%02x", (unsigned char) *cp);
|
||||
} else if (*cp == ',') {
|
||||
nn += "|";
|
||||
|
|
|
|||
|
|
@ -1,26 +1,4 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2019 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
|
|
|
|||
|
|
@ -28,6 +28,8 @@
|
|||
#include "dbCell.h"
|
||||
#include "dbCellInst.h"
|
||||
#include "dbLayoutDiff.h"
|
||||
#include "dbNetlist.h"
|
||||
#include "dbNetlistCompare.h"
|
||||
|
||||
#include "tlUnitTest.h"
|
||||
#include "tlFileUtils.h"
|
||||
|
|
@ -152,4 +154,175 @@ void compare_layouts (tl::TestBase *_this, const db::Layout &layout, const std::
|
|||
}
|
||||
}
|
||||
|
||||
class CompareLogger
|
||||
: public db::NetlistCompareLogger
|
||||
{
|
||||
public:
|
||||
CompareLogger ()
|
||||
: m_new_circuit (true) { }
|
||||
|
||||
void out (const std::string &text)
|
||||
{
|
||||
if (m_new_circuit) {
|
||||
tl::info << m_circuit;
|
||||
m_new_circuit = false;
|
||||
}
|
||||
tl::info << text;
|
||||
}
|
||||
|
||||
virtual void begin_netlist (const db::Netlist * /*a*/, const db::Netlist * /*b*/)
|
||||
{
|
||||
tl::info << "Comparing netlists:";
|
||||
}
|
||||
|
||||
virtual void end_netlist (const db::Netlist * /*a*/, const db::Netlist * /*b*/)
|
||||
{
|
||||
tl::info << "End of difference log.";
|
||||
}
|
||||
|
||||
virtual void begin_circuit (const db::Circuit *a, const db::Circuit *b)
|
||||
{
|
||||
m_new_circuit = true;
|
||||
m_circuit = circuit2str (a) + " vs. " + circuit2str (b);
|
||||
}
|
||||
|
||||
virtual void device_class_mismatch (const db::DeviceClass *a, const db::DeviceClass *b)
|
||||
{
|
||||
out ("device_class_mismatch " + device_class2str (a) + " " + device_class2str (b));
|
||||
}
|
||||
|
||||
virtual void circuit_skipped (const db::Circuit *a, const db::Circuit *b)
|
||||
{
|
||||
out ("circuit_skipped " + circuit2str (a) + " " + circuit2str (b));
|
||||
}
|
||||
|
||||
virtual void circuit_mismatch (const db::Circuit *a, const db::Circuit *b)
|
||||
{
|
||||
out ("circuit_mismatch " + circuit2str (a) + " " + circuit2str (b));
|
||||
}
|
||||
|
||||
virtual void match_nets (const db::Net *a, const db::Net *b)
|
||||
{
|
||||
out ("match_nets " + net2str (a) + " " + net2str (b));
|
||||
}
|
||||
|
||||
virtual void match_ambiguous_nets (const db::Net *a, const db::Net *b)
|
||||
{
|
||||
out ("match_ambiguous_nets " + net2str (a) + " " + net2str (b));
|
||||
}
|
||||
|
||||
virtual void net_mismatch (const db::Net *a, const db::Net *b)
|
||||
{
|
||||
out ("net_mismatch " + net2str (a) + " " + net2str (b));
|
||||
}
|
||||
|
||||
virtual void match_devices (const db::Device *a, const db::Device *b)
|
||||
{
|
||||
out ("match_devices " + device2str (a) + " " + device2str (b));
|
||||
}
|
||||
|
||||
virtual void device_mismatch (const db::Device *a, const db::Device *b)
|
||||
{
|
||||
out ("device_mismatch " + device2str (a) + " " + device2str (b));
|
||||
}
|
||||
|
||||
virtual void match_devices_with_different_parameters (const db::Device *a, const db::Device *b)
|
||||
{
|
||||
out ("match_devices_with_different_parameters " + device2str (a) + " " + device2str (b));
|
||||
}
|
||||
|
||||
virtual void match_devices_with_different_device_classes (const db::Device *a, const db::Device *b)
|
||||
{
|
||||
out ("match_devices_with_different_device_classes " + device2str (a) + " " + device2str (b));
|
||||
}
|
||||
|
||||
virtual void match_pins (const db::Pin *a, const db::Pin *b)
|
||||
{
|
||||
out ("match_pins " + pin2str (a) + " " + pin2str (b));
|
||||
}
|
||||
|
||||
virtual void pin_mismatch (const db::Pin *a, const db::Pin *b)
|
||||
{
|
||||
out ("pin_mismatch " + pin2str (a) + " " + pin2str (b));
|
||||
}
|
||||
|
||||
virtual void match_subcircuits (const db::SubCircuit *a, const db::SubCircuit *b)
|
||||
{
|
||||
out ("match_subcircuits " + subcircuit2str (a) + " " + subcircuit2str (b));
|
||||
}
|
||||
|
||||
virtual void subcircuit_mismatch (const db::SubCircuit *a, const db::SubCircuit *b)
|
||||
{
|
||||
out ("subcircuit_mismatch " + subcircuit2str (a) + " " + subcircuit2str (b));
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_new_circuit;
|
||||
std::string m_circuit;
|
||||
|
||||
std::string device_class2str (const db::DeviceClass *x) const
|
||||
{
|
||||
return x ? x->name () : "(null)";
|
||||
}
|
||||
|
||||
std::string circuit2str (const db::Circuit *x) const
|
||||
{
|
||||
return x ? x->name () : "(null)";
|
||||
}
|
||||
|
||||
std::string device2str (const db::Device *x) const
|
||||
{
|
||||
return x ? x->expanded_name () : "(null)";
|
||||
}
|
||||
|
||||
std::string net2str (const db::Net *x) const
|
||||
{
|
||||
return x ? x->expanded_name () : "(null)";
|
||||
}
|
||||
|
||||
std::string pin2str (const db::Pin *x) const
|
||||
{
|
||||
return x ? x->expanded_name () : "(null)";
|
||||
}
|
||||
|
||||
std::string subcircuit2str (const db::SubCircuit *x) const
|
||||
{
|
||||
return x ? x->expanded_name () : "(null)";
|
||||
}
|
||||
};
|
||||
|
||||
void DB_PUBLIC compare_netlist (tl::TestBase *_this, const db::Netlist &netlist, const std::string &au_nl_string)
|
||||
{
|
||||
db::Netlist au_nl;
|
||||
for (db::Netlist::const_device_class_iterator d = netlist.begin_device_classes (); d != netlist.end_device_classes (); ++d) {
|
||||
au_nl.add_device_class (d->clone ());
|
||||
}
|
||||
|
||||
au_nl.from_string (au_nl_string);
|
||||
|
||||
db::NetlistComparer comp (0);
|
||||
|
||||
if (! comp.compare (&netlist, &au_nl)) {
|
||||
_this->raise ("Compare failed - see log for details.\n\nActual:\n" + netlist.to_string () + "\nGolden:\n" + au_nl_string);
|
||||
// Compare once again - this time with logger
|
||||
CompareLogger logger;
|
||||
db::NetlistComparer comp (&logger);
|
||||
comp.compare (&netlist, &au_nl);
|
||||
}
|
||||
}
|
||||
|
||||
void DB_PUBLIC compare_netlist (tl::TestBase *_this, const db::Netlist &netlist, const db::Netlist &netlist_au)
|
||||
{
|
||||
db::NetlistComparer comp (0);
|
||||
|
||||
if (! comp.compare (&netlist, &netlist_au)) {
|
||||
_this->raise ("Compare failed - see log for details.\n\nActual:\n" + netlist.to_string () + "\nGolden:\n" + netlist_au.to_string ());
|
||||
// Compare once again - this time with logger
|
||||
CompareLogger logger;
|
||||
db::NetlistComparer comp (&logger);
|
||||
comp.compare (&netlist, &netlist_au);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ namespace db
|
|||
class Layout;
|
||||
class Cell;
|
||||
class LayerMap;
|
||||
class Netlist;
|
||||
|
||||
/**
|
||||
* @brief Specifies the normalization mode for compare_layouts
|
||||
|
|
@ -73,6 +74,16 @@ void DB_PUBLIC compare_layouts (tl::TestBase *_this, const db::Layout &layout, c
|
|||
*/
|
||||
void DB_PUBLIC compare_layouts (tl::TestBase *_this, const db::Layout &layout, const std::string &au_file, const db::LayerMap &lmap, bool read_all_others, NormalizationMode norm = WriteGDS2, db::Coord tolerance = 0);
|
||||
|
||||
/**
|
||||
* @brief Compares a netlist against a string
|
||||
*/
|
||||
void DB_PUBLIC compare_netlist (tl::TestBase *_this, const db::Netlist &netlist, const std::string &au_nl_string);
|
||||
|
||||
/**
|
||||
* @brief Compares a netlist against another netlist
|
||||
*/
|
||||
void DB_PUBLIC compare_netlist (tl::TestBase *_this, const db::Netlist &netlist, const db::Netlist &netlist_au);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -288,10 +288,23 @@ Class<db::LayoutToNetlist> decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
|
|||
gsi::method ("global_net_name", &db::LayoutToNetlist::global_net_name, gsi::arg ("global_net_id"),
|
||||
"@brief Gets the global net name for the given global net ID."
|
||||
) +
|
||||
gsi::method ("extract_netlist", &db::LayoutToNetlist::extract_netlist, gsi::arg ("join_nets_by_label", true),
|
||||
gsi::method ("extract_netlist", &db::LayoutToNetlist::extract_netlist, gsi::arg ("join_net_names", std::string ()),
|
||||
"@brief Runs the netlist extraction\n"
|
||||
"If join_nets_by_label is true, nets on the same hierarchy level carrying the same label will be connected "
|
||||
"implicitly even if there is no physical connection.\n"
|
||||
"'join_net_names' is a glob expression for labels. Nets on top level carrying the same label which matches this glob "
|
||||
"expression will be connected implicitly even if there is no physical connection. This feature is useful to simulate a connection "
|
||||
"which will be made later when integrating the component.\n"
|
||||
"\n"
|
||||
"Valid glob expressions are:\n"
|
||||
"@ul\n"
|
||||
"@li \"\" no implicit connections.@/li\n"
|
||||
"@li \"*\" to make all labels candidates for implicit connections.@/li\n"
|
||||
"@li \"VDD\" to make all 'VDD'' nets candidates for implicit connections.@/li\n"
|
||||
"@li \"VDD\" to make all 'VDD'+suffix nets candidates for implicit connections.@/li\n"
|
||||
"@li \"{VDD,VSS}\" to all VDD and VSS nets candidates for implicit connections.@/li\n"
|
||||
"@/ul\n"
|
||||
"\n"
|
||||
"Label matching is case sensitive.\n"
|
||||
"\n"
|
||||
"See the class description for more details.\n"
|
||||
) +
|
||||
gsi::method_ext ("internal_layout", &l2n_internal_layout,
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@
|
|||
#include "dbNetlist.h"
|
||||
#include "dbNetlistWriter.h"
|
||||
#include "dbNetlistSpiceWriter.h"
|
||||
#include "dbNetlistReader.h"
|
||||
#include "dbNetlistSpiceReader.h"
|
||||
#include "tlException.h"
|
||||
#include "tlInternational.h"
|
||||
#include "tlStream.h"
|
||||
|
|
@ -37,6 +39,10 @@ Class<db::Pin> decl_dbPin ("db", "Pin",
|
|||
) +
|
||||
gsi::method ("name", &db::Pin::name,
|
||||
"@brief Gets the name of the pin.\n"
|
||||
) +
|
||||
gsi::method ("expanded_name", &db::Pin::expanded_name,
|
||||
"@brief Gets the expanded name of the pin.\n"
|
||||
"The expanded name is the name or a generic identifier made from the ID if the name is empty."
|
||||
),
|
||||
"@brief A pin of a circuit.\n"
|
||||
"Pin objects are used to describe the outgoing pins of "
|
||||
|
|
@ -456,6 +462,15 @@ Class<db::DeviceParameterDefinition> decl_dbDeviceParameterDefinition ("db", "De
|
|||
"@brief Sets the default value of the parameter.\n"
|
||||
"The default value is used to initialize parameters of \\Device objects."
|
||||
) +
|
||||
gsi::method ("is_primary?", &db::DeviceParameterDefinition::is_primary,
|
||||
"@brief Gets a value indicating whether the parameter is a primary parameter\n"
|
||||
"See \\is_primary= for details about this predicate."
|
||||
) +
|
||||
gsi::method ("is_primary=", &db::DeviceParameterDefinition::set_is_primary, gsi::arg ("primary"),
|
||||
"@brief Sets a value indicating whether the parameter is a primary parameter\n"
|
||||
"If this flag is set to true (the default), the parameter is considered a primary parameter.\n"
|
||||
"Only primary parameters are compared by default.\n"
|
||||
) +
|
||||
gsi::method ("id", &db::DeviceParameterDefinition::id,
|
||||
"@brief Gets the ID of the parameter.\n"
|
||||
"The ID of the parameter is used in some places to refer to a specific parameter (e.g. in "
|
||||
|
|
@ -467,11 +482,120 @@ Class<db::DeviceParameterDefinition> decl_dbDeviceParameterDefinition ("db", "De
|
|||
"This class has been added in version 0.26."
|
||||
);
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief A DeviceParameterCompare implementation that allows reimplementation of the virtual methods
|
||||
*/
|
||||
class GenericDeviceParameterCompare
|
||||
: public db::EqualDeviceParameters
|
||||
{
|
||||
public:
|
||||
GenericDeviceParameterCompare ()
|
||||
: db::EqualDeviceParameters ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
virtual bool less (const db::Device &a, const db::Device &b) const
|
||||
{
|
||||
if (cb_less.can_issue ()) {
|
||||
return cb_less.issue<db::EqualDeviceParameters, bool, const db::Device &, const db::Device &> (&db::EqualDeviceParameters::less, a, b);
|
||||
} else {
|
||||
return db::EqualDeviceParameters::less (a, b);
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool equal (const db::Device &a, const db::Device &b) const
|
||||
{
|
||||
if (cb_equal.can_issue ()) {
|
||||
return cb_equal.issue<db::EqualDeviceParameters, bool, const db::Device &, const db::Device &> (&db::EqualDeviceParameters::equal, a, b);
|
||||
} else {
|
||||
return db::EqualDeviceParameters::equal (a, b);
|
||||
}
|
||||
}
|
||||
|
||||
gsi::Callback cb_less, cb_equal;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
db::EqualDeviceParameters *make_equal_dp (size_t param_id, double absolute, double relative)
|
||||
{
|
||||
return new db::EqualDeviceParameters (param_id, absolute, relative);
|
||||
}
|
||||
|
||||
Class<db::EqualDeviceParameters> decl_dbEqualDeviceParameters ("db", "EqualDeviceParameters",
|
||||
gsi::constructor ("new", &make_equal_dp, gsi::arg ("param_id"), gsi::arg ("absolute", 0.0), gsi::arg ("relative", 0.0),
|
||||
"@brief Creates a device parameter comparer for a single parameter.\n"
|
||||
"'absolute' is the absolute deviation allowed for the parameter values. "
|
||||
"'relative' is the relative deviation allowed for the parameter values (a value between 0 and 1).\n"
|
||||
"\n"
|
||||
"A value of 0 for both absolute and relative deviation means the parameters have to match exactly.\n"
|
||||
"\n"
|
||||
"If 'absolute' and 'relative' are both given, their deviations will add to the allowed difference between "
|
||||
"two parameter values. The relative deviation will be applied to the mean value of both parameter values. "
|
||||
"For example, when comparing parameter values of 40 and 60, a relative deviation of 0.35 means an absolute "
|
||||
"deviation of 17.5 (= 0.35 * average of 40 and 60) which does not make both values match."
|
||||
) +
|
||||
gsi::method ("+", &db::EqualDeviceParameters::operator+, gsi::arg ("other"),
|
||||
"@brief Combines two parameters for comparison.\n"
|
||||
"The '+' operator will join the parameter comparers and produce one that checks the combined parameters.\n"
|
||||
) +
|
||||
gsi::method ("+=", &db::EqualDeviceParameters::operator+, gsi::arg ("other"),
|
||||
"@brief Combines two parameters for comparison (in-place).\n"
|
||||
"The '+=' operator will join the parameter comparers and produce one that checks the combined parameters.\n"
|
||||
),
|
||||
"@brief A device parameter equality comparer.\n"
|
||||
"Attach this object to a device class with \\DeviceClass#equal_parameters= to make the device "
|
||||
"class use this comparer:\n"
|
||||
"\n"
|
||||
"@code\n"
|
||||
"# 20nm tolerance for length:\n"
|
||||
"equal_device_parameters = RBA::EqualDeviceParameters::new(RBA::DeviceClassMOS4Transistor::PARAM_L, 0.02, 0.0)\n"
|
||||
"# one percent tolerance for width:\n"
|
||||
"equal_device_parameters += RBA::EqualDeviceParameters::new(RBA::DeviceClassMOS4Transistor::PARAM_W, 0.0, 0.01)\n"
|
||||
"# applies the compare delegate:\n"
|
||||
"netlist.device_class_by_name(\"NMOS\").equal_parameters = equal_device_parameters\n"
|
||||
"@/code\n"
|
||||
"\n"
|
||||
"You can use this class to specify fuzzy equality criteria for the comparison of device parameters in "
|
||||
"netlist verification or to confine the equality of devices to certain parameters only.\n"
|
||||
"\n"
|
||||
"This class has been added in version 0.26."
|
||||
);
|
||||
|
||||
Class<GenericDeviceParameterCompare> decl_GenericDeviceParameterCompare (decl_dbEqualDeviceParameters, "db", "GenericDeviceParameterCompare",
|
||||
gsi::callback ("equal", &GenericDeviceParameterCompare::equal, &GenericDeviceParameterCompare::cb_equal, gsi::arg ("device_a"), gsi::arg ("device_b"),
|
||||
"@brief Compares the parameters of two devices for equality. "
|
||||
"Returns true, if the parameters of device a and b are considered equal."
|
||||
) +
|
||||
gsi::callback ("less", &GenericDeviceParameterCompare::less, &GenericDeviceParameterCompare::cb_less, gsi::arg ("device_a"), gsi::arg ("device_b"),
|
||||
"@brief Compares the parameters of two devices for a begin less than b. "
|
||||
"Returns true, if the parameters of device a are considered less than those of device b."
|
||||
),
|
||||
"@brief A class implementing the comparison of device parameters.\n"
|
||||
"Reimplement this class to provide a custom device parameter compare scheme.\n"
|
||||
"Attach this object to a device class with \\DeviceClass#equal_parameters= to make the device "
|
||||
"class use this comparer.\n"
|
||||
"\n"
|
||||
"This class is intended for special cases. In most scenarios it is easier to use \\EqualDeviceParameters instead of "
|
||||
"implementing a custom comparer class.\n"
|
||||
"\n"
|
||||
"This class has been added in version 0.26."
|
||||
);
|
||||
|
||||
static tl::id_type id_of_device_class (const db::DeviceClass *cls)
|
||||
{
|
||||
return tl::id_of (cls);
|
||||
}
|
||||
|
||||
static void equal_parameters (db::DeviceClass *cls, db::EqualDeviceParameters *comparer)
|
||||
{
|
||||
cls->set_parameter_compare_delegate (comparer);
|
||||
}
|
||||
|
||||
Class<db::DeviceClass> decl_dbDeviceClass ("db", "DeviceClass",
|
||||
gsi::method ("name", &db::DeviceClass::name,
|
||||
"@brief Gets the name of the device class."
|
||||
|
|
@ -527,6 +651,15 @@ Class<db::DeviceClass> decl_dbDeviceClass ("db", "DeviceClass",
|
|||
"@brief Returns the terminal ID of the terminal with the given name.\n"
|
||||
"An exception is thrown if there is no terminal with the given name. Use \\has_terminal to check "
|
||||
"whether the name is a valid terminal name."
|
||||
) +
|
||||
gsi::method_ext ("equal_parameters=", &equal_parameters, gsi::arg ("comparer"),
|
||||
"@brief Specifies a device parameter comparer for netlist verification.\n"
|
||||
"By default, all devices are compared with all parameters. If you want to select only certain parameters "
|
||||
"for comparison or use a fuzzy compare criterion, use an \\EqualDeviceParameters object and assign it "
|
||||
"to the device class of one netlist. You can also chain multiple \\EqualDeviceParameters objects with the '+' operator "
|
||||
"for specifying multiple parameters in the equality check.\n"
|
||||
"\n"
|
||||
"In special cases, you can even implement a custom compare scheme by deriving your own comparer from the \\GenericDeviceParameterCompare class."
|
||||
),
|
||||
"@brief A class describing a specific type of device.\n"
|
||||
"Device class objects live in the context of a \\Netlist object. After a "
|
||||
|
|
@ -586,11 +719,27 @@ public:
|
|||
m_supports_serial_combination = f;
|
||||
}
|
||||
|
||||
void equivalent_terminal_id (size_t tid, size_t equiv_tid)
|
||||
{
|
||||
m_equivalent_terminal_ids.insert (std::make_pair (tid, equiv_tid));
|
||||
}
|
||||
|
||||
virtual size_t normalize_terminal_id (size_t tid) const
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
gsi::Callback cb_combine_devices;
|
||||
|
||||
private:
|
||||
bool m_supports_parallel_combination;
|
||||
bool m_supports_serial_combination;
|
||||
std::map<size_t, size_t> m_equivalent_terminal_ids;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -655,6 +804,11 @@ Class<GenericDeviceClass> decl_GenericDeviceClass (decl_dbDeviceClass, "db", "Ge
|
|||
"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."
|
||||
),
|
||||
"@brief A generic device class\n"
|
||||
"This class allows building generic device classes. Specificially, terminals can be defined "
|
||||
|
|
@ -811,6 +965,11 @@ Class<db::Circuit> decl_dbCircuit ("db", "Circuit",
|
|||
gsi::method ("remove_subcircuit", &db::Circuit::remove_subcircuit, gsi::arg ("subcircuit"),
|
||||
"@brief Removes the given subcircuit from the circuit\n"
|
||||
) +
|
||||
gsi::method ("flatten_subcircuit", &db::Circuit::flatten_subcircuit, gsi::arg ("subcircuit"),
|
||||
"@brief Flattens a subcircuit\n"
|
||||
"This method will substitute the given subcircuit by it's contents. The subcircuit is removed "
|
||||
"after this."
|
||||
) +
|
||||
gsi::iterator ("each_subcircuit", (db::Circuit::subcircuit_iterator (db::Circuit::*) ()) &db::Circuit::begin_subcircuits, (db::Circuit::subcircuit_iterator (db::Circuit::*) ()) &db::Circuit::end_subcircuits,
|
||||
"@brief Iterates over the subcircuits of the circuit"
|
||||
) +
|
||||
|
|
@ -922,6 +1081,13 @@ static void write_netlist (const db::Netlist *nl, const std::string &file, db::N
|
|||
writer->write (os, *nl, description);
|
||||
}
|
||||
|
||||
static void read_netlist (db::Netlist *nl, const std::string &file, db::NetlistReader *reader)
|
||||
{
|
||||
tl_assert (reader != 0);
|
||||
tl::InputStream os (file);
|
||||
reader->read (os, *nl);
|
||||
}
|
||||
|
||||
Class<db::Netlist> decl_dbNetlist ("db", "Netlist",
|
||||
gsi::method_ext ("add", &gsi::add_circuit, gsi::arg ("circuit"),
|
||||
"@brief Adds the circuit to the netlist\n"
|
||||
|
|
@ -932,13 +1098,18 @@ Class<db::Netlist> decl_dbNetlist ("db", "Netlist",
|
|||
"@brief Removes the given circuit object from the netlist\n"
|
||||
"After the object has been removed, it becomes invalid and cannot be used further."
|
||||
) +
|
||||
gsi::method ("flatten_circuit", &db::Netlist::flatten_circuit, gsi::arg ("circuit"),
|
||||
"@brief Flattens a subcircuit\n"
|
||||
"This method will substitute all instances (subcircuits) of the given circuit by it's "
|
||||
"contents. After this, the circuit is removed."
|
||||
) +
|
||||
gsi::method ("circuit_by_cell_index", (db::Circuit *(db::Netlist::*) (db::cell_index_type)) &db::Netlist::circuit_by_cell_index, gsi::arg ("cell_index"),
|
||||
"@brief Gets the circuit object for a given cell index.\n"
|
||||
"If the cell index is not valid or no circuit is registered with this index, nil is returned."
|
||||
) +
|
||||
gsi::method ("circuit_by_name", (db::Circuit *(db::Netlist::*) (const std::string &)) &db::Netlist::circuit_by_name, gsi::arg ("name"),
|
||||
"@brief Gets the circuit object for a given name.\n"
|
||||
"If the ID is not a valid circuit name, nil is returned."
|
||||
"If the name is not a valid circuit name, nil is returned."
|
||||
) +
|
||||
gsi::iterator ("each_circuit_top_down", (db::Netlist::top_down_circuit_iterator (db::Netlist::*) ()) &db::Netlist::begin_top_down, (db::Netlist::top_down_circuit_iterator (db::Netlist::*) ()) &db::Netlist::end_top_down,
|
||||
"@brief Iterates over the circuits top-down\n"
|
||||
|
|
@ -969,6 +1140,10 @@ Class<db::Netlist> decl_dbNetlist ("db", "Netlist",
|
|||
"Use this method with care as it may corrupt the internal structure of the netlist. "
|
||||
"Only use this method when device refers to this device class."
|
||||
) +
|
||||
gsi::method ("device_class_by_name", (db::DeviceClass *(db::Netlist::*) (const std::string &)) &db::Netlist::device_class_by_name, gsi::arg ("name"),
|
||||
"@brief Gets the device class for a given name.\n"
|
||||
"If the name is not a valid device class name, nil is returned."
|
||||
) +
|
||||
gsi::iterator ("each_device_class", (db::Netlist::device_class_iterator (db::Netlist::*) ()) &db::Netlist::begin_device_classes, (db::Netlist::device_class_iterator (db::Netlist::*) ()) &db::Netlist::end_device_classes,
|
||||
"@brief Iterates over the device classes of the netlist"
|
||||
) +
|
||||
|
|
@ -976,6 +1151,11 @@ Class<db::Netlist> decl_dbNetlist ("db", "Netlist",
|
|||
"@brief Converts the netlist to a string representation.\n"
|
||||
"This method is intended for test purposes mainly."
|
||||
) +
|
||||
gsi::method ("from_s", &db::Netlist::from_string, gsi::arg ("str"),
|
||||
"@brief Reads the netlist from a string representation.\n"
|
||||
"This method is intended for test purposes mainly. It turns a string returned by \\to_s back into "
|
||||
"a netlist. Note that the device classes must be created before as they are not persisted inside the string."
|
||||
) +
|
||||
gsi::method ("combine_devices", &db::Netlist::combine_devices,
|
||||
"@brief Combines devices where possible\n"
|
||||
"This method will combine devices that can be combined according "
|
||||
|
|
@ -999,6 +1179,10 @@ Class<db::Netlist> decl_dbNetlist ("db", "Netlist",
|
|||
"Floating nets can be created as effect of reconnections of devices or pins. "
|
||||
"This method will eliminate all nets that make less than two connections."
|
||||
) +
|
||||
gsi::method_ext ("read", &read_netlist, gsi::arg ("file"), gsi::arg ("reader"),
|
||||
"@brief Writes the netlist to the given file using the given reader object to parse the file\n"
|
||||
"See \\NetlistSpiceReader for an example for a parser. "
|
||||
) +
|
||||
gsi::method_ext ("write", &write_netlist, gsi::arg ("file"), gsi::arg ("writer"), gsi::arg ("description", std::string ()),
|
||||
"@brief Writes the netlist to the given file using the given writer object to format the file\n"
|
||||
"See \\NetlistSpiceWriter for an example for a formatter. "
|
||||
|
|
@ -1184,14 +1368,14 @@ Class<db::NetlistSpiceWriter> db_NetlistSpiceWriter (db_NetlistWriter, "db", "Ne
|
|||
"@code\n"
|
||||
"writer = RBA::NetlistSpiceWriter::new\n"
|
||||
"netlist.write(path, writer)\n"
|
||||
"@endcode\n"
|
||||
"@/code\n"
|
||||
"\n"
|
||||
"You can give a custom description for the headline:\n"
|
||||
"\n"
|
||||
"@code\n"
|
||||
"writer = RBA::NetlistSpiceWriter::new\n"
|
||||
"netlist.write(path, writer, \"A custom description\")\n"
|
||||
"@endcode\n"
|
||||
"@/code\n"
|
||||
"\n"
|
||||
"To customize the output, you can use a device writer delegate.\n"
|
||||
"The delegate is an object of a class derived from \\NetlistSpiceWriterDelegate which "
|
||||
|
|
@ -1232,9 +1416,36 @@ Class<db::NetlistSpiceWriter> db_NetlistSpiceWriter (db_NetlistWriter, "db", "Ne
|
|||
"# write the netlist with delegate:\n"
|
||||
"writer = RBA::NetlistSpiceWriter::new(MyDelegate::new)\n"
|
||||
"netlist.write(path, writer)\n"
|
||||
"@endcode\n"
|
||||
"@/code\n"
|
||||
"\n"
|
||||
"This class has been introduced in version 0.26."
|
||||
);
|
||||
|
||||
Class<db::NetlistReader> db_NetlistReader ("db", "NetlistReader",
|
||||
gsi::Methods (),
|
||||
"@hide\n"
|
||||
);
|
||||
|
||||
db::NetlistSpiceReader *new_spice_reader ()
|
||||
{
|
||||
return new db::NetlistSpiceReader ();
|
||||
}
|
||||
|
||||
Class<db::NetlistSpiceReader> db_NetlistSpiceReader (db_NetlistReader, "db", "NetlistSpiceReader",
|
||||
gsi::constructor ("new", &new_spice_reader,
|
||||
"@brief Creates a new reader.\n"
|
||||
),
|
||||
"@brief Implements a netlist Reader for the SPICE format.\n"
|
||||
"Use the SPICE reader like this:\n"
|
||||
"\n"
|
||||
"@code\n"
|
||||
"writer = RBA::NetlistSpiceReader::new\n"
|
||||
"netlist = RBA::Netlist::new\n"
|
||||
"netlist.read(path, reader)\n"
|
||||
"@/code\n"
|
||||
"\n"
|
||||
"This class has been introduced in version 0.26."
|
||||
);
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,531 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2019 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include "gsiDecl.h"
|
||||
#include "dbNetlistCompare.h"
|
||||
|
||||
namespace {
|
||||
|
||||
/**
|
||||
* @brief A NetlistDeviceExtractor implementation that allows reimplementation of the virtual methods
|
||||
*/
|
||||
class GenericNetlistCompareLogger
|
||||
: public gsi::ObjectBase, public db::NetlistCompareLogger
|
||||
{
|
||||
public:
|
||||
GenericNetlistCompareLogger ()
|
||||
: db::NetlistCompareLogger ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
virtual void begin_netlist (const db::Netlist *a, const db::Netlist *b)
|
||||
{
|
||||
if (cb_begin_netlist.can_issue ()) {
|
||||
cb_begin_netlist.issue<GenericNetlistCompareLogger> (&GenericNetlistCompareLogger::begin_netlist_fb, a, b);
|
||||
} else {
|
||||
db::NetlistCompareLogger::begin_netlist (a, b);
|
||||
}
|
||||
}
|
||||
|
||||
void begin_netlist_fb (const db::Netlist *a, const db::Netlist *b)
|
||||
{
|
||||
db::NetlistCompareLogger::begin_netlist (a, b);
|
||||
}
|
||||
|
||||
virtual void end_netlist (const db::Netlist *a, const db::Netlist *b)
|
||||
{
|
||||
if (cb_end_netlist.can_issue ()) {
|
||||
cb_end_netlist.issue<GenericNetlistCompareLogger> (&GenericNetlistCompareLogger::end_netlist_fb, a, b);
|
||||
} else {
|
||||
db::NetlistCompareLogger::end_netlist (a, b);
|
||||
}
|
||||
}
|
||||
|
||||
void end_netlist_fb (const db::Netlist *a, const db::Netlist *b)
|
||||
{
|
||||
db::NetlistCompareLogger::end_netlist (a, b);
|
||||
}
|
||||
|
||||
virtual void device_class_mismatch (const db::DeviceClass *a, const db::DeviceClass *b)
|
||||
{
|
||||
if (cb_device_class_mismatch.can_issue ()) {
|
||||
cb_device_class_mismatch.issue<GenericNetlistCompareLogger> (&GenericNetlistCompareLogger::device_class_mismatch_fb, a, b);
|
||||
} else {
|
||||
db::NetlistCompareLogger::device_class_mismatch (a, b);
|
||||
}
|
||||
}
|
||||
|
||||
void device_class_mismatch_fb (const db::DeviceClass *a, const db::DeviceClass *b)
|
||||
{
|
||||
db::NetlistCompareLogger::device_class_mismatch (a, b);
|
||||
}
|
||||
|
||||
virtual void begin_circuit (const db::Circuit *a, const db::Circuit *b)
|
||||
{
|
||||
if (cb_begin_circuit.can_issue ()) {
|
||||
cb_begin_circuit.issue<GenericNetlistCompareLogger> (&GenericNetlistCompareLogger::begin_circuit_fb, a, b);
|
||||
} else {
|
||||
db::NetlistCompareLogger::begin_circuit (a, b);
|
||||
}
|
||||
}
|
||||
|
||||
void begin_circuit_fb (const db::Circuit *a, const db::Circuit *b)
|
||||
{
|
||||
db::NetlistCompareLogger::begin_circuit (a, b);
|
||||
}
|
||||
|
||||
virtual void end_circuit (const db::Circuit *a, const db::Circuit *b, bool matching)
|
||||
{
|
||||
if (cb_end_circuit.can_issue ()) {
|
||||
cb_end_circuit.issue<GenericNetlistCompareLogger> (&GenericNetlistCompareLogger::end_circuit_fb, a, b, matching);
|
||||
} else {
|
||||
db::NetlistCompareLogger::end_circuit (a, b, matching);
|
||||
}
|
||||
}
|
||||
|
||||
void end_circuit_fb (const db::Circuit *a, const db::Circuit *b, bool matching)
|
||||
{
|
||||
db::NetlistCompareLogger::end_circuit (a, b, matching);
|
||||
}
|
||||
|
||||
virtual void circuit_skipped (const db::Circuit *a, const db::Circuit *b)
|
||||
{
|
||||
if (cb_circuit_skipped.can_issue ()) {
|
||||
cb_circuit_skipped.issue<GenericNetlistCompareLogger> (&GenericNetlistCompareLogger::circuit_skipped_fb, a, b);
|
||||
} else {
|
||||
db::NetlistCompareLogger::circuit_skipped (a, b);
|
||||
}
|
||||
}
|
||||
|
||||
void circuit_skipped_fb (const db::Circuit *a, const db::Circuit *b)
|
||||
{
|
||||
db::NetlistCompareLogger::circuit_skipped (a, b);
|
||||
}
|
||||
|
||||
virtual void circuit_mismatch (const db::Circuit *a, const db::Circuit *b)
|
||||
{
|
||||
if (cb_circuit_mismatch.can_issue ()) {
|
||||
cb_circuit_mismatch.issue<GenericNetlistCompareLogger> (&GenericNetlistCompareLogger::circuit_mismatch_fb, a, b);
|
||||
} else {
|
||||
db::NetlistCompareLogger::circuit_mismatch (a, b);
|
||||
}
|
||||
}
|
||||
|
||||
void circuit_mismatch_fb (const db::Circuit *a, const db::Circuit *b)
|
||||
{
|
||||
db::NetlistCompareLogger::circuit_mismatch (a, b);
|
||||
}
|
||||
|
||||
virtual void match_nets (const db::Net *a, const db::Net *b)
|
||||
{
|
||||
if (cb_match_nets.can_issue ()) {
|
||||
cb_match_nets.issue<GenericNetlistCompareLogger> (&GenericNetlistCompareLogger::match_nets_fb, a, b);
|
||||
} else {
|
||||
db::NetlistCompareLogger::match_nets (a, b);
|
||||
}
|
||||
}
|
||||
|
||||
void match_nets_fb (const db::Net *a, const db::Net *b)
|
||||
{
|
||||
db::NetlistCompareLogger::match_nets (a, b);
|
||||
}
|
||||
|
||||
virtual void match_ambiguous_nets (const db::Net *a, const db::Net *b)
|
||||
{
|
||||
if (cb_match_ambiguous_nets.can_issue ()) {
|
||||
cb_match_ambiguous_nets.issue<GenericNetlistCompareLogger> (&GenericNetlistCompareLogger::match_ambiguous_nets_fb, a, b);
|
||||
} else {
|
||||
db::NetlistCompareLogger::match_ambiguous_nets (a, b);
|
||||
}
|
||||
}
|
||||
|
||||
void match_ambiguous_nets_fb (const db::Net *a, const db::Net *b)
|
||||
{
|
||||
db::NetlistCompareLogger::match_ambiguous_nets (a, b);
|
||||
}
|
||||
|
||||
virtual void net_mismatch (const db::Net *a, const db::Net *b)
|
||||
{
|
||||
if (cb_net_mismatch.can_issue ()) {
|
||||
cb_net_mismatch.issue<GenericNetlistCompareLogger> (&GenericNetlistCompareLogger::net_mismatch_fb, a, b);
|
||||
} else {
|
||||
db::NetlistCompareLogger::net_mismatch (a, b);
|
||||
}
|
||||
}
|
||||
|
||||
void net_mismatch_fb (const db::Net *a, const db::Net *b)
|
||||
{
|
||||
db::NetlistCompareLogger::net_mismatch (a, b);
|
||||
}
|
||||
|
||||
virtual void match_devices (const db::Device *a, const db::Device *b)
|
||||
{
|
||||
if (cb_match_devices.can_issue ()) {
|
||||
cb_match_devices.issue<GenericNetlistCompareLogger> (&GenericNetlistCompareLogger::match_devices_fb, a, b);
|
||||
} else {
|
||||
db::NetlistCompareLogger::match_devices (a, b);
|
||||
}
|
||||
}
|
||||
|
||||
void match_devices_fb (const db::Device *a, const db::Device *b)
|
||||
{
|
||||
db::NetlistCompareLogger::match_devices (a, b);
|
||||
}
|
||||
|
||||
virtual void match_devices_with_different_parameters (const db::Device *a, const db::Device *b)
|
||||
{
|
||||
if (cb_match_devices_with_different_parameters.can_issue ()) {
|
||||
cb_match_devices_with_different_parameters.issue<GenericNetlistCompareLogger> (&GenericNetlistCompareLogger::match_devices_with_different_parameters_fb, a, b);
|
||||
} else {
|
||||
db::NetlistCompareLogger::match_devices_with_different_parameters (a, b);
|
||||
}
|
||||
}
|
||||
|
||||
void match_devices_with_different_parameters_fb (const db::Device *a, const db::Device *b)
|
||||
{
|
||||
db::NetlistCompareLogger::match_devices_with_different_parameters (a, b);
|
||||
}
|
||||
|
||||
virtual void match_devices_with_different_device_classes (const db::Device *a, const db::Device *b)
|
||||
{
|
||||
if (cb_match_devices_with_different_device_classes.can_issue ()) {
|
||||
cb_match_devices_with_different_device_classes.issue<GenericNetlistCompareLogger> (&GenericNetlistCompareLogger::match_devices_with_different_device_classes_fb, a, b);
|
||||
} else {
|
||||
db::NetlistCompareLogger::match_devices_with_different_device_classes (a, b);
|
||||
}
|
||||
}
|
||||
|
||||
void match_devices_with_different_device_classes_fb (const db::Device *a, const db::Device *b)
|
||||
{
|
||||
db::NetlistCompareLogger::match_devices_with_different_device_classes (a, b);
|
||||
}
|
||||
|
||||
virtual void device_mismatch (const db::Device *a, const db::Device *b)
|
||||
{
|
||||
if (cb_device_mismatch.can_issue ()) {
|
||||
cb_device_mismatch.issue<GenericNetlistCompareLogger> (&GenericNetlistCompareLogger::device_mismatch_fb, a, b);
|
||||
} else {
|
||||
db::NetlistCompareLogger::device_mismatch (a, b);
|
||||
}
|
||||
}
|
||||
|
||||
void device_mismatch_fb (const db::Device *a, const db::Device *b)
|
||||
{
|
||||
db::NetlistCompareLogger::device_mismatch (a, b);
|
||||
}
|
||||
|
||||
virtual void match_pins (const db::Pin *a, const db::Pin *b)
|
||||
{
|
||||
if (cb_match_pins.can_issue ()) {
|
||||
cb_match_pins.issue<GenericNetlistCompareLogger> (&GenericNetlistCompareLogger::match_pins_fb, a, b);
|
||||
} else {
|
||||
db::NetlistCompareLogger::match_pins (a, b);
|
||||
}
|
||||
}
|
||||
|
||||
void match_pins_fb (const db::Pin *a, const db::Pin *b)
|
||||
{
|
||||
db::NetlistCompareLogger::match_pins (a, b);
|
||||
}
|
||||
|
||||
virtual void pin_mismatch (const db::Pin *a, const db::Pin *b)
|
||||
{
|
||||
if (cb_pin_mismatch.can_issue ()) {
|
||||
cb_pin_mismatch.issue<GenericNetlistCompareLogger> (&GenericNetlistCompareLogger::pin_mismatch_fb, a, b);
|
||||
} else {
|
||||
db::NetlistCompareLogger::pin_mismatch (a, b);
|
||||
}
|
||||
}
|
||||
|
||||
void pin_mismatch_fb (const db::Pin *a, const db::Pin *b)
|
||||
{
|
||||
db::NetlistCompareLogger::pin_mismatch (a, b);
|
||||
}
|
||||
|
||||
virtual void match_subcircuits (const db::SubCircuit *a, const db::SubCircuit *b)
|
||||
{
|
||||
if (cb_match_subcircuits.can_issue ()) {
|
||||
cb_match_subcircuits.issue<GenericNetlistCompareLogger> (&GenericNetlistCompareLogger::match_subcircuits_fb, a, b);
|
||||
} else {
|
||||
db::NetlistCompareLogger::match_subcircuits (a, b);
|
||||
}
|
||||
}
|
||||
|
||||
void match_subcircuits_fb (const db::SubCircuit *a, const db::SubCircuit *b)
|
||||
{
|
||||
db::NetlistCompareLogger::match_subcircuits (a, b);
|
||||
}
|
||||
|
||||
virtual void subcircuit_mismatch (const db::SubCircuit *a, const db::SubCircuit *b)
|
||||
{
|
||||
if (cb_subcircuit_mismatch.can_issue ()) {
|
||||
cb_subcircuit_mismatch.issue<GenericNetlistCompareLogger> (&GenericNetlistCompareLogger::subcircuit_mismatch_fb, a, b);
|
||||
} else {
|
||||
db::NetlistCompareLogger::subcircuit_mismatch (a, b);
|
||||
}
|
||||
}
|
||||
|
||||
void subcircuit_mismatch_fb (const db::SubCircuit *a, const db::SubCircuit *b)
|
||||
{
|
||||
db::NetlistCompareLogger::subcircuit_mismatch (a, b);
|
||||
}
|
||||
|
||||
gsi::Callback cb_begin_netlist;
|
||||
gsi::Callback cb_end_netlist;
|
||||
gsi::Callback cb_device_class_mismatch;
|
||||
gsi::Callback cb_begin_circuit;
|
||||
gsi::Callback cb_end_circuit;
|
||||
gsi::Callback cb_circuit_skipped;
|
||||
gsi::Callback cb_match_nets;
|
||||
gsi::Callback cb_net_mismatch;
|
||||
gsi::Callback cb_circuit_mismatch;
|
||||
gsi::Callback cb_match_ambiguous_nets;
|
||||
gsi::Callback cb_match_devices;
|
||||
gsi::Callback cb_match_devices_with_different_parameters;
|
||||
gsi::Callback cb_match_devices_with_different_device_classes;
|
||||
gsi::Callback cb_device_mismatch;
|
||||
gsi::Callback cb_match_pins;
|
||||
gsi::Callback cb_pin_mismatch;
|
||||
gsi::Callback cb_match_subcircuits;
|
||||
gsi::Callback cb_subcircuit_mismatch;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace gsi
|
||||
{
|
||||
|
||||
Class<GenericNetlistCompareLogger> decl_GenericNetlistCompareLogger ("db", "GenericNetlistCompareLogger",
|
||||
gsi::callback ("begin_netlist", &GenericNetlistCompareLogger::begin_netlist, &GenericNetlistCompareLogger::cb_begin_netlist, gsi::arg ("a"), gsi::arg ("b"),
|
||||
"@brief This function is called at the beginning of the compare process.\n"
|
||||
"This method is called once when the compare run begins.\n"
|
||||
) +
|
||||
gsi::callback ("end_netlist", &GenericNetlistCompareLogger::end_netlist, &GenericNetlistCompareLogger::cb_end_netlist, gsi::arg ("a"), gsi::arg ("b"),
|
||||
"@brief This function is called at the end of the compare process.\n"
|
||||
"This method is called once when the compare run ended.\n"
|
||||
) +
|
||||
gsi::callback ("device_class_mismatch", &GenericNetlistCompareLogger::device_class_mismatch, &GenericNetlistCompareLogger::cb_device_class_mismatch, gsi::arg ("a"), gsi::arg ("b"),
|
||||
"@brief This function is called when device classes can't be compared.\n"
|
||||
"This method is called when a device class can't be mapped to a partner in the other netlist. In this case, "
|
||||
"this method is called with the one device class and nil for the other class.\n"
|
||||
) +
|
||||
gsi::callback ("begin_circuit", &GenericNetlistCompareLogger::begin_circuit, &GenericNetlistCompareLogger::cb_begin_circuit, gsi::arg ("a"), gsi::arg ("b"),
|
||||
"@brief This function is called when a new circuit is compared.\n"
|
||||
"This compare procedure will run the netlist compare circuit vs. circuit in a bottom-up fashion.\n"
|
||||
"Before each circuit is compared, this method is called once with the circuits that are about to be compared.\n"
|
||||
"After the circuit has been compared, \\end_circuit will be called.\n"
|
||||
"\n"
|
||||
"In some cases, the compare algorithm will decide that circuits can't be compared. This happens if for "
|
||||
"some or all subcircuits the pin assignment can't be derived. In this case, \\circuit_skipped will be called once "
|
||||
"instead of \\begin_circuit and \\end_circuit.\n"
|
||||
) +
|
||||
gsi::callback ("end_circuit", &GenericNetlistCompareLogger::end_circuit, &GenericNetlistCompareLogger::cb_end_circuit, gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("matching"),
|
||||
"@brief This function is called at the end of the compare process.\n"
|
||||
"The 'matching' argument indicates whether the circuits have been identified as identical.\n"
|
||||
"See \\begin_circuit for details."
|
||||
) +
|
||||
gsi::callback ("circuit_skipped", &GenericNetlistCompareLogger::circuit_skipped, &GenericNetlistCompareLogger::cb_circuit_skipped, gsi::arg ("a"), gsi::arg ("b"),
|
||||
"@brief This function is called when circuits can't be compared.\n"
|
||||
"If there is a known circuit pair, but the circuits can be compared - for example because subcircuits can't be identified - this method will be called with "
|
||||
"both circuits.\n"
|
||||
"\n"
|
||||
"This method is called instead of \\begin_circuit and \\end_circuit."
|
||||
) +
|
||||
gsi::callback ("circuit_mismatch", &GenericNetlistCompareLogger::circuit_mismatch, &GenericNetlistCompareLogger::cb_circuit_mismatch, gsi::arg ("a"), gsi::arg ("b"),
|
||||
"@brief This function is called when circuits can't be compared.\n"
|
||||
"This method is called when a circuit can't be mapped to a partner in the other netlist. In this case, "
|
||||
"this method is called with the one circuit and nil for the other circuit.\n"
|
||||
"\n"
|
||||
"This method is called instead of \\begin_circuit and \\end_circuit."
|
||||
) +
|
||||
gsi::callback ("match_nets", &GenericNetlistCompareLogger::match_nets, &GenericNetlistCompareLogger::cb_match_nets, gsi::arg ("a"), gsi::arg ("b"),
|
||||
"@brief This function is called when two nets are identified.\n"
|
||||
"If two nets are identified as a corresponding pair, this method will be called with both nets.\n"
|
||||
"If the nets can be paired, but this match is ambiguous, \\match_ambiguous_nets will be called instead.\n"
|
||||
"If nets can't be matched to a partner, \\net_mismatch will be called.\n"
|
||||
) +
|
||||
gsi::callback ("match_ambiguous_nets", &GenericNetlistCompareLogger::match_ambiguous_nets, &GenericNetlistCompareLogger::cb_match_ambiguous_nets, gsi::arg ("a"), gsi::arg ("b"),
|
||||
"@brief This function is called when two nets are identified, but this choice is ambiguous.\n"
|
||||
"This choice is a last-resort fallback to allow continuation of the compare procedure. It is likely that this "
|
||||
"compare will fail later. Looking for ambiguous nets allows deduction of the origin of this faulty decision. "
|
||||
"See \\match_nets for more details."
|
||||
) +
|
||||
gsi::callback ("net_mismatch", &GenericNetlistCompareLogger::net_mismatch, &GenericNetlistCompareLogger::cb_net_mismatch, gsi::arg ("a"), gsi::arg ("b"),
|
||||
"@brief This function is called when a net can't be paired.\n"
|
||||
"This method will be called, if a net cannot be identified as identical with another net. The corresponding argument "
|
||||
"will identify the net and source netlist. The other argument will be nil.\n"
|
||||
) +
|
||||
gsi::callback ("match_devices", &GenericNetlistCompareLogger::match_devices, &GenericNetlistCompareLogger::cb_match_devices, gsi::arg ("a"), gsi::arg ("b"),
|
||||
"@brief This function is called when two devices are identified.\n"
|
||||
"If two devices are identified as a corresponding pair, this method will be called with both devices.\n"
|
||||
"If the devices can be paired, but the device parameters don't match, \\match_devices_with_different_parameters will be called instead.\n"
|
||||
"If the devices can be paired, but the device classes don't match, \\match_devices_with_different_device_classes will be called instead.\n"
|
||||
"If devices can't be matched, \\device_mismatch will be called with the one device considered and the other device being nil."
|
||||
) +
|
||||
gsi::callback ("match_devices_with_different_parameters", &GenericNetlistCompareLogger::match_devices_with_different_parameters, &GenericNetlistCompareLogger::cb_match_devices_with_different_parameters, gsi::arg ("a"), gsi::arg ("b"),
|
||||
"@brief This function is called when two devices are identified but have different parameters.\n"
|
||||
"See \\match_devices for details.\n"
|
||||
) +
|
||||
gsi::callback ("match_devices_with_different_device_classes", &GenericNetlistCompareLogger::match_devices_with_different_device_classes, &GenericNetlistCompareLogger::cb_match_devices_with_different_device_classes, gsi::arg ("a"), gsi::arg ("b"),
|
||||
"@brief This function is called when two devices are identified but have different device classes.\n"
|
||||
"See \\match_devices for details.\n"
|
||||
) +
|
||||
gsi::callback ("device_mismatch", &GenericNetlistCompareLogger::device_mismatch, &GenericNetlistCompareLogger::cb_device_mismatch, gsi::arg ("a"), gsi::arg ("b"),
|
||||
"@brief This function is called when two devices can't be paired.\n"
|
||||
"This will report the device considered in a or b. The other argument is nil. "
|
||||
"See \\match_devices for details.\n"
|
||||
) +
|
||||
gsi::callback ("match_pins", &GenericNetlistCompareLogger::match_pins, &GenericNetlistCompareLogger::cb_match_pins, gsi::arg ("a"), gsi::arg ("b"),
|
||||
"@brief This function is called when two pins are identified.\n"
|
||||
"If two pins are identified as a corresponding pair, this method will be called with both pins.\n"
|
||||
"If pins can't be matched, \\pin_mismatch will be called with the one pin considered and the other pin being nil."
|
||||
) +
|
||||
gsi::callback ("pin_mismatch", &GenericNetlistCompareLogger::pin_mismatch, &GenericNetlistCompareLogger::cb_pin_mismatch, gsi::arg ("a"), gsi::arg ("b"),
|
||||
"@brief This function is called when two pins can't be paired.\n"
|
||||
"This will report the pin considered in a or b. The other argument is nil. "
|
||||
"See \\match_pins for details.\n"
|
||||
) +
|
||||
gsi::callback ("match_subcircuits", &GenericNetlistCompareLogger::match_subcircuits, &GenericNetlistCompareLogger::cb_match_subcircuits, gsi::arg ("a"), gsi::arg ("b"),
|
||||
"@brief This function is called when two subcircuits are identified.\n"
|
||||
"If two subcircuits are identified as a corresponding pair, this method will be called with both subcircuits.\n"
|
||||
"If subcircuits can't be matched, \\subcircuit_mismatch will be called with the one subcircuit considered and the other subcircuit being nil."
|
||||
) +
|
||||
gsi::callback ("subcircuit_mismatch", &GenericNetlistCompareLogger::subcircuit_mismatch, &GenericNetlistCompareLogger::cb_subcircuit_mismatch, gsi::arg ("a"), gsi::arg ("b"),
|
||||
"@brief This function is called when two subcircuits can't be paired.\n"
|
||||
"This will report the subcircuit considered in a or b. The other argument is nil. "
|
||||
"See \\match_subcircuits for details.\n"
|
||||
),
|
||||
"@brief An event receiver for the netlist compare feature.\n"
|
||||
"The \\NetlistComparer class will send compare events to a logger derived from this class. "
|
||||
"Use this class to implement your own logger class. You can override on of it's methods to receive certain "
|
||||
"kind of events."
|
||||
"\n"
|
||||
"This class has been introduced in version 0.26.\n"
|
||||
);
|
||||
|
||||
static db::NetlistComparer *make_comparer0 ()
|
||||
{
|
||||
return new db::NetlistComparer (0);
|
||||
}
|
||||
|
||||
static db::NetlistComparer *make_comparer1 (GenericNetlistCompareLogger *logger)
|
||||
{
|
||||
return new db::NetlistComparer (logger);
|
||||
}
|
||||
|
||||
Class<db::NetlistComparer> decl_dbNetlistComparer ("db", "NetlistComparer",
|
||||
gsi::constructor ("new", &make_comparer0,
|
||||
"@brief Creates a new comparer object.\n"
|
||||
"See the class description for more details."
|
||||
) +
|
||||
gsi::constructor ("new", &make_comparer1, gsi::arg ("logger"),
|
||||
"@brief Creates a new comparer object.\n"
|
||||
"The logger is a delegate or event receiver which the comparer will send compare events to. "
|
||||
"See the class description for more details."
|
||||
) +
|
||||
gsi::method ("same_nets", &db::NetlistComparer::same_nets, gsi::arg ("net_a"), gsi::arg ("net_b"),
|
||||
"@brief Marks two nets as identical.\n"
|
||||
"This makes a net net_a in netlist a identical to the corresponding\n"
|
||||
"net net_b in netlist b (see \\compare).\n"
|
||||
"Otherwise, the algorithm will try to identify nets according to their topology. "
|
||||
"This method can be used to supply hints to the compare algorithm. It will use "
|
||||
"these hints to derive further identities."
|
||||
) +
|
||||
gsi::method ("equivalent_pins", (void (db::NetlistComparer::*) (const db::Circuit *, size_t, size_t)) &db::NetlistComparer::equivalent_pins, gsi::arg ("circuit_b"), gsi::arg ("pin_id1"), gsi::arg ("pin_id2"),
|
||||
"@brief Marks two pins of the given circuit as equivalent (i.e. they can be swapped).\n"
|
||||
"Only circuits from the second input can be given swappable pins. "
|
||||
"This will imply the same swappable pins on the equivalent circuit of the first input. "
|
||||
"To mark multiple pins as swappable, use the version that takes a list of pins."
|
||||
) +
|
||||
gsi::method ("equivalent_pins", (void (db::NetlistComparer::*) (const db::Circuit *, const std::vector<size_t> &)) &db::NetlistComparer::equivalent_pins, gsi::arg ("circuit_b"), gsi::arg ("pin_ids"),
|
||||
"@brief Marks several pins of the given circuit as equivalent (i.e. they can be swapped).\n"
|
||||
"Only circuits from the second input can be given swappable pins. "
|
||||
"This will imply the same swappable pins on the equivalent circuit of the first input. "
|
||||
"This version is a generic variant of the two-pin version of this method."
|
||||
) +
|
||||
gsi::method ("same_device_classes", &db::NetlistComparer::same_device_classes, gsi::arg ("dev_cls_a"), gsi::arg ("dev_cls_b"),
|
||||
"@brief Marks two device classes as identical.\n"
|
||||
"This makes a device class dev_cls_a in netlist a identical to the corresponding\n"
|
||||
"device class dev_cls_b in netlist b (see \\compare).\n"
|
||||
"By default device classes with the same name are identical.\n"
|
||||
) +
|
||||
gsi::method ("same_circuits", &db::NetlistComparer::same_circuits, gsi::arg ("circuit_a"), gsi::arg ("circuit_b"),
|
||||
"@brief Marks two circuits as identical.\n"
|
||||
"This method makes a circuit circuit_a in netlist a identical to the corresponding\n"
|
||||
"circuit circuit_b in netlist b (see \\compare). By default circuits with the same name are identical.\n"
|
||||
) +
|
||||
gsi::method ("min_capacitance=", &db::NetlistComparer::exclude_caps, gsi::arg ("threshold"),
|
||||
"@brief Excludes all capacitor devices with a capacitance values less than the given threshold.\n"
|
||||
"To reset this constraint, set this attribute to zero."
|
||||
) +
|
||||
gsi::method ("max_resistance=", &db::NetlistComparer::exclude_resistors, gsi::arg ("threshold"),
|
||||
"@brief Excludes all resistor devices with a resistance values higher than the given threshold.\n"
|
||||
"To reset this constraint, set this attribute to zero."
|
||||
) +
|
||||
gsi::method ("max_depth=", &db::NetlistComparer::set_max_depth, gsi::arg ("n"),
|
||||
"@brief Sets the maximum seach depth\n"
|
||||
"This value limits the search depth of the backtracking algorithm to the\n"
|
||||
"given number of jumps.\n"
|
||||
) +
|
||||
gsi::method ("max_depth", &db::NetlistComparer::max_depth,
|
||||
"@brief Gets the maximum seach depth\n"
|
||||
"See \\max_depth= for details."
|
||||
) +
|
||||
gsi::method ("max_branch_complexity=", &db::NetlistComparer::set_max_branch_complexity, gsi::arg ("n"),
|
||||
"@brief Sets the maximum branch complexity\n"
|
||||
"This value limits the maximum branch complexity of the backtracking algorithm.\n"
|
||||
"The complexity is the accumulated number of branch options with ambiguous\n"
|
||||
"net matches. Backtracking will stop when the maximum number of options\n"
|
||||
"has been exceeded.\n"
|
||||
"\n"
|
||||
"As the computational complexity is the square of the branch count,\n"
|
||||
"this value should be adjusted carefully.\n"
|
||||
) +
|
||||
gsi::method ("max_branch_complexity", &db::NetlistComparer::max_branch_complexity,
|
||||
"@brief Gets the maximum branch complexity\n"
|
||||
"See \\max_branch_complexity= for details."
|
||||
) +
|
||||
gsi::method ("compare", &db::NetlistComparer::compare, gsi::arg ("netlist_a"), gsi::arg ("netlist_b"),
|
||||
"@brief Compares two netlists.\n"
|
||||
"This method will perform the actual netlist compare. It will return true if both netlists are identical. "
|
||||
"If the comparer has been configured with \\same_nets or similar methods, the objects given there must "
|
||||
"be located inside 'circuit_a' and 'circuit_b' respectively."
|
||||
),
|
||||
"@brief Compares two netlists\n"
|
||||
"This class performs a comparison of two netlists.\n"
|
||||
"It can be used with an event receiver (logger) to track the errors and net mismatches. "
|
||||
"Event receivers are derived from class \\GenericNetlistCompareLogger."
|
||||
"\n"
|
||||
"The netlist comparer can be configured in different ways. Specific hints can be given for nets, device classes or circuits "
|
||||
"to improve efficiency and reliability of the graph equivalence deduction algorithm. "
|
||||
"For example, objects can be marked as equivalent using \\same_nets, \\same_circuits etc. "
|
||||
"The compare algorithm will then use these hints to derive further equivalences. This way, "
|
||||
"ambiguities can be resolved.\n"
|
||||
"\n"
|
||||
"Another configuration option relates to swappable pins of subcircuits. If pins are marked this way, the compare algorithm may swap them to "
|
||||
"achieve net matching. Swappable pins belong to an 'equivalence group' and can be defined with \\equivalent_pins.\n"
|
||||
"\n"
|
||||
"This class has been introduced in version 0.26."
|
||||
);
|
||||
|
||||
}
|
||||
|
|
@ -337,28 +337,32 @@ TEST(1_BasicExtraction)
|
|||
db::compare_layouts (_this, ly, au);
|
||||
|
||||
// compare netlist as string
|
||||
EXPECT_EQ (l2n.netlist ()->to_string (),
|
||||
"Circuit RINGO ():\n"
|
||||
" XINV2 $1 (IN=$I8,$2=FB,OUT=OSC,$4=VSS,$5=VDD)\n"
|
||||
" XINV2 $2 (IN=FB,$2=$I38,OUT=$I19,$4=VSS,$5=VDD)\n"
|
||||
" XINV2 $3 (IN=$I19,$2=$I39,OUT=$I1,$4=VSS,$5=VDD)\n"
|
||||
" XINV2 $4 (IN=$I1,$2=$I40,OUT=$I2,$4=VSS,$5=VDD)\n"
|
||||
" XINV2 $5 (IN=$I2,$2=$I41,OUT=$I3,$4=VSS,$5=VDD)\n"
|
||||
" XINV2 $6 (IN=$I3,$2=$I42,OUT=$I4,$4=VSS,$5=VDD)\n"
|
||||
" XINV2 $7 (IN=$I4,$2=$I43,OUT=$I5,$4=VSS,$5=VDD)\n"
|
||||
" XINV2 $8 (IN=$I5,$2=$I44,OUT=$I6,$4=VSS,$5=VDD)\n"
|
||||
" XINV2 $9 (IN=$I6,$2=$I45,OUT=$I7,$4=VSS,$5=VDD)\n"
|
||||
" XINV2 $10 (IN=$I7,$2=$I46,OUT=$I8,$4=VSS,$5=VDD)\n"
|
||||
"Circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5):\n"
|
||||
" DPMOS $1 (S=$2,G=IN,D=$5) [L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5]\n"
|
||||
" DPMOS $2 (S=$5,G=$2,D=OUT) [L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95]\n"
|
||||
" DNMOS $3 (S=$2,G=IN,D=$4) [L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5]\n"
|
||||
" DNMOS $4 (S=$4,G=$2,D=OUT) [L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95]\n"
|
||||
" XTRANS $1 ($1=$2,$2=$4,$3=IN)\n"
|
||||
" XTRANS $2 ($1=$2,$2=$5,$3=IN)\n"
|
||||
" XTRANS $3 ($1=$5,$2=OUT,$3=$2)\n"
|
||||
" XTRANS $4 ($1=$4,$2=OUT,$3=$2)\n"
|
||||
"Circuit TRANS ($1=$1,$2=$2,$3=$3):\n"
|
||||
CHECKPOINT ();
|
||||
db::compare_netlist (_this, *l2n.netlist (),
|
||||
"circuit RINGO ();\n"
|
||||
" subcircuit INV2 $1 (IN=$I8,$2=FB,OUT=OSC,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $2 (IN=FB,$2=$I38,OUT=$I19,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $3 (IN=$I19,$2=$I39,OUT=$I1,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $4 (IN=$I1,$2=$I40,OUT=$I2,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $5 (IN=$I2,$2=$I41,OUT=$I3,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $6 (IN=$I3,$2=$I42,OUT=$I4,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $7 (IN=$I4,$2=$I43,OUT=$I5,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $8 (IN=$I5,$2=$I44,OUT=$I6,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $9 (IN=$I6,$2=$I45,OUT=$I7,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $10 (IN=$I7,$2=$I46,OUT=$I8,$4=VSS,$5=VDD);\n"
|
||||
"end;\n"
|
||||
"circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5);\n"
|
||||
" device PMOS $1 (S=$2,G=IN,D=$5) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device PMOS $2 (S=$5,G=$2,D=OUT) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||
" device NMOS $3 (S=$2,G=IN,D=$4) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device NMOS $4 (S=$4,G=$2,D=OUT) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||
" subcircuit TRANS $1 ($1=$2,$2=$4,$3=IN);\n"
|
||||
" subcircuit TRANS $2 ($1=$2,$2=$5,$3=IN);\n"
|
||||
" subcircuit TRANS $3 ($1=$5,$2=OUT,$3=$2);\n"
|
||||
" subcircuit TRANS $4 ($1=$4,$2=OUT,$3=$2);\n"
|
||||
"end;\n"
|
||||
"circuit TRANS ($1=$1,$2=$2,$3=$3);\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
// do some probing before purging
|
||||
|
|
@ -492,23 +496,26 @@ TEST(1_BasicExtraction)
|
|||
l2n.netlist ()->purge ();
|
||||
|
||||
// compare netlist as string
|
||||
EXPECT_EQ (l2n.netlist ()->to_string (),
|
||||
"Circuit RINGO (FB=FB,OSC=OSC,VSS=VSS,VDD=VDD):\n"
|
||||
" XINV2 $1 (IN=$I8,$2=FB,OUT=OSC,$4=VSS,$5=VDD)\n"
|
||||
" XINV2 $2 (IN=FB,$2=(null),OUT=$I19,$4=VSS,$5=VDD)\n"
|
||||
" XINV2 $3 (IN=$I19,$2=(null),OUT=$I1,$4=VSS,$5=VDD)\n"
|
||||
" XINV2 $4 (IN=$I1,$2=(null),OUT=$I2,$4=VSS,$5=VDD)\n"
|
||||
" XINV2 $5 (IN=$I2,$2=(null),OUT=$I3,$4=VSS,$5=VDD)\n"
|
||||
" XINV2 $6 (IN=$I3,$2=(null),OUT=$I4,$4=VSS,$5=VDD)\n"
|
||||
" XINV2 $7 (IN=$I4,$2=(null),OUT=$I5,$4=VSS,$5=VDD)\n"
|
||||
" XINV2 $8 (IN=$I5,$2=(null),OUT=$I6,$4=VSS,$5=VDD)\n"
|
||||
" XINV2 $9 (IN=$I6,$2=(null),OUT=$I7,$4=VSS,$5=VDD)\n"
|
||||
" XINV2 $10 (IN=$I7,$2=(null),OUT=$I8,$4=VSS,$5=VDD)\n"
|
||||
"Circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5):\n"
|
||||
" DPMOS $1 (S=$2,G=IN,D=$5) [L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5]\n"
|
||||
" DPMOS $2 (S=$5,G=$2,D=OUT) [L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95]\n"
|
||||
" DNMOS $3 (S=$2,G=IN,D=$4) [L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5]\n"
|
||||
" DNMOS $4 (S=$4,G=$2,D=OUT) [L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95]\n"
|
||||
CHECKPOINT ();
|
||||
db::compare_netlist (_this, *l2n.netlist (),
|
||||
"circuit RINGO (FB=FB,OSC=OSC,VSS=VSS,VDD=VDD);\n"
|
||||
" subcircuit INV2 $1 (IN=$I8,$2=FB,OUT=OSC,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $2 (IN=FB,$2=(null),OUT=$I19,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $3 (IN=$I19,$2=(null),OUT=$I1,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $4 (IN=$I1,$2=(null),OUT=$I2,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $5 (IN=$I2,$2=(null),OUT=$I3,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $6 (IN=$I3,$2=(null),OUT=$I4,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $7 (IN=$I4,$2=(null),OUT=$I5,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $8 (IN=$I5,$2=(null),OUT=$I6,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $9 (IN=$I6,$2=(null),OUT=$I7,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $10 (IN=$I7,$2=(null),OUT=$I8,$4=VSS,$5=VDD);\n"
|
||||
"end;\n"
|
||||
"circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5);\n"
|
||||
" device PMOS $1 (S=$2,G=IN,D=$5) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device PMOS $2 (S=$5,G=$2,D=OUT) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||
" device NMOS $3 (S=$2,G=IN,D=$4) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device NMOS $4 (S=$4,G=$2,D=OUT) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
// do some probing after purging
|
||||
|
|
@ -684,26 +691,31 @@ TEST(2_Probing)
|
|||
dump_recursive_nets_to_layout (l2n, ly, dump_map, cm);
|
||||
|
||||
// compare netlist as string
|
||||
EXPECT_EQ (l2n.netlist ()->to_string (),
|
||||
"Circuit RINGO ():\n"
|
||||
" XINV2PAIR $1 ($1=FB,$2=VDD,$3=VSS,$4=$I3,$5=OSC)\n"
|
||||
" XINV2PAIR $2 ($1=$I18,$2=VDD,$3=VSS,$4=FB,$5=$I9)\n"
|
||||
" XINV2PAIR $3 ($1=$I19,$2=VDD,$3=VSS,$4=$I9,$5=$I1)\n"
|
||||
" XINV2PAIR $4 ($1=$I20,$2=VDD,$3=VSS,$4=$I1,$5=$I2)\n"
|
||||
" XINV2PAIR $5 ($1=$I21,$2=VDD,$3=VSS,$4=$I2,$5=$I3)\n"
|
||||
"Circuit INV2PAIR ($1=$I7,$2=$I5,$3=$I4,$4=$I2,$5=$I1):\n"
|
||||
" XINV2 $1 (IN=$I3,$2=$I7,OUT=$I1,$4=$I4,$5=$I5)\n"
|
||||
" XINV2 $2 (IN=$I2,$2=$I6,OUT=$I3,$4=$I4,$5=$I5)\n"
|
||||
"Circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5):\n"
|
||||
" DPMOS $1 (S=$2,G=IN,D=$5) [L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5]\n"
|
||||
" DPMOS $2 (S=$5,G=$2,D=OUT) [L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95]\n"
|
||||
" DNMOS $3 (S=$2,G=IN,D=$4) [L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5]\n"
|
||||
" DNMOS $4 (S=$4,G=$2,D=OUT) [L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95]\n"
|
||||
" XTRANS $1 ($1=$2,$2=$4,$3=IN)\n"
|
||||
" XTRANS $2 ($1=$2,$2=$5,$3=IN)\n"
|
||||
" XTRANS $3 ($1=$5,$2=OUT,$3=$2)\n"
|
||||
" XTRANS $4 ($1=$4,$2=OUT,$3=$2)\n"
|
||||
"Circuit TRANS ($1=$1,$2=$2,$3=$3):\n"
|
||||
CHECKPOINT ();
|
||||
db::compare_netlist (_this, *l2n.netlist (),
|
||||
"circuit RINGO ();\n"
|
||||
" subcircuit INV2PAIR $1 ($1=FB,$2=VDD,$3=VSS,$4=$I3,$5=OSC);\n"
|
||||
" subcircuit INV2PAIR $2 ($1=$I18,$2=VDD,$3=VSS,$4=FB,$5=$I9);\n"
|
||||
" subcircuit INV2PAIR $3 ($1=$I19,$2=VDD,$3=VSS,$4=$I9,$5=$I1);\n"
|
||||
" subcircuit INV2PAIR $4 ($1=$I20,$2=VDD,$3=VSS,$4=$I1,$5=$I2);\n"
|
||||
" subcircuit INV2PAIR $5 ($1=$I21,$2=VDD,$3=VSS,$4=$I2,$5=$I3);\n"
|
||||
"end;\n"
|
||||
"circuit INV2PAIR ($1=$I7,$2=$I5,$3=$I4,$4=$I2,$5=$I1);\n"
|
||||
" subcircuit INV2 $1 (IN=$I3,$2=$I7,OUT=$I1,$4=$I4,$5=$I5);\n"
|
||||
" subcircuit INV2 $2 (IN=$I2,$2=$I6,OUT=$I3,$4=$I4,$5=$I5);\n"
|
||||
"end;\n"
|
||||
"circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5);\n"
|
||||
" device PMOS $1 (S=$2,G=IN,D=$5) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device PMOS $2 (S=$5,G=$2,D=OUT) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||
" device NMOS $3 (S=$2,G=IN,D=$4) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device NMOS $4 (S=$4,G=$2,D=OUT) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||
" subcircuit TRANS $1 ($1=$2,$2=$4,$3=IN);\n"
|
||||
" subcircuit TRANS $2 ($1=$2,$2=$5,$3=IN);\n"
|
||||
" subcircuit TRANS $3 ($1=$5,$2=OUT,$3=$2);\n"
|
||||
" subcircuit TRANS $4 ($1=$4,$2=OUT,$3=$2);\n"
|
||||
"end;\n"
|
||||
"circuit TRANS ($1=$1,$2=$2,$3=$3);\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
// compare the collected test data
|
||||
|
|
@ -736,21 +748,25 @@ TEST(2_Probing)
|
|||
l2n.netlist ()->purge ();
|
||||
|
||||
// compare netlist as string
|
||||
EXPECT_EQ (l2n.netlist ()->to_string (),
|
||||
"Circuit RINGO (FB=FB,OSC=OSC,VSS=VSS,VDD=VDD):\n"
|
||||
" XINV2PAIR $1 ($1=FB,$2=VDD,$3=VSS,$4=$I3,$5=OSC)\n"
|
||||
" XINV2PAIR $2 ($1=(null),$2=VDD,$3=VSS,$4=FB,$5=$I9)\n"
|
||||
" XINV2PAIR $3 ($1=(null),$2=VDD,$3=VSS,$4=$I9,$5=$I1)\n"
|
||||
" XINV2PAIR $4 ($1=(null),$2=VDD,$3=VSS,$4=$I1,$5=$I2)\n"
|
||||
" XINV2PAIR $5 ($1=(null),$2=VDD,$3=VSS,$4=$I2,$5=$I3)\n"
|
||||
"Circuit INV2PAIR ($1=$I7,$2=$I5,$3=$I4,$4=$I2,$5=$I1):\n"
|
||||
" XINV2 $1 (IN=$I3,$2=$I7,OUT=$I1,$4=$I4,$5=$I5)\n"
|
||||
" XINV2 $2 (IN=$I2,$2=(null),OUT=$I3,$4=$I4,$5=$I5)\n"
|
||||
"Circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5):\n"
|
||||
" DPMOS $1 (S=$2,G=IN,D=$5) [L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5]\n"
|
||||
" DPMOS $2 (S=$5,G=$2,D=OUT) [L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95]\n"
|
||||
" DNMOS $3 (S=$2,G=IN,D=$4) [L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5]\n"
|
||||
" DNMOS $4 (S=$4,G=$2,D=OUT) [L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95]\n"
|
||||
CHECKPOINT ();
|
||||
db::compare_netlist (_this, *l2n.netlist (),
|
||||
"circuit RINGO (FB=FB,OSC=OSC,VSS=VSS,VDD=VDD);\n"
|
||||
" subcircuit INV2PAIR $1 ($1=FB,$2=VDD,$3=VSS,$4=$I3,$5=OSC);\n"
|
||||
" subcircuit INV2PAIR $2 ($1=(null),$2=VDD,$3=VSS,$4=FB,$5=$I9);\n"
|
||||
" subcircuit INV2PAIR $3 ($1=(null),$2=VDD,$3=VSS,$4=$I9,$5=$I1);\n"
|
||||
" subcircuit INV2PAIR $4 ($1=(null),$2=VDD,$3=VSS,$4=$I1,$5=$I2);\n"
|
||||
" subcircuit INV2PAIR $5 ($1=(null),$2=VDD,$3=VSS,$4=$I2,$5=$I3);\n"
|
||||
"end;\n"
|
||||
"circuit INV2PAIR ($1=$I7,$2=$I5,$3=$I4,$4=$I2,$5=$I1);\n"
|
||||
" subcircuit INV2 $1 (IN=$I3,$2=$I7,OUT=$I1,$4=$I4,$5=$I5);\n"
|
||||
" subcircuit INV2 $2 (IN=$I2,$2=(null),OUT=$I3,$4=$I4,$5=$I5);\n"
|
||||
"end;\n"
|
||||
"circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5);\n"
|
||||
" device PMOS $1 (S=$2,G=IN,D=$5) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device PMOS $2 (S=$5,G=$2,D=OUT) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||
" device NMOS $3 (S=$2,G=IN,D=$4) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device NMOS $4 (S=$4,G=$2,D=OUT) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
// do some probing after purging
|
||||
|
|
@ -956,26 +972,31 @@ TEST(3_GlobalNetConnections)
|
|||
dump_recursive_nets_to_layout (l2n, ly, dump_map, cm);
|
||||
|
||||
// compare netlist as string
|
||||
EXPECT_EQ (l2n.netlist ()->to_string (),
|
||||
"Circuit RINGO ():\n"
|
||||
" XINV2PAIR $1 (BULK='BULK,VSS',$2=FB,$3=VDD,$4='BULK,VSS',$5=$I7,$6=OSC,$7=VDD)\n"
|
||||
" XINV2PAIR $2 (BULK='BULK,VSS',$2=$I22,$3=VDD,$4='BULK,VSS',$5=FB,$6=$I13,$7=VDD)\n"
|
||||
" XINV2PAIR $3 (BULK='BULK,VSS',$2=$I23,$3=VDD,$4='BULK,VSS',$5=$I13,$6=$I5,$7=VDD)\n"
|
||||
" XINV2PAIR $4 (BULK='BULK,VSS',$2=$I24,$3=VDD,$4='BULK,VSS',$5=$I5,$6=$I6,$7=VDD)\n"
|
||||
" XINV2PAIR $5 (BULK='BULK,VSS',$2=$I25,$3=VDD,$4='BULK,VSS',$5=$I6,$6=$I7,$7=VDD)\n"
|
||||
"Circuit INV2PAIR (BULK=BULK,$2=$I8,$3=$I6,$4=$I5,$5=$I3,$6=$I2,$7=$I1):\n"
|
||||
" XINV2 $1 ($1=$I1,IN=$I3,$3=$I7,OUT=$I4,VSS=$I5,VDD=$I6,BULK=BULK)\n"
|
||||
" XINV2 $2 ($1=$I1,IN=$I4,$3=$I8,OUT=$I2,VSS=$I5,VDD=$I6,BULK=BULK)\n"
|
||||
"Circuit INV2 ($1=$1,IN=IN,$3=$3,OUT=OUT,VSS=VSS,VDD=VDD,BULK=BULK):\n"
|
||||
" DPMOS $1 (S=$3,G=IN,D=VDD) [L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5]\n"
|
||||
" DPMOS $2 (S=VDD,G=$3,D=OUT) [L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95]\n"
|
||||
" DNMOS $3 (S=$3,G=IN,D=VSS) [L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5]\n"
|
||||
" DNMOS $4 (S=VSS,G=$3,D=OUT) [L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95]\n"
|
||||
" XTRANS $1 ($1=$3,$2=VSS,$3=IN)\n"
|
||||
" XTRANS $2 ($1=$3,$2=VDD,$3=IN)\n"
|
||||
" XTRANS $3 ($1=VDD,$2=OUT,$3=$3)\n"
|
||||
" XTRANS $4 ($1=VSS,$2=OUT,$3=$3)\n"
|
||||
"Circuit TRANS ($1=$1,$2=$2,$3=$3):\n"
|
||||
CHECKPOINT ();
|
||||
db::compare_netlist (_this, *l2n.netlist (),
|
||||
"circuit RINGO ();\n"
|
||||
" subcircuit INV2PAIR $1 (BULK='BULK,VSS',$2=FB,$3=VDD,$4='BULK,VSS',$5=$I7,$6=OSC,$7=VDD);\n"
|
||||
" subcircuit INV2PAIR $2 (BULK='BULK,VSS',$2=$I22,$3=VDD,$4='BULK,VSS',$5=FB,$6=$I13,$7=VDD);\n"
|
||||
" subcircuit INV2PAIR $3 (BULK='BULK,VSS',$2=$I23,$3=VDD,$4='BULK,VSS',$5=$I13,$6=$I5,$7=VDD);\n"
|
||||
" subcircuit INV2PAIR $4 (BULK='BULK,VSS',$2=$I24,$3=VDD,$4='BULK,VSS',$5=$I5,$6=$I6,$7=VDD);\n"
|
||||
" subcircuit INV2PAIR $5 (BULK='BULK,VSS',$2=$I25,$3=VDD,$4='BULK,VSS',$5=$I6,$6=$I7,$7=VDD);\n"
|
||||
"end;\n"
|
||||
"circuit INV2PAIR (BULK=BULK,$2=$I8,$3=$I6,$4=$I5,$5=$I3,$6=$I2,$7=$I1);\n"
|
||||
" subcircuit INV2 $1 ($1=$I1,IN=$I3,$3=$I7,OUT=$I4,VSS=$I5,VDD=$I6,BULK=BULK);\n"
|
||||
" subcircuit INV2 $2 ($1=$I1,IN=$I4,$3=$I8,OUT=$I2,VSS=$I5,VDD=$I6,BULK=BULK);\n"
|
||||
"end;\n"
|
||||
"circuit INV2 ($1=$1,IN=IN,$3=$3,OUT=OUT,VSS=VSS,VDD=VDD,BULK=BULK);\n"
|
||||
" device PMOS $1 (S=$3,G=IN,D=VDD) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device PMOS $2 (S=VDD,G=$3,D=OUT) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||
" device NMOS $3 (S=$3,G=IN,D=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device NMOS $4 (S=VSS,G=$3,D=OUT) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||
" subcircuit TRANS $1 ($1=$3,$2=VSS,$3=IN);\n"
|
||||
" subcircuit TRANS $2 ($1=$3,$2=VDD,$3=IN);\n"
|
||||
" subcircuit TRANS $3 ($1=VDD,$2=OUT,$3=$3);\n"
|
||||
" subcircuit TRANS $4 ($1=VSS,$2=OUT,$3=$3);\n"
|
||||
"end;\n"
|
||||
"circuit TRANS ($1=$1,$2=$2,$3=$3);\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
// compare the collected test data
|
||||
|
|
@ -1008,21 +1029,25 @@ TEST(3_GlobalNetConnections)
|
|||
l2n.netlist ()->purge ();
|
||||
|
||||
// compare netlist as string
|
||||
EXPECT_EQ (l2n.netlist ()->to_string (),
|
||||
"Circuit RINGO (FB=FB,OSC=OSC,VDD=VDD,'BULK,VSS'='BULK,VSS'):\n"
|
||||
" XINV2PAIR $1 (BULK='BULK,VSS',$2=FB,$3=VDD,$4='BULK,VSS',$5=$I7,$6=OSC,$7=VDD)\n"
|
||||
" XINV2PAIR $2 (BULK='BULK,VSS',$2=(null),$3=VDD,$4='BULK,VSS',$5=FB,$6=$I13,$7=VDD)\n"
|
||||
" XINV2PAIR $3 (BULK='BULK,VSS',$2=(null),$3=VDD,$4='BULK,VSS',$5=$I13,$6=$I5,$7=VDD)\n"
|
||||
" XINV2PAIR $4 (BULK='BULK,VSS',$2=(null),$3=VDD,$4='BULK,VSS',$5=$I5,$6=$I6,$7=VDD)\n"
|
||||
" XINV2PAIR $5 (BULK='BULK,VSS',$2=(null),$3=VDD,$4='BULK,VSS',$5=$I6,$6=$I7,$7=VDD)\n"
|
||||
"Circuit INV2PAIR (BULK=BULK,$2=$I8,$3=$I6,$4=$I5,$5=$I3,$6=$I2,$7=$I1):\n"
|
||||
" XINV2 $1 ($1=$I1,IN=$I3,$3=(null),OUT=$I4,VSS=$I5,VDD=$I6,BULK=BULK)\n"
|
||||
" XINV2 $2 ($1=$I1,IN=$I4,$3=$I8,OUT=$I2,VSS=$I5,VDD=$I6,BULK=BULK)\n"
|
||||
"Circuit INV2 ($1=(null),IN=IN,$3=$3,OUT=OUT,VSS=VSS,VDD=VDD,BULK=(null)):\n"
|
||||
" DPMOS $1 (S=$3,G=IN,D=VDD) [L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5]\n"
|
||||
" DPMOS $2 (S=VDD,G=$3,D=OUT) [L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95]\n"
|
||||
" DNMOS $3 (S=$3,G=IN,D=VSS) [L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5]\n"
|
||||
" DNMOS $4 (S=VSS,G=$3,D=OUT) [L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95]\n"
|
||||
CHECKPOINT ();
|
||||
db::compare_netlist (_this, *l2n.netlist (),
|
||||
"circuit RINGO (FB=FB,OSC=OSC,VDD=VDD,'BULK,VSS'='BULK,VSS');\n"
|
||||
" subcircuit INV2PAIR $1 (BULK='BULK,VSS',$2=FB,$3=VDD,$4='BULK,VSS',$5=$I7,$6=OSC,$7=VDD);\n"
|
||||
" subcircuit INV2PAIR $2 (BULK='BULK,VSS',$2=(null),$3=VDD,$4='BULK,VSS',$5=FB,$6=$I13,$7=VDD);\n"
|
||||
" subcircuit INV2PAIR $3 (BULK='BULK,VSS',$2=(null),$3=VDD,$4='BULK,VSS',$5=$I13,$6=$I5,$7=VDD);\n"
|
||||
" subcircuit INV2PAIR $4 (BULK='BULK,VSS',$2=(null),$3=VDD,$4='BULK,VSS',$5=$I5,$6=$I6,$7=VDD);\n"
|
||||
" subcircuit INV2PAIR $5 (BULK='BULK,VSS',$2=(null),$3=VDD,$4='BULK,VSS',$5=$I6,$6=$I7,$7=VDD);\n"
|
||||
"end;\n"
|
||||
"circuit INV2PAIR (BULK=BULK,$2=$I8,$3=$I6,$4=$I5,$5=$I3,$6=$I2,$7=$I1);\n"
|
||||
" subcircuit INV2 $1 ($1=$I1,IN=$I3,$3=(null),OUT=$I4,VSS=$I5,VDD=$I6,BULK=BULK);\n"
|
||||
" subcircuit INV2 $2 ($1=$I1,IN=$I4,$3=$I8,OUT=$I2,VSS=$I5,VDD=$I6,BULK=BULK);\n"
|
||||
"end;\n"
|
||||
"circuit INV2 ($1=(null),IN=IN,$3=$3,OUT=OUT,VSS=VSS,VDD=VDD,BULK=(null));\n"
|
||||
" device PMOS $1 (S=$3,G=IN,D=VDD) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device PMOS $2 (S=VDD,G=$3,D=OUT) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||
" device NMOS $3 (S=$3,G=IN,D=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device NMOS $4 (S=VSS,G=$3,D=OUT) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
// do some probing after purging
|
||||
|
|
@ -1234,26 +1259,31 @@ TEST(4_GlobalNetDeviceExtraction)
|
|||
dump_recursive_nets_to_layout (l2n, ly, dump_map, cm);
|
||||
|
||||
// compare netlist as string
|
||||
EXPECT_EQ (l2n.netlist ()->to_string (),
|
||||
"Circuit RINGO ():\n"
|
||||
" XINV2PAIR $1 (BULK='BULK,VSS',$2=FB,$3=VDD,$4='BULK,VSS',$5=$I7,$6=OSC,$7=VDD)\n"
|
||||
" XINV2PAIR $2 (BULK='BULK,VSS',$2=$I22,$3=VDD,$4='BULK,VSS',$5=FB,$6=$I13,$7=VDD)\n"
|
||||
" XINV2PAIR $3 (BULK='BULK,VSS',$2=$I23,$3=VDD,$4='BULK,VSS',$5=$I13,$6=$I5,$7=VDD)\n"
|
||||
" XINV2PAIR $4 (BULK='BULK,VSS',$2=$I24,$3=VDD,$4='BULK,VSS',$5=$I5,$6=$I6,$7=VDD)\n"
|
||||
" XINV2PAIR $5 (BULK='BULK,VSS',$2=$I25,$3=VDD,$4='BULK,VSS',$5=$I6,$6=$I7,$7=VDD)\n"
|
||||
"Circuit INV2PAIR (BULK=BULK,$2=$I8,$3=$I6,$4=$I5,$5=$I3,$6=$I2,$7=$I1):\n"
|
||||
" XINV2 $1 ($1=$I1,IN=$I3,$3=$I7,OUT=$I4,VSS=$I5,VDD=$I6,BULK=BULK)\n"
|
||||
" XINV2 $2 ($1=$I1,IN=$I4,$3=$I8,OUT=$I2,VSS=$I5,VDD=$I6,BULK=BULK)\n"
|
||||
"Circuit INV2 ($1=$1,IN=IN,$3=$3,OUT=OUT,VSS=VSS,VDD=VDD,BULK=BULK):\n"
|
||||
" DPMOS $1 (S=$3,G=IN,D=VDD,B=$1) [L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5]\n"
|
||||
" DPMOS $2 (S=VDD,G=$3,D=OUT,B=$1) [L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95]\n"
|
||||
" DNMOS $3 (S=$3,G=IN,D=VSS,B=BULK) [L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5]\n"
|
||||
" DNMOS $4 (S=VSS,G=$3,D=OUT,B=BULK) [L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95]\n"
|
||||
" XTRANS $1 ($1=$3,$2=VSS,$3=IN)\n"
|
||||
" XTRANS $2 ($1=$3,$2=VDD,$3=IN)\n"
|
||||
" XTRANS $3 ($1=VDD,$2=OUT,$3=$3)\n"
|
||||
" XTRANS $4 ($1=VSS,$2=OUT,$3=$3)\n"
|
||||
"Circuit TRANS ($1=$1,$2=$2,$3=$3):\n"
|
||||
CHECKPOINT ();
|
||||
db::compare_netlist (_this, *l2n.netlist (),
|
||||
"circuit RINGO ();\n"
|
||||
" subcircuit INV2PAIR $1 (BULK='BULK,VSS',$2=FB,$3=VDD,$4='BULK,VSS',$5=$I7,$6=OSC,$7=VDD);\n"
|
||||
" subcircuit INV2PAIR $2 (BULK='BULK,VSS',$2=$I22,$3=VDD,$4='BULK,VSS',$5=FB,$6=$I13,$7=VDD);\n"
|
||||
" subcircuit INV2PAIR $3 (BULK='BULK,VSS',$2=$I23,$3=VDD,$4='BULK,VSS',$5=$I13,$6=$I5,$7=VDD);\n"
|
||||
" subcircuit INV2PAIR $4 (BULK='BULK,VSS',$2=$I24,$3=VDD,$4='BULK,VSS',$5=$I5,$6=$I6,$7=VDD);\n"
|
||||
" subcircuit INV2PAIR $5 (BULK='BULK,VSS',$2=$I25,$3=VDD,$4='BULK,VSS',$5=$I6,$6=$I7,$7=VDD);\n"
|
||||
"end;\n"
|
||||
"circuit INV2PAIR (BULK=BULK,$2=$I8,$3=$I6,$4=$I5,$5=$I3,$6=$I2,$7=$I1);\n"
|
||||
" subcircuit INV2 $1 ($1=$I1,IN=$I3,$3=$I7,OUT=$I4,VSS=$I5,VDD=$I6,BULK=BULK);\n"
|
||||
" subcircuit INV2 $2 ($1=$I1,IN=$I4,$3=$I8,OUT=$I2,VSS=$I5,VDD=$I6,BULK=BULK);\n"
|
||||
"end;\n"
|
||||
"circuit INV2 ($1=$1,IN=IN,$3=$3,OUT=OUT,VSS=VSS,VDD=VDD,BULK=BULK);\n"
|
||||
" device PMOS $1 (S=$3,G=IN,D=VDD,B=$1) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device PMOS $2 (S=VDD,G=$3,D=OUT,B=$1) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||
" device NMOS $3 (S=$3,G=IN,D=VSS,B=BULK) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device NMOS $4 (S=VSS,G=$3,D=OUT,B=BULK) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||
" subcircuit TRANS $1 ($1=$3,$2=VSS,$3=IN);\n"
|
||||
" subcircuit TRANS $2 ($1=$3,$2=VDD,$3=IN);\n"
|
||||
" subcircuit TRANS $3 ($1=VDD,$2=OUT,$3=$3);\n"
|
||||
" subcircuit TRANS $4 ($1=VSS,$2=OUT,$3=$3);\n"
|
||||
"end;\n"
|
||||
"circuit TRANS ($1=$1,$2=$2,$3=$3);\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
// compare the collected test data
|
||||
|
|
@ -1286,21 +1316,25 @@ TEST(4_GlobalNetDeviceExtraction)
|
|||
l2n.netlist ()->purge ();
|
||||
|
||||
// compare netlist as string
|
||||
EXPECT_EQ (l2n.netlist ()->to_string (),
|
||||
"Circuit RINGO (FB=FB,OSC=OSC,VDD=VDD,'BULK,VSS'='BULK,VSS'):\n"
|
||||
" XINV2PAIR $1 (BULK='BULK,VSS',$2=FB,$3=VDD,$4='BULK,VSS',$5=$I7,$6=OSC,$7=VDD)\n"
|
||||
" XINV2PAIR $2 (BULK='BULK,VSS',$2=(null),$3=VDD,$4='BULK,VSS',$5=FB,$6=$I13,$7=VDD)\n"
|
||||
" XINV2PAIR $3 (BULK='BULK,VSS',$2=(null),$3=VDD,$4='BULK,VSS',$5=$I13,$6=$I5,$7=VDD)\n"
|
||||
" XINV2PAIR $4 (BULK='BULK,VSS',$2=(null),$3=VDD,$4='BULK,VSS',$5=$I5,$6=$I6,$7=VDD)\n"
|
||||
" XINV2PAIR $5 (BULK='BULK,VSS',$2=(null),$3=VDD,$4='BULK,VSS',$5=$I6,$6=$I7,$7=VDD)\n"
|
||||
"Circuit INV2PAIR (BULK=BULK,$2=$I8,$3=$I6,$4=$I5,$5=$I3,$6=$I2,$7=$I1):\n"
|
||||
" XINV2 $1 ($1=$I1,IN=$I3,$3=(null),OUT=$I4,VSS=$I5,VDD=$I6,BULK=BULK)\n"
|
||||
" XINV2 $2 ($1=$I1,IN=$I4,$3=$I8,OUT=$I2,VSS=$I5,VDD=$I6,BULK=BULK)\n"
|
||||
"Circuit INV2 ($1=$1,IN=IN,$3=$3,OUT=OUT,VSS=VSS,VDD=VDD,BULK=BULK):\n"
|
||||
" DPMOS $1 (S=$3,G=IN,D=VDD,B=$1) [L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5]\n"
|
||||
" DPMOS $2 (S=VDD,G=$3,D=OUT,B=$1) [L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95]\n"
|
||||
" DNMOS $3 (S=$3,G=IN,D=VSS,B=BULK) [L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5]\n"
|
||||
" DNMOS $4 (S=VSS,G=$3,D=OUT,B=BULK) [L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95]\n"
|
||||
CHECKPOINT ();
|
||||
db::compare_netlist (_this, *l2n.netlist (),
|
||||
"circuit RINGO (FB=FB,OSC=OSC,VDD=VDD,'BULK,VSS'='BULK,VSS');\n"
|
||||
" subcircuit INV2PAIR $1 (BULK='BULK,VSS',$2=FB,$3=VDD,$4='BULK,VSS',$5=$I7,$6=OSC,$7=VDD);\n"
|
||||
" subcircuit INV2PAIR $2 (BULK='BULK,VSS',$2=(null),$3=VDD,$4='BULK,VSS',$5=FB,$6=$I13,$7=VDD);\n"
|
||||
" subcircuit INV2PAIR $3 (BULK='BULK,VSS',$2=(null),$3=VDD,$4='BULK,VSS',$5=$I13,$6=$I5,$7=VDD);\n"
|
||||
" subcircuit INV2PAIR $4 (BULK='BULK,VSS',$2=(null),$3=VDD,$4='BULK,VSS',$5=$I5,$6=$I6,$7=VDD);\n"
|
||||
" subcircuit INV2PAIR $5 (BULK='BULK,VSS',$2=(null),$3=VDD,$4='BULK,VSS',$5=$I6,$6=$I7,$7=VDD);\n"
|
||||
"end;\n"
|
||||
"circuit INV2PAIR (BULK=BULK,$2=$I8,$3=$I6,$4=$I5,$5=$I3,$6=$I2,$7=$I1);\n"
|
||||
" subcircuit INV2 $1 ($1=$I1,IN=$I3,$3=(null),OUT=$I4,VSS=$I5,VDD=$I6,BULK=BULK);\n"
|
||||
" subcircuit INV2 $2 ($1=$I1,IN=$I4,$3=$I8,OUT=$I2,VSS=$I5,VDD=$I6,BULK=BULK);\n"
|
||||
"end;\n"
|
||||
"circuit INV2 ($1=$1,IN=IN,$3=$3,OUT=OUT,VSS=VSS,VDD=VDD,BULK=BULK);\n"
|
||||
" device PMOS $1 (S=$3,G=IN,D=VDD,B=$1) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device PMOS $2 (S=VDD,G=$3,D=OUT,B=$1) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||
" device NMOS $3 (S=$3,G=IN,D=VSS,B=BULK) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device NMOS $4 (S=VSS,G=$3,D=OUT,B=BULK) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
// do some probing after purging
|
||||
|
|
@ -1512,26 +1546,31 @@ TEST(5_DeviceExtractionWithDeviceCombination)
|
|||
dump_recursive_nets_to_layout (l2n, ly, dump_map, cm);
|
||||
|
||||
// compare netlist as string
|
||||
EXPECT_EQ (l2n.netlist ()->to_string (),
|
||||
"Circuit RINGO ():\n"
|
||||
" XINV2PAIR $1 (BULK='BULK,VSS',$2=VDD,$3='BULK,VSS',$4=FB,$5=$I7,$6=OSC,$7=VDD)\n"
|
||||
" XINV2PAIR $2 (BULK='BULK,VSS',$2=VDD,$3='BULK,VSS',$4=$I22,$5=FB,$6=$I13,$7=VDD)\n"
|
||||
" XINV2PAIR $3 (BULK='BULK,VSS',$2=VDD,$3='BULK,VSS',$4=$I23,$5=$I13,$6=$I5,$7=VDD)\n"
|
||||
" XINV2PAIR $4 (BULK='BULK,VSS',$2=VDD,$3='BULK,VSS',$4=$I24,$5=$I5,$6=$I6,$7=VDD)\n"
|
||||
" XINV2PAIR $5 (BULK='BULK,VSS',$2=VDD,$3='BULK,VSS',$4=$I25,$5=$I6,$6=$I7,$7=VDD)\n"
|
||||
"Circuit INV2PAIR (BULK=BULK,$2=$I6,$3=$I5,$4=$I4,$5=$I3,$6=$I2,$7=$I1):\n"
|
||||
" XINV2 $1 ($1=$I1,IN=$I3,OUT=$I4,VSS=$I5,VDD=$I6,BULK=BULK)\n"
|
||||
" XINV2 $2 ($1=$I1,IN=$I4,OUT=$I2,VSS=$I5,VDD=$I6,BULK=BULK)\n"
|
||||
"Circuit INV2 ($1=$1,IN=IN,OUT=OUT,VSS=VSS,VDD=VDD,BULK=BULK):\n"
|
||||
" DPMOS $1 (S=OUT,G=IN,D=VDD,B=$1) [L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3]\n"
|
||||
" DPMOS $2 (S=VDD,G=IN,D=OUT,B=$1) [L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55]\n"
|
||||
" DNMOS $3 (S=OUT,G=IN,D=VSS,B=BULK) [L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3]\n"
|
||||
" DNMOS $4 (S=VSS,G=IN,D=OUT,B=BULK) [L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55]\n"
|
||||
" XTRANS $1 ($1=OUT,$2=VSS,$3=IN)\n"
|
||||
" XTRANS $2 ($1=OUT,$2=VDD,$3=IN)\n"
|
||||
" XTRANS $3 ($1=OUT,$2=VSS,$3=IN)\n"
|
||||
" XTRANS $4 ($1=OUT,$2=VDD,$3=IN)\n"
|
||||
"Circuit TRANS ($1=$1,$2=$2,$3=$3):\n"
|
||||
CHECKPOINT ();
|
||||
db::compare_netlist (_this, *l2n.netlist (),
|
||||
"circuit RINGO ();\n"
|
||||
" subcircuit INV2PAIR $1 (BULK='BULK,VSS',$2=VDD,$3='BULK,VSS',$4=FB,$5=$I7,$6=OSC,$7=VDD);\n"
|
||||
" subcircuit INV2PAIR $2 (BULK='BULK,VSS',$2=VDD,$3='BULK,VSS',$4=$I22,$5=FB,$6=$I13,$7=VDD);\n"
|
||||
" subcircuit INV2PAIR $3 (BULK='BULK,VSS',$2=VDD,$3='BULK,VSS',$4=$I23,$5=$I13,$6=$I5,$7=VDD);\n"
|
||||
" subcircuit INV2PAIR $4 (BULK='BULK,VSS',$2=VDD,$3='BULK,VSS',$4=$I24,$5=$I5,$6=$I6,$7=VDD);\n"
|
||||
" subcircuit INV2PAIR $5 (BULK='BULK,VSS',$2=VDD,$3='BULK,VSS',$4=$I25,$5=$I6,$6=$I7,$7=VDD);\n"
|
||||
"end;\n"
|
||||
"circuit INV2PAIR (BULK=BULK,$2=$I6,$3=$I5,$4=$I4,$5=$I3,$6=$I2,$7=$I1);\n"
|
||||
" subcircuit INV2 $1 ($1=$I1,IN=$I3,OUT=$I4,VSS=$I5,VDD=$I6,BULK=BULK);\n"
|
||||
" subcircuit INV2 $2 ($1=$I1,IN=$I4,OUT=$I2,VSS=$I5,VDD=$I6,BULK=BULK);\n"
|
||||
"end;\n"
|
||||
"circuit INV2 ($1=$1,IN=IN,OUT=OUT,VSS=VSS,VDD=VDD,BULK=BULK);\n"
|
||||
" device PMOS $1 (S=OUT,G=IN,D=VDD,B=$1) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n"
|
||||
" device PMOS $2 (S=VDD,G=IN,D=OUT,B=$1) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n"
|
||||
" device NMOS $3 (S=OUT,G=IN,D=VSS,B=BULK) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n"
|
||||
" device NMOS $4 (S=VSS,G=IN,D=OUT,B=BULK) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n"
|
||||
" subcircuit TRANS $1 ($1=OUT,$2=VSS,$3=IN);\n"
|
||||
" subcircuit TRANS $2 ($1=OUT,$2=VDD,$3=IN);\n"
|
||||
" subcircuit TRANS $3 ($1=OUT,$2=VSS,$3=IN);\n"
|
||||
" subcircuit TRANS $4 ($1=OUT,$2=VDD,$3=IN);\n"
|
||||
"end;\n"
|
||||
"circuit TRANS ($1=$1,$2=$2,$3=$3);\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
// compare the collected test data
|
||||
|
|
@ -1561,19 +1600,23 @@ TEST(5_DeviceExtractionWithDeviceCombination)
|
|||
l2n.netlist ()->purge ();
|
||||
|
||||
// compare netlist as string
|
||||
EXPECT_EQ (l2n.netlist ()->to_string (),
|
||||
"Circuit RINGO (FB=FB,OSC=OSC,VDD=VDD,'BULK,VSS'='BULK,VSS'):\n"
|
||||
" XINV2PAIR $1 (BULK='BULK,VSS',$2=VDD,$3='BULK,VSS',$4=FB,$5=$I7,$6=OSC,$7=VDD)\n"
|
||||
" XINV2PAIR $2 (BULK='BULK,VSS',$2=VDD,$3='BULK,VSS',$4=(null),$5=FB,$6=$I13,$7=VDD)\n"
|
||||
" XINV2PAIR $3 (BULK='BULK,VSS',$2=VDD,$3='BULK,VSS',$4=(null),$5=$I13,$6=$I5,$7=VDD)\n"
|
||||
" XINV2PAIR $4 (BULK='BULK,VSS',$2=VDD,$3='BULK,VSS',$4=(null),$5=$I5,$6=$I6,$7=VDD)\n"
|
||||
" XINV2PAIR $5 (BULK='BULK,VSS',$2=VDD,$3='BULK,VSS',$4=(null),$5=$I6,$6=$I7,$7=VDD)\n"
|
||||
"Circuit INV2PAIR (BULK=BULK,$2=$I6,$3=$I5,$4=$I4,$5=$I3,$6=$I2,$7=$I1):\n"
|
||||
" XINV2 $1 ($1=$I1,IN=$I3,OUT=$I4,VSS=$I5,VDD=$I6,BULK=BULK)\n"
|
||||
" XINV2 $2 ($1=$I1,IN=$I4,OUT=$I2,VSS=$I5,VDD=$I6,BULK=BULK)\n"
|
||||
"Circuit INV2 ($1=$1,IN=IN,OUT=OUT,VSS=VSS,VDD=VDD,BULK=BULK):\n"
|
||||
" DPMOS $1 (S=OUT,G=IN,D=VDD,B=$1) [L=0.25,W=3.5,AS=1.4,AD=1.4,PS=6.85,PD=6.85]\n"
|
||||
" DNMOS $3 (S=OUT,G=IN,D=VSS,B=BULK) [L=0.25,W=3.5,AS=1.4,AD=1.4,PS=6.85,PD=6.85]\n"
|
||||
CHECKPOINT ();
|
||||
db::compare_netlist (_this, *l2n.netlist (),
|
||||
"circuit RINGO (FB=FB,OSC=OSC,VDD=VDD,'BULK,VSS'='BULK,VSS');\n"
|
||||
" subcircuit INV2PAIR $1 (BULK='BULK,VSS',$2=VDD,$3='BULK,VSS',$4=FB,$5=$I7,$6=OSC,$7=VDD);\n"
|
||||
" subcircuit INV2PAIR $2 (BULK='BULK,VSS',$2=VDD,$3='BULK,VSS',$4=(null),$5=FB,$6=$I13,$7=VDD);\n"
|
||||
" subcircuit INV2PAIR $3 (BULK='BULK,VSS',$2=VDD,$3='BULK,VSS',$4=(null),$5=$I13,$6=$I5,$7=VDD);\n"
|
||||
" subcircuit INV2PAIR $4 (BULK='BULK,VSS',$2=VDD,$3='BULK,VSS',$4=(null),$5=$I5,$6=$I6,$7=VDD);\n"
|
||||
" subcircuit INV2PAIR $5 (BULK='BULK,VSS',$2=VDD,$3='BULK,VSS',$4=(null),$5=$I6,$6=$I7,$7=VDD);\n"
|
||||
"end;\n"
|
||||
"circuit INV2PAIR (BULK=BULK,$2=$I6,$3=$I5,$4=$I4,$5=$I3,$6=$I2,$7=$I1);\n"
|
||||
" subcircuit INV2 $1 ($1=$I1,IN=$I3,OUT=$I4,VSS=$I5,VDD=$I6,BULK=BULK);\n"
|
||||
" subcircuit INV2 $2 ($1=$I1,IN=$I4,OUT=$I2,VSS=$I5,VDD=$I6,BULK=BULK);\n"
|
||||
"end;\n"
|
||||
"circuit INV2 ($1=$1,IN=IN,OUT=OUT,VSS=VSS,VDD=VDD,BULK=BULK);\n"
|
||||
" device PMOS $1 (S=OUT,G=IN,D=VDD,B=$1) (L=0.25,W=3.5,AS=1.4,AD=1.4,PS=6.85,PD=6.85);\n"
|
||||
" device NMOS $3 (S=OUT,G=IN,D=VSS,B=BULK) (L=0.25,W=3.5,AS=1.4,AD=1.4,PS=6.85,PD=6.85);\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
// do some probing after purging
|
||||
|
|
@ -1732,14 +1775,16 @@ TEST(6_MoreDeviceTypes)
|
|||
l2n.extract_netlist ();
|
||||
|
||||
// compare netlist as string
|
||||
EXPECT_EQ (l2n.netlist ()->to_string (),
|
||||
"Circuit TOP ():\n"
|
||||
" DHVPMOS $1 (S=Z,G=$5,D=VDD2,B=$8) [L=1.5,W=4.05,AS=5.4675,AD=2.73375,PS=10.8,PD=5.4]\n"
|
||||
" DHVPMOS $2 (S=VDD2,G=Z,D=$5,B=$8) [L=1.5,W=4.05,AS=2.73375,AD=5.4675,PS=5.4,PD=10.8]\n"
|
||||
" DLVPMOS $3 (S=$10,G=A,D=$6,B=$9) [L=1.5,W=2.475,AS=1.11375,AD=3.155625,PS=5.85,PD=7.5]\n"
|
||||
" DHVNMOS $4 (S=Z,G=$6,D=VSS,B=BULK) [L=1.5,W=5.25,AS=7.0875,AD=3.54375,PS=13.2,PD=6.6]\n"
|
||||
" DHVNMOS $5 (S=VSS,G=A,D=$5,B=BULK) [L=1.5,W=5.25,AS=3.54375,AD=7.0875,PS=6.6,PD=13.2]\n"
|
||||
" DLVNMOS $6 (S=VSS,G=A,D=$6,B=BULK) [L=1.2,W=1.7,AS=2.346,AD=2.1165,PS=6.16,PD=5.89]\n"
|
||||
CHECKPOINT ();
|
||||
db::compare_netlist (_this, *l2n.netlist (),
|
||||
"circuit TOP ();\n"
|
||||
" device HVPMOS $1 (S=Z,G=$5,D=VDD2,B=$8) (L=1.5,W=4.05,AS=5.4675,AD=2.73375,PS=10.8,PD=5.4);\n"
|
||||
" device HVPMOS $2 (S=VDD2,G=Z,D=$5,B=$8) (L=1.5,W=4.05,AS=2.73375,AD=5.4675,PS=5.4,PD=10.8);\n"
|
||||
" device LVPMOS $3 (S=$10,G=A,D=$6,B=$9) (L=1.5,W=2.475,AS=4.77675,AD=3.155625,PS=8.81,PD=7.5);\n"
|
||||
" device HVNMOS $4 (S=Z,G=$6,D=VSS,B=BULK) (L=1.5,W=5.25,AS=7.0875,AD=3.54375,PS=13.2,PD=6.6);\n"
|
||||
" device HVNMOS $5 (S=VSS,G=A,D=$5,B=BULK) (L=1.5,W=5.25,AS=3.54375,AD=7.0875,PS=6.6,PD=13.2);\n"
|
||||
" device LVNMOS $6 (S=VSS,G=A,D=$6,B=BULK) (L=1.2,W=1.7,AS=2.346,AD=2.1165,PS=6.16,PD=5.89);\n"
|
||||
"end;\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -1887,14 +1932,16 @@ TEST(7_MoreByEmptyDeviceTypes)
|
|||
l2n.extract_netlist ();
|
||||
|
||||
// compare netlist as string
|
||||
EXPECT_EQ (l2n.netlist ()->to_string (),
|
||||
"Circuit TOP ():\n"
|
||||
" DLVPMOS $1 (S=Z,G=$5,D=VDD2,B=$8) [L=1.5,W=4.05,AS=5.4675,AD=2.73375,PS=10.8,PD=5.4]\n"
|
||||
" DLVPMOS $2 (S=VDD2,G=Z,D=$5,B=$8) [L=1.5,W=4.05,AS=2.73375,AD=5.4675,PS=5.4,PD=10.8]\n"
|
||||
" DLVPMOS $3 (S=$10,G=A,D=$6,B=$9) [L=1.5,W=2.475,AS=1.11375,AD=3.155625,PS=5.85,PD=7.5]\n"
|
||||
" DLVNMOS $4 (S=VSS,G=A,D=$6,B=BULK) [L=1.2,W=1.7,AS=2.346,AD=2.1165,PS=6.16,PD=5.89]\n"
|
||||
" DLVNMOS $5 (S=Z,G=$6,D=VSS,B=BULK) [L=1.5,W=5.25,AS=7.0875,AD=3.54375,PS=13.2,PD=6.6]\n"
|
||||
" DLVNMOS $6 (S=VSS,G=A,D=$5,B=BULK) [L=1.5,W=5.25,AS=3.54375,AD=7.0875,PS=6.6,PD=13.2]\n"
|
||||
CHECKPOINT ();
|
||||
db::compare_netlist (_this, *l2n.netlist (),
|
||||
"circuit TOP ();\n"
|
||||
" device LVPMOS $1 (S=Z,G=$5,D=VDD2,B=$8) (L=1.5,W=4.05,AS=5.4675,AD=2.73375,PS=10.8,PD=5.4);\n"
|
||||
" device LVPMOS $2 (S=VDD2,G=Z,D=$5,B=$8) (L=1.5,W=4.05,AS=2.73375,AD=5.4675,PS=5.4,PD=10.8);\n"
|
||||
" device LVPMOS $3 (S=$10,G=A,D=$6,B=$9) (L=1.5,W=2.475,AS=4.77675,AD=3.155625,PS=8.81,PD=7.5);\n"
|
||||
" device LVNMOS $4 (S=VSS,G=A,D=$6,B=BULK) (L=1.2,W=1.7,AS=2.346,AD=2.1165,PS=6.16,PD=5.89);\n"
|
||||
" device LVNMOS $5 (S=Z,G=$6,D=VSS,B=BULK) (L=1.5,W=5.25,AS=7.0875,AD=3.54375,PS=13.2,PD=6.6);\n"
|
||||
" device LVNMOS $6 (S=VSS,G=A,D=$5,B=BULK) (L=1.5,W=5.25,AS=3.54375,AD=7.0875,PS=6.6,PD=13.2);\n"
|
||||
"end;\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -2064,14 +2111,16 @@ TEST(8_FlatExtraction)
|
|||
l2n.extract_netlist ();
|
||||
|
||||
// compare netlist as string
|
||||
EXPECT_EQ (l2n.netlist ()->to_string (),
|
||||
"Circuit TOP ():\n"
|
||||
" DHVPMOS $1 (S=Z,G=$5,D=VDD2,B=$8) [L=1.5,W=4.05,AS=5.4675,AD=2.73375,PS=10.8,PD=5.4]\n"
|
||||
" DHVPMOS $2 (S=VDD2,G=Z,D=$5,B=$8) [L=1.5,W=4.05,AS=2.73375,AD=5.4675,PS=5.4,PD=10.8]\n"
|
||||
" DLVPMOS $3 (S=$10,G=A,D=$6,B=$9) [L=1.5,W=2.475,AS=1.11375,AD=3.155625,PS=5.85,PD=7.5]\n"
|
||||
" DHVNMOS $4 (S=Z,G=$6,D=VSS,B=BULK) [L=1.5,W=5.25,AS=7.0875,AD=3.54375,PS=13.2,PD=6.6]\n"
|
||||
" DHVNMOS $5 (S=VSS,G=A,D=$5,B=BULK) [L=1.5,W=5.25,AS=3.54375,AD=7.0875,PS=6.6,PD=13.2]\n"
|
||||
" DLVNMOS $6 (S=VSS,G=A,D=$6,B=BULK) [L=1.2,W=1.7,AS=2.346,AD=2.1165,PS=6.16,PD=5.89]\n"
|
||||
CHECKPOINT ();
|
||||
db::compare_netlist (_this, *l2n.netlist (),
|
||||
"circuit TOP ();\n"
|
||||
" device HVPMOS $1 (S=Z,G=$5,D=VDD2,B=$8) (L=1.5,W=4.05,AS=5.4675,AD=2.73375,PS=10.8,PD=5.4);\n"
|
||||
" device HVPMOS $2 (S=VDD2,G=Z,D=$5,B=$8) (L=1.5,W=4.05,AS=2.73375,AD=5.4675,PS=5.4,PD=10.8);\n"
|
||||
" device LVPMOS $3 (S=$10,G=A,D=$6,B=$9) (L=1.5,W=2.475,AS=4.77675,AD=3.155625,PS=8.81,PD=7.5);\n"
|
||||
" device HVNMOS $4 (S=Z,G=$6,D=VSS,B=BULK) (L=1.5,W=5.25,AS=7.0875,AD=3.54375,PS=13.2,PD=6.6);\n"
|
||||
" device HVNMOS $5 (S=VSS,G=A,D=$5,B=BULK) (L=1.5,W=5.25,AS=3.54375,AD=7.0875,PS=6.6,PD=13.2);\n"
|
||||
" device LVNMOS $6 (S=VSS,G=A,D=$6,B=BULK) (L=1.2,W=1.7,AS=2.346,AD=2.1165,PS=6.16,PD=5.89);\n"
|
||||
"end;\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -2246,14 +2295,16 @@ TEST(9_FlatExtractionWithExternalDSS)
|
|||
l2n.extract_netlist ();
|
||||
|
||||
// compare netlist as string
|
||||
EXPECT_EQ (l2n.netlist ()->to_string (),
|
||||
"Circuit TOP ():\n"
|
||||
" DLVPMOS $1 (S=Z,G=$5,D=VDD2,B=$8) [L=1.5,W=4.05,AS=5.4675,AD=2.73375,PS=10.8,PD=5.4]\n"
|
||||
" DLVPMOS $2 (S=VDD2,G=Z,D=$5,B=$8) [L=1.5,W=4.05,AS=2.73375,AD=5.4675,PS=5.4,PD=10.8]\n"
|
||||
" DLVPMOS $3 (S=$10,G=A,D=$6,B=$9) [L=1.5,W=2.475,AS=1.11375,AD=3.155625,PS=5.85,PD=7.5]\n"
|
||||
" DLVNMOS $4 (S=VSS,G=A,D=$6,B=BULK) [L=1.2,W=1.7,AS=2.346,AD=2.1165,PS=6.16,PD=5.89]\n"
|
||||
" DLVNMOS $5 (S=Z,G=$6,D=VSS,B=BULK) [L=1.5,W=5.25,AS=7.0875,AD=3.54375,PS=13.2,PD=6.6]\n"
|
||||
" DLVNMOS $6 (S=VSS,G=A,D=$5,B=BULK) [L=1.5,W=5.25,AS=3.54375,AD=7.0875,PS=6.6,PD=13.2]\n"
|
||||
CHECKPOINT ();
|
||||
db::compare_netlist (_this, *l2n.netlist (),
|
||||
"circuit TOP ();\n"
|
||||
" device LVPMOS $1 (S=Z,G=$5,D=VDD2,B=$8) (L=1.5,W=4.05,AS=5.4675,AD=2.73375,PS=10.8,PD=5.4);\n"
|
||||
" device LVPMOS $2 (S=VDD2,G=Z,D=$5,B=$8) (L=1.5,W=4.05,AS=2.73375,AD=5.4675,PS=5.4,PD=10.8);\n"
|
||||
" device LVPMOS $3 (S=$10,G=A,D=$6,B=$9) (L=1.5,W=2.475,AS=4.77675,AD=3.155625,PS=8.81,PD=7.5);\n"
|
||||
" device LVNMOS $4 (S=VSS,G=A,D=$6,B=BULK) (L=1.2,W=1.7,AS=2.346,AD=2.1165,PS=6.16,PD=5.89);\n"
|
||||
" device LVNMOS $5 (S=Z,G=$6,D=VSS,B=BULK) (L=1.5,W=5.25,AS=7.0875,AD=3.54375,PS=13.2,PD=6.6);\n"
|
||||
" device LVNMOS $6 (S=VSS,G=A,D=$5,B=BULK) (L=1.5,W=5.25,AS=3.54375,AD=7.0875,PS=6.6,PD=13.2);\n"
|
||||
"end;\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -65,17 +65,19 @@ TEST(1_SerialResistors)
|
|||
circuit->connect_pin (pin_b.id (), n3);
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit (A=n1,B=n3):\n"
|
||||
" D r1 (A=n1,B=n2) [R=1]\n"
|
||||
" D r2 (A=n2,B=n3) [R=3]\n"
|
||||
"circuit '' (A=n1,B=n3);\n"
|
||||
" device '' r1 (A=n1,B=n2) (R=1);\n"
|
||||
" device '' r2 (A=n2,B=n3) (R=3);\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
nl.combine_devices ();
|
||||
nl.purge ();
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit (A=n1,B=n3):\n"
|
||||
" D r1 (A=n1,B=n3) [R=4]\n"
|
||||
"circuit '' (A=n1,B=n3);\n"
|
||||
" device '' r1 (A=n1,B=n3) (R=4);\n"
|
||||
"end;\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -116,17 +118,19 @@ TEST(2_SerialResistors1Swapped)
|
|||
circuit->connect_pin (pin_b.id (), n3);
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit (A=n1,B=n3):\n"
|
||||
" D r1 (A=n1,B=n2) [R=1]\n"
|
||||
" D r2 (A=n3,B=n2) [R=3]\n"
|
||||
"circuit '' (A=n1,B=n3);\n"
|
||||
" device '' r1 (A=n1,B=n2) (R=1);\n"
|
||||
" device '' r2 (A=n3,B=n2) (R=3);\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
nl.combine_devices ();
|
||||
nl.purge ();
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit (A=n1,B=n3):\n"
|
||||
" D r1 (A=n1,B=n3) [R=4]\n"
|
||||
"circuit '' (A=n1,B=n3);\n"
|
||||
" device '' r1 (A=n1,B=n3) (R=4);\n"
|
||||
"end;\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -167,17 +171,19 @@ TEST(3_SerialResistors1OtherSwapped)
|
|||
circuit->connect_pin (pin_b.id (), n3);
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit (A=n1,B=n3):\n"
|
||||
" D r1 (A=n2,B=n1) [R=1]\n"
|
||||
" D r2 (A=n2,B=n3) [R=3]\n"
|
||||
"circuit '' (A=n1,B=n3);\n"
|
||||
" device '' r1 (A=n2,B=n1) (R=1);\n"
|
||||
" device '' r2 (A=n2,B=n3) (R=3);\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
nl.combine_devices ();
|
||||
nl.purge ();
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit (A=n1,B=n3):\n"
|
||||
" D r1 (A=n3,B=n1) [R=4]\n"
|
||||
"circuit '' (A=n1,B=n3);\n"
|
||||
" device '' r1 (A=n3,B=n1) (R=4);\n"
|
||||
"end;\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -218,17 +224,19 @@ TEST(4_SerialResistors2Swapped)
|
|||
circuit->connect_pin (pin_b.id (), n3);
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit (A=n1,B=n3):\n"
|
||||
" D r1 (A=n2,B=n1) [R=1]\n"
|
||||
" D r2 (A=n3,B=n2) [R=3]\n"
|
||||
"circuit '' (A=n1,B=n3);\n"
|
||||
" device '' r1 (A=n2,B=n1) (R=1);\n"
|
||||
" device '' r2 (A=n3,B=n2) (R=3);\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
nl.combine_devices ();
|
||||
nl.purge ();
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit (A=n1,B=n3):\n"
|
||||
" D r1 (A=n3,B=n1) [R=4]\n"
|
||||
"circuit '' (A=n1,B=n3);\n"
|
||||
" device '' r1 (A=n3,B=n1) (R=4);\n"
|
||||
"end;\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -271,18 +279,20 @@ TEST(5_SerialResistorsNoCombination)
|
|||
circuit->connect_pin (pin_b.id (), n3);
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit (A=n1,B=n3,C=n2):\n"
|
||||
" D r1 (A=n1,B=n2) [R=1]\n"
|
||||
" D r2 (A=n2,B=n3) [R=3]\n"
|
||||
"circuit '' (A=n1,B=n3,C=n2);\n"
|
||||
" device '' r1 (A=n1,B=n2) (R=1);\n"
|
||||
" device '' r2 (A=n2,B=n3) (R=3);\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
nl.combine_devices ();
|
||||
nl.purge ();
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit (A=n1,B=n3,C=n2):\n"
|
||||
" D r1 (A=n1,B=n2) [R=1]\n"
|
||||
" D r2 (A=n2,B=n3) [R=3]\n"
|
||||
"circuit '' (A=n1,B=n3,C=n2);\n"
|
||||
" device '' r1 (A=n1,B=n2) (R=1);\n"
|
||||
" device '' r2 (A=n2,B=n3) (R=3);\n"
|
||||
"end;\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -320,17 +330,19 @@ TEST(6_ParallelResistors)
|
|||
r2->connect_terminal (db::DeviceClassResistor::terminal_id_B, n2);
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit (A=n1,B=n2):\n"
|
||||
" D r1 (A=n1,B=n2) [R=2]\n"
|
||||
" D r2 (A=n1,B=n2) [R=3]\n"
|
||||
"circuit '' (A=n1,B=n2);\n"
|
||||
" device '' r1 (A=n1,B=n2) (R=2);\n"
|
||||
" device '' r2 (A=n1,B=n2) (R=3);\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
nl.combine_devices ();
|
||||
nl.purge ();
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit (A=n1,B=n2):\n"
|
||||
" D r1 (A=n1,B=n2) [R=1.2]\n"
|
||||
"circuit '' (A=n1,B=n2);\n"
|
||||
" device '' r1 (A=n1,B=n2) (R=1.2);\n"
|
||||
"end;\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -368,17 +380,19 @@ TEST(7_ParallelResistors1Swapped)
|
|||
r2->connect_terminal (db::DeviceClassResistor::terminal_id_B, n2);
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit (A=n1,B=n2):\n"
|
||||
" D r1 (A=n2,B=n1) [R=2]\n"
|
||||
" D r2 (A=n1,B=n2) [R=3]\n"
|
||||
"circuit '' (A=n1,B=n2);\n"
|
||||
" device '' r1 (A=n2,B=n1) (R=2);\n"
|
||||
" device '' r2 (A=n1,B=n2) (R=3);\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
nl.combine_devices ();
|
||||
nl.purge ();
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit (A=n1,B=n2):\n"
|
||||
" D r1 (A=n2,B=n1) [R=1.2]\n"
|
||||
"circuit '' (A=n1,B=n2);\n"
|
||||
" device '' r1 (A=n2,B=n1) (R=1.2);\n"
|
||||
"end;\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -416,17 +430,19 @@ TEST(8_ParallelResistors1OtherSwapped)
|
|||
r2->connect_terminal (db::DeviceClassResistor::terminal_id_A, n2);
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit (A=n1,B=n2):\n"
|
||||
" D r1 (A=n1,B=n2) [R=2]\n"
|
||||
" D r2 (A=n2,B=n1) [R=3]\n"
|
||||
"circuit '' (A=n1,B=n2);\n"
|
||||
" device '' r1 (A=n1,B=n2) (R=2);\n"
|
||||
" device '' r2 (A=n2,B=n1) (R=3);\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
nl.combine_devices ();
|
||||
nl.purge ();
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit (A=n1,B=n2):\n"
|
||||
" D r1 (A=n1,B=n2) [R=1.2]\n"
|
||||
"circuit '' (A=n1,B=n2);\n"
|
||||
" device '' r1 (A=n1,B=n2) (R=1.2);\n"
|
||||
"end;\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -464,17 +480,19 @@ TEST(9_ParallelResistors2Swapped)
|
|||
r2->connect_terminal (db::DeviceClassResistor::terminal_id_A, n2);
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit (A=n1,B=n2):\n"
|
||||
" D r1 (A=n2,B=n1) [R=2]\n"
|
||||
" D r2 (A=n2,B=n1) [R=3]\n"
|
||||
"circuit '' (A=n1,B=n2);\n"
|
||||
" device '' r1 (A=n2,B=n1) (R=2);\n"
|
||||
" device '' r2 (A=n2,B=n1) (R=3);\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
nl.combine_devices ();
|
||||
nl.purge ();
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit (A=n1,B=n2):\n"
|
||||
" D r1 (A=n2,B=n1) [R=1.2]\n"
|
||||
"circuit '' (A=n1,B=n2);\n"
|
||||
" device '' r1 (A=n2,B=n1) (R=1.2);\n"
|
||||
"end;\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -537,19 +555,21 @@ TEST(10_ComplexRegistorCombination)
|
|||
r4->connect_terminal (db::DeviceClassResistor::terminal_id_B, n4);
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit (A=n1,B=n4):\n"
|
||||
" D r1 (A=n1,B=n2) [R=1]\n"
|
||||
" D r2 (A=n2,B=n3) [R=1]\n"
|
||||
" D r3 (A=n1,B=n3) [R=3]\n"
|
||||
" D r4 (A=n3,B=n4) [R=0.8]\n"
|
||||
"circuit '' (A=n1,B=n4);\n"
|
||||
" device '' r1 (A=n1,B=n2) (R=1);\n"
|
||||
" device '' r2 (A=n2,B=n3) (R=1);\n"
|
||||
" device '' r3 (A=n1,B=n3) (R=3);\n"
|
||||
" device '' r4 (A=n3,B=n4) (R=0.8);\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
nl.combine_devices ();
|
||||
nl.purge ();
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit (A=n1,B=n4):\n"
|
||||
" D r4 (A=n1,B=n4) [R=2]\n"
|
||||
"circuit '' (A=n1,B=n4);\n"
|
||||
" device '' r4 (A=n1,B=n4) (R=2);\n"
|
||||
"end;\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -590,17 +610,19 @@ TEST(11_SerialInductors)
|
|||
circuit->connect_pin (pin_b.id (), n3);
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit (A=n1,B=n3):\n"
|
||||
" D l1 (A=n1,B=n2) [L=1]\n"
|
||||
" D l2 (A=n2,B=n3) [L=3]\n"
|
||||
"circuit '' (A=n1,B=n3);\n"
|
||||
" device '' l1 (A=n1,B=n2) (L=1);\n"
|
||||
" device '' l2 (A=n2,B=n3) (L=3);\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
nl.combine_devices ();
|
||||
nl.purge ();
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit (A=n1,B=n3):\n"
|
||||
" D l1 (A=n1,B=n3) [L=4]\n"
|
||||
"circuit '' (A=n1,B=n3);\n"
|
||||
" device '' l1 (A=n1,B=n3) (L=4);\n"
|
||||
"end;\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -638,17 +660,19 @@ TEST(12_ParallelInductors)
|
|||
l2->connect_terminal (db::DeviceClassInductor::terminal_id_B, n2);
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit (A=n1,B=n2):\n"
|
||||
" D l1 (A=n1,B=n2) [L=2]\n"
|
||||
" D l2 (A=n1,B=n2) [L=3]\n"
|
||||
"circuit '' (A=n1,B=n2);\n"
|
||||
" device '' l1 (A=n1,B=n2) (L=2);\n"
|
||||
" device '' l2 (A=n1,B=n2) (L=3);\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
nl.combine_devices ();
|
||||
nl.purge ();
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit (A=n1,B=n2):\n"
|
||||
" D l1 (A=n1,B=n2) [L=1.2]\n"
|
||||
"circuit '' (A=n1,B=n2);\n"
|
||||
" device '' l1 (A=n1,B=n2) (L=1.2);\n"
|
||||
"end;\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -689,17 +713,19 @@ TEST(13_SerialCapacitors)
|
|||
circuit->connect_pin (pin_b.id (), n3);
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit (A=n1,B=n3):\n"
|
||||
" D c1 (A=n1,B=n2) [C=2]\n"
|
||||
" D c2 (A=n2,B=n3) [C=3]\n"
|
||||
"circuit '' (A=n1,B=n3);\n"
|
||||
" device '' c1 (A=n1,B=n2) (C=2);\n"
|
||||
" device '' c2 (A=n2,B=n3) (C=3);\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
nl.combine_devices ();
|
||||
nl.purge ();
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit (A=n1,B=n3):\n"
|
||||
" D c1 (A=n1,B=n3) [C=1.2]\n"
|
||||
"circuit '' (A=n1,B=n3);\n"
|
||||
" device '' c1 (A=n1,B=n3) (C=1.2);\n"
|
||||
"end;\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -737,17 +763,19 @@ TEST(14_ParallelCapacitors)
|
|||
c2->connect_terminal (db::DeviceClassCapacitor::terminal_id_B, n2);
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit (A=n1,B=n2):\n"
|
||||
" D c1 (A=n1,B=n2) [C=1]\n"
|
||||
" D c2 (A=n1,B=n2) [C=3]\n"
|
||||
"circuit '' (A=n1,B=n2);\n"
|
||||
" device '' c1 (A=n1,B=n2) (C=1);\n"
|
||||
" device '' c2 (A=n1,B=n2) (C=3);\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
nl.combine_devices ();
|
||||
nl.purge ();
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit (A=n1,B=n2):\n"
|
||||
" D c1 (A=n1,B=n2) [C=4]\n"
|
||||
"circuit '' (A=n1,B=n2);\n"
|
||||
" device '' c1 (A=n1,B=n2) (C=4);\n"
|
||||
"end;\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -788,9 +816,10 @@ TEST(15_SerialDiodes)
|
|||
circuit->connect_pin (pin_b.id (), n3);
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit (A=n1,B=n3):\n"
|
||||
" D d1 (A=n1,C=n2) [A=2]\n"
|
||||
" D d2 (A=n2,C=n3) [A=3]\n"
|
||||
"circuit '' (A=n1,B=n3);\n"
|
||||
" device '' d1 (A=n1,C=n2) (A=2);\n"
|
||||
" device '' d2 (A=n2,C=n3) (A=3);\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
nl.combine_devices ();
|
||||
|
|
@ -799,9 +828,10 @@ TEST(15_SerialDiodes)
|
|||
// serial diodes are not combined!
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit (A=n1,B=n3):\n"
|
||||
" D d1 (A=n1,C=n2) [A=2]\n"
|
||||
" D d2 (A=n2,C=n3) [A=3]\n"
|
||||
"circuit '' (A=n1,B=n3);\n"
|
||||
" device '' d1 (A=n1,C=n2) (A=2);\n"
|
||||
" device '' d2 (A=n2,C=n3) (A=3);\n"
|
||||
"end;\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -839,17 +869,19 @@ TEST(16_ParallelDiodes)
|
|||
d2->connect_terminal (db::DeviceClassDiode::terminal_id_C, n2);
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit (A=n1,B=n2):\n"
|
||||
" D d1 (A=n1,C=n2) [A=1]\n"
|
||||
" D d2 (A=n1,C=n2) [A=3]\n"
|
||||
"circuit '' (A=n1,B=n2);\n"
|
||||
" device '' d1 (A=n1,C=n2) (A=1);\n"
|
||||
" device '' d2 (A=n1,C=n2) (A=3);\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
nl.combine_devices ();
|
||||
nl.purge ();
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit (A=n1,B=n2):\n"
|
||||
" D d1 (A=n1,C=n2) [A=4]\n"
|
||||
"circuit '' (A=n1,B=n2);\n"
|
||||
" device '' d1 (A=n1,C=n2) (A=4);\n"
|
||||
"end;\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -887,9 +919,10 @@ TEST(17_AntiParallelDiodes)
|
|||
d2->connect_terminal (db::DeviceClassDiode::terminal_id_A, n2);
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit (A=n1,B=n2):\n"
|
||||
" D d1 (A=n1,C=n2) [A=1]\n"
|
||||
" D d2 (A=n2,C=n1) [A=3]\n"
|
||||
"circuit '' (A=n1,B=n2);\n"
|
||||
" device '' d1 (A=n1,C=n2) (A=1);\n"
|
||||
" device '' d2 (A=n2,C=n1) (A=3);\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
nl.combine_devices ();
|
||||
|
|
@ -898,9 +931,10 @@ TEST(17_AntiParallelDiodes)
|
|||
// anti-parallel diodes are not combined
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit (A=n1,B=n2):\n"
|
||||
" D d1 (A=n1,C=n2) [A=1]\n"
|
||||
" D d2 (A=n2,C=n1) [A=3]\n"
|
||||
"circuit '' (A=n1,B=n2);\n"
|
||||
" device '' d1 (A=n1,C=n2) (A=1);\n"
|
||||
" device '' d2 (A=n2,C=n1) (A=3);\n"
|
||||
"end;\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -955,17 +989,19 @@ TEST(20_ParallelMOS3Transistors)
|
|||
d2->connect_terminal (db::DeviceClassMOS3Transistor::terminal_id_G, n3);
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit (A=n1,B=n2,C=n3):\n"
|
||||
" D d1 (S=n1,G=n3,D=n2) [L=0.5,W=1,AS=2,AD=3,PS=12,PD=13]\n"
|
||||
" D d2 (S=n1,G=n3,D=n2) [L=0.5,W=2,AS=3,AD=4,PS=13,PD=14]\n"
|
||||
"circuit '' (A=n1,B=n2,C=n3);\n"
|
||||
" device '' d1 (S=n1,G=n3,D=n2) (L=0.5,W=1,AS=2,AD=3,PS=12,PD=13);\n"
|
||||
" device '' d2 (S=n1,G=n3,D=n2) (L=0.5,W=2,AS=3,AD=4,PS=13,PD=14);\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
nl.combine_devices ();
|
||||
nl.purge ();
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit (A=n1,B=n2,C=n3):\n"
|
||||
" D d1 (S=n1,G=n3,D=n2) [L=0.5,W=3,AS=5,AD=7,PS=25,PD=27]\n"
|
||||
"circuit '' (A=n1,B=n2,C=n3);\n"
|
||||
" device '' d1 (S=n1,G=n3,D=n2) (L=0.5,W=3,AS=5,AD=7,PS=25,PD=27);\n"
|
||||
"end;\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -1020,17 +1056,19 @@ TEST(21_AntiParallelMOS3Transistors)
|
|||
d2->connect_terminal (db::DeviceClassMOS3Transistor::terminal_id_G, n3);
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit (A=n1,B=n2,C=n3):\n"
|
||||
" D d1 (S=n1,G=n3,D=n2) [L=0.5,W=1,AS=2,AD=3,PS=12,PD=13]\n"
|
||||
" D d2 (S=n2,G=n3,D=n1) [L=0.5,W=2,AS=3,AD=4,PS=13,PD=14]\n"
|
||||
"circuit '' (A=n1,B=n2,C=n3);\n"
|
||||
" device '' d1 (S=n1,G=n3,D=n2) (L=0.5,W=1,AS=2,AD=3,PS=12,PD=13);\n"
|
||||
" device '' d2 (S=n2,G=n3,D=n1) (L=0.5,W=2,AS=3,AD=4,PS=13,PD=14);\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
nl.combine_devices ();
|
||||
nl.purge ();
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit (A=n1,B=n2,C=n3):\n"
|
||||
" D d1 (S=n1,G=n3,D=n2) [L=0.5,W=3,AS=5,AD=7,PS=25,PD=27]\n"
|
||||
"circuit '' (A=n1,B=n2,C=n3);\n"
|
||||
" device '' d1 (S=n1,G=n3,D=n2) (L=0.5,W=3,AS=5,AD=7,PS=25,PD=27);\n"
|
||||
"end;\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -1090,9 +1128,10 @@ TEST(22_ParallelMOS3TransistorsDisconnectedGates)
|
|||
d2->connect_terminal (db::DeviceClassMOS3Transistor::terminal_id_G, n4);
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit (A=n1,B=n2,C1=n3,C2=n4):\n"
|
||||
" D d1 (S=n1,G=n3,D=n2) [L=0.5,W=1,AS=2,AD=3,PS=12,PD=13]\n"
|
||||
" D d2 (S=n1,G=n4,D=n2) [L=0.5,W=2,AS=3,AD=4,PS=13,PD=14]\n"
|
||||
"circuit '' (A=n1,B=n2,C1=n3,C2=n4);\n"
|
||||
" device '' d1 (S=n1,G=n3,D=n2) (L=0.5,W=1,AS=2,AD=3,PS=12,PD=13);\n"
|
||||
" device '' d2 (S=n1,G=n4,D=n2) (L=0.5,W=2,AS=3,AD=4,PS=13,PD=14);\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
nl.combine_devices ();
|
||||
|
|
@ -1101,9 +1140,10 @@ TEST(22_ParallelMOS3TransistorsDisconnectedGates)
|
|||
// because of the disconnected gates, devices will no be joined:
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit (A=n1,B=n2,C1=n3,C2=n4):\n"
|
||||
" D d1 (S=n1,G=n3,D=n2) [L=0.5,W=1,AS=2,AD=3,PS=12,PD=13]\n"
|
||||
" D d2 (S=n1,G=n4,D=n2) [L=0.5,W=2,AS=3,AD=4,PS=13,PD=14]\n"
|
||||
"circuit '' (A=n1,B=n2,C1=n3,C2=n4);\n"
|
||||
" device '' d1 (S=n1,G=n3,D=n2) (L=0.5,W=1,AS=2,AD=3,PS=12,PD=13);\n"
|
||||
" device '' d2 (S=n1,G=n4,D=n2) (L=0.5,W=2,AS=3,AD=4,PS=13,PD=14);\n"
|
||||
"end;\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -1158,9 +1198,10 @@ TEST(23_ParallelMOS3TransistorsDifferentLength)
|
|||
d2->connect_terminal (db::DeviceClassMOS3Transistor::terminal_id_G, n3);
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit (A=n1,B=n2,C=n3):\n"
|
||||
" D d1 (S=n1,G=n3,D=n2) [L=0.5,W=1,AS=2,AD=3,PS=12,PD=13]\n"
|
||||
" D d2 (S=n1,G=n3,D=n2) [L=0.75,W=2,AS=3,AD=4,PS=13,PD=14]\n"
|
||||
"circuit '' (A=n1,B=n2,C=n3);\n"
|
||||
" device '' d1 (S=n1,G=n3,D=n2) (L=0.5,W=1,AS=2,AD=3,PS=12,PD=13);\n"
|
||||
" device '' d2 (S=n1,G=n3,D=n2) (L=0.75,W=2,AS=3,AD=4,PS=13,PD=14);\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
nl.combine_devices ();
|
||||
|
|
@ -1169,9 +1210,10 @@ TEST(23_ParallelMOS3TransistorsDifferentLength)
|
|||
// because of different length, the devices will not be combined:
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit (A=n1,B=n2,C=n3):\n"
|
||||
" D d1 (S=n1,G=n3,D=n2) [L=0.5,W=1,AS=2,AD=3,PS=12,PD=13]\n"
|
||||
" D d2 (S=n1,G=n3,D=n2) [L=0.75,W=2,AS=3,AD=4,PS=13,PD=14]\n"
|
||||
"circuit '' (A=n1,B=n2,C=n3);\n"
|
||||
" device '' d1 (S=n1,G=n3,D=n2) (L=0.5,W=1,AS=2,AD=3,PS=12,PD=13);\n"
|
||||
" device '' d2 (S=n1,G=n3,D=n2) (L=0.75,W=2,AS=3,AD=4,PS=13,PD=14);\n"
|
||||
"end;\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -1233,17 +1275,19 @@ TEST(30_ParallelMOS4Transistors)
|
|||
d2->connect_terminal (db::DeviceClassMOS4Transistor::terminal_id_B, n0);
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit (A=n1,B=n2,C=n3,D=n0):\n"
|
||||
" D d1 (S=n1,G=n3,D=n2,B=n0) [L=0.5,W=1,AS=2,AD=3,PS=12,PD=13]\n"
|
||||
" D d2 (S=n1,G=n3,D=n2,B=n0) [L=0.5,W=2,AS=3,AD=4,PS=13,PD=14]\n"
|
||||
"circuit '' (A=n1,B=n2,C=n3,D=n0);\n"
|
||||
" device '' d1 (S=n1,G=n3,D=n2,B=n0) (L=0.5,W=1,AS=2,AD=3,PS=12,PD=13);\n"
|
||||
" device '' d2 (S=n1,G=n3,D=n2,B=n0) (L=0.5,W=2,AS=3,AD=4,PS=13,PD=14);\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
nl.combine_devices ();
|
||||
nl.purge ();
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit (A=n1,B=n2,C=n3,D=n0):\n"
|
||||
" D d1 (S=n1,G=n3,D=n2,B=n0) [L=0.5,W=3,AS=5,AD=7,PS=25,PD=27]\n"
|
||||
"circuit '' (A=n1,B=n2,C=n3,D=n0);\n"
|
||||
" device '' d1 (S=n1,G=n3,D=n2,B=n0) (L=0.5,W=3,AS=5,AD=7,PS=25,PD=27);\n"
|
||||
"end;\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -1305,17 +1349,19 @@ TEST(31_AntiParallelMOS4Transistors)
|
|||
d2->connect_terminal (db::DeviceClassMOS4Transistor::terminal_id_B, n0);
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit (A=n1,B=n2,C=n3,D=n0):\n"
|
||||
" D d1 (S=n1,G=n3,D=n2,B=n0) [L=0.5,W=1,AS=2,AD=3,PS=12,PD=13]\n"
|
||||
" D d2 (S=n2,G=n3,D=n1,B=n0) [L=0.5,W=2,AS=3,AD=4,PS=13,PD=14]\n"
|
||||
"circuit '' (A=n1,B=n2,C=n3,D=n0);\n"
|
||||
" device '' d1 (S=n1,G=n3,D=n2,B=n0) (L=0.5,W=1,AS=2,AD=3,PS=12,PD=13);\n"
|
||||
" device '' d2 (S=n2,G=n3,D=n1,B=n0) (L=0.5,W=2,AS=3,AD=4,PS=13,PD=14);\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
nl.combine_devices ();
|
||||
nl.purge ();
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit (A=n1,B=n2,C=n3,D=n0):\n"
|
||||
" D d1 (S=n1,G=n3,D=n2,B=n0) [L=0.5,W=3,AS=5,AD=7,PS=25,PD=27]\n"
|
||||
"circuit '' (A=n1,B=n2,C=n3,D=n0);\n"
|
||||
" device '' d1 (S=n1,G=n3,D=n2,B=n0) (L=0.5,W=3,AS=5,AD=7,PS=25,PD=27);\n"
|
||||
"end;\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -1382,9 +1428,10 @@ TEST(32_ParallelMOS4TransistorsDisconnectedGates)
|
|||
d2->connect_terminal (db::DeviceClassMOS4Transistor::terminal_id_B, n0);
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit (A=n1,B=n2,C1=n3a,C2=n3b,D=n0):\n"
|
||||
" D d1 (S=n1,G=n3a,D=n2,B=n0) [L=0.5,W=1,AS=2,AD=3,PS=12,PD=13]\n"
|
||||
" D d2 (S=n1,G=n3b,D=n2,B=n0) [L=0.5,W=2,AS=3,AD=4,PS=13,PD=14]\n"
|
||||
"circuit '' (A=n1,B=n2,C1=n3a,C2=n3b,D=n0);\n"
|
||||
" device '' d1 (S=n1,G=n3a,D=n2,B=n0) (L=0.5,W=1,AS=2,AD=3,PS=12,PD=13);\n"
|
||||
" device '' d2 (S=n1,G=n3b,D=n2,B=n0) (L=0.5,W=2,AS=3,AD=4,PS=13,PD=14);\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
nl.combine_devices ();
|
||||
|
|
@ -1393,9 +1440,10 @@ TEST(32_ParallelMOS4TransistorsDisconnectedGates)
|
|||
// not combined because gate is different:
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit (A=n1,B=n2,C1=n3a,C2=n3b,D=n0):\n"
|
||||
" D d1 (S=n1,G=n3a,D=n2,B=n0) [L=0.5,W=1,AS=2,AD=3,PS=12,PD=13]\n"
|
||||
" D d2 (S=n1,G=n3b,D=n2,B=n0) [L=0.5,W=2,AS=3,AD=4,PS=13,PD=14]\n"
|
||||
"circuit '' (A=n1,B=n2,C1=n3a,C2=n3b,D=n0);\n"
|
||||
" device '' d1 (S=n1,G=n3a,D=n2,B=n0) (L=0.5,W=1,AS=2,AD=3,PS=12,PD=13);\n"
|
||||
" device '' d2 (S=n1,G=n3b,D=n2,B=n0) (L=0.5,W=2,AS=3,AD=4,PS=13,PD=14);\n"
|
||||
"end;\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -1462,9 +1510,10 @@ TEST(33_ParallelMOS4TransistorsDisconnectedBulk)
|
|||
d2->connect_terminal (db::DeviceClassMOS4Transistor::terminal_id_B, n0b);
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit (A=n1,B=n2,C=n3,D1=n0a,D2=n0b):\n"
|
||||
" D d1 (S=n1,G=n3,D=n2,B=n0a) [L=0.5,W=1,AS=2,AD=3,PS=12,PD=13]\n"
|
||||
" D d2 (S=n1,G=n3,D=n2,B=n0b) [L=0.5,W=2,AS=3,AD=4,PS=13,PD=14]\n"
|
||||
"circuit '' (A=n1,B=n2,C=n3,D1=n0a,D2=n0b);\n"
|
||||
" device '' d1 (S=n1,G=n3,D=n2,B=n0a) (L=0.5,W=1,AS=2,AD=3,PS=12,PD=13);\n"
|
||||
" device '' d2 (S=n1,G=n3,D=n2,B=n0b) (L=0.5,W=2,AS=3,AD=4,PS=13,PD=14);\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
// not combined because bulk is different:
|
||||
|
|
@ -1473,9 +1522,10 @@ TEST(33_ParallelMOS4TransistorsDisconnectedBulk)
|
|||
nl.purge ();
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit (A=n1,B=n2,C=n3,D1=n0a,D2=n0b):\n"
|
||||
" D d1 (S=n1,G=n3,D=n2,B=n0a) [L=0.5,W=1,AS=2,AD=3,PS=12,PD=13]\n"
|
||||
" D d2 (S=n1,G=n3,D=n2,B=n0b) [L=0.5,W=2,AS=3,AD=4,PS=13,PD=14]\n"
|
||||
"circuit '' (A=n1,B=n2,C=n3,D1=n0a,D2=n0b);\n"
|
||||
" device '' d1 (S=n1,G=n3,D=n2,B=n0a) (L=0.5,W=1,AS=2,AD=3,PS=12,PD=13);\n"
|
||||
" device '' d2 (S=n1,G=n3,D=n2,B=n0b) (L=0.5,W=2,AS=3,AD=4,PS=13,PD=14);\n"
|
||||
"end;\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -1537,9 +1587,10 @@ TEST(34_ParallelMOS4TransistorsDifferentLength)
|
|||
d2->connect_terminal (db::DeviceClassMOS4Transistor::terminal_id_B, n0);
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit (A=n1,B=n2,C=n3,D=n0):\n"
|
||||
" D d1 (S=n1,G=n3,D=n2,B=n0) [L=0.5,W=1,AS=2,AD=3,PS=12,PD=13]\n"
|
||||
" D d2 (S=n1,G=n3,D=n2,B=n0) [L=0.75,W=2,AS=3,AD=4,PS=13,PD=14]\n"
|
||||
"circuit '' (A=n1,B=n2,C=n3,D=n0);\n"
|
||||
" device '' d1 (S=n1,G=n3,D=n2,B=n0) (L=0.5,W=1,AS=2,AD=3,PS=12,PD=13);\n"
|
||||
" device '' d2 (S=n1,G=n3,D=n2,B=n0) (L=0.75,W=2,AS=3,AD=4,PS=13,PD=14);\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
nl.combine_devices ();
|
||||
|
|
@ -1548,9 +1599,10 @@ TEST(34_ParallelMOS4TransistorsDifferentLength)
|
|||
// not combined because length is different:
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit (A=n1,B=n2,C=n3,D=n0):\n"
|
||||
" D d1 (S=n1,G=n3,D=n2,B=n0) [L=0.5,W=1,AS=2,AD=3,PS=12,PD=13]\n"
|
||||
" D d2 (S=n1,G=n3,D=n2,B=n0) [L=0.75,W=2,AS=3,AD=4,PS=13,PD=14]\n"
|
||||
"circuit '' (A=n1,B=n2,C=n3,D=n0);\n"
|
||||
" device '' d1 (S=n1,G=n3,D=n2,B=n0) (L=0.5,W=1,AS=2,AD=3,PS=12,PD=13);\n"
|
||||
" device '' d2 (S=n1,G=n3,D=n2,B=n0) (L=0.75,W=2,AS=3,AD=4,PS=13,PD=14);\n"
|
||||
"end;\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
#include "dbCommonReader.h"
|
||||
#include "dbTestSupport.h"
|
||||
#include "dbCellMapping.h"
|
||||
#include "dbTestSupport.h"
|
||||
|
||||
#include "tlUnitTest.h"
|
||||
#include "tlString.h"
|
||||
|
|
@ -280,55 +281,71 @@ TEST(1_DeviceAndNetExtraction)
|
|||
dump_nets_to_layout (nl, cl, ly, dump_map, cm);
|
||||
|
||||
// compare netlist as string
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit RINGO ():\n"
|
||||
" XINV2 $1 (IN=$I8,$2=FB,OUT=OSC,$4=VSS,$5=VDD)\n"
|
||||
" XINV2 $2 (IN=FB,$2=$I38,OUT=$I19,$4=VSS,$5=VDD)\n"
|
||||
" XINV2 $3 (IN=$I19,$2=$I39,OUT=$I1,$4=VSS,$5=VDD)\n"
|
||||
" XINV2 $4 (IN=$I1,$2=$I40,OUT=$I2,$4=VSS,$5=VDD)\n"
|
||||
" XINV2 $5 (IN=$I2,$2=$I41,OUT=$I3,$4=VSS,$5=VDD)\n"
|
||||
" XINV2 $6 (IN=$I3,$2=$I42,OUT=$I4,$4=VSS,$5=VDD)\n"
|
||||
" XINV2 $7 (IN=$I4,$2=$I43,OUT=$I5,$4=VSS,$5=VDD)\n"
|
||||
" XINV2 $8 (IN=$I5,$2=$I44,OUT=$I6,$4=VSS,$5=VDD)\n"
|
||||
" XINV2 $9 (IN=$I6,$2=$I45,OUT=$I7,$4=VSS,$5=VDD)\n"
|
||||
" XINV2 $10 (IN=$I7,$2=$I46,OUT=$I8,$4=VSS,$5=VDD)\n"
|
||||
"Circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5):\n"
|
||||
" DPMOS $1 (S=$2,G=IN,D=$5) [L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5]\n"
|
||||
" DPMOS $2 (S=$5,G=$2,D=OUT) [L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95]\n"
|
||||
" DNMOS $3 (S=$2,G=IN,D=$4) [L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5]\n"
|
||||
" DNMOS $4 (S=$4,G=$2,D=OUT) [L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95]\n"
|
||||
" XTRANS $1 ($1=$2,$2=$4,$3=IN)\n"
|
||||
" XTRANS $2 ($1=$2,$2=$5,$3=IN)\n"
|
||||
" XTRANS $3 ($1=$5,$2=OUT,$3=$2)\n"
|
||||
" XTRANS $4 ($1=$4,$2=OUT,$3=$2)\n"
|
||||
"Circuit TRANS ($1=$1,$2=$2,$3=$3):\n"
|
||||
CHECKPOINT ();
|
||||
db::compare_netlist (_this, nl,
|
||||
"circuit RINGO ();\n"
|
||||
" subcircuit INV2 $1 (IN=$I8,$2=FB,OUT=OSC,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $2 (IN=FB,$2=$I38,OUT=$I19,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $3 (IN=$I19,$2=$I39,OUT=$I1,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $4 (IN=$I1,$2=$I40,OUT=$I2,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $5 (IN=$I2,$2=$I41,OUT=$I3,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $6 (IN=$I3,$2=$I42,OUT=$I4,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $7 (IN=$I4,$2=$I43,OUT=$I5,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $8 (IN=$I5,$2=$I44,OUT=$I6,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $9 (IN=$I6,$2=$I45,OUT=$I7,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $10 (IN=$I7,$2=$I46,OUT=$I8,$4=VSS,$5=VDD);\n"
|
||||
"end;\n"
|
||||
"circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5);\n"
|
||||
" device PMOS $1 (S=$2,G=IN,D=$5) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device PMOS $2 (S=$5,G=$2,D=OUT) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||
" device NMOS $3 (S=$2,G=IN,D=$4) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device NMOS $4 (S=$4,G=$2,D=OUT) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||
" subcircuit TRANS $1 ($1=$2,$2=$4,$3=IN);\n"
|
||||
" subcircuit TRANS $2 ($1=$2,$2=$5,$3=IN);\n"
|
||||
" subcircuit TRANS $3 ($1=$5,$2=OUT,$3=$2);\n"
|
||||
" subcircuit TRANS $4 ($1=$4,$2=OUT,$3=$2);\n"
|
||||
"end;\n"
|
||||
"circuit TRANS ($1=$1,$2=$2,$3=$3);\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
// use this opportunity to test serialization to and from string
|
||||
db::Netlist nldup;
|
||||
for (db::Netlist::device_class_iterator i = nl.begin_device_classes (); i != nl.end_device_classes (); ++i) {
|
||||
nldup.add_device_class (i->clone ());
|
||||
}
|
||||
nldup.from_string (nl.to_string ());
|
||||
EXPECT_EQ (nldup.to_string (), nl.to_string ());
|
||||
|
||||
// doesn't do anything here, but we test that this does not destroy anything:
|
||||
nl.combine_devices ();
|
||||
|
||||
// make pins for named nets of top-level circuits - this way they are not purged
|
||||
nl.make_top_level_pins ();
|
||||
nl.purge ();
|
||||
nl.purge_nets ();
|
||||
|
||||
// compare netlist as string
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit RINGO (FB=FB,OSC=OSC,VSS=VSS,VDD=VDD):\n"
|
||||
" XINV2 $1 (IN=$I8,$2=FB,OUT=OSC,$4=VSS,$5=VDD)\n"
|
||||
" XINV2 $2 (IN=FB,$2=(null),OUT=$I19,$4=VSS,$5=VDD)\n"
|
||||
" XINV2 $3 (IN=$I19,$2=(null),OUT=$I1,$4=VSS,$5=VDD)\n"
|
||||
" XINV2 $4 (IN=$I1,$2=(null),OUT=$I2,$4=VSS,$5=VDD)\n"
|
||||
" XINV2 $5 (IN=$I2,$2=(null),OUT=$I3,$4=VSS,$5=VDD)\n"
|
||||
" XINV2 $6 (IN=$I3,$2=(null),OUT=$I4,$4=VSS,$5=VDD)\n"
|
||||
" XINV2 $7 (IN=$I4,$2=(null),OUT=$I5,$4=VSS,$5=VDD)\n"
|
||||
" XINV2 $8 (IN=$I5,$2=(null),OUT=$I6,$4=VSS,$5=VDD)\n"
|
||||
" XINV2 $9 (IN=$I6,$2=(null),OUT=$I7,$4=VSS,$5=VDD)\n"
|
||||
" XINV2 $10 (IN=$I7,$2=(null),OUT=$I8,$4=VSS,$5=VDD)\n"
|
||||
"Circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5):\n"
|
||||
" DPMOS $1 (S=$2,G=IN,D=$5) [L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5]\n"
|
||||
" DPMOS $2 (S=$5,G=$2,D=OUT) [L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95]\n"
|
||||
" DNMOS $3 (S=$2,G=IN,D=$4) [L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5]\n"
|
||||
" DNMOS $4 (S=$4,G=$2,D=OUT) [L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95]\n"
|
||||
CHECKPOINT ();
|
||||
db::compare_netlist (_this, nl,
|
||||
"circuit RINGO (FB=FB,OSC=OSC,VSS=VSS,VDD=VDD);\n"
|
||||
" subcircuit INV2 $1 (IN=$I8,$2=FB,OUT=OSC,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $2 (IN=FB,$2=(null),OUT=$I19,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $3 (IN=$I19,$2=(null),OUT=$I1,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $4 (IN=$I1,$2=(null),OUT=$I2,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $5 (IN=$I2,$2=(null),OUT=$I3,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $6 (IN=$I3,$2=(null),OUT=$I4,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $7 (IN=$I4,$2=(null),OUT=$I5,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $8 (IN=$I5,$2=(null),OUT=$I6,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $9 (IN=$I6,$2=(null),OUT=$I7,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $10 (IN=$I7,$2=(null),OUT=$I8,$4=VSS,$5=VDD);\n"
|
||||
"end;\n"
|
||||
"circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5);\n"
|
||||
" device PMOS $1 (S=$2,G=IN,D=$5) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device PMOS $2 (S=$5,G=$2,D=OUT) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||
" device NMOS $3 (S=$2,G=IN,D=$4) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device NMOS $4 (S=$4,G=$2,D=OUT) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
// compare the collected test data
|
||||
|
|
@ -466,7 +483,7 @@ TEST(2_DeviceAndNetExtractionFlat)
|
|||
// extract the nets
|
||||
|
||||
// don't use "join_nets_by_label" because the flattened texts will spoil everything
|
||||
net_ex.extract_nets (dss, 0, conn, nl, cl, false);
|
||||
net_ex.extract_nets (dss, 0, conn, nl, cl);
|
||||
|
||||
// debug layers produced for nets
|
||||
// 202/0 -> Active
|
||||
|
|
@ -493,50 +510,50 @@ TEST(2_DeviceAndNetExtractionFlat)
|
|||
dump_nets_to_layout (nl, cl, ly, dump_map, cm);
|
||||
|
||||
// compare netlist as string
|
||||
// NOTE: some of the nets are called IN,OUT but are different ones. They
|
||||
// happen to be the same because they share the same label.
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit RINGO ():\n"
|
||||
" DPMOS $1 (S=$16,G='IN,OUT',D=VDD) [L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5]\n"
|
||||
" DPMOS $2 (S=VDD,G=$16,D='IN,OUT') [L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95]\n"
|
||||
" DPMOS $3 (S=$14,G='IN,OUT',D=VDD) [L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5]\n"
|
||||
" DPMOS $4 (S=VDD,G=$14,D='IN,OUT') [L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95]\n"
|
||||
" DPMOS $5 (S=$12,G='IN,OUT',D=VDD) [L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5]\n"
|
||||
" DPMOS $6 (S=VDD,G=$12,D='IN,OUT') [L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95]\n"
|
||||
" DPMOS $7 (S='IN,FB',G='IN,OUT',D=VDD) [L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5]\n"
|
||||
" DPMOS $8 (S=VDD,G='IN,FB',D='OUT,OSC') [L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95]\n"
|
||||
" DPMOS $9 (S=$4,G='IN,OUT',D=VDD) [L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5]\n"
|
||||
" DPMOS $10 (S=VDD,G=$4,D='IN,OUT') [L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95]\n"
|
||||
" DPMOS $11 (S=$8,G='IN,OUT',D=VDD) [L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5]\n"
|
||||
" DPMOS $12 (S=VDD,G=$8,D='IN,OUT') [L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95]\n"
|
||||
" DPMOS $13 (S=$2,G='IN,FB',D=VDD) [L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5]\n"
|
||||
" DPMOS $14 (S=VDD,G=$2,D='IN,OUT') [L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95]\n"
|
||||
" DPMOS $15 (S=$6,G='IN,OUT',D=VDD) [L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5]\n"
|
||||
" DPMOS $16 (S=VDD,G=$6,D='IN,OUT') [L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95]\n"
|
||||
" DPMOS $17 (S=$18,G='IN,OUT',D=VDD) [L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5]\n"
|
||||
" DPMOS $18 (S=VDD,G=$18,D='IN,OUT') [L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95]\n"
|
||||
" DPMOS $19 (S=$10,G='IN,OUT',D=VDD) [L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5]\n"
|
||||
" DPMOS $20 (S=VDD,G=$10,D='IN,OUT') [L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95]\n"
|
||||
" DNMOS $21 (S='IN,FB',G='IN,OUT',D=VSS) [L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5]\n"
|
||||
" DNMOS $22 (S=VSS,G='IN,FB',D='OUT,OSC') [L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95]\n"
|
||||
" DNMOS $23 (S=$18,G='IN,OUT',D=VSS) [L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5]\n"
|
||||
" DNMOS $24 (S=VSS,G=$18,D='IN,OUT') [L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95]\n"
|
||||
" DNMOS $25 (S=$14,G='IN,OUT',D=VSS) [L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5]\n"
|
||||
" DNMOS $26 (S=VSS,G=$14,D='IN,OUT') [L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95]\n"
|
||||
" DNMOS $27 (S=$12,G='IN,OUT',D=VSS) [L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5]\n"
|
||||
" DNMOS $28 (S=VSS,G=$12,D='IN,OUT') [L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95]\n"
|
||||
" DNMOS $29 (S=$4,G='IN,OUT',D=VSS) [L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5]\n"
|
||||
" DNMOS $30 (S=VSS,G=$4,D='IN,OUT') [L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95]\n"
|
||||
" DNMOS $31 (S=$2,G='IN,FB',D=VSS) [L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5]\n"
|
||||
" DNMOS $32 (S=VSS,G=$2,D='IN,OUT') [L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95]\n"
|
||||
" DNMOS $33 (S=$8,G='IN,OUT',D=VSS) [L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5]\n"
|
||||
" DNMOS $34 (S=VSS,G=$8,D='IN,OUT') [L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95]\n"
|
||||
" DNMOS $35 (S=$6,G='IN,OUT',D=VSS) [L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5]\n"
|
||||
" DNMOS $36 (S=VSS,G=$6,D='IN,OUT') [L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95]\n"
|
||||
" DNMOS $37 (S=$16,G='IN,OUT',D=VSS) [L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5]\n"
|
||||
" DNMOS $38 (S=VSS,G=$16,D='IN,OUT') [L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95]\n"
|
||||
" DNMOS $39 (S=$10,G='IN,OUT',D=VSS) [L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5]\n"
|
||||
" DNMOS $40 (S=VSS,G=$10,D='IN,OUT') [L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95]\n"
|
||||
CHECKPOINT ();
|
||||
db::compare_netlist (_this, nl,
|
||||
"circuit RINGO ();\n"
|
||||
" device PMOS $1 (S=$16,G='IN,OUT$6',D=VDD) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device PMOS $2 (S=VDD,G=$16,D='IN,OUT$7') (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||
" device PMOS $3 (S=$14,G='IN,OUT$5',D=VDD) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device PMOS $4 (S=VDD,G=$14,D='IN,OUT$6') (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||
" device PMOS $5 (S=$12,G='IN,OUT$4',D=VDD) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device PMOS $6 (S=VDD,G=$12,D='IN,OUT$5') (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||
" device PMOS $7 (S='IN,FB',G='IN,OUT$8',D=VDD) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device PMOS $8 (S=VDD,G='IN,FB',D='OUT,OSC') (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||
" device PMOS $9 (S=$4,G='IN,OUT',D=VDD) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device PMOS $10 (S=VDD,G=$4,D='IN,OUT$1') (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||
" device PMOS $11 (S=$8,G='IN,OUT$2',D=VDD) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device PMOS $12 (S=VDD,G=$8,D='IN,OUT$3') (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||
" device PMOS $13 (S=$2,G='IN,FB',D=VDD) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device PMOS $14 (S=VDD,G=$2,D='IN,OUT') (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||
" device PMOS $15 (S=$6,G='IN,OUT$1',D=VDD) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device PMOS $16 (S=VDD,G=$6,D='IN,OUT$2') (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||
" device PMOS $17 (S=$18,G='IN,OUT$7',D=VDD) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device PMOS $18 (S=VDD,G=$18,D='IN,OUT$8') (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||
" device PMOS $19 (S=$10,G='IN,OUT$3',D=VDD) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device PMOS $20 (S=VDD,G=$10,D='IN,OUT$4') (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||
" device NMOS $21 (S='IN,FB',G='IN,OUT$8',D=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device NMOS $22 (S=VSS,G='IN,FB',D='OUT,OSC') (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||
" device NMOS $23 (S=$18,G='IN,OUT$7',D=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device NMOS $24 (S=VSS,G=$18,D='IN,OUT$8') (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||
" device NMOS $25 (S=$14,G='IN,OUT$5',D=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device NMOS $26 (S=VSS,G=$14,D='IN,OUT$6') (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||
" device NMOS $27 (S=$12,G='IN,OUT$4',D=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device NMOS $28 (S=VSS,G=$12,D='IN,OUT$5') (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||
" device NMOS $29 (S=$4,G='IN,OUT',D=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device NMOS $30 (S=VSS,G=$4,D='IN,OUT$1') (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||
" device NMOS $31 (S=$2,G='IN,FB',D=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device NMOS $32 (S=VSS,G=$2,D='IN,OUT') (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||
" device NMOS $33 (S=$8,G='IN,OUT$2',D=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device NMOS $34 (S=VSS,G=$8,D='IN,OUT$3') (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||
" device NMOS $35 (S=$6,G='IN,OUT$1',D=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device NMOS $36 (S=VSS,G=$6,D='IN,OUT$2') (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||
" device NMOS $37 (S=$16,G='IN,OUT$6',D=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device NMOS $38 (S=VSS,G=$16,D='IN,OUT$7') (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||
" device NMOS $39 (S=$10,G='IN,OUT$3',D=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device NMOS $40 (S=VSS,G=$10,D='IN,OUT$4') (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
// compare the collected test data
|
||||
|
|
@ -699,7 +716,17 @@ TEST(3_DeviceAndNetExtractionWithImplicitConnections)
|
|||
|
||||
// extract the nets
|
||||
|
||||
net_ex.extract_nets (dss, 0, conn, nl, cl);
|
||||
db::Netlist nl2 = nl;
|
||||
net_ex.extract_nets (dss, 0, conn, nl2, cl, "{VDDZ,VSSZ,NEXT,FB}");
|
||||
|
||||
EXPECT_EQ (all_net_names_unique (nl2), true);
|
||||
|
||||
nl2 = nl;
|
||||
net_ex.extract_nets (dss, 0, conn, nl2, cl, "{VDDZ,VSSZ,NEXT}");
|
||||
|
||||
EXPECT_EQ (all_net_names_unique (nl2), false);
|
||||
|
||||
net_ex.extract_nets (dss, 0, conn, nl, cl, "*");
|
||||
|
||||
EXPECT_EQ (all_net_names_unique (nl), true);
|
||||
|
||||
|
|
@ -728,28 +755,32 @@ TEST(3_DeviceAndNetExtractionWithImplicitConnections)
|
|||
dump_nets_to_layout (nl, cl, ly, dump_map, cm);
|
||||
|
||||
// compare netlist as string
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit RINGO ():\n"
|
||||
" XINV2 $1 (IN=$I8,$2=FB,OUT=OSC,$4='VSSZ,VSS',$5='VDDZ,VDD')\n"
|
||||
" XINV2 $2 (IN=FB,$2=$I38,OUT=$I19,$4='VSSZ,VSS',$5='VDDZ,VDD')\n"
|
||||
" XINV2 $3 (IN=NEXT,$2=$I43,OUT=$I5,$4='VSSZ,VSS',$5='VDDZ,VDD')\n"
|
||||
" XINV2 $4 (IN=$I3,$2=$I42,OUT=NEXT,$4='VSSZ,VSS',$5='VDDZ,VDD')\n"
|
||||
" XINV2 $5 (IN=$I5,$2=$I44,OUT=$I6,$4='VSSZ,VSS',$5='VDDZ,VDD')\n"
|
||||
" XINV2 $6 (IN=$I6,$2=$I45,OUT=$I7,$4='VSSZ,VSS',$5='VDDZ,VDD')\n"
|
||||
" XINV2 $7 (IN=$I7,$2=$I46,OUT=$I8,$4='VSSZ,VSS',$5='VDDZ,VDD')\n"
|
||||
" XINV2 $8 (IN=$I19,$2=$I39,OUT=$I1,$4='VSSZ,VSS',$5='VDDZ,VDD')\n"
|
||||
" XINV2 $9 (IN=$I1,$2=$I40,OUT=$I2,$4='VSSZ,VSS',$5='VDDZ,VDD')\n"
|
||||
" XINV2 $10 (IN=$I2,$2=$I41,OUT=$I3,$4='VSSZ,VSS',$5='VDDZ,VDD')\n"
|
||||
"Circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5):\n"
|
||||
" DPMOS $1 (S=$2,G=IN,D=$5) [L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5]\n"
|
||||
" DPMOS $2 (S=$5,G=$2,D=OUT) [L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95]\n"
|
||||
" DNMOS $3 (S=$2,G=IN,D=$4) [L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5]\n"
|
||||
" DNMOS $4 (S=$4,G=$2,D=OUT) [L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95]\n"
|
||||
" XTRANS $1 ($1=$2,$2=$4,$3=IN)\n"
|
||||
" XTRANS $2 ($1=$2,$2=$5,$3=IN)\n"
|
||||
" XTRANS $3 ($1=$5,$2=OUT,$3=$2)\n"
|
||||
" XTRANS $4 ($1=$4,$2=OUT,$3=$2)\n"
|
||||
"Circuit TRANS ($1=$1,$2=$2,$3=$3):\n"
|
||||
CHECKPOINT ();
|
||||
db::compare_netlist (_this, nl,
|
||||
"circuit RINGO ();\n"
|
||||
" subcircuit INV2 $1 (IN=$I8,$2=FB,OUT=OSC,$4='VSSZ,VSS',$5='VDDZ,VDD');\n"
|
||||
" subcircuit INV2 $2 (IN=FB,$2=$I38,OUT=$I19,$4='VSSZ,VSS',$5='VDDZ,VDD');\n"
|
||||
" subcircuit INV2 $3 (IN=NEXT,$2=$I43,OUT=$I5,$4='VSSZ,VSS',$5='VDDZ,VDD');\n"
|
||||
" subcircuit INV2 $4 (IN=$I3,$2=$I42,OUT=NEXT,$4='VSSZ,VSS',$5='VDDZ,VDD');\n"
|
||||
" subcircuit INV2 $5 (IN=$I5,$2=$I44,OUT=$I6,$4='VSSZ,VSS',$5='VDDZ,VDD');\n"
|
||||
" subcircuit INV2 $6 (IN=$I6,$2=$I45,OUT=$I7,$4='VSSZ,VSS',$5='VDDZ,VDD');\n"
|
||||
" subcircuit INV2 $7 (IN=$I7,$2=$I46,OUT=$I8,$4='VSSZ,VSS',$5='VDDZ,VDD');\n"
|
||||
" subcircuit INV2 $8 (IN=$I19,$2=$I39,OUT=$I1,$4='VSSZ,VSS',$5='VDDZ,VDD');\n"
|
||||
" subcircuit INV2 $9 (IN=$I1,$2=$I40,OUT=$I2,$4='VSSZ,VSS',$5='VDDZ,VDD');\n"
|
||||
" subcircuit INV2 $10 (IN=$I2,$2=$I41,OUT=$I3,$4='VSSZ,VSS',$5='VDDZ,VDD');\n"
|
||||
"end;\n"
|
||||
"circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5);\n"
|
||||
" device PMOS $1 (S=$2,G=IN,D=$5) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device PMOS $2 (S=$5,G=$2,D=OUT) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||
" device NMOS $3 (S=$2,G=IN,D=$4) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device NMOS $4 (S=$4,G=$2,D=OUT) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||
" subcircuit TRANS $1 ($1=$2,$2=$4,$3=IN);\n"
|
||||
" subcircuit TRANS $2 ($1=$2,$2=$5,$3=IN);\n"
|
||||
" subcircuit TRANS $3 ($1=$5,$2=OUT,$3=$2);\n"
|
||||
" subcircuit TRANS $4 ($1=$4,$2=OUT,$3=$2);\n"
|
||||
"end;\n"
|
||||
"circuit TRANS ($1=$1,$2=$2,$3=$3);\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
// doesn't do anything here, but we test that this does not destroy anything:
|
||||
|
|
@ -760,23 +791,26 @@ TEST(3_DeviceAndNetExtractionWithImplicitConnections)
|
|||
nl.purge ();
|
||||
|
||||
// compare netlist as string
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"Circuit RINGO (FB=FB,OSC=OSC,NEXT=NEXT,'VSSZ,VSS'='VSSZ,VSS','VDDZ,VDD'='VDDZ,VDD'):\n"
|
||||
" XINV2 $1 (IN=$I8,$2=FB,OUT=OSC,$4='VSSZ,VSS',$5='VDDZ,VDD')\n"
|
||||
" XINV2 $2 (IN=FB,$2=(null),OUT=$I19,$4='VSSZ,VSS',$5='VDDZ,VDD')\n"
|
||||
" XINV2 $3 (IN=NEXT,$2=(null),OUT=$I5,$4='VSSZ,VSS',$5='VDDZ,VDD')\n"
|
||||
" XINV2 $4 (IN=$I3,$2=(null),OUT=NEXT,$4='VSSZ,VSS',$5='VDDZ,VDD')\n"
|
||||
" XINV2 $5 (IN=$I5,$2=(null),OUT=$I6,$4='VSSZ,VSS',$5='VDDZ,VDD')\n"
|
||||
" XINV2 $6 (IN=$I6,$2=(null),OUT=$I7,$4='VSSZ,VSS',$5='VDDZ,VDD')\n"
|
||||
" XINV2 $7 (IN=$I7,$2=(null),OUT=$I8,$4='VSSZ,VSS',$5='VDDZ,VDD')\n"
|
||||
" XINV2 $8 (IN=$I19,$2=(null),OUT=$I1,$4='VSSZ,VSS',$5='VDDZ,VDD')\n"
|
||||
" XINV2 $9 (IN=$I1,$2=(null),OUT=$I2,$4='VSSZ,VSS',$5='VDDZ,VDD')\n"
|
||||
" XINV2 $10 (IN=$I2,$2=(null),OUT=$I3,$4='VSSZ,VSS',$5='VDDZ,VDD')\n"
|
||||
"Circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5):\n"
|
||||
" DPMOS $1 (S=$2,G=IN,D=$5) [L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5]\n"
|
||||
" DPMOS $2 (S=$5,G=$2,D=OUT) [L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95]\n"
|
||||
" DNMOS $3 (S=$2,G=IN,D=$4) [L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5]\n"
|
||||
" DNMOS $4 (S=$4,G=$2,D=OUT) [L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95]\n"
|
||||
CHECKPOINT ();
|
||||
db::compare_netlist (_this, nl,
|
||||
"circuit RINGO (FB=FB,OSC=OSC,NEXT=NEXT,'VSSZ,VSS'='VSSZ,VSS','VDDZ,VDD'='VDDZ,VDD');\n"
|
||||
" subcircuit INV2 $1 (IN=$I8,$2=FB,OUT=OSC,$4='VSSZ,VSS',$5='VDDZ,VDD');\n"
|
||||
" subcircuit INV2 $2 (IN=FB,$2=(null),OUT=$I19,$4='VSSZ,VSS',$5='VDDZ,VDD');\n"
|
||||
" subcircuit INV2 $3 (IN=NEXT,$2=(null),OUT=$I5,$4='VSSZ,VSS',$5='VDDZ,VDD');\n"
|
||||
" subcircuit INV2 $4 (IN=$I3,$2=(null),OUT=NEXT,$4='VSSZ,VSS',$5='VDDZ,VDD');\n"
|
||||
" subcircuit INV2 $5 (IN=$I5,$2=(null),OUT=$I6,$4='VSSZ,VSS',$5='VDDZ,VDD');\n"
|
||||
" subcircuit INV2 $6 (IN=$I6,$2=(null),OUT=$I7,$4='VSSZ,VSS',$5='VDDZ,VDD');\n"
|
||||
" subcircuit INV2 $7 (IN=$I7,$2=(null),OUT=$I8,$4='VSSZ,VSS',$5='VDDZ,VDD');\n"
|
||||
" subcircuit INV2 $8 (IN=$I19,$2=(null),OUT=$I1,$4='VSSZ,VSS',$5='VDDZ,VDD');\n"
|
||||
" subcircuit INV2 $9 (IN=$I1,$2=(null),OUT=$I2,$4='VSSZ,VSS',$5='VDDZ,VDD');\n"
|
||||
" subcircuit INV2 $10 (IN=$I2,$2=(null),OUT=$I3,$4='VSSZ,VSS',$5='VDDZ,VDD');\n"
|
||||
"end;\n"
|
||||
"circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5);\n"
|
||||
" device PMOS $1 (S=$2,G=IN,D=$5) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device PMOS $2 (S=$5,G=$2,D=OUT) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||
" device NMOS $3 (S=$2,G=IN,D=$4) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device NMOS $4 (S=$4,G=$2,D=OUT) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
// compare the collected test data
|
||||
|
|
|
|||
|
|
@ -0,0 +1,125 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2019 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include "dbNetlistSpiceReader.h"
|
||||
#include "dbNetlist.h"
|
||||
#include "dbNetlistDeviceClasses.h"
|
||||
|
||||
#include "tlUnitTest.h"
|
||||
#include "tlStream.h"
|
||||
#include "tlFileUtils.h"
|
||||
|
||||
TEST(1_BasicReader)
|
||||
{
|
||||
db::Netlist nl;
|
||||
|
||||
std::string path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "nreader1.cir");
|
||||
|
||||
db::NetlistSpiceReader reader;
|
||||
tl::InputStream is (path);
|
||||
reader.read (is, nl);
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"circuit TOP ();\n"
|
||||
" device RES $1 (A='6',B='1') (R=7650);\n"
|
||||
" device RES $2 (A='3',B='1') (R=7650);\n"
|
||||
" device RES $3 (A='3',B='2') (R=2670);\n"
|
||||
" device MHVPMOS $4 (S='6',G='4',D='7',B='7') (L=0.25,W=1.5,AS=0.63,AD=0.63,PS=3.84,PD=3.84);\n"
|
||||
"end;\n"
|
||||
);
|
||||
}
|
||||
|
||||
TEST(2_ReaderWithSubcircuits)
|
||||
{
|
||||
db::Netlist nl;
|
||||
|
||||
std::string path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "nreader2.cir");
|
||||
|
||||
db::NetlistSpiceReader reader;
|
||||
tl::InputStream is (path);
|
||||
reader.read (is, nl);
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"circuit RINGO ($1='11',$2='12',$3='13',$4='14',$5='15');\n"
|
||||
" subcircuit ND2X1 $1 ($1='12',$2='1',$3='15',$4='12',$5='11',$6='14',$7='15');\n"
|
||||
" subcircuit INVX1 $2 ($1='12',$2='2',$3='15',$4='12',$5='1',$6='15');\n"
|
||||
" subcircuit INVX1 $3 ($1='12',$2='3',$3='15',$4='12',$5='2',$6='15');\n"
|
||||
" subcircuit INVX1 $4 ($1='12',$2='4',$3='15',$4='12',$5='3',$6='15');\n"
|
||||
" subcircuit INVX1 $5 ($1='12',$2='5',$3='15',$4='12',$5='4',$6='15');\n"
|
||||
" subcircuit INVX1 $6 ($1='12',$2='6',$3='15',$4='12',$5='5',$6='15');\n"
|
||||
" subcircuit INVX1 $7 ($1='12',$2='7',$3='15',$4='12',$5='6',$6='15');\n"
|
||||
" subcircuit INVX1 $8 ($1='12',$2='8',$3='15',$4='12',$5='7',$6='15');\n"
|
||||
" subcircuit INVX1 $9 ($1='12',$2='9',$3='15',$4='12',$5='8',$6='15');\n"
|
||||
" subcircuit INVX1 $10 ($1='12',$2='10',$3='15',$4='12',$5='9',$6='15');\n"
|
||||
" subcircuit INVX1 $11 ($1='12',$2='11',$3='15',$4='12',$5='10',$6='15');\n"
|
||||
" subcircuit INVX1 $12 ($1='12',$2='13',$3='15',$4='12',$5='11',$6='15');\n"
|
||||
"end;\n"
|
||||
"circuit ND2X1 ($1='1',$2='2',$3='3',$4='4',$5='5',$6='6',$7='7');\n"
|
||||
" device MLVPMOS $1 (S='2',G='6',D='1',B='4') (L=0.25,W=1.5,AS=0.6375,AD=0.3375,PS=3.85,PD=1.95);\n"
|
||||
" device MLVPMOS $2 (S='1',G='5',D='2',B='4') (L=0.25,W=1.5,AS=0.3375,AD=0.6375,PS=1.95,PD=3.85);\n"
|
||||
" device MLVNMOS $3 (S='3',G='6',D='8',B='7') (L=0.25,W=0.95,AS=0.40375,AD=0.21375,PS=2.75,PD=1.4);\n"
|
||||
" device MLVNMOS $4 (S='8',G='5',D='2',B='7') (L=0.25,W=0.95,AS=0.21375,AD=0.40375,PS=1.4,PD=2.75);\n"
|
||||
"end;\n"
|
||||
"circuit INVX1 ($1='1',$2='2',$3='3',$4='4',$5='5',$6='6');\n"
|
||||
" device MLVPMOS $1 (S='1',G='5',D='2',B='4') (L=0.25,W=1.5,AS=0.6375,AD=0.6375,PS=3.85,PD=3.85);\n"
|
||||
" device MLVNMOS $2 (S='3',G='5',D='2',B='6') (L=0.25,W=0.95,AS=0.40375,AD=0.40375,PS=2.75,PD=2.75);\n"
|
||||
"end;\n"
|
||||
);
|
||||
}
|
||||
|
||||
TEST(3_ReaderWithSubcircuitsAltOrder)
|
||||
{
|
||||
db::Netlist nl;
|
||||
|
||||
std::string path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "nreader3.cir");
|
||||
|
||||
db::NetlistSpiceReader reader;
|
||||
tl::InputStream is (path);
|
||||
reader.read (is, nl);
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"circuit INVX1 ($1='1',$2='2',$3='3',$4='4',$5='5',$6='6');\n"
|
||||
" device MLVPMOS $1 (S='1',G='5',D='2',B='4') (L=0.25,W=1.5,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
" device MLVNMOS $2 (S='3',G='5',D='2',B='6') (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
"end;\n"
|
||||
"circuit ND2X1 ($1='1',$2='2',$3='3',$4='4',$5='5',$6='6',$7='7');\n"
|
||||
" device MLVPMOS $1 (S='2',G='6',D='1',B='4') (L=0.25,W=1.5,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
" device MLVPMOS $2 (S='1',G='5',D='2',B='4') (L=0.25,W=1.5,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
" device MLVNMOS $3 (S='3',G='6',D='8',B='7') (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
" device MLVNMOS $4 (S='8',G='5',D='2',B='7') (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
"end;\n"
|
||||
"circuit RINGO ($1='11',$2='12',$3='13',$4='14',$5='15');\n"
|
||||
" subcircuit ND2X1 $1 ($1='12',$2='1',$3='15',$4='12',$5='11',$6='14',$7='15');\n"
|
||||
" subcircuit INVX1 $2 ($1='12',$2='2',$3='15',$4='12',$5='1',$6='15');\n"
|
||||
" subcircuit INVX1 $3 ($1='12',$2='3',$3='15',$4='12',$5='2',$6='15');\n"
|
||||
" subcircuit INVX1 $4 ($1='12',$2='4',$3='15',$4='12',$5='3',$6='15');\n"
|
||||
" subcircuit INVX1 $5 ($1='12',$2='5',$3='15',$4='12',$5='4',$6='15');\n"
|
||||
" subcircuit INVX1 $6 ($1='12',$2='6',$3='15',$4='12',$5='5',$6='15');\n"
|
||||
" subcircuit INVX1 $7 ($1='12',$2='7',$3='15',$4='12',$5='6',$6='15');\n"
|
||||
" subcircuit INVX1 $8 ($1='12',$2='8',$3='15',$4='12',$5='7',$6='15');\n"
|
||||
" subcircuit INVX1 $9 ($1='12',$2='9',$3='15',$4='12',$5='8',$6='15');\n"
|
||||
" subcircuit INVX1 $10 ($1='12',$2='10',$3='15',$4='12',$5='9',$6='15');\n"
|
||||
" subcircuit INVX1 $11 ($1='12',$2='11',$3='15',$4='12',$5='10',$6='15');\n"
|
||||
" subcircuit INVX1 $12 ($1='12',$2='13',$3='15',$4='12',$5='11',$6='15');\n"
|
||||
"end;\n"
|
||||
);
|
||||
}
|
||||
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
|
||||
#include "dbNetlist.h"
|
||||
#include "dbNetlistDeviceClasses.h"
|
||||
|
||||
#include "tlUnitTest.h"
|
||||
#include "tlString.h"
|
||||
|
|
@ -258,11 +259,13 @@ TEST(1_DeviceTerminalDefinition)
|
|||
dc.clear_terminal_definitions ();
|
||||
EXPECT_EQ (dc.terminal_definitions ().empty (), true);
|
||||
|
||||
db::DeviceParameterDefinition ppd ("P1", "Parameter 1", 1.0);
|
||||
db::DeviceParameterDefinition ppd ("P1", "Parameter 1", 1.0, false);
|
||||
dc.add_parameter_definition (ppd);
|
||||
EXPECT_EQ (ppd.is_primary (), false);
|
||||
|
||||
db::DeviceParameterDefinition ppd2 ("P2", "Parameter 2");
|
||||
dc.add_parameter_definition (ppd2);
|
||||
EXPECT_EQ (ppd2.is_primary (), true);
|
||||
|
||||
EXPECT_EQ (pd2string (dc.parameter_definitions ()[0]), "P1(Parameter 1)=1 #0");
|
||||
EXPECT_EQ (pd2string (dc.parameter_definitions ()[1]), "P2(Parameter 2)=0 #1");
|
||||
|
|
@ -501,6 +504,9 @@ TEST(4_NetlistSubcircuits)
|
|||
dc->add_terminal_definition (db::DeviceTerminalDefinition ("B", ""));
|
||||
nl->add_device_class (dc);
|
||||
|
||||
std::auto_ptr<db::Netlist> nldup (new db::Netlist ());
|
||||
nldup->add_device_class (dc->clone ());
|
||||
|
||||
db::DeviceAbstract *dm = new db::DeviceAbstract ();
|
||||
dm->set_device_class (dc);
|
||||
EXPECT_EQ (dm->device_class () == dc, true);
|
||||
|
|
@ -609,6 +615,28 @@ TEST(4_NetlistSubcircuits)
|
|||
"D:B,+c2p2\n"
|
||||
);
|
||||
|
||||
EXPECT_EQ (nl->to_string (),
|
||||
"circuit c1 (c1p1=n1a,c1p2=n1c);\n"
|
||||
" subcircuit c2 sc1 (c2p1=n1a,c2p2=n1b);\n"
|
||||
" subcircuit c2 sc2 (c2p1=n1b,c2p2=n1c);\n"
|
||||
"end;\n"
|
||||
"circuit c2 (c2p1=n2a,c2p2=n2b);\n"
|
||||
" device dc2 D (A=n2a,B=n2b) ();\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
nldup->from_string (nl->to_string ());
|
||||
|
||||
EXPECT_EQ (nldup->to_string (),
|
||||
"circuit c1 (c1p1=n1a,c1p2=n1c);\n"
|
||||
" subcircuit c2 sc1 (c2p1=n1a,c2p2=n1b);\n"
|
||||
" subcircuit c2 sc2 (c2p1=n1b,c2p2=n1c);\n"
|
||||
"end;\n"
|
||||
"circuit c2 (c2p1=n2a,c2p2=n2b);\n"
|
||||
" device dc2 D (A=n2a,B=n2b) ();\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
EXPECT_EQ (netlist2 (*nl),
|
||||
"c1:c1p1=n1a,c1p2=n1c\n"
|
||||
" Xsc1:c2p1=n1a,c2p2=n1b\n"
|
||||
|
|
@ -1079,3 +1107,176 @@ TEST(13_DeviceAbstract)
|
|||
EXPECT_EQ (nl.begin_device_abstracts () == nl.end_device_abstracts (), true);
|
||||
}
|
||||
|
||||
TEST(20_FlattenSubCircuit)
|
||||
{
|
||||
db::Netlist nl;
|
||||
|
||||
db::DeviceClass *dc;
|
||||
|
||||
dc = new db::DeviceClassMOS3Transistor ();
|
||||
dc->set_name ("NMOS");
|
||||
nl.add_device_class (dc);
|
||||
|
||||
dc = new db::DeviceClassMOS3Transistor ();
|
||||
dc->set_name ("PMOS");
|
||||
nl.add_device_class (dc);
|
||||
|
||||
nl.from_string (
|
||||
"circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5);\n"
|
||||
" subcircuit PTRANS SC1 ($1=$5,$2=$2,$3=IN);\n"
|
||||
" subcircuit NTRANS SC2 ($1=$4,$2=$2,$3=IN);\n"
|
||||
" subcircuit PTRANS SC3 ($1=$5,$2=OUT,$3=$2);\n"
|
||||
" subcircuit NTRANS SC4 ($1=$4,$2=OUT,$3=$2);\n"
|
||||
"end;\n"
|
||||
"circuit PTRANS ($1=$1,$2=$2,$3=$3);\n"
|
||||
" device PMOS $1 (S=$1,D=$2,G=$3) (L=0.25,W=0.95);\n"
|
||||
"end;\n"
|
||||
"circuit NTRANS ($1=$1,$2=$2,$3=$3);\n"
|
||||
" device NMOS $1 (S=$1,D=$2,G=$3) (L=0.25,W=0.95);\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
db::Netlist nl2;
|
||||
|
||||
nl2 = nl;
|
||||
db::Circuit *inv2 = nl2.circuit_by_name ("INV2");
|
||||
inv2->flatten_subcircuit (inv2->subcircuit_by_name ("SC1"));
|
||||
|
||||
EXPECT_EQ (nl2.to_string (),
|
||||
"circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5);\n"
|
||||
" device PMOS $1 (S=$5,G=IN,D=$2) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
" subcircuit NTRANS SC2 ($1=$4,$2=$2,$3=IN);\n"
|
||||
" subcircuit PTRANS SC3 ($1=$5,$2=OUT,$3=$2);\n"
|
||||
" subcircuit NTRANS SC4 ($1=$4,$2=OUT,$3=$2);\n"
|
||||
"end;\n"
|
||||
"circuit PTRANS ($1=$1,$2=$2,$3=$3);\n"
|
||||
" device PMOS $1 (S=$1,G=$3,D=$2) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
"end;\n"
|
||||
"circuit NTRANS ($1=$1,$2=$2,$3=$3);\n"
|
||||
" device NMOS $1 (S=$1,G=$3,D=$2) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
nl2.flatten_circuit (nl2.circuit_by_name ("PTRANS"));
|
||||
nl2.flatten_circuit (nl2.circuit_by_name ("NTRANS"));
|
||||
|
||||
EXPECT_EQ (nl2.to_string (),
|
||||
"circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5);\n"
|
||||
" device PMOS $1 (S=$5,G=IN,D=$2) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
" device PMOS $2 (S=$5,G=$2,D=OUT) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
" device NMOS $3 (S=$4,G=IN,D=$2) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
" device NMOS $4 (S=$4,G=$2,D=OUT) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
"end;\n"
|
||||
);
|
||||
}
|
||||
|
||||
TEST(21_FlattenSubCircuit2)
|
||||
{
|
||||
db::Netlist nl;
|
||||
|
||||
db::DeviceClass *dc;
|
||||
|
||||
dc = new db::DeviceClassMOS3Transistor ();
|
||||
dc->set_name ("NMOS");
|
||||
nl.add_device_class (dc);
|
||||
|
||||
dc = new db::DeviceClassMOS3Transistor ();
|
||||
dc->set_name ("PMOS");
|
||||
nl.add_device_class (dc);
|
||||
|
||||
nl.from_string (
|
||||
"circuit RINGO (IN=IN,OSC=OSC,VSS=VSS,VDD=VDD);\n"
|
||||
" subcircuit INV2 INV2_SC1 (IN=$I8,$2=FB,OUT=OSC,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 INV2_SC2 (IN=FB,$2=(null),OUT=$I8,$4=VSS,$5=VDD);\n"
|
||||
"end;\n"
|
||||
"circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5);\n"
|
||||
" subcircuit PTRANS SC1 ($1=$5,$2=$2,$3=IN);\n"
|
||||
" subcircuit NTRANS SC2 ($1=$4,$2=$2,$3=IN);\n"
|
||||
" subcircuit PTRANS SC3 ($1=$5,$2=OUT,$3=$2);\n"
|
||||
" subcircuit NTRANS SC4 ($1=$4,$2=OUT,$3=$2);\n"
|
||||
"end;\n"
|
||||
"circuit PTRANS ($1=$1,$2=$2,$3=$3);\n"
|
||||
" device PMOS $1 (S=$1,D=$2,G=$3) (L=0.25,W=0.95);\n"
|
||||
"end;\n"
|
||||
"circuit NTRANS ($1=$1,$2=$2,$3=$3);\n"
|
||||
" device NMOS $1 (S=$1,D=$2,G=$3) (L=0.25,W=0.95);\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
db::Netlist nl2;
|
||||
|
||||
nl2 = nl;
|
||||
db::Circuit *inv2 = nl2.circuit_by_name ("RINGO");
|
||||
inv2->flatten_subcircuit (inv2->subcircuit_by_name ("INV2_SC1"));
|
||||
|
||||
EXPECT_EQ (nl2.to_string (),
|
||||
"circuit RINGO (IN=IN,OSC=OSC,VSS=VSS,VDD=VDD);\n"
|
||||
" subcircuit INV2 INV2_SC2 (IN=FB,$2=(null),OUT=$I8,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit PTRANS INV2_SC1.SC1 ($1=VDD,$2=FB,$3=$I8);\n"
|
||||
" subcircuit NTRANS INV2_SC1.SC2 ($1=VSS,$2=FB,$3=$I8);\n"
|
||||
" subcircuit PTRANS INV2_SC1.SC3 ($1=VDD,$2=OSC,$3=FB);\n"
|
||||
" subcircuit NTRANS INV2_SC1.SC4 ($1=VSS,$2=OSC,$3=FB);\n"
|
||||
"end;\n"
|
||||
"circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5);\n"
|
||||
" subcircuit PTRANS SC1 ($1=$5,$2=$2,$3=IN);\n"
|
||||
" subcircuit NTRANS SC2 ($1=$4,$2=$2,$3=IN);\n"
|
||||
" subcircuit PTRANS SC3 ($1=$5,$2=OUT,$3=$2);\n"
|
||||
" subcircuit NTRANS SC4 ($1=$4,$2=OUT,$3=$2);\n"
|
||||
"end;\n"
|
||||
"circuit PTRANS ($1=$1,$2=$2,$3=$3);\n"
|
||||
" device PMOS $1 (S=$1,G=$3,D=$2) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
"end;\n"
|
||||
"circuit NTRANS ($1=$1,$2=$2,$3=$3);\n"
|
||||
" device NMOS $1 (S=$1,G=$3,D=$2) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
inv2->flatten_subcircuit (inv2->subcircuit_by_name ("INV2_SC2"));
|
||||
|
||||
EXPECT_EQ (nl2.to_string (),
|
||||
"circuit RINGO (IN=IN,OSC=OSC,VSS=VSS,VDD=VDD);\n"
|
||||
" subcircuit PTRANS INV2_SC1.SC1 ($1=VDD,$2=FB,$3=$I8);\n"
|
||||
" subcircuit NTRANS INV2_SC1.SC2 ($1=VSS,$2=FB,$3=$I8);\n"
|
||||
" subcircuit PTRANS INV2_SC1.SC3 ($1=VDD,$2=OSC,$3=FB);\n"
|
||||
" subcircuit NTRANS INV2_SC1.SC4 ($1=VSS,$2=OSC,$3=FB);\n"
|
||||
" subcircuit PTRANS INV2_SC2.SC1 ($1=VDD,$2=(null),$3=FB);\n"
|
||||
" subcircuit NTRANS INV2_SC2.SC2 ($1=VSS,$2=(null),$3=FB);\n"
|
||||
" subcircuit PTRANS INV2_SC2.SC3 ($1=VDD,$2=$I8,$3=(null));\n"
|
||||
" subcircuit NTRANS INV2_SC2.SC4 ($1=VSS,$2=$I8,$3=(null));\n"
|
||||
"end;\n"
|
||||
"circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5);\n"
|
||||
" subcircuit PTRANS SC1 ($1=$5,$2=$2,$3=IN);\n"
|
||||
" subcircuit NTRANS SC2 ($1=$4,$2=$2,$3=IN);\n"
|
||||
" subcircuit PTRANS SC3 ($1=$5,$2=OUT,$3=$2);\n"
|
||||
" subcircuit NTRANS SC4 ($1=$4,$2=OUT,$3=$2);\n"
|
||||
"end;\n"
|
||||
"circuit PTRANS ($1=$1,$2=$2,$3=$3);\n"
|
||||
" device PMOS $1 (S=$1,G=$3,D=$2) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
"end;\n"
|
||||
"circuit NTRANS ($1=$1,$2=$2,$3=$3);\n"
|
||||
" device NMOS $1 (S=$1,G=$3,D=$2) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
nl2 = nl;
|
||||
nl2.flatten_circuit (nl2.circuit_by_name ("INV2"));
|
||||
|
||||
EXPECT_EQ (nl2.to_string (),
|
||||
"circuit RINGO (IN=IN,OSC=OSC,VSS=VSS,VDD=VDD);\n"
|
||||
" subcircuit PTRANS INV2_SC1.SC1 ($1=VDD,$2=FB,$3=$I8);\n"
|
||||
" subcircuit NTRANS INV2_SC1.SC2 ($1=VSS,$2=FB,$3=$I8);\n"
|
||||
" subcircuit PTRANS INV2_SC1.SC3 ($1=VDD,$2=OSC,$3=FB);\n"
|
||||
" subcircuit NTRANS INV2_SC1.SC4 ($1=VSS,$2=OSC,$3=FB);\n"
|
||||
" subcircuit PTRANS INV2_SC2.SC1 ($1=VDD,$2=(null),$3=FB);\n"
|
||||
" subcircuit NTRANS INV2_SC2.SC2 ($1=VSS,$2=(null),$3=FB);\n"
|
||||
" subcircuit PTRANS INV2_SC2.SC3 ($1=VDD,$2=$I8,$3=(null));\n"
|
||||
" subcircuit NTRANS INV2_SC2.SC4 ($1=VSS,$2=$I8,$3=(null));\n"
|
||||
"end;\n"
|
||||
"circuit PTRANS ($1=$1,$2=$2,$3=$3);\n"
|
||||
" device PMOS $1 (S=$1,G=$3,D=$2) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
"end;\n"
|
||||
"circuit NTRANS ($1=$1,$2=$2,$3=$3);\n"
|
||||
" device NMOS $1 (S=$1,G=$3,D=$2) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
"end;\n"
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,7 +69,9 @@ SOURCES = \
|
|||
dbNetlistWriterTests.cc \
|
||||
dbCellVariantsTests.cc \
|
||||
dbDeepEdgesTests.cc \
|
||||
dbDeepEdgePairsTests.cc
|
||||
dbDeepEdgePairsTests.cc \
|
||||
dbNetlistCompareTests.cc \
|
||||
dbNetlistReaderTests.cc
|
||||
|
||||
INCLUDEPATH += $$TL_INC $$DB_INC $$GSI_INC
|
||||
DEPENDPATH += $$TL_INC $$DB_INC $$GSI_INC
|
||||
|
|
|
|||
|
|
@ -2367,7 +2367,7 @@ CODE
|
|||
# to a flat collection of polygons, edges or edge pairs.
|
||||
|
||||
def flatten
|
||||
@engine._cmd(@data, :flatten)
|
||||
DRC::DRCLayer::new(@engine, @engine._cmd(@data, :flatten))
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
|
|
@ -3804,9 +3804,36 @@ CODE
|
|||
@connections = []
|
||||
@global_connections = []
|
||||
@layers = {}
|
||||
@join_nets = ""
|
||||
modified
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
# @name join_nets
|
||||
# @brief Specifies a search pattern for labels which create implicit net connections
|
||||
# @synopsis join_nets(label_pattern)
|
||||
# Use this method to supply a glob pattern for labels which create implicit net connections
|
||||
# on the top level circuit. This feature is useful to connect identically labelled nets
|
||||
# while a component isn't integrated yet. If the component is integrated, net may be connected
|
||||
# on a higher hierarchy level - e.g. by a power mesh. Inside the component this net consists
|
||||
# of individual islands. To properly perform netlist extraction and comparison, these islands
|
||||
# need to be connected even though there isn't a physical connection. "join_nets" can
|
||||
# achive this if these islands are labelled with the same text on the top level of the
|
||||
# component.
|
||||
#
|
||||
# Glob pattern are used which resemble shell file pattern: "*" is for all labels, "VDD"
|
||||
# for all "VDD" labels (pattern act case sensitive). "VDD*" is for all labels beginning
|
||||
# with "VDD" (still different labels will be connected to different nets!). "{VDD,VSS}"
|
||||
# is either "VDD" or "VSS".
|
||||
#
|
||||
# The search pattern is applied on the next net extraction. The search pattern is cleared
|
||||
# on "clear_connections".
|
||||
|
||||
def join_nets(arg)
|
||||
@join_nets = arg
|
||||
modified
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
# @brief Performs an antenna check
|
||||
# @name antenna_check
|
||||
|
|
@ -3957,7 +3984,7 @@ CODE
|
|||
@global_connections.each { |l,n| @l2n.connect_global(@layers[l], n) }
|
||||
|
||||
# run extraction in a timed environment
|
||||
@engine._cmd(@l2n, :extract_netlist)
|
||||
@engine._cmd(@l2n, :extract_netlist, @join_nets)
|
||||
@l2n
|
||||
|
||||
end
|
||||
|
|
@ -4922,6 +4949,12 @@ CODE
|
|||
# @synopsis clear_connections
|
||||
# See \Netter#clear_connections for a description of that function
|
||||
|
||||
# %DRC%
|
||||
# @name join_nets
|
||||
# @brief Specifies a label pattern for implicit net connections
|
||||
# @synopsis join_nets(label_pattern)
|
||||
# See \Netter#join_nets for a description of that function
|
||||
|
||||
# %DRC%
|
||||
# @name antenna_check
|
||||
# @brief Performs an antenna check
|
||||
|
|
@ -4940,7 +4973,7 @@ CODE
|
|||
# @synopsis extract_devices(extractor, layer_hash)
|
||||
# See \Netter#extract_devices for a description of that function
|
||||
|
||||
%w(connect connect_global clear_connections antenna_check l2n_data extract_devices).each do |f|
|
||||
%w(connect connect_global clear_connections join_nets antenna_check l2n_data extract_devices).each do |f|
|
||||
eval <<"CODE"
|
||||
def #{f}(*args)
|
||||
_netter.#{f}(*args)
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@
|
|||
#include "tlUnitTest.h"
|
||||
#include "dbReader.h"
|
||||
#include "dbTestSupport.h"
|
||||
#include "dbNetlist.h"
|
||||
#include "dbNetlistSpiceReader.h"
|
||||
#include "lymMacro.h"
|
||||
#include "tlFileUtils.h"
|
||||
|
||||
|
|
@ -343,6 +345,27 @@ TEST(8_TextsAndPolygons)
|
|||
db::compare_layouts (_this, layout, au, db::NoNormalization);
|
||||
}
|
||||
|
||||
static void compare_netlists (tl::TestBase *_this, const std::string &cir, const std::string &cir_au)
|
||||
{
|
||||
db::Netlist nl, nl_au;
|
||||
|
||||
db::NetlistSpiceReader reader;
|
||||
|
||||
{
|
||||
tl::info << "Output: " << cir;
|
||||
tl::InputStream is (cir);
|
||||
reader.read (is, nl);
|
||||
}
|
||||
|
||||
{
|
||||
tl::info << "Golden: " << cir_au;
|
||||
tl::InputStream is (cir_au);
|
||||
reader.read (is, nl_au);
|
||||
}
|
||||
|
||||
db::compare_netlist (_this, nl, nl_au);
|
||||
}
|
||||
|
||||
TEST(9_NetlistExtraction)
|
||||
{
|
||||
std::string rs = tl::testsrc ();
|
||||
|
|
@ -380,27 +403,11 @@ TEST(9_NetlistExtraction)
|
|||
|
||||
// verify
|
||||
|
||||
{
|
||||
tl::InputStream is (output);
|
||||
tl::InputStream is_au (au);
|
||||
CHECKPOINT ();
|
||||
compare_netlists (_this, output, au);
|
||||
|
||||
if (is.read_all () != is_au.read_all ()) {
|
||||
_this->raise (tl::sprintf ("Compare failed - see\n actual: %s\n golden: %s",
|
||||
tl::absolute_file_path (output),
|
||||
tl::absolute_file_path (au)));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
tl::InputStream is (output_simplified);
|
||||
tl::InputStream is_au (au_simplified);
|
||||
|
||||
if (is.read_all () != is_au.read_all ()) {
|
||||
_this->raise (tl::sprintf ("Compare failed (simplified netlist) - see\n actual: %s\n golden: %s",
|
||||
tl::absolute_file_path (output_simplified),
|
||||
tl::absolute_file_path (au_simplified)));
|
||||
}
|
||||
}
|
||||
CHECKPOINT ();
|
||||
compare_netlists (_this, output_simplified, au_simplified);
|
||||
}
|
||||
|
||||
TEST(10_NetlistExtractionFlat)
|
||||
|
|
@ -440,27 +447,11 @@ TEST(10_NetlistExtractionFlat)
|
|||
|
||||
// verify
|
||||
|
||||
{
|
||||
tl::InputStream is (output);
|
||||
tl::InputStream is_au (au);
|
||||
CHECKPOINT ();
|
||||
compare_netlists (_this, output, au);
|
||||
|
||||
if (is.read_all () != is_au.read_all ()) {
|
||||
_this->raise (tl::sprintf ("Compare failed - see\n actual: %s\n golden: %s",
|
||||
tl::absolute_file_path (output),
|
||||
tl::absolute_file_path (au)));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
tl::InputStream is (output_simplified);
|
||||
tl::InputStream is_au (au_simplified);
|
||||
|
||||
if (is.read_all () != is_au.read_all ()) {
|
||||
_this->raise (tl::sprintf ("Compare failed (simplified netlist) - see\n actual: %s\n golden: %s",
|
||||
tl::absolute_file_path (output_simplified),
|
||||
tl::absolute_file_path (au_simplified)));
|
||||
}
|
||||
}
|
||||
CHECKPOINT ();
|
||||
compare_netlists (_this, output_simplified, au_simplified);
|
||||
}
|
||||
|
||||
TEST(11_CustomDevices)
|
||||
|
|
@ -500,25 +491,45 @@ TEST(11_CustomDevices)
|
|||
|
||||
// verify
|
||||
|
||||
{
|
||||
tl::InputStream is (output);
|
||||
tl::InputStream is_au (au);
|
||||
CHECKPOINT ();
|
||||
compare_netlists (_this, output, au);
|
||||
|
||||
if (is.read_all () != is_au.read_all ()) {
|
||||
_this->raise (tl::sprintf ("Compare failed - see\n actual: %s\n golden: %s",
|
||||
tl::absolute_file_path (output),
|
||||
tl::absolute_file_path (au)));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
tl::InputStream is (output_simplified);
|
||||
tl::InputStream is_au (au_simplified);
|
||||
|
||||
if (is.read_all () != is_au.read_all ()) {
|
||||
_this->raise (tl::sprintf ("Compare failed (simplified netlist) - see\n actual: %s\n golden: %s",
|
||||
tl::absolute_file_path (output_simplified),
|
||||
tl::absolute_file_path (au_simplified)));
|
||||
}
|
||||
}
|
||||
CHECKPOINT ();
|
||||
compare_netlists (_this, output_simplified, au_simplified);
|
||||
}
|
||||
|
||||
TEST(12_NetlistJoinLabels)
|
||||
{
|
||||
std::string rs = tl::testsrc ();
|
||||
rs += "/testdata/drc/drcSimpleTests_12.drc";
|
||||
|
||||
std::string input = tl::testsrc ();
|
||||
input += "/testdata/drc/implicit_nets.gds";
|
||||
|
||||
std::string au = tl::testsrc ();
|
||||
au += "/testdata/drc/drcSimpleTests_au12a.cir";
|
||||
|
||||
std::string output = this->tmp_file ("tmp.cir");
|
||||
|
||||
{
|
||||
// Set some variables
|
||||
lym::Macro config;
|
||||
config.set_text (tl::sprintf (
|
||||
"$drc_test_source = '%s'\n"
|
||||
"$drc_test_target = '%s'\n"
|
||||
"$drc_test_target_simplified = nil\n"
|
||||
, input, output)
|
||||
);
|
||||
config.set_interpreter (lym::Macro::Ruby);
|
||||
EXPECT_EQ (config.run (), 0);
|
||||
}
|
||||
|
||||
lym::Macro drc;
|
||||
drc.load_from (rs);
|
||||
EXPECT_EQ (drc.run (), 0);
|
||||
|
||||
// verify
|
||||
|
||||
CHECKPOINT ();
|
||||
compare_netlists (_this, output, au);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -113,6 +113,7 @@ RUBYTEST (dbMatrix, "dbMatrix.rb")
|
|||
RUBYTEST (dbNetlist, "dbNetlist.rb")
|
||||
RUBYTEST (dbNetlistDeviceClasses, "dbNetlistDeviceClasses.rb")
|
||||
RUBYTEST (dbNetlistWriterTests, "dbNetlistWriterTests.rb")
|
||||
RUBYTEST (dbNetlistCompare, "dbNetlistCompare.rb")
|
||||
RUBYTEST (dbPathTest, "dbPathTest.rb")
|
||||
RUBYTEST (dbPCells, "dbPCells.rb")
|
||||
RUBYTEST (dbPointTest, "dbPointTest.rb")
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ namespace tl
|
|||
static std::locale c_locale ("C");
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// lower and upper case for wchar_t
|
||||
// lower and upper case for wchar_t and uint32_t
|
||||
|
||||
#include "utf_casefolding.h"
|
||||
|
||||
|
|
@ -66,9 +66,44 @@ wchar_t wupcase (wchar_t c)
|
|||
}
|
||||
}
|
||||
|
||||
uint32_t utf32_downcase (uint32_t c32)
|
||||
{
|
||||
if (sizeof (wchar_t) == 2 && c32 >= 0x10000) {
|
||||
return c32;
|
||||
} else {
|
||||
return uint32_t (wdowncase (wchar_t (c32)));
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t utf32_upcase (uint32_t c32)
|
||||
{
|
||||
if (sizeof (wchar_t) == 2 && c32 >= 0x10000) {
|
||||
return c32;
|
||||
} else {
|
||||
return uint32_t (wupcase (wchar_t (c32)));
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Conversion of UTF8 to wchar_t
|
||||
|
||||
uint32_t utf32_from_utf8 (const char *&cp, const char *cpe = 0)
|
||||
{
|
||||
uint32_t c32 = (unsigned char) *cp++;
|
||||
if (c32 >= 0xf0 && ((cpe && cp + 2 < cpe) || (! cpe && cp [0] && cp [1] && cp [2]))) {
|
||||
c32 = ((c32 & 0x7) << 18) | ((uint32_t (cp [0]) & 0x3f) << 12) | ((uint32_t (cp [1]) & 0x3f) << 6) | (uint32_t (cp [2]) & 0x3f);
|
||||
cp += 3;
|
||||
} else if (c32 >= 0xe0 && ((cpe && cp + 1 < cpe) || (! cpe && cp [0] && cp [1]))) {
|
||||
c32 = ((c32 & 0xf) << 12) | ((uint32_t (cp [0]) & 0x3f) << 6) | (uint32_t (cp [1]) & 0x3f);
|
||||
cp += 2;
|
||||
} else if (c32 >= 0xc0 && ((cpe && cp < cpe) || (! cpe && cp [0]))) {
|
||||
c32 = ((c32 & 0x1f) << 6) | (uint32_t (*cp) & 0x3f);
|
||||
++cp;
|
||||
}
|
||||
|
||||
return c32;
|
||||
}
|
||||
|
||||
std::wstring to_wstring (const std::string &s)
|
||||
{
|
||||
std::wstring ws;
|
||||
|
|
@ -76,17 +111,7 @@ std::wstring to_wstring (const std::string &s)
|
|||
const char *cpe = s.c_str () + s.size ();
|
||||
for (const char *cp = s.c_str (); cp < cpe; ) {
|
||||
|
||||
uint32_t c32 = (unsigned char) *cp++;
|
||||
if (c32 >= 0xf0 && cp + 2 < cpe) {
|
||||
c32 = ((c32 & 0x7) << 18) | ((uint32_t (cp [0]) & 0x3f) << 12) | ((uint32_t (cp [1]) & 0x3f) << 6) | (uint32_t (cp [2]) & 0x3f);
|
||||
cp += 3;
|
||||
} else if (c32 >= 0xe0 && cp + 1 < cpe) {
|
||||
c32 = ((c32 & 0xf) << 12) | ((uint32_t (cp [0]) & 0x3f) << 6) | (uint32_t (cp [1]) & 0x3f);
|
||||
cp += 2;
|
||||
} else if (c32 >= 0xc0 && cp < cpe) {
|
||||
c32 = ((c32 & 0x1f) << 6) | (uint32_t (*cp) & 0x3f);
|
||||
++cp;
|
||||
}
|
||||
uint32_t c32 = utf32_from_utf8 (cp, cpe);
|
||||
|
||||
if (sizeof (wchar_t) == 2 && c32 >= 0x10000) {
|
||||
c32 -= 0x10000;
|
||||
|
|
@ -1324,6 +1349,28 @@ Extractor::test (const char *token)
|
|||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Extractor::test_without_case (const char *token)
|
||||
{
|
||||
skip ();
|
||||
|
||||
const char *cp = m_cp;
|
||||
while (*cp && *token) {
|
||||
uint32_t c = utf32_downcase (utf32_from_utf8 (cp));
|
||||
uint32_t ct = utf32_downcase (utf32_from_utf8 (token));
|
||||
if (c != ct) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (! *token) {
|
||||
m_cp = cp;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const char *
|
||||
Extractor::skip ()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -669,6 +669,13 @@ public:
|
|||
*/
|
||||
bool test (const char *token);
|
||||
|
||||
/**
|
||||
* @brief Test for a token (a certain string) in case-insensitive mode
|
||||
*
|
||||
* If the token is not present, return false.
|
||||
*/
|
||||
bool test_without_case (const char *token);
|
||||
|
||||
/**
|
||||
* @brief Skip blanks
|
||||
*
|
||||
|
|
|
|||
|
|
@ -388,6 +388,33 @@ TEST(8)
|
|||
EXPECT_EQ (x.try_read_quoted (s), true);
|
||||
EXPECT_EQ (s, "a_word\'!");
|
||||
EXPECT_EQ (x.at_end (), true);
|
||||
|
||||
x = Extractor (" foobar");
|
||||
EXPECT_EQ (x.test ("foo"), true);
|
||||
EXPECT_EQ (x.test ("bar"), true);
|
||||
|
||||
x = Extractor (" foo bar");
|
||||
EXPECT_EQ (x.test ("foo"), true);
|
||||
EXPECT_EQ (x.test ("bar"), true);
|
||||
|
||||
x = Extractor (" FOObar");
|
||||
EXPECT_EQ (x.test ("foo"), false);
|
||||
EXPECT_EQ (x.test ("BAR"), false);
|
||||
|
||||
x = Extractor (" FOObar");
|
||||
EXPECT_EQ (x.test_without_case ("foo"), true);
|
||||
EXPECT_EQ (x.test_without_case ("BAR"), true);
|
||||
|
||||
x = Extractor (" µm");
|
||||
EXPECT_EQ (x.test ("µm"), true);
|
||||
|
||||
x = Extractor (" µM");
|
||||
EXPECT_EQ (x.test ("µm"), false);
|
||||
EXPECT_EQ (x.test_without_case ("µm"), true);
|
||||
|
||||
x = Extractor (" µm");
|
||||
EXPECT_EQ (x.test ("µM"), false);
|
||||
EXPECT_EQ (x.test_without_case ("µM"), true);
|
||||
}
|
||||
|
||||
TEST(9)
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -0,0 +1,17 @@
|
|||
* VDIV netlist before simplification
|
||||
|
||||
* cell TOP
|
||||
.SUBCKT TOP
|
||||
* net 1 OUT
|
||||
* net 2 GND
|
||||
* net 4 IN
|
||||
* net 7 VDD
|
||||
* device instance $1 1.025,0.335 RES
|
||||
R$1 6 1 7650
|
||||
* device instance $2 2.85,0.335 RES
|
||||
R$2 3 1 7650
|
||||
* device instance $3 4.665,0.335 RES
|
||||
R$3 3 2 2670
|
||||
* device instance $4 1.765,7.485 HVPMOS
|
||||
M$4 6 4 7 7 MHVPMOS L=0.25U W=1.5U AS=0.63P AD=0.63P PS=3.84U PD=3.84U
|
||||
.ENDS TOP
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
* RINGO netlist after simplification
|
||||
|
||||
* cell RINGO
|
||||
* pin FB
|
||||
* pin VDD
|
||||
* pin OUT
|
||||
* pin ENABLE
|
||||
* pin BULK,VSS
|
||||
.SUBCKT RINGO 11 12 13 14 15
|
||||
* net 11 FB
|
||||
* net 12 VDD
|
||||
* net 13 OUT
|
||||
* net 14 ENABLE
|
||||
* net 15 BULK,VSS
|
||||
* cell instance $1 r0 *1 1.8,0
|
||||
X$1 12 1 15 12 11 14 15 ND2X1
|
||||
* cell instance $2 r0 *1 4.2,0
|
||||
X$2 12 2 15 12 1 15 INVX1
|
||||
* cell instance $3 r0 *1 6,0
|
||||
X$3 12 3 15 12 2 15 INVX1
|
||||
* cell instance $4 r0 *1 7.8,0
|
||||
X$4 12 4 15 12 3 15 INVX1
|
||||
* cell instance $5 r0 *1 9.6,0
|
||||
X$5 12 5 15 12 4 15 INVX1
|
||||
* cell instance $6 r0 *1 11.4,0
|
||||
X$6 12 6 15 12 5 15 INVX1
|
||||
* cell instance $7 r0 *1 13.2,0
|
||||
X$7 12 7 15 12 6 15 INVX1
|
||||
* cell instance $8 r0 *1 15,0
|
||||
X$8 12 8 15 12 7 15 INVX1
|
||||
* cell instance $9 r0 *1 16.8,0
|
||||
X$9 12 9 15 12 8 15 INVX1
|
||||
* cell instance $10 r0 *1 18.6,0
|
||||
X$10 12 10 15 12 9 15 INVX1
|
||||
* cell instance $11 r0 *1 20.4,0
|
||||
X$11 12 11 15 12 10 15 INVX1
|
||||
* cell instance $12 r0 *1 22.2,0
|
||||
X$12 12 13 15 12 11 15 INVX1
|
||||
.ENDS RINGO
|
||||
|
||||
* cell ND2X1
|
||||
* pin VDD
|
||||
* pin OUT
|
||||
* pin VSS
|
||||
* pin
|
||||
* pin B
|
||||
* pin A
|
||||
* pin BULK
|
||||
.SUBCKT ND2X1 1 2 3 4 5 6 7
|
||||
* net 1 VDD
|
||||
* net 2 OUT
|
||||
* net 3 VSS
|
||||
* net 5 B
|
||||
* net 6 A
|
||||
* net 7 BULK
|
||||
* device instance $1 0.85,5.8 LVPMOS
|
||||
M$1 2 6 1 4 MLVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.3375P PS=3.85U PD=1.95U
|
||||
* device instance $2 1.55,5.8 LVPMOS
|
||||
M$2 1 5 2 4 MLVPMOS L=0.25U W=1.5U AS=0.3375P AD=0.6375P PS=1.95U PD=3.85U
|
||||
* device instance $3 0.85,2.135 LVNMOS
|
||||
M$3 3 6 8 7 MLVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.21375P PS=2.75U PD=1.4U
|
||||
* device instance $4 1.55,2.135 LVNMOS
|
||||
M$4 8 5 2 7 MLVNMOS L=0.25U W=0.95U AS=0.21375P AD=0.40375P PS=1.4U PD=2.75U
|
||||
.ENDS ND2X1
|
||||
|
||||
* cell INVX1
|
||||
* pin VDD
|
||||
* pin OUT
|
||||
* pin VSS
|
||||
* pin
|
||||
* pin IN
|
||||
* pin BULK
|
||||
.SUBCKT INVX1 1 2 3 4 5 6
|
||||
* net 1 VDD
|
||||
* net 2 OUT
|
||||
* net 3 VSS
|
||||
* net 5 IN
|
||||
* net 6 BULK
|
||||
* device instance $1 0.85,5.8 LVPMOS
|
||||
M$1 1 5 2 4 MLVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U
|
||||
* device instance $2 0.85,2.135 LVNMOS
|
||||
M$2 3 5 2 6 MLVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U PD=2.75U
|
||||
.ENDS INVX1
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
.subckt INVX1 1 2 3 4 5 6
|
||||
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
|
||||
.ends
|
||||
|
||||
.subckt ND2X1 1 2 3 4 5 6 7
|
||||
m$1 2 6 1 4 MLVPMOS L=0.25um W=1.5um
|
||||
m$2 1 5 2 4 MLVPMOS L=0.25um W=1.5um
|
||||
m$3 3 6 8 7 MLVNMOS L=0.25um W=0.95um
|
||||
m$4 8 5 2 7 MLVNMOS L=0.25um W=0.95um
|
||||
.ends ND2X1
|
||||
|
||||
.subckt RINGO 11 12 13 14 15
|
||||
x$1 12 1 15 12 11 14 15 ND2X1
|
||||
x$2 12 2 15 12 1 15 INVX1
|
||||
x$3 12 3 15 12 2 15 INVX1
|
||||
x$4 12 4 15 12 3 15 INVX1
|
||||
x$5 12 5 15 12 4 15 INVX1
|
||||
x$6 12 6 15 12 5 15 INVX1
|
||||
x$7 12 7 15 12 6 15 INVX1
|
||||
x$8 12 8 15 12 7 15 INVX1
|
||||
x$9 12 9 15 12 8 15 INVX1
|
||||
x$10 12 10 15 12 9 15 INVX1
|
||||
x$11 12 11 15 12 10 15 INVX1
|
||||
x$12 12 13 15 12 11 15 INVX1
|
||||
.ends RINGO
|
||||
|
||||
|
|
@ -10,7 +10,7 @@
|
|||
* net 3 n3
|
||||
* net 4 n4
|
||||
* device instance $1 0,0 M3CLS
|
||||
M$1 1 4 3 1 MM3CLS L=0.25U W=0.18U AS=1.2P AD=0.75P PS=2.2U PD=1.75U
|
||||
M$1 1 4 3 1 M3CLS L=0.25U W=0.18U AS=1.2P AD=0.75P PS=2.2U PD=1.75U
|
||||
* device instance $2 0,0 M3CLS
|
||||
M$2 3 4 2 3 MM3CLS L=1.4U W=0.25U AS=1.3P AD=0.85P PS=2.3U PD=1.85U
|
||||
M$2 3 4 2 3 M3CLS L=1.4U W=0.25U AS=1.3P AD=0.85P PS=2.3U PD=1.85U
|
||||
.ENDS C1
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
* net 4 n4
|
||||
* net 5 n5
|
||||
* device instance $1 0,0 M4CLS
|
||||
M$1 1 4 3 5 MM4CLS L=0.25U W=0.18U AS=1.2P AD=0.75P PS=2.2U PD=1.75U
|
||||
M$1 1 4 3 5 M4CLS L=0.25U W=0.18U AS=1.2P AD=0.75P PS=2.2U PD=1.75U
|
||||
* device instance $2 0,0 M4CLS
|
||||
M$2 3 4 2 5 MM4CLS L=1.4U W=0.25U AS=1.3P AD=0.85P PS=2.3U PD=1.85U
|
||||
M$2 3 4 2 5 M4CLS L=1.4U W=0.25U AS=1.3P AD=0.85P PS=2.3U PD=1.85U
|
||||
.ENDS C1
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ XSC2 3 2 4 3 C1
|
|||
* net 4 n4
|
||||
* net 5 n5
|
||||
* device instance $1 0,0 M4CLS
|
||||
M$1 1 4 3 5 MM4CLS L=0.25U W=0.18U AS=1.2P AD=0.75P PS=2.2U PD=1.75U
|
||||
M$1 1 4 3 5 M4CLS L=0.25U W=0.18U AS=1.2P AD=0.75P PS=2.2U PD=1.75U
|
||||
* device instance $2 0,0 M4CLS
|
||||
M$2 3 4 2 5 MM4CLS L=1.4U W=0.25U AS=1.3P AD=0.85P PS=2.3U PD=1.85U
|
||||
M$2 3 4 2 5 M4CLS L=1.4U W=0.25U AS=1.3P AD=0.85P PS=2.3U PD=1.85U
|
||||
.ENDS C1
|
||||
|
|
|
|||
|
|
@ -0,0 +1,66 @@
|
|||
# Flat extraction
|
||||
|
||||
source($drc_test_source)
|
||||
|
||||
deep
|
||||
|
||||
# Drawing layers
|
||||
|
||||
nwell = input(1, 0)
|
||||
active = input(2, 0)
|
||||
poly = input(3, 0)
|
||||
poly_lbl = input(3, 1)
|
||||
diff_cont = input(4, 0)
|
||||
poly_cont = input(5, 0)
|
||||
metal1 = input(6, 0)
|
||||
metal1_lbl = input(6, 1)
|
||||
via1 = input(7, 0)
|
||||
metal2 = input(8, 0)
|
||||
metal2_lbl = input(8, 1)
|
||||
|
||||
# Computed layers
|
||||
|
||||
pactive = active & nwell
|
||||
pgate = active & poly
|
||||
psd = active - pgate
|
||||
|
||||
nactive = active - nwell
|
||||
ngate = nactive & poly
|
||||
nsd = nactive - ngate
|
||||
|
||||
# PMOS transistor device extraction
|
||||
|
||||
pmos_ex = RBA::DeviceExtractorMOS3Transistor::new("PMOS")
|
||||
extract_devices(pmos_ex, { "SD" => psd, "G" => pgate, "P" => poly })
|
||||
|
||||
# NMOS transistor device extraction
|
||||
|
||||
nmos_ex = RBA::DeviceExtractorMOS3Transistor::new("NMOS")
|
||||
extract_devices(nmos_ex, { "SD" => nsd, "G" => ngate, "P" => poly })
|
||||
|
||||
# Define connectivity for netlist extraction
|
||||
|
||||
# Inter-layer
|
||||
connect(psd, diff_cont)
|
||||
connect(nsd, diff_cont)
|
||||
connect(poly, poly_cont)
|
||||
connect(poly_cont, metal1)
|
||||
connect(diff_cont, metal1)
|
||||
connect(metal1, via1)
|
||||
connect(via1, metal2)
|
||||
connect(poly, poly_lbl)
|
||||
connect(metal1, metal1_lbl)
|
||||
connect(metal2, metal2_lbl)
|
||||
|
||||
# Actually performs the extraction
|
||||
|
||||
join_nets("{VDDZ,VSSZ,NEXT,FB}")
|
||||
|
||||
netlist = l2n_data.netlist
|
||||
|
||||
# Writes the netlist
|
||||
|
||||
writer = RBA::NetlistSpiceWriter::new
|
||||
|
||||
netlist.write($drc_test_target, writer, "RINGO netlist")
|
||||
|
||||
|
|
@ -8,60 +8,60 @@
|
|||
* net 29 FB
|
||||
* net 43 BULK,VSS
|
||||
* device instance $1 2.65,5.8 LVPMOS
|
||||
M$1 2 27 28 28 MLVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.3375P PS=3.85U PD=1.95U
|
||||
M$1 2 27 28 28 LVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.3375P PS=3.85U PD=1.95U
|
||||
* device instance $2 3.35,5.8 LVPMOS
|
||||
M$2 28 29 2 28 MLVPMOS L=0.25U W=1.5U AS=0.3375P AD=0.6375P PS=1.95U PD=3.85U
|
||||
M$2 28 29 2 28 LVPMOS L=0.25U W=1.5U AS=0.3375P AD=0.6375P PS=1.95U PD=3.85U
|
||||
* device instance $3 5.05,5.8 LVPMOS
|
||||
M$3 28 2 3 28 MLVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U
|
||||
M$3 28 2 3 28 LVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U
|
||||
* device instance $4 6.85,5.8 LVPMOS
|
||||
M$4 28 3 4 28 MLVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U
|
||||
M$4 28 3 4 28 LVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U
|
||||
* device instance $5 8.65,5.8 LVPMOS
|
||||
M$5 28 4 5 28 MLVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U
|
||||
M$5 28 4 5 28 LVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U
|
||||
* device instance $6 10.45,5.8 LVPMOS
|
||||
M$6 28 5 6 28 MLVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U
|
||||
M$6 28 5 6 28 LVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U
|
||||
* device instance $7 12.25,5.8 LVPMOS
|
||||
M$7 28 6 7 28 MLVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U
|
||||
M$7 28 6 7 28 LVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U
|
||||
* device instance $8 14.05,5.8 LVPMOS
|
||||
M$8 28 7 8 28 MLVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U
|
||||
M$8 28 7 8 28 LVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U
|
||||
* device instance $9 15.85,5.8 LVPMOS
|
||||
M$9 28 8 9 28 MLVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U
|
||||
M$9 28 8 9 28 LVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U
|
||||
* device instance $10 17.65,5.8 LVPMOS
|
||||
M$10 28 9 10 28 MLVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U
|
||||
M$10 28 9 10 28 LVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U
|
||||
* device instance $11 19.45,5.8 LVPMOS
|
||||
M$11 28 10 11 28 MLVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U
|
||||
M$11 28 10 11 28 LVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U
|
||||
* device instance $12 21.25,5.8 LVPMOS
|
||||
M$12 28 11 29 28 MLVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U
|
||||
M$12 28 11 29 28 LVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U
|
||||
* device instance $13 23.05,5.8 LVPMOS
|
||||
M$13 28 29 12 28 MLVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U
|
||||
M$13 28 29 12 28 LVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U
|
||||
* device instance $14 2.65,2.135 LVNMOS
|
||||
M$14 43 27 14 43 MLVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.21375P PS=2.75U
|
||||
M$14 43 27 14 43 LVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.21375P PS=2.75U
|
||||
+ PD=1.4U
|
||||
* device instance $15 3.35,2.135 LVNMOS
|
||||
M$15 14 29 2 43 MLVNMOS L=0.25U W=0.95U AS=0.21375P AD=0.40375P PS=1.4U PD=2.75U
|
||||
M$15 14 29 2 43 LVNMOS L=0.25U W=0.95U AS=0.21375P AD=0.40375P PS=1.4U PD=2.75U
|
||||
* device instance $16 5.05,2.135 LVNMOS
|
||||
M$16 43 2 3 43 MLVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U PD=2.75U
|
||||
M$16 43 2 3 43 LVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U PD=2.75U
|
||||
* device instance $17 6.85,2.135 LVNMOS
|
||||
M$17 43 3 4 43 MLVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U PD=2.75U
|
||||
M$17 43 3 4 43 LVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U PD=2.75U
|
||||
* device instance $18 8.65,2.135 LVNMOS
|
||||
M$18 43 4 5 43 MLVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U PD=2.75U
|
||||
M$18 43 4 5 43 LVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U PD=2.75U
|
||||
* device instance $19 10.45,2.135 LVNMOS
|
||||
M$19 43 5 6 43 MLVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U PD=2.75U
|
||||
M$19 43 5 6 43 LVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U PD=2.75U
|
||||
* device instance $20 12.25,2.135 LVNMOS
|
||||
M$20 43 6 7 43 MLVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U PD=2.75U
|
||||
M$20 43 6 7 43 LVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U PD=2.75U
|
||||
* device instance $21 14.05,2.135 LVNMOS
|
||||
M$21 43 7 8 43 MLVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U PD=2.75U
|
||||
M$21 43 7 8 43 LVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U PD=2.75U
|
||||
* device instance $22 15.85,2.135 LVNMOS
|
||||
M$22 43 8 9 43 MLVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U PD=2.75U
|
||||
M$22 43 8 9 43 LVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U PD=2.75U
|
||||
* device instance $23 17.65,2.135 LVNMOS
|
||||
M$23 43 9 10 43 MLVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U
|
||||
M$23 43 9 10 43 LVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U
|
||||
+ PD=2.75U
|
||||
* device instance $24 19.45,2.135 LVNMOS
|
||||
M$24 43 10 11 43 MLVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U
|
||||
M$24 43 10 11 43 LVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U
|
||||
+ PD=2.75U
|
||||
* device instance $25 21.25,2.135 LVNMOS
|
||||
M$25 43 11 29 43 MLVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U
|
||||
M$25 43 11 29 43 LVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U
|
||||
+ PD=2.75U
|
||||
* device instance $26 23.05,2.135 LVNMOS
|
||||
M$26 43 29 12 43 MLVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U
|
||||
M$26 43 29 12 43 LVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U
|
||||
+ PD=2.75U
|
||||
.ENDS RINGO
|
||||
|
|
|
|||
|
|
@ -13,59 +13,59 @@
|
|||
* net 15 FB
|
||||
* net 16 BULK,VSS
|
||||
* device instance $1 2.65,5.8 LVPMOS
|
||||
M$1 1 13 14 14 MLVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.3375P PS=3.85U PD=1.95U
|
||||
M$1 1 13 14 14 LVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.3375P PS=3.85U PD=1.95U
|
||||
* device instance $2 3.35,5.8 LVPMOS
|
||||
M$2 14 15 1 14 MLVPMOS L=0.25U W=1.5U AS=0.3375P AD=0.6375P PS=1.95U PD=3.85U
|
||||
M$2 14 15 1 14 LVPMOS L=0.25U W=1.5U AS=0.3375P AD=0.6375P PS=1.95U PD=3.85U
|
||||
* device instance $3 5.05,5.8 LVPMOS
|
||||
M$3 14 1 2 14 MLVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U
|
||||
M$3 14 1 2 14 LVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U
|
||||
* device instance $4 6.85,5.8 LVPMOS
|
||||
M$4 14 2 3 14 MLVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U
|
||||
M$4 14 2 3 14 LVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U
|
||||
* device instance $5 8.65,5.8 LVPMOS
|
||||
M$5 14 3 4 14 MLVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U
|
||||
M$5 14 3 4 14 LVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U
|
||||
* device instance $6 10.45,5.8 LVPMOS
|
||||
M$6 14 4 5 14 MLVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U
|
||||
M$6 14 4 5 14 LVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U
|
||||
* device instance $7 12.25,5.8 LVPMOS
|
||||
M$7 14 5 6 14 MLVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U
|
||||
M$7 14 5 6 14 LVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U
|
||||
* device instance $8 14.05,5.8 LVPMOS
|
||||
M$8 14 6 7 14 MLVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U
|
||||
M$8 14 6 7 14 LVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U
|
||||
* device instance $9 15.85,5.8 LVPMOS
|
||||
M$9 14 7 8 14 MLVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U
|
||||
M$9 14 7 8 14 LVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U
|
||||
* device instance $10 17.65,5.8 LVPMOS
|
||||
M$10 14 8 9 14 MLVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U
|
||||
M$10 14 8 9 14 LVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U
|
||||
* device instance $11 19.45,5.8 LVPMOS
|
||||
M$11 14 9 10 14 MLVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U
|
||||
M$11 14 9 10 14 LVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U
|
||||
* device instance $12 21.25,5.8 LVPMOS
|
||||
M$12 14 10 15 14 MLVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U
|
||||
M$12 14 10 15 14 LVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U
|
||||
* device instance $13 23.05,5.8 LVPMOS
|
||||
M$13 14 15 11 14 MLVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U
|
||||
M$13 14 15 11 14 LVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U
|
||||
* device instance $14 2.65,2.135 LVNMOS
|
||||
M$14 16 13 12 16 MLVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.21375P PS=2.75U
|
||||
M$14 16 13 12 16 LVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.21375P PS=2.75U
|
||||
+ PD=1.4U
|
||||
* device instance $15 3.35,2.135 LVNMOS
|
||||
M$15 12 15 1 16 MLVNMOS L=0.25U W=0.95U AS=0.21375P AD=0.40375P PS=1.4U PD=2.75U
|
||||
M$15 12 15 1 16 LVNMOS L=0.25U W=0.95U AS=0.21375P AD=0.40375P PS=1.4U PD=2.75U
|
||||
* device instance $16 5.05,2.135 LVNMOS
|
||||
M$16 16 1 2 16 MLVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U PD=2.75U
|
||||
M$16 16 1 2 16 LVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U PD=2.75U
|
||||
* device instance $17 6.85,2.135 LVNMOS
|
||||
M$17 16 2 3 16 MLVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U PD=2.75U
|
||||
M$17 16 2 3 16 LVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U PD=2.75U
|
||||
* device instance $18 8.65,2.135 LVNMOS
|
||||
M$18 16 3 4 16 MLVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U PD=2.75U
|
||||
M$18 16 3 4 16 LVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U PD=2.75U
|
||||
* device instance $19 10.45,2.135 LVNMOS
|
||||
M$19 16 4 5 16 MLVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U PD=2.75U
|
||||
M$19 16 4 5 16 LVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U PD=2.75U
|
||||
* device instance $20 12.25,2.135 LVNMOS
|
||||
M$20 16 5 6 16 MLVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U PD=2.75U
|
||||
M$20 16 5 6 16 LVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U PD=2.75U
|
||||
* device instance $21 14.05,2.135 LVNMOS
|
||||
M$21 16 6 7 16 MLVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U PD=2.75U
|
||||
M$21 16 6 7 16 LVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U PD=2.75U
|
||||
* device instance $22 15.85,2.135 LVNMOS
|
||||
M$22 16 7 8 16 MLVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U PD=2.75U
|
||||
M$22 16 7 8 16 LVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U PD=2.75U
|
||||
* device instance $23 17.65,2.135 LVNMOS
|
||||
M$23 16 8 9 16 MLVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U PD=2.75U
|
||||
M$23 16 8 9 16 LVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U PD=2.75U
|
||||
* device instance $24 19.45,2.135 LVNMOS
|
||||
M$24 16 9 10 16 MLVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U
|
||||
M$24 16 9 10 16 LVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U
|
||||
+ PD=2.75U
|
||||
* device instance $25 21.25,2.135 LVNMOS
|
||||
M$25 16 10 15 16 MLVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U
|
||||
M$25 16 10 15 16 LVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U
|
||||
+ PD=2.75U
|
||||
* device instance $26 23.05,2.135 LVNMOS
|
||||
M$26 16 15 11 16 MLVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U
|
||||
M$26 16 15 11 16 LVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U
|
||||
+ PD=2.75U
|
||||
.ENDS RINGO
|
||||
|
|
|
|||
|
|
@ -13,5 +13,5 @@ R$2 3 1 7650
|
|||
* device instance $3 4.665,0.335 RES
|
||||
R$3 3 2 2670
|
||||
* device instance $4 1.765,7.485 HVPMOS
|
||||
M$4 6 4 7 7 MHVPMOS L=0.25U W=1.5U AS=0.63P AD=0.63P PS=3.84U PD=3.84U
|
||||
M$4 6 4 7 7 HVPMOS L=0.25U W=1.5U AS=0.63P AD=0.63P PS=3.84U PD=3.84U
|
||||
.ENDS TOP
|
||||
|
|
|
|||
|
|
@ -15,5 +15,5 @@ R$1 4 1 7650
|
|||
* device instance $2 2.85,0.335 RES
|
||||
R$2 2 1 10320
|
||||
* device instance $4 1.765,7.485 HVPMOS
|
||||
M$4 4 3 5 5 MHVPMOS L=0.25U W=1.5U AS=0.63P AD=0.63P PS=3.84U PD=3.84U
|
||||
M$4 4 3 5 5 HVPMOS L=0.25U W=1.5U AS=0.63P AD=0.63P PS=3.84U PD=3.84U
|
||||
.ENDS TOP
|
||||
|
|
|
|||
|
|
@ -0,0 +1,68 @@
|
|||
* RINGO netlist
|
||||
|
||||
* cell RINGO
|
||||
.SUBCKT RINGO
|
||||
* net 1 FB
|
||||
* net 2 OSC
|
||||
* net 3 NEXT
|
||||
* net 4 VSSZ,VSS
|
||||
* net 5 VDDZ,VDD
|
||||
* cell instance $1 r180 *1 -0.24,9.18
|
||||
X$1 16 1 2 4 5 INV2
|
||||
* cell instance $2 r0 *1 0,0
|
||||
X$2 1 14 15 4 5 INV2
|
||||
* cell instance $3 r180 *1 10.32,9.18
|
||||
X$3 3 9 19 4 5 INV2
|
||||
* cell instance $4 r0 *1 10.56,0
|
||||
X$4 20 10 3 4 5 INV2
|
||||
* cell instance $5 r180 *1 7.68,9.18
|
||||
X$5 19 8 18 4 5 INV2
|
||||
* cell instance $6 r180 *1 5.04,9.18
|
||||
X$6 18 7 17 4 5 INV2
|
||||
* cell instance $7 r180 *1 2.4,9.18
|
||||
X$7 17 6 16 4 5 INV2
|
||||
* cell instance $8 r0 *1 2.64,0
|
||||
X$8 15 13 22 4 5 INV2
|
||||
* cell instance $9 r0 *1 5.28,0
|
||||
X$9 22 12 21 4 5 INV2
|
||||
* cell instance $10 r0 *1 7.92,0
|
||||
X$10 21 11 20 4 5 INV2
|
||||
.ENDS RINGO
|
||||
|
||||
* cell INV2
|
||||
* pin IN
|
||||
* pin
|
||||
* pin OUT
|
||||
* pin
|
||||
* pin
|
||||
.SUBCKT INV2 1 2 3 4 5
|
||||
* net 1 IN
|
||||
* net 3 OUT
|
||||
* cell instance $1 r0 *1 -0.4,0
|
||||
X$1 2 4 1 TRANS
|
||||
* cell instance $2 r0 *1 -0.4,2.8
|
||||
X$2 2 5 1 TRANS
|
||||
* cell instance $3 m0 *1 0.4,2.8
|
||||
X$3 5 3 2 TRANS
|
||||
* cell instance $4 m0 *1 0.4,0
|
||||
X$4 4 3 2 TRANS
|
||||
* device instance $1 -0.4,0 PMOS
|
||||
M$1 2 1 4 2 PMOS L=0.25U W=0.95U AS=0.49875P AD=0.26125P PS=2.95U PD=1.5U
|
||||
* device instance $2 0.4,0 PMOS
|
||||
M$2 4 2 3 4 PMOS L=0.25U W=0.95U AS=0.26125P AD=0.49875P PS=1.5U PD=2.95U
|
||||
* device instance $3 -0.4,2.8 PMOS
|
||||
M$3 2 1 5 2 PMOS L=0.25U W=0.95U AS=0.49875P AD=0.26125P PS=2.95U PD=1.5U
|
||||
* device instance $4 0.4,2.8 PMOS
|
||||
M$4 5 2 3 5 PMOS L=0.25U W=0.95U AS=0.26125P AD=0.49875P PS=1.5U PD=2.95U
|
||||
* device instance $5 -0.4,0 NMOS
|
||||
M$5 2 1 4 2 NMOS L=0.25U W=0.95U AS=0.49875P AD=0.26125P PS=2.95U PD=1.5U
|
||||
* device instance $6 0.4,0 NMOS
|
||||
M$6 4 2 3 4 NMOS L=0.25U W=0.95U AS=0.26125P AD=0.49875P PS=1.5U PD=2.95U
|
||||
.ENDS INV2
|
||||
|
||||
* cell TRANS
|
||||
* pin
|
||||
* pin
|
||||
* pin
|
||||
.SUBCKT TRANS 1 2 3
|
||||
.ENDS TRANS
|
||||
|
|
@ -77,13 +77,13 @@ X$5 5 POLYM1
|
|||
* cell instance $6 r0 *1 0.8,3.1
|
||||
X$6 6 POLYM1
|
||||
* device instance $1 0.85,5.8 LVPMOS
|
||||
M$1 2 6 1 4 MLVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.3375P PS=3.85U PD=1.95U
|
||||
M$1 2 6 1 4 LVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.3375P PS=3.85U PD=1.95U
|
||||
* device instance $2 1.55,5.8 LVPMOS
|
||||
M$2 1 5 2 4 MLVPMOS L=0.25U W=1.5U AS=0.3375P AD=0.6375P PS=1.95U PD=3.85U
|
||||
M$2 1 5 2 4 LVPMOS L=0.25U W=1.5U AS=0.3375P AD=0.6375P PS=1.95U PD=3.85U
|
||||
* device instance $3 0.85,2.135 LVNMOS
|
||||
M$3 3 6 10 9 MLVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.21375P PS=2.75U PD=1.4U
|
||||
M$3 3 6 10 9 LVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.21375P PS=2.75U PD=1.4U
|
||||
* device instance $4 1.55,2.135 LVNMOS
|
||||
M$4 10 5 2 9 MLVNMOS L=0.25U W=0.95U AS=0.21375P AD=0.40375P PS=1.4U PD=2.75U
|
||||
M$4 10 5 2 9 LVNMOS L=0.25U W=0.95U AS=0.21375P AD=0.40375P PS=1.4U PD=2.75U
|
||||
.ENDS ND2X1
|
||||
|
||||
* cell INVX1
|
||||
|
|
@ -106,9 +106,9 @@ X$2 5 2 3 NMOS2
|
|||
* cell instance $3 r0 *1 0.6,3.1
|
||||
X$3 5 POLYM1
|
||||
* device instance $1 0.85,5.8 LVPMOS
|
||||
M$1 1 5 2 4 MLVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U
|
||||
M$1 1 5 2 4 LVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U
|
||||
* device instance $2 0.85,2.135 LVNMOS
|
||||
M$2 3 5 2 7 MLVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U PD=2.75U
|
||||
M$2 3 5 2 7 LVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U PD=2.75U
|
||||
.ENDS INVX1
|
||||
|
||||
* cell M1M2
|
||||
|
|
|
|||
|
|
@ -54,13 +54,13 @@ X$12 12 13 15 12 11 15 INVX1
|
|||
* net 6 A
|
||||
* net 7 BULK
|
||||
* device instance $1 0.85,5.8 LVPMOS
|
||||
M$1 2 6 1 4 MLVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.3375P PS=3.85U PD=1.95U
|
||||
M$1 2 6 1 4 LVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.3375P PS=3.85U PD=1.95U
|
||||
* device instance $2 1.55,5.8 LVPMOS
|
||||
M$2 1 5 2 4 MLVPMOS L=0.25U W=1.5U AS=0.3375P AD=0.6375P PS=1.95U PD=3.85U
|
||||
M$2 1 5 2 4 LVPMOS L=0.25U W=1.5U AS=0.3375P AD=0.6375P PS=1.95U PD=3.85U
|
||||
* device instance $3 0.85,2.135 LVNMOS
|
||||
M$3 3 6 8 7 MLVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.21375P PS=2.75U PD=1.4U
|
||||
M$3 3 6 8 7 LVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.21375P PS=2.75U PD=1.4U
|
||||
* device instance $4 1.55,2.135 LVNMOS
|
||||
M$4 8 5 2 7 MLVNMOS L=0.25U W=0.95U AS=0.21375P AD=0.40375P PS=1.4U PD=2.75U
|
||||
M$4 8 5 2 7 LVNMOS L=0.25U W=0.95U AS=0.21375P AD=0.40375P PS=1.4U PD=2.75U
|
||||
.ENDS ND2X1
|
||||
|
||||
* cell INVX1
|
||||
|
|
@ -77,7 +77,7 @@ M$4 8 5 2 7 MLVNMOS L=0.25U W=0.95U AS=0.21375P AD=0.40375P PS=1.4U PD=2.75U
|
|||
* net 5 IN
|
||||
* net 6 BULK
|
||||
* device instance $1 0.85,5.8 LVPMOS
|
||||
M$1 1 5 2 4 MLVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U
|
||||
M$1 1 5 2 4 LVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U
|
||||
* device instance $2 0.85,2.135 LVNMOS
|
||||
M$2 3 5 2 6 MLVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U PD=2.75U
|
||||
M$2 3 5 2 6 LVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U PD=2.75U
|
||||
.ENDS INVX1
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -97,23 +97,26 @@ class DBLayoutToNetlist_TestClass < TestBase
|
|||
l2n.extract_netlist
|
||||
|
||||
assert_equal(l2n.netlist.to_s, <<END)
|
||||
Circuit TRANS ($1=$1,$2=$2):
|
||||
Circuit INV2 (OUT=OUT,$2=$2,$3=$3,$4=$4):
|
||||
XTRANS $1 ($1=$4,$2=OUT)
|
||||
XTRANS $2 ($1=$3,$2=OUT)
|
||||
XTRANS $3 ($1=$2,$2=$4)
|
||||
XTRANS $4 ($1=$2,$2=$3)
|
||||
Circuit RINGO ():
|
||||
XINV2 $1 (OUT=OSC,$2=FB,$3=VSS,$4=VDD)
|
||||
XINV2 $2 (OUT=$I29,$2=$I20,$3=VSS,$4=VDD)
|
||||
XINV2 $3 (OUT=$I28,$2=$I19,$3=VSS,$4=VDD)
|
||||
XINV2 $4 (OUT=$I30,$2=$I21,$3=VSS,$4=VDD)
|
||||
XINV2 $5 (OUT=$I31,$2=$I22,$3=VSS,$4=VDD)
|
||||
XINV2 $6 (OUT=$I32,$2=$I23,$3=VSS,$4=VDD)
|
||||
XINV2 $7 (OUT=$I33,$2=$I24,$3=VSS,$4=VDD)
|
||||
XINV2 $8 (OUT=$I34,$2=$I25,$3=VSS,$4=VDD)
|
||||
XINV2 $9 (OUT=$I35,$2=$I26,$3=VSS,$4=VDD)
|
||||
XINV2 $10 (OUT=$I36,$2=$I27,$3=VSS,$4=VDD)
|
||||
circuit TRANS ($1=$1,$2=$2);
|
||||
end;
|
||||
circuit INV2 (OUT=OUT,$2=$2,$3=$3,$4=$4);
|
||||
subcircuit TRANS $1 ($1=$4,$2=OUT);
|
||||
subcircuit TRANS $2 ($1=$3,$2=OUT);
|
||||
subcircuit TRANS $3 ($1=$2,$2=$4);
|
||||
subcircuit TRANS $4 ($1=$2,$2=$3);
|
||||
end;
|
||||
circuit RINGO ();
|
||||
subcircuit INV2 $1 (OUT=OSC,$2=FB,$3=VSS,$4=VDD);
|
||||
subcircuit INV2 $2 (OUT=$I29,$2=$I20,$3=VSS,$4=VDD);
|
||||
subcircuit INV2 $3 (OUT=$I28,$2=$I19,$3=VSS,$4=VDD);
|
||||
subcircuit INV2 $4 (OUT=$I30,$2=$I21,$3=VSS,$4=VDD);
|
||||
subcircuit INV2 $5 (OUT=$I31,$2=$I22,$3=VSS,$4=VDD);
|
||||
subcircuit INV2 $6 (OUT=$I32,$2=$I23,$3=VSS,$4=VDD);
|
||||
subcircuit INV2 $7 (OUT=$I33,$2=$I24,$3=VSS,$4=VDD);
|
||||
subcircuit INV2 $8 (OUT=$I34,$2=$I25,$3=VSS,$4=VDD);
|
||||
subcircuit INV2 $9 (OUT=$I35,$2=$I26,$3=VSS,$4=VDD);
|
||||
subcircuit INV2 $10 (OUT=$I36,$2=$I27,$3=VSS,$4=VDD);
|
||||
end;
|
||||
END
|
||||
|
||||
assert_equal(l2n.probe_net(rmetal2, RBA::DPoint::new(0.0, 1.8)).inspect, "RINGO:FB")
|
||||
|
|
@ -180,23 +183,26 @@ END
|
|||
l2n.extract_netlist
|
||||
|
||||
assert_equal(l2n.netlist.to_s, <<END)
|
||||
Circuit TRANS ($1=$1,$2=$2,$3=$3):
|
||||
Circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5):
|
||||
XTRANS $1 ($1=$2,$2=$4,$3=IN)
|
||||
XTRANS $2 ($1=$2,$2=$5,$3=IN)
|
||||
XTRANS $3 ($1=$5,$2=OUT,$3=$2)
|
||||
XTRANS $4 ($1=$4,$2=OUT,$3=$2)
|
||||
Circuit RINGO ():
|
||||
XINV2 $1 (IN=$I8,$2=FB,OUT=OSC,$4=VSS,$5=VDD)
|
||||
XINV2 $2 (IN=FB,$2=$I38,OUT=$I19,$4=VSS,$5=VDD)
|
||||
XINV2 $3 (IN=$I19,$2=$I39,OUT=$I1,$4=VSS,$5=VDD)
|
||||
XINV2 $4 (IN=$I1,$2=$I40,OUT=$I2,$4=VSS,$5=VDD)
|
||||
XINV2 $5 (IN=$I2,$2=$I41,OUT=$I3,$4=VSS,$5=VDD)
|
||||
XINV2 $6 (IN=$I3,$2=$I42,OUT=$I4,$4=VSS,$5=VDD)
|
||||
XINV2 $7 (IN=$I4,$2=$I43,OUT=$I5,$4=VSS,$5=VDD)
|
||||
XINV2 $8 (IN=$I5,$2=$I44,OUT=$I6,$4=VSS,$5=VDD)
|
||||
XINV2 $9 (IN=$I6,$2=$I45,OUT=$I7,$4=VSS,$5=VDD)
|
||||
XINV2 $10 (IN=$I7,$2=$I46,OUT=$I8,$4=VSS,$5=VDD)
|
||||
circuit TRANS ($1=$1,$2=$2,$3=$3);
|
||||
end;
|
||||
circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5);
|
||||
subcircuit TRANS $1 ($1=$2,$2=$4,$3=IN);
|
||||
subcircuit TRANS $2 ($1=$2,$2=$5,$3=IN);
|
||||
subcircuit TRANS $3 ($1=$5,$2=OUT,$3=$2);
|
||||
subcircuit TRANS $4 ($1=$4,$2=OUT,$3=$2);
|
||||
end;
|
||||
circuit RINGO ();
|
||||
subcircuit INV2 $1 (IN=$I8,$2=FB,OUT=OSC,$4=VSS,$5=VDD);
|
||||
subcircuit INV2 $2 (IN=FB,$2=$I38,OUT=$I19,$4=VSS,$5=VDD);
|
||||
subcircuit INV2 $3 (IN=$I19,$2=$I39,OUT=$I1,$4=VSS,$5=VDD);
|
||||
subcircuit INV2 $4 (IN=$I1,$2=$I40,OUT=$I2,$4=VSS,$5=VDD);
|
||||
subcircuit INV2 $5 (IN=$I2,$2=$I41,OUT=$I3,$4=VSS,$5=VDD);
|
||||
subcircuit INV2 $6 (IN=$I3,$2=$I42,OUT=$I4,$4=VSS,$5=VDD);
|
||||
subcircuit INV2 $7 (IN=$I4,$2=$I43,OUT=$I5,$4=VSS,$5=VDD);
|
||||
subcircuit INV2 $8 (IN=$I5,$2=$I44,OUT=$I6,$4=VSS,$5=VDD);
|
||||
subcircuit INV2 $9 (IN=$I6,$2=$I45,OUT=$I7,$4=VSS,$5=VDD);
|
||||
subcircuit INV2 $10 (IN=$I7,$2=$I46,OUT=$I8,$4=VSS,$5=VDD);
|
||||
end;
|
||||
END
|
||||
|
||||
end
|
||||
|
|
@ -267,27 +273,30 @@ END
|
|||
l2n.extract_netlist
|
||||
|
||||
assert_equal(l2n.netlist.to_s, <<END)
|
||||
Circuit RINGO ():
|
||||
XINV2 $1 (IN=$I8,$2=FB,OUT=OSC,$4=VSS,$5=VDD)
|
||||
XINV2 $2 (IN=FB,$2=$I38,OUT=$I19,$4=VSS,$5=VDD)
|
||||
XINV2 $3 (IN=$I19,$2=$I39,OUT=$I1,$4=VSS,$5=VDD)
|
||||
XINV2 $4 (IN=$I1,$2=$I40,OUT=$I2,$4=VSS,$5=VDD)
|
||||
XINV2 $5 (IN=$I2,$2=$I41,OUT=$I3,$4=VSS,$5=VDD)
|
||||
XINV2 $6 (IN=$I3,$2=$I42,OUT=$I4,$4=VSS,$5=VDD)
|
||||
XINV2 $7 (IN=$I4,$2=$I43,OUT=$I5,$4=VSS,$5=VDD)
|
||||
XINV2 $8 (IN=$I5,$2=$I44,OUT=$I6,$4=VSS,$5=VDD)
|
||||
XINV2 $9 (IN=$I6,$2=$I45,OUT=$I7,$4=VSS,$5=VDD)
|
||||
XINV2 $10 (IN=$I7,$2=$I46,OUT=$I8,$4=VSS,$5=VDD)
|
||||
Circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5):
|
||||
DPMOS $1 (S=$2,G=IN,D=$5) [L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5]
|
||||
DPMOS $2 (S=$5,G=$2,D=OUT) [L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95]
|
||||
DNMOS $3 (S=$2,G=IN,D=$4) [L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5]
|
||||
DNMOS $4 (S=$4,G=$2,D=OUT) [L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95]
|
||||
XTRANS $1 ($1=$2,$2=$4,$3=IN)
|
||||
XTRANS $2 ($1=$2,$2=$5,$3=IN)
|
||||
XTRANS $3 ($1=$5,$2=OUT,$3=$2)
|
||||
XTRANS $4 ($1=$4,$2=OUT,$3=$2)
|
||||
Circuit TRANS ($1=$1,$2=$2,$3=$3):
|
||||
circuit RINGO ();
|
||||
subcircuit INV2 $1 (IN=$I8,$2=FB,OUT=OSC,$4=VSS,$5=VDD);
|
||||
subcircuit INV2 $2 (IN=FB,$2=$I38,OUT=$I19,$4=VSS,$5=VDD);
|
||||
subcircuit INV2 $3 (IN=$I19,$2=$I39,OUT=$I1,$4=VSS,$5=VDD);
|
||||
subcircuit INV2 $4 (IN=$I1,$2=$I40,OUT=$I2,$4=VSS,$5=VDD);
|
||||
subcircuit INV2 $5 (IN=$I2,$2=$I41,OUT=$I3,$4=VSS,$5=VDD);
|
||||
subcircuit INV2 $6 (IN=$I3,$2=$I42,OUT=$I4,$4=VSS,$5=VDD);
|
||||
subcircuit INV2 $7 (IN=$I4,$2=$I43,OUT=$I5,$4=VSS,$5=VDD);
|
||||
subcircuit INV2 $8 (IN=$I5,$2=$I44,OUT=$I6,$4=VSS,$5=VDD);
|
||||
subcircuit INV2 $9 (IN=$I6,$2=$I45,OUT=$I7,$4=VSS,$5=VDD);
|
||||
subcircuit INV2 $10 (IN=$I7,$2=$I46,OUT=$I8,$4=VSS,$5=VDD);
|
||||
end;
|
||||
circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5);
|
||||
device PMOS $1 (S=$2,G=IN,D=$5) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device PMOS $2 (S=$5,G=$2,D=OUT) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);
|
||||
device NMOS $3 (S=$2,G=IN,D=$4) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device NMOS $4 (S=$4,G=$2,D=OUT) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);
|
||||
subcircuit TRANS $1 ($1=$2,$2=$4,$3=IN);
|
||||
subcircuit TRANS $2 ($1=$2,$2=$5,$3=IN);
|
||||
subcircuit TRANS $3 ($1=$5,$2=OUT,$3=$2);
|
||||
subcircuit TRANS $4 ($1=$4,$2=OUT,$3=$2);
|
||||
end;
|
||||
circuit TRANS ($1=$1,$2=$2,$3=$3);
|
||||
end;
|
||||
END
|
||||
|
||||
# cleanup now
|
||||
|
|
@ -380,25 +389,29 @@ END
|
|||
l2n.extract_netlist
|
||||
|
||||
assert_equal(l2n.netlist.to_s, <<END)
|
||||
Circuit RINGO ():
|
||||
XINV2PAIR $1 (BULK='BULK,VSS',$2=FB,$3=VDD,$4='BULK,VSS',$5=$I7,$6=OSC,$7=VDD)
|
||||
XINV2PAIR $2 (BULK='BULK,VSS',$2=$I22,$3=VDD,$4='BULK,VSS',$5=FB,$6=$I13,$7=VDD)
|
||||
XINV2PAIR $3 (BULK='BULK,VSS',$2=$I23,$3=VDD,$4='BULK,VSS',$5=$I13,$6=$I5,$7=VDD)
|
||||
XINV2PAIR $4 (BULK='BULK,VSS',$2=$I24,$3=VDD,$4='BULK,VSS',$5=$I5,$6=$I6,$7=VDD)
|
||||
XINV2PAIR $5 (BULK='BULK,VSS',$2=$I25,$3=VDD,$4='BULK,VSS',$5=$I6,$6=$I7,$7=VDD)
|
||||
Circuit INV2PAIR (BULK=BULK,$2=$I8,$3=$I6,$4=$I5,$5=$I3,$6=$I2,$7=$I1):
|
||||
XINV2 $1 ($1=$I1,IN=$I3,$3=$I7,OUT=$I4,VSS=$I5,VDD=$I6,BULK=BULK)
|
||||
XINV2 $2 ($1=$I1,IN=$I4,$3=$I8,OUT=$I2,VSS=$I5,VDD=$I6,BULK=BULK)
|
||||
Circuit INV2 ($1=$1,IN=IN,$3=$3,OUT=OUT,VSS=VSS,VDD=VDD,BULK=BULK):
|
||||
DPMOS $1 (S=$3,G=IN,D=VDD,B=$1) [L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5]
|
||||
DPMOS $2 (S=VDD,G=$3,D=OUT,B=$1) [L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95]
|
||||
DNMOS $3 (S=$3,G=IN,D=VSS,B=BULK) [L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5]
|
||||
DNMOS $4 (S=VSS,G=$3,D=OUT,B=BULK) [L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95]
|
||||
XTRANS $1 ($1=$3,$2=VSS,$3=IN)
|
||||
XTRANS $2 ($1=$3,$2=VDD,$3=IN)
|
||||
XTRANS $3 ($1=VDD,$2=OUT,$3=$3)
|
||||
XTRANS $4 ($1=VSS,$2=OUT,$3=$3)
|
||||
Circuit TRANS ($1=$1,$2=$2,$3=$3):
|
||||
circuit RINGO ();
|
||||
subcircuit INV2PAIR $1 (BULK='BULK,VSS',$2=FB,$3=VDD,$4='BULK,VSS',$5=$I7,$6=OSC,$7=VDD);
|
||||
subcircuit INV2PAIR $2 (BULK='BULK,VSS',$2=$I22,$3=VDD,$4='BULK,VSS',$5=FB,$6=$I13,$7=VDD);
|
||||
subcircuit INV2PAIR $3 (BULK='BULK,VSS',$2=$I23,$3=VDD,$4='BULK,VSS',$5=$I13,$6=$I5,$7=VDD);
|
||||
subcircuit INV2PAIR $4 (BULK='BULK,VSS',$2=$I24,$3=VDD,$4='BULK,VSS',$5=$I5,$6=$I6,$7=VDD);
|
||||
subcircuit INV2PAIR $5 (BULK='BULK,VSS',$2=$I25,$3=VDD,$4='BULK,VSS',$5=$I6,$6=$I7,$7=VDD);
|
||||
end;
|
||||
circuit INV2PAIR (BULK=BULK,$2=$I8,$3=$I6,$4=$I5,$5=$I3,$6=$I2,$7=$I1);
|
||||
subcircuit INV2 $1 ($1=$I1,IN=$I3,$3=$I7,OUT=$I4,VSS=$I5,VDD=$I6,BULK=BULK);
|
||||
subcircuit INV2 $2 ($1=$I1,IN=$I4,$3=$I8,OUT=$I2,VSS=$I5,VDD=$I6,BULK=BULK);
|
||||
end;
|
||||
circuit INV2 ($1=$1,IN=IN,$3=$3,OUT=OUT,VSS=VSS,VDD=VDD,BULK=BULK);
|
||||
device PMOS $1 (S=$3,G=IN,D=VDD,B=$1) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device PMOS $2 (S=VDD,G=$3,D=OUT,B=$1) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);
|
||||
device NMOS $3 (S=$3,G=IN,D=VSS,B=BULK) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device NMOS $4 (S=VSS,G=$3,D=OUT,B=BULK) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);
|
||||
subcircuit TRANS $1 ($1=$3,$2=VSS,$3=IN);
|
||||
subcircuit TRANS $2 ($1=$3,$2=VDD,$3=IN);
|
||||
subcircuit TRANS $3 ($1=VDD,$2=OUT,$3=$3);
|
||||
subcircuit TRANS $4 ($1=VSS,$2=OUT,$3=$3);
|
||||
end;
|
||||
circuit TRANS ($1=$1,$2=$2,$3=$3);
|
||||
end;
|
||||
END
|
||||
|
||||
l2n.netlist.combine_devices
|
||||
|
|
@ -406,20 +419,23 @@ END
|
|||
l2n.netlist.purge
|
||||
|
||||
assert_equal(l2n.netlist.to_s, <<END)
|
||||
Circuit RINGO (FB=FB,OSC=OSC,VDD=VDD,'BULK,VSS'='BULK,VSS'):
|
||||
XINV2PAIR $1 (BULK='BULK,VSS',$2=FB,$3=VDD,$4='BULK,VSS',$5=$I7,$6=OSC,$7=VDD)
|
||||
XINV2PAIR $2 (BULK='BULK,VSS',$2=(null),$3=VDD,$4='BULK,VSS',$5=FB,$6=$I13,$7=VDD)
|
||||
XINV2PAIR $3 (BULK='BULK,VSS',$2=(null),$3=VDD,$4='BULK,VSS',$5=$I13,$6=$I5,$7=VDD)
|
||||
XINV2PAIR $4 (BULK='BULK,VSS',$2=(null),$3=VDD,$4='BULK,VSS',$5=$I5,$6=$I6,$7=VDD)
|
||||
XINV2PAIR $5 (BULK='BULK,VSS',$2=(null),$3=VDD,$4='BULK,VSS',$5=$I6,$6=$I7,$7=VDD)
|
||||
Circuit INV2PAIR (BULK=BULK,$2=$I8,$3=$I6,$4=$I5,$5=$I3,$6=$I2,$7=$I1):
|
||||
XINV2 $1 ($1=$I1,IN=$I3,$3=(null),OUT=$I4,VSS=$I5,VDD=$I6,BULK=BULK)
|
||||
XINV2 $2 ($1=$I1,IN=$I4,$3=$I8,OUT=$I2,VSS=$I5,VDD=$I6,BULK=BULK)
|
||||
Circuit INV2 ($1=$1,IN=IN,$3=$3,OUT=OUT,VSS=VSS,VDD=VDD,BULK=BULK):
|
||||
DPMOS $1 (S=$3,G=IN,D=VDD,B=$1) [L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5]
|
||||
DPMOS $2 (S=VDD,G=$3,D=OUT,B=$1) [L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95]
|
||||
DNMOS $3 (S=$3,G=IN,D=VSS,B=BULK) [L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5]
|
||||
DNMOS $4 (S=VSS,G=$3,D=OUT,B=BULK) [L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95]
|
||||
circuit RINGO (FB=FB,OSC=OSC,VDD=VDD,'BULK,VSS'='BULK,VSS');
|
||||
subcircuit INV2PAIR $1 (BULK='BULK,VSS',$2=FB,$3=VDD,$4='BULK,VSS',$5=$I7,$6=OSC,$7=VDD);
|
||||
subcircuit INV2PAIR $2 (BULK='BULK,VSS',$2=(null),$3=VDD,$4='BULK,VSS',$5=FB,$6=$I13,$7=VDD);
|
||||
subcircuit INV2PAIR $3 (BULK='BULK,VSS',$2=(null),$3=VDD,$4='BULK,VSS',$5=$I13,$6=$I5,$7=VDD);
|
||||
subcircuit INV2PAIR $4 (BULK='BULK,VSS',$2=(null),$3=VDD,$4='BULK,VSS',$5=$I5,$6=$I6,$7=VDD);
|
||||
subcircuit INV2PAIR $5 (BULK='BULK,VSS',$2=(null),$3=VDD,$4='BULK,VSS',$5=$I6,$6=$I7,$7=VDD);
|
||||
end;
|
||||
circuit INV2PAIR (BULK=BULK,$2=$I8,$3=$I6,$4=$I5,$5=$I3,$6=$I2,$7=$I1);
|
||||
subcircuit INV2 $1 ($1=$I1,IN=$I3,$3=(null),OUT=$I4,VSS=$I5,VDD=$I6,BULK=BULK);
|
||||
subcircuit INV2 $2 ($1=$I1,IN=$I4,$3=$I8,OUT=$I2,VSS=$I5,VDD=$I6,BULK=BULK);
|
||||
end;
|
||||
circuit INV2 ($1=$1,IN=IN,$3=$3,OUT=OUT,VSS=VSS,VDD=VDD,BULK=BULK);
|
||||
device PMOS $1 (S=$3,G=IN,D=VDD,B=$1) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device PMOS $2 (S=VDD,G=$3,D=OUT,B=$1) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);
|
||||
device NMOS $3 (S=$3,G=IN,D=VSS,B=BULK) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device NMOS $4 (S=VSS,G=$3,D=OUT,B=BULK) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);
|
||||
end;
|
||||
END
|
||||
|
||||
# cleanup now
|
||||
|
|
|
|||
|
|
@ -105,6 +105,9 @@ class DBNetlist_TestClass < TestBase
|
|||
nl.add(cc)
|
||||
cc.name = "UVW"
|
||||
|
||||
assert_equal(nl.device_class_by_name("UVW") == cc, true)
|
||||
assert_equal(nl.device_class_by_name("doesntexist") == nil, true)
|
||||
|
||||
names = []
|
||||
nl.each_device_class { |i| names << i.name }
|
||||
assert_equal(names, [ c.name, cc.name ])
|
||||
|
|
@ -439,6 +442,10 @@ class DBNetlist_TestClass < TestBase
|
|||
assert_equal(pd.default_value, 2.0)
|
||||
pd.default_value = 1.0
|
||||
assert_equal(pd.default_value, 1.0)
|
||||
pd.is_primary = false
|
||||
assert_equal(pd.is_primary?, false)
|
||||
pd.is_primary = true
|
||||
assert_equal(pd.is_primary?, true)
|
||||
|
||||
dc.add_parameter(pd)
|
||||
|
||||
|
|
@ -610,8 +617,9 @@ class DBNetlist_TestClass < TestBase
|
|||
assert_equal(d1.parameter(1), 42)
|
||||
|
||||
assert_equal(nl.to_s, <<END)
|
||||
Circuit C ():
|
||||
DDC $1 () [U=-0.5,V=42]
|
||||
circuit C ();
|
||||
device DC $1 () (U=-0.5,V=42);
|
||||
end;
|
||||
END
|
||||
|
||||
end
|
||||
|
|
@ -710,6 +718,66 @@ END
|
|||
|
||||
end
|
||||
|
||||
def test_11_FlattenCircuits
|
||||
|
||||
nl = RBA::Netlist::new
|
||||
|
||||
dc = RBA::DeviceClassMOS3Transistor::new
|
||||
dc.name = "NMOS"
|
||||
nl.add(dc)
|
||||
|
||||
dc = RBA::DeviceClassMOS3Transistor::new
|
||||
dc.name = "PMOS"
|
||||
nl.add(dc)
|
||||
|
||||
nl.from_s(<<"END")
|
||||
circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5);
|
||||
subcircuit PTRANS SC1 ($1=$5,$2=$2,$3=IN);
|
||||
subcircuit NTRANS SC2 ($1=$4,$2=$2,$3=IN);
|
||||
subcircuit PTRANS SC3 ($1=$5,$2=OUT,$3=$2);
|
||||
subcircuit NTRANS SC4 ($1=$4,$2=OUT,$3=$2);
|
||||
end;
|
||||
circuit PTRANS ($1=$1,$2=$2,$3=$3);
|
||||
device PMOS $1 (S=$1,D=$2,G=$3) (L=0.25,W=0.95);
|
||||
end;
|
||||
circuit NTRANS ($1=$1,$2=$2,$3=$3);
|
||||
device NMOS $1 (S=$1,D=$2,G=$3) (L=0.25,W=0.95);
|
||||
end;
|
||||
END
|
||||
|
||||
nl2 = nl.dup
|
||||
inv2 = nl2.circuit_by_name("INV2")
|
||||
inv2.flatten_subcircuit(inv2.subcircuit_by_name("SC1"))
|
||||
|
||||
assert_equal(nl2.to_s, <<"END")
|
||||
circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5);
|
||||
device PMOS $1 (S=$5,G=IN,D=$2) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);
|
||||
subcircuit NTRANS SC2 ($1=$4,$2=$2,$3=IN);
|
||||
subcircuit PTRANS SC3 ($1=$5,$2=OUT,$3=$2);
|
||||
subcircuit NTRANS SC4 ($1=$4,$2=OUT,$3=$2);
|
||||
end;
|
||||
circuit PTRANS ($1=$1,$2=$2,$3=$3);
|
||||
device PMOS $1 (S=$1,G=$3,D=$2) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);
|
||||
end;
|
||||
circuit NTRANS ($1=$1,$2=$2,$3=$3);
|
||||
device NMOS $1 (S=$1,G=$3,D=$2) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);
|
||||
end;
|
||||
END
|
||||
|
||||
nl2.flatten_circuit(nl2.circuit_by_name("PTRANS"))
|
||||
nl2.flatten_circuit(nl2.circuit_by_name("NTRANS"))
|
||||
|
||||
assert_equal(nl2.to_s, <<"END")
|
||||
circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5);
|
||||
device PMOS $1 (S=$5,G=IN,D=$2) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);
|
||||
device PMOS $2 (S=$5,G=$2,D=OUT) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);
|
||||
device NMOS $3 (S=$4,G=IN,D=$2) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);
|
||||
device NMOS $4 (S=$4,G=$2,D=OUT) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);
|
||||
end;
|
||||
END
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
load("test_epilogue.rb")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,992 @@
|
|||
# encoding: UTF-8
|
||||
|
||||
# KLayout Layout Viewer
|
||||
# Copyright(C) 2006-2019 Matthias Koefferlein
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
#(at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
if !$:.member?(File::dirname($0))
|
||||
$:.push(File::dirname($0))
|
||||
end
|
||||
|
||||
load("test_prologue.rb")
|
||||
|
||||
class NetlistCompareTestLogger < RBA::GenericNetlistCompareLogger
|
||||
|
||||
def initialize
|
||||
@texts = []
|
||||
end
|
||||
|
||||
def out(text)
|
||||
@texts << text
|
||||
end
|
||||
|
||||
def device_class_mismatch(a, b)
|
||||
out("device_class_mismatch " + dc2str(a) + " " + dc2str(b))
|
||||
end
|
||||
|
||||
def begin_circuit(a, b)
|
||||
out("begin_circuit " + circuit2str(a) + " " + circuit2str(b))
|
||||
end
|
||||
|
||||
def end_circuit(a, b, matching)
|
||||
out("end_circuit " + circuit2str(a) + " " + circuit2str(b) + " " + (matching ? "MATCH" : "NOMATCH"))
|
||||
end
|
||||
|
||||
def circuit_skipped(a, b)
|
||||
out("circuit_skipped " + circuit2str(a) + " " + circuit2str(b))
|
||||
end
|
||||
|
||||
def circuit_mismatch(a, b)
|
||||
out("circuit_mismatch " + circuit2str(a) + " " + circuit2str(b))
|
||||
end
|
||||
|
||||
def match_nets(a, b)
|
||||
out("match_nets " + net2str(a) + " " + net2str(b))
|
||||
end
|
||||
|
||||
def match_ambiguous_nets(a, b)
|
||||
out("match_ambiguous_nets " + net2str(a) + " " + net2str(b))
|
||||
end
|
||||
|
||||
def net_mismatch(a, b)
|
||||
out("net_mismatch " + net2str(a) + " " + net2str(b))
|
||||
end
|
||||
|
||||
def match_devices(a, b)
|
||||
out("match_devices " + device2str(a) + " " + device2str(b))
|
||||
end
|
||||
|
||||
def device_mismatch(a, b)
|
||||
out("device_mismatch " + device2str(a) + " " + device2str(b))
|
||||
end
|
||||
|
||||
def match_devices_with_different_parameters(a, b)
|
||||
out("match_devices_with_different_parameters " + device2str(a) + " " + device2str(b))
|
||||
end
|
||||
|
||||
def match_devices_with_different_device_classes(a, b)
|
||||
out("match_devices_with_different_device_classes " + device2str(a) + " " + device2str(b))
|
||||
end
|
||||
|
||||
def match_pins(a, b)
|
||||
out("match_pins " + pin2str(a) + " " + pin2str(b))
|
||||
end
|
||||
|
||||
def pin_mismatch(a, b)
|
||||
out("pin_mismatch " + pin2str(a) + " " + pin2str(b))
|
||||
end
|
||||
|
||||
def match_subcircuits(a, b)
|
||||
out("match_subcircuits " + subcircuit2str(a) + " " + subcircuit2str(b))
|
||||
end
|
||||
|
||||
def subcircuit_mismatch(a, b)
|
||||
out("subcircuit_mismatch " + subcircuit2str(a) + " " + subcircuit2str(b))
|
||||
end
|
||||
|
||||
def text
|
||||
return @texts.join("\n") + "\n"
|
||||
end
|
||||
|
||||
def clear
|
||||
@texts = []
|
||||
end
|
||||
|
||||
def dc2str(x)
|
||||
return x ? x.name : "(null)"
|
||||
end
|
||||
|
||||
def circuit2str(x)
|
||||
return x ? x.name : "(null)"
|
||||
end
|
||||
|
||||
def device2str(x)
|
||||
return x ? x.expanded_name : "(null)"
|
||||
end
|
||||
|
||||
def net2str(x)
|
||||
return x ? x.expanded_name : "(null)"
|
||||
end
|
||||
|
||||
def pin2str(x)
|
||||
return x ? x.expanded_name : "(null)"
|
||||
end
|
||||
|
||||
def subcircuit2str(x)
|
||||
return x ? x.expanded_name : "(null)"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def prep_nl(nl, str)
|
||||
|
||||
dc = RBA::DeviceClassMOS3Transistor::new
|
||||
dc.name = "PMOS"
|
||||
nl.add(dc)
|
||||
|
||||
dc = RBA::DeviceClassMOS3Transistor::new
|
||||
dc.name = "NMOS"
|
||||
nl.add(dc)
|
||||
|
||||
dc = RBA::DeviceClassMOS3Transistor::new
|
||||
dc.name = "PMOSB"
|
||||
nl.add(dc)
|
||||
|
||||
dc = RBA::DeviceClassMOS3Transistor::new
|
||||
dc.name = "NMOSB"
|
||||
nl.add(dc)
|
||||
|
||||
dc = RBA::DeviceClassMOS4Transistor::new
|
||||
dc.name = "PMOS4"
|
||||
nl.add(dc)
|
||||
|
||||
dc = RBA::DeviceClassMOS4Transistor::new
|
||||
dc.name = "NMOS4"
|
||||
nl.add(dc)
|
||||
|
||||
dc = RBA::DeviceClassResistor::new
|
||||
dc.name = "RES"
|
||||
nl.add(dc)
|
||||
|
||||
dc = RBA::DeviceClassCapacitor::new
|
||||
dc.name = "CAP"
|
||||
nl.add(dc)
|
||||
|
||||
dc = RBA::DeviceClassInductor::new
|
||||
dc.name = "IND"
|
||||
nl.add(dc)
|
||||
|
||||
dc = RBA::DeviceClassDiode::new
|
||||
dc.name = "DIODE"
|
||||
nl.add(dc)
|
||||
|
||||
nl.from_s(str)
|
||||
|
||||
end
|
||||
|
||||
class NetlistCompare_TestClass < TestBase
|
||||
|
||||
def test_1
|
||||
|
||||
nl1 = RBA::Netlist::new
|
||||
nl2 = RBA::Netlist::new
|
||||
dc = RBA::DeviceClass::new
|
||||
dc.name = "A"
|
||||
nl1.add(dc)
|
||||
dc = RBA::DeviceClass::new
|
||||
dc.name = "B"
|
||||
nl2.add(dc)
|
||||
|
||||
logger = NetlistCompareTestLogger::new
|
||||
comp = RBA::NetlistComparer::new(logger)
|
||||
|
||||
good = comp.compare(nl1, nl2)
|
||||
|
||||
assert_equal(logger.text, <<"END")
|
||||
device_class_mismatch A (null)
|
||||
device_class_mismatch (null) B
|
||||
END
|
||||
|
||||
assert_equal(good, false)
|
||||
|
||||
nls1 = <<"END"
|
||||
circuit INV($1=IN,$2=OUT,$3=VDD,$4=VSS);
|
||||
device PMOS $1(S=VDD,G=IN,D=OUT)(L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device NMOS $2(S=VSS,G=IN,D=OUT)(L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
end;
|
||||
END
|
||||
|
||||
nls2 = <<"END"
|
||||
circuit INV($1=VDD,$2=IN,$3=VSS,$4=OUT);
|
||||
device NMOS $1(S=OUT,G=IN,D=VSS)(L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device PMOS $2(S=VDD,G=IN,D=OUT)(L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
end;
|
||||
END
|
||||
|
||||
nl1 = RBA::Netlist::new
|
||||
nl2 = RBA::Netlist::new
|
||||
prep_nl(nl1, nls1)
|
||||
prep_nl(nl2, nls2)
|
||||
|
||||
logger = NetlistCompareTestLogger::new
|
||||
comp = RBA::NetlistComparer::new(logger)
|
||||
|
||||
good = comp.compare(nl1, nl2)
|
||||
|
||||
assert_equal(logger.text, <<"END")
|
||||
begin_circuit INV INV
|
||||
match_nets VDD VDD
|
||||
match_nets OUT OUT
|
||||
match_nets IN IN
|
||||
match_nets VSS VSS
|
||||
match_pins $0 $1
|
||||
match_pins $1 $3
|
||||
match_pins $2 $0
|
||||
match_pins $3 $2
|
||||
match_devices $2 $1
|
||||
match_devices $1 $2
|
||||
end_circuit INV INV MATCH
|
||||
END
|
||||
|
||||
assert_equal(good, true)
|
||||
|
||||
end
|
||||
|
||||
def test_2
|
||||
|
||||
nls1 = <<"END"
|
||||
circuit INV($1=IN,$2=OUT,$3=VDD,$4=VSS);
|
||||
device PMOS $1(S=VDD,G=IN,D=OUT)(L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device NMOS $2(S=VSS,G=IN,D=OUT)(L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
end;
|
||||
END
|
||||
|
||||
nls2 = <<"END"
|
||||
circuit INV($1=VDD,$2=IN,$3=VSS,$4=OUT);
|
||||
device NMOSB $1(S=OUT,G=IN,D=VSS)(L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device PMOSB $2(S=VDD,G=IN,D=OUT)(L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
end;
|
||||
END
|
||||
|
||||
nl1 = RBA::Netlist::new
|
||||
nl2 = RBA::Netlist::new
|
||||
prep_nl(nl1, nls1)
|
||||
prep_nl(nl2, nls2)
|
||||
|
||||
logger = NetlistCompareTestLogger::new
|
||||
comp = RBA::NetlistComparer::new(logger)
|
||||
|
||||
comp.same_device_classes(nl1.device_class_by_name("PMOS"), nl2.device_class_by_name("PMOSB"))
|
||||
|
||||
good = comp.compare(nl1, nl2)
|
||||
assert_equal(good, false)
|
||||
|
||||
logger.clear
|
||||
comp.same_device_classes(nl1.device_class_by_name("NMOS"), nl2.device_class_by_name("NMOSB"))
|
||||
# avoids device class mismatch errors
|
||||
comp.same_device_classes(nl1.device_class_by_name("NMOSB"), nl2.device_class_by_name("NMOS"))
|
||||
comp.same_device_classes(nl1.device_class_by_name("PMOSB"), nl2.device_class_by_name("PMOS"))
|
||||
good = comp.compare(nl1, nl2)
|
||||
|
||||
assert_equal(logger.text(), <<"END")
|
||||
begin_circuit INV INV
|
||||
match_nets VDD VDD
|
||||
match_nets OUT OUT
|
||||
match_nets IN IN
|
||||
match_nets VSS VSS
|
||||
match_pins $0 $1
|
||||
match_pins $1 $3
|
||||
match_pins $2 $0
|
||||
match_pins $3 $2
|
||||
match_devices $2 $1
|
||||
match_devices $1 $2
|
||||
end_circuit INV INV MATCH
|
||||
END
|
||||
|
||||
assert_equal(good, true)
|
||||
|
||||
end
|
||||
|
||||
def test_3
|
||||
|
||||
nls1 = <<"END"
|
||||
circuit INV($1=IN,$2=OUT,$3=VDD,$4=VSS);
|
||||
device PMOS $1(S=VDD,G=IN,D=OUT)(L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device NMOS $2(S=VSS,G=IN,D=OUT)(L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
end;
|
||||
END
|
||||
|
||||
nls2 = <<"END"
|
||||
circuit INV($1=VDD,$2=IN,$3=VSS,$4=OUT);
|
||||
device NMOS $1(S=OUT,G=IN,D=VSS)(L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device PMOS $2(S=VDD,G=IN,D=OUT)(L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
end;
|
||||
END
|
||||
|
||||
nl1 = RBA::Netlist::new
|
||||
nl2 = RBA::Netlist::new
|
||||
prep_nl(nl1, nls1)
|
||||
prep_nl(nl2, nls2)
|
||||
|
||||
logger = NetlistCompareTestLogger::new
|
||||
comp = RBA::NetlistComparer::new(logger)
|
||||
|
||||
ca = nl1.circuit_by_name("INV")
|
||||
cb = nl2.circuit_by_name("INV")
|
||||
comp.same_nets(ca.net_by_name("VDD"), cb.net_by_name("VDD"))
|
||||
comp.same_nets(ca.net_by_name("VSS"), cb.net_by_name("VSS"))
|
||||
|
||||
good = comp.compare(nl1, nl2)
|
||||
|
||||
assert_equal(logger.text(), <<"END")
|
||||
begin_circuit INV INV
|
||||
match_nets OUT OUT
|
||||
match_nets IN IN
|
||||
match_pins $0 $1
|
||||
match_pins $1 $3
|
||||
match_pins $2 $0
|
||||
match_pins $3 $2
|
||||
match_devices $2 $1
|
||||
match_devices $1 $2
|
||||
end_circuit INV INV MATCH
|
||||
END
|
||||
|
||||
assert_equal(good, true)
|
||||
|
||||
end
|
||||
|
||||
def test_4
|
||||
|
||||
nls1 = <<"END"
|
||||
circuit BUF ($1=IN,$2=OUT,$3=VDD,$4=VSS);
|
||||
device PMOS $1 (S=VDD,G=IN,D=INT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device NMOS $2 (S=VSS,G=IN,D=INT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device PMOS $3 (S=VDD,G=INT,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device NMOS $4 (S=VSS,G=INT,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device PMOS $5 (S=VDD,G=IN,D=INT2) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device NMOS $6 (S=VSS,G=IN,D=INT2) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device PMOS $7 (S=VDD,G=INT2,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device NMOS $8 (S=VSS,G=INT2,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
end;
|
||||
END
|
||||
|
||||
nls2 = <<"END"
|
||||
circuit BUF ($1=VDD,$2=IN,$3=VSS,$4=OUT);
|
||||
device PMOS $1 (S=VDD,G=IN,D=$10) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device PMOS $2 (S=VDD,G=$10,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device PMOS $3 (S=VDD,G=IN,D=$11) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device PMOS $4 (S=VDD,G=$11,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device NMOS $5 (S=$10,G=IN,D=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device NMOS $6 (S=OUT,G=$10,D=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device NMOS $7 (S=$11,G=IN,D=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device NMOS $8 (S=OUT,G=$11,D=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
end;
|
||||
END
|
||||
|
||||
nl1 = RBA::Netlist::new
|
||||
nl2 = RBA::Netlist::new
|
||||
prep_nl(nl1, nls1)
|
||||
prep_nl(nl2, nls2)
|
||||
|
||||
logger = NetlistCompareTestLogger::new
|
||||
comp = RBA::NetlistComparer::new(logger)
|
||||
|
||||
good = comp.compare(nl1, nl2)
|
||||
|
||||
assert_equal(logger.text, <<"END")
|
||||
begin_circuit BUF BUF
|
||||
match_nets VDD VDD
|
||||
match_nets OUT OUT
|
||||
match_nets VSS VSS
|
||||
match_nets IN IN
|
||||
match_ambiguous_nets INT $10
|
||||
match_ambiguous_nets INT2 $11
|
||||
match_pins $0 $1
|
||||
match_pins $1 $3
|
||||
match_pins $2 $0
|
||||
match_pins $3 $2
|
||||
match_devices $1 $1
|
||||
match_devices $3 $2
|
||||
match_devices $5 $3
|
||||
match_devices $7 $4
|
||||
match_devices $2 $5
|
||||
match_devices $4 $6
|
||||
match_devices $6 $7
|
||||
match_devices $8 $8
|
||||
end_circuit BUF BUF MATCH
|
||||
END
|
||||
|
||||
assert_equal(good, true)
|
||||
|
||||
end
|
||||
|
||||
def test_5
|
||||
|
||||
nls1 = <<"END"
|
||||
circuit BUF ($1=IN,$2=OUT,$3=VDD,$4=VSS);
|
||||
device PMOS $1 (S=VDD,G=IN,D=INT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device NMOS $2 (S=VSS,G=IN,D=INT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device PMOS $3 (S=VDD,G=INT,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device NMOS $4 (S=VSS,G=INT,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device PMOS $5 (S=VDD,G=IN,D=INT2) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device NMOS $6 (S=VSS,G=IN,D=INT2) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device PMOS $7 (S=VDD,G=INT2,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device NMOS $8 (S=VSS,G=INT2,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
end;
|
||||
END
|
||||
|
||||
nls2 = <<"END"
|
||||
circuit BUF ($1=VDD,$2=IN,$3=VSS,$4=OUT);
|
||||
device PMOS $1 (S=VDD,G=IN,D=$10) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device PMOS $2 (S=VDD,G=$10,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device PMOS $3 (S=VDD,G=IN,D=$11) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device PMOS $4 (S=VDD,G=$11,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device NMOS $5 (S=$10,G=IN,D=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device NMOS $6 (S=OUT,G=$10,D=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device NMOS $7 (S=$11,G=IN,D=VSS) (L=0.35,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device NMOS $8 (S=OUT,G=$11,D=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
end;
|
||||
END
|
||||
|
||||
nl1 = RBA::Netlist::new
|
||||
nl2 = RBA::Netlist::new
|
||||
prep_nl(nl1, nls1)
|
||||
prep_nl(nl2, nls2)
|
||||
|
||||
logger = NetlistCompareTestLogger::new
|
||||
comp = RBA::NetlistComparer::new(logger)
|
||||
|
||||
# NOTE: adding this power hint makes the device class error harder to detect
|
||||
ca = nl1.circuit_by_name("BUF")
|
||||
cb = nl2.circuit_by_name("BUF")
|
||||
comp.same_nets(ca.net_by_name("VDD"), cb.net_by_name("VDD"))
|
||||
comp.same_nets(ca.net_by_name("VSS"), cb.net_by_name("VSS"))
|
||||
|
||||
good = comp.compare(nl1, nl2)
|
||||
|
||||
assert_equal(logger.text, <<"END")
|
||||
begin_circuit BUF BUF
|
||||
match_nets OUT OUT
|
||||
match_nets INT $10
|
||||
match_nets IN IN
|
||||
match_nets INT2 $11
|
||||
match_pins $0 $1
|
||||
match_pins $1 $3
|
||||
match_pins $2 $0
|
||||
match_pins $3 $2
|
||||
match_devices $1 $1
|
||||
match_devices $3 $2
|
||||
match_devices $5 $3
|
||||
match_devices $7 $4
|
||||
match_devices $2 $5
|
||||
match_devices $4 $6
|
||||
match_devices_with_different_parameters $6 $7
|
||||
match_devices $8 $8
|
||||
end_circuit BUF BUF NOMATCH
|
||||
END
|
||||
|
||||
assert_equal(good, false)
|
||||
|
||||
logger.clear
|
||||
eqp = RBA::EqualDeviceParameters::new(RBA::DeviceClassMOS3Transistor::PARAM_L, 0.2, 0.0)
|
||||
nl2.device_class_by_name("NMOS").equal_parameters = eqp
|
||||
good = comp.compare(nl1, nl2)
|
||||
|
||||
assert_equal(logger.text, <<"END")
|
||||
begin_circuit BUF BUF
|
||||
match_nets OUT OUT
|
||||
match_nets IN IN
|
||||
match_ambiguous_nets INT $10
|
||||
match_ambiguous_nets INT2 $11
|
||||
match_pins $0 $1
|
||||
match_pins $1 $3
|
||||
match_pins $2 $0
|
||||
match_pins $3 $2
|
||||
match_devices $1 $1
|
||||
match_devices $3 $2
|
||||
match_devices $5 $3
|
||||
match_devices $7 $4
|
||||
match_devices $2 $5
|
||||
match_devices $4 $6
|
||||
match_devices $6 $7
|
||||
match_devices $8 $8
|
||||
end_circuit BUF BUF MATCH
|
||||
END
|
||||
|
||||
assert_equal(good, true)
|
||||
|
||||
logger.clear
|
||||
eqp = RBA::EqualDeviceParameters::new(RBA::DeviceClassMOS3Transistor::PARAM_W, 0.01, 0.0)
|
||||
eqp = eqp + RBA::EqualDeviceParameters::new(RBA::DeviceClassMOS3Transistor::PARAM_L, 0.2, 0.0)
|
||||
nl2.device_class_by_name("NMOS").equal_parameters = eqp
|
||||
good = comp.compare(nl1, nl2)
|
||||
|
||||
assert_equal(logger.text, <<"END")
|
||||
begin_circuit BUF BUF
|
||||
match_nets OUT OUT
|
||||
match_nets IN IN
|
||||
match_ambiguous_nets INT $10
|
||||
match_ambiguous_nets INT2 $11
|
||||
match_pins $0 $1
|
||||
match_pins $1 $3
|
||||
match_pins $2 $0
|
||||
match_pins $3 $2
|
||||
match_devices $1 $1
|
||||
match_devices $3 $2
|
||||
match_devices $5 $3
|
||||
match_devices $7 $4
|
||||
match_devices $2 $5
|
||||
match_devices $4 $6
|
||||
match_devices $6 $7
|
||||
match_devices $8 $8
|
||||
end_circuit BUF BUF MATCH
|
||||
END
|
||||
|
||||
assert_equal(good, true)
|
||||
|
||||
logger.clear
|
||||
eqp = RBA::EqualDeviceParameters::new(RBA::DeviceClassMOS3Transistor::PARAM_W, 0.01, 0.0)
|
||||
eqp += RBA::EqualDeviceParameters::new(RBA::DeviceClassMOS3Transistor::PARAM_L, 0.2, 0.0)
|
||||
nl2.device_class_by_name("NMOS").equal_parameters = eqp
|
||||
good = comp.compare(nl1, nl2)
|
||||
|
||||
assert_equal(logger.text, <<"END")
|
||||
begin_circuit BUF BUF
|
||||
match_nets OUT OUT
|
||||
match_nets IN IN
|
||||
match_ambiguous_nets INT $10
|
||||
match_ambiguous_nets INT2 $11
|
||||
match_pins $0 $1
|
||||
match_pins $1 $3
|
||||
match_pins $2 $0
|
||||
match_pins $3 $2
|
||||
match_devices $1 $1
|
||||
match_devices $3 $2
|
||||
match_devices $5 $3
|
||||
match_devices $7 $4
|
||||
match_devices $2 $5
|
||||
match_devices $4 $6
|
||||
match_devices $6 $7
|
||||
match_devices $8 $8
|
||||
end_circuit BUF BUF MATCH
|
||||
END
|
||||
|
||||
assert_equal(good, true)
|
||||
|
||||
end
|
||||
|
||||
def test_6
|
||||
|
||||
nls1 = <<"END"
|
||||
circuit BUF ($1=IN,$2=OUT,$3=VDD,$4=VSS);
|
||||
device PMOS $1 (S=VDD,G=IN,D=INT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device NMOS $2 (S=VSS,G=IN,D=INT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device PMOS $3 (S=VDD,G=INT,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device NMOS $4 (S=VSS,G=INT,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device PMOS $5 (S=VDD,G=IN,D=INT2) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device NMOS $6 (S=VSS,G=IN,D=INT2) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device PMOSB $7 (S=VDD,G=INT2,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device NMOSB $8 (S=VSS,G=INT2,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
end;
|
||||
END
|
||||
|
||||
nls2 = <<"END"
|
||||
circuit BUF ($1=VDD,$2=IN,$3=VSS,$4=OUT);
|
||||
device PMOS $1 (S=VDD,G=IN,D=$10) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device PMOS $2 (S=VDD,G=$10,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device PMOS $3 (S=VDD,G=IN,D=$11) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device PMOS $4 (S=VDD,G=$11,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device NMOS $5 (S=$10,G=IN,D=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device NMOS $6 (S=OUT,G=$10,D=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device NMOS $7 (S=$11,G=IN,D=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device NMOSB $8 (S=OUT,G=$11,D=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
end;
|
||||
END
|
||||
|
||||
nl1 = RBA::Netlist::new
|
||||
nl2 = RBA::Netlist::new
|
||||
prep_nl(nl1, nls1)
|
||||
prep_nl(nl2, nls2)
|
||||
|
||||
logger = NetlistCompareTestLogger::new
|
||||
comp = RBA::NetlistComparer::new(logger)
|
||||
|
||||
# NOTE: adding this power hint makes the device class error harder to detect
|
||||
ca = nl1.circuit_by_name("BUF")
|
||||
cb = nl2.circuit_by_name("BUF")
|
||||
comp.same_nets(ca.net_by_name("VDD"), cb.net_by_name("VDD"))
|
||||
comp.same_nets(ca.net_by_name("VSS"), cb.net_by_name("VSS"))
|
||||
|
||||
good = comp.compare(nl1, nl2)
|
||||
|
||||
assert_equal(logger.text, <<"END")
|
||||
begin_circuit BUF BUF
|
||||
match_nets INT $10
|
||||
match_nets IN IN
|
||||
match_nets OUT OUT
|
||||
match_nets INT2 $11
|
||||
match_pins $0 $1
|
||||
match_pins $1 $3
|
||||
match_pins $2 $0
|
||||
match_pins $3 $2
|
||||
match_devices $1 $1
|
||||
match_devices $3 $2
|
||||
match_devices $5 $3
|
||||
match_devices_with_different_device_classes $7 $4
|
||||
match_devices $2 $5
|
||||
match_devices $4 $6
|
||||
match_devices $6 $7
|
||||
match_devices $8 $8
|
||||
end_circuit BUF BUF NOMATCH
|
||||
END
|
||||
|
||||
assert_equal(good, false)
|
||||
|
||||
end
|
||||
|
||||
def test_7
|
||||
|
||||
nls1 = <<"END"
|
||||
circuit BUF ($1=IN,$2=OUT,$3=VDD,$4=VSS);
|
||||
device PMOS $1 (S=VDD,G=IN,D=INT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device NMOS $2 (S=VSS,G=IN,D=INT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device PMOS $3 (S=VDD,G=INT,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device NMOS $4 (S=VSS,G=INT,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device PMOS $5 (S=VDD,G=IN,D=INT2) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device NMOS $6 (S=VSS,G=IN,D=INT2) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device PMOSB $7 (S=VDD,G=INT2,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device NMOSB $8 (S=VSS,G=INT2,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
end;
|
||||
END
|
||||
|
||||
nls2 = <<"END"
|
||||
circuit BUF ($1=VDD,$2=IN,$3=VSS,$4=OUT);
|
||||
device PMOS $1 (S=VDD,G=IN,D=$10) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device PMOS $2 (S=VDD,G=$10,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device PMOS $3 (S=VDD,G=IN,D=$11) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device PMOSB $4 (S=VDD,G=$11,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device NMOS $5 (S=$10,G=IN,D=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device NMOS $6 (S=OUT,G=$10,D=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device NMOS $7 (S=$11,G=IN,D=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device NMOSB $8 (S=OUT,G=$11,D=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device RES $9 (A=$10,B=$11) (R=42);
|
||||
end;
|
||||
END
|
||||
|
||||
nl1 = RBA::Netlist::new
|
||||
nl2 = RBA::Netlist::new
|
||||
prep_nl(nl1, nls1)
|
||||
prep_nl(nl2, nls2)
|
||||
|
||||
logger = NetlistCompareTestLogger::new
|
||||
comp = RBA::NetlistComparer::new(logger)
|
||||
|
||||
# Forcing the power nets into equality makes the resistor error harder to detect
|
||||
ca = nl1.circuit_by_name("BUF")
|
||||
cb = nl2.circuit_by_name("BUF")
|
||||
comp.same_nets(ca.net_by_name("VDD"), cb.net_by_name("VDD"))
|
||||
comp.same_nets(ca.net_by_name("VSS"), cb.net_by_name("VSS"))
|
||||
|
||||
good = comp.compare(nl1, nl2)
|
||||
|
||||
assert_equal(logger.text, <<"END")
|
||||
begin_circuit BUF BUF
|
||||
match_nets INT $10
|
||||
match_nets IN IN
|
||||
match_nets OUT OUT
|
||||
match_nets INT2 $11
|
||||
match_pins $0 $1
|
||||
match_pins $1 $3
|
||||
match_pins $2 $0
|
||||
match_pins $3 $2
|
||||
match_devices $1 $1
|
||||
match_devices $3 $2
|
||||
match_devices $5 $3
|
||||
match_devices $7 $4
|
||||
match_devices $2 $5
|
||||
match_devices $4 $6
|
||||
match_devices $6 $7
|
||||
match_devices $8 $8
|
||||
device_mismatch (null) $9
|
||||
end_circuit BUF BUF NOMATCH
|
||||
END
|
||||
|
||||
assert_equal(good, false)
|
||||
|
||||
end
|
||||
|
||||
def test_8
|
||||
|
||||
nls1 = <<"END"
|
||||
circuit INV ($1=IN,$2=OUT,$3=VDD,$4=VSS);
|
||||
device PMOS $1 (S=VDD,G=IN,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device NMOS $2 (S=VSS,G=IN,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
end;
|
||||
circuit TOP ($1=IN,$2=OUT,$3=VDD,$4=VSS);
|
||||
subcircuit INV $1 ($1=IN,$2=INT,$3=VDD,$4=VSS);
|
||||
subcircuit INV $2 ($1=INT,$2=OUT,$3=VDD,$4=VSS);
|
||||
end;
|
||||
END
|
||||
|
||||
nls2 = <<"END"
|
||||
circuit INVB ($1=VDD,$2=IN,$3=VSS,$4=OUT);
|
||||
device NMOS $1 (S=OUT,G=IN,D=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device PMOS $2 (S=VDD,G=IN,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
end;
|
||||
circuit TOP ($1=OUT,$2=VDD,$3=IN,$4=VSS);
|
||||
subcircuit INVB $1 ($1=VDD,$2=INT,$3=VSS,$4=OUT);
|
||||
subcircuit INVB $2 ($1=VDD,$2=IN,$3=VSS,$4=INT);
|
||||
end;
|
||||
END
|
||||
|
||||
nl1 = RBA::Netlist::new
|
||||
nl2 = RBA::Netlist::new
|
||||
prep_nl(nl1, nls1)
|
||||
prep_nl(nl2, nls2)
|
||||
|
||||
logger = NetlistCompareTestLogger::new
|
||||
comp = RBA::NetlistComparer::new(logger)
|
||||
|
||||
good = comp.compare(nl1, nl2)
|
||||
assert_equal(good, false)
|
||||
|
||||
logger.clear
|
||||
comp.same_circuits(nl1.circuit_by_name("INV"), nl2.circuit_by_name("INVB"))
|
||||
|
||||
good = comp.compare(nl1, nl2)
|
||||
|
||||
assert_equal(logger.text, <<"END")
|
||||
begin_circuit INV INVB
|
||||
match_nets VDD VDD
|
||||
match_nets OUT OUT
|
||||
match_nets IN IN
|
||||
match_nets VSS VSS
|
||||
match_pins $0 $1
|
||||
match_pins $1 $3
|
||||
match_pins $2 $0
|
||||
match_pins $3 $2
|
||||
match_devices $2 $1
|
||||
match_devices $1 $2
|
||||
end_circuit INV INVB MATCH
|
||||
begin_circuit TOP TOP
|
||||
match_nets OUT OUT
|
||||
match_nets VDD VDD
|
||||
match_nets IN IN
|
||||
match_nets VSS VSS
|
||||
match_nets INT INT
|
||||
match_pins $0 $2
|
||||
match_pins $1 $0
|
||||
match_pins $2 $1
|
||||
match_pins $3 $3
|
||||
match_subcircuits $2 $1
|
||||
match_subcircuits $1 $2
|
||||
end_circuit TOP TOP MATCH
|
||||
END
|
||||
|
||||
assert_equal(good, true)
|
||||
|
||||
end
|
||||
|
||||
def test_9
|
||||
|
||||
nls1 = <<"END"
|
||||
circuit NAND ($0=A,$1=B,$2=OUT,$3=VDD,$4=VSS);
|
||||
device PMOS $1 (S=VDD,G=A,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device PMOS $2 (S=VDD,G=B,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device NMOS $3 (S=VSS,G=A,D=INT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device NMOS $4 (S=INT,G=B,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
end;
|
||||
circuit TOP ($0=IN1,$1=IN2,$2=OUT,$3=VDD,$4=VSS);
|
||||
subcircuit NAND $1 ($0=IN1,$1=IN2,$2=INT,$3=VDD,$4=VSS);
|
||||
subcircuit NAND $2 ($0=IN1,$1=INT,$2=OUT,$3=VDD,$4=VSS);
|
||||
end;
|
||||
END
|
||||
|
||||
nls2 = <<"END"
|
||||
circuit NAND ($0=A,$1=B,$2=OUT,$3=VDD,$4=VSS);
|
||||
device PMOS $1 (S=VDD,G=A,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device PMOS $2 (S=VDD,G=B,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device NMOS $3 (S=VSS,G=A,D=INT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device NMOS $4 (S=INT,G=B,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
end;
|
||||
circuit TOP ($0=IN1,$1=IN2,$2=OUT,$3=VDD,$4=VSS);
|
||||
subcircuit NAND $2 ($0=IN1,$1=INT,$2=OUT,$3=VDD,$4=VSS);
|
||||
subcircuit NAND $1 ($0=IN1,$1=IN2,$2=INT,$3=VDD,$4=VSS);
|
||||
end;
|
||||
END
|
||||
|
||||
nl1 = RBA::Netlist::new
|
||||
nl2 = RBA::Netlist::new
|
||||
prep_nl(nl1, nls1)
|
||||
prep_nl(nl2, nls2)
|
||||
|
||||
logger = NetlistCompareTestLogger::new
|
||||
comp = RBA::NetlistComparer::new(logger)
|
||||
|
||||
comp.equivalent_pins(nl2.circuit_by_name("NAND"), 0, 1)
|
||||
|
||||
good = comp.compare(nl1, nl2)
|
||||
|
||||
assert_equal(logger.text, <<"END")
|
||||
begin_circuit NAND NAND
|
||||
match_nets VSS VSS
|
||||
match_nets INT INT
|
||||
match_nets OUT OUT
|
||||
match_nets VDD VDD
|
||||
match_nets B B
|
||||
match_nets A A
|
||||
match_pins $0 $0
|
||||
match_pins $1 $1
|
||||
match_pins $2 $2
|
||||
match_pins $3 $3
|
||||
match_pins $4 $4
|
||||
match_devices $1 $1
|
||||
match_devices $2 $2
|
||||
match_devices $3 $3
|
||||
match_devices $4 $4
|
||||
end_circuit NAND NAND MATCH
|
||||
begin_circuit TOP TOP
|
||||
match_nets OUT OUT
|
||||
match_nets INT INT
|
||||
match_nets IN2 IN2
|
||||
match_nets IN1 IN1
|
||||
match_nets VDD VDD
|
||||
match_nets VSS VSS
|
||||
match_pins $0 $0
|
||||
match_pins $1 $1
|
||||
match_pins $2 $2
|
||||
match_pins $3 $3
|
||||
match_pins $4 $4
|
||||
match_subcircuits $2 $1
|
||||
match_subcircuits $1 $2
|
||||
end_circuit TOP TOP MATCH
|
||||
END
|
||||
|
||||
assert_equal(good, true)
|
||||
|
||||
logger.clear
|
||||
comp = RBA::NetlistComparer::new(logger)
|
||||
|
||||
comp.equivalent_pins(nl2.circuit_by_name("NAND"), [ 1, 0 ])
|
||||
|
||||
good = comp.compare(nl1, nl2)
|
||||
|
||||
assert_equal(logger.text, <<"END")
|
||||
begin_circuit NAND NAND
|
||||
match_nets VSS VSS
|
||||
match_nets INT INT
|
||||
match_nets OUT OUT
|
||||
match_nets VDD VDD
|
||||
match_nets B B
|
||||
match_nets A A
|
||||
match_pins $0 $0
|
||||
match_pins $1 $1
|
||||
match_pins $2 $2
|
||||
match_pins $3 $3
|
||||
match_pins $4 $4
|
||||
match_devices $1 $1
|
||||
match_devices $2 $2
|
||||
match_devices $3 $3
|
||||
match_devices $4 $4
|
||||
end_circuit NAND NAND MATCH
|
||||
begin_circuit TOP TOP
|
||||
match_nets OUT OUT
|
||||
match_nets INT INT
|
||||
match_nets IN2 IN2
|
||||
match_nets IN1 IN1
|
||||
match_nets VDD VDD
|
||||
match_nets VSS VSS
|
||||
match_pins $0 $0
|
||||
match_pins $1 $1
|
||||
match_pins $2 $2
|
||||
match_pins $3 $3
|
||||
match_pins $4 $4
|
||||
match_subcircuits $2 $1
|
||||
match_subcircuits $1 $2
|
||||
end_circuit TOP TOP MATCH
|
||||
END
|
||||
|
||||
assert_equal(good, true)
|
||||
|
||||
end
|
||||
|
||||
def test_10
|
||||
|
||||
nls1 = <<"END"
|
||||
circuit INV($1=IN,$2=OUT,$3=VDD,$4=VSS);
|
||||
device PMOS $1(S=VDD,G=IN,D=OUT)(L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device CAP $2 (A=OUT,B=IN) (C=1e-12);
|
||||
device NMOS $2(S=VSS,G=IN,D=OUT)(L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
end;
|
||||
END
|
||||
|
||||
nls2 = <<"END"
|
||||
circuit INV($1=VDD,$2=IN,$3=VSS,$4=OUT);
|
||||
device NMOSB $1(S=OUT,G=IN,D=VSS)(L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
device CAP $2 (A=OUT,B=IN) (C=1e-13);
|
||||
device RES $3 (A=OUT,B=IN) (R=1000);
|
||||
device PMOSB $2(S=VDD,G=IN,D=OUT)(L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
|
||||
end;
|
||||
END
|
||||
|
||||
nl1 = RBA::Netlist::new
|
||||
nl2 = RBA::Netlist::new
|
||||
prep_nl(nl1, nls1)
|
||||
prep_nl(nl2, nls2)
|
||||
|
||||
logger = NetlistCompareTestLogger::new
|
||||
comp = RBA::NetlistComparer::new(logger)
|
||||
|
||||
comp.same_device_classes(nl1.device_class_by_name("PMOS"), nl2.device_class_by_name("PMOSB"))
|
||||
|
||||
good = comp.compare(nl1, nl2)
|
||||
assert_equal(good, false)
|
||||
|
||||
logger.clear
|
||||
comp.same_device_classes(nl1.device_class_by_name("NMOS"), nl2.device_class_by_name("NMOSB"))
|
||||
# avoids device class mismatch errors
|
||||
comp.same_device_classes(nl1.device_class_by_name("NMOSB"), nl2.device_class_by_name("NMOS"))
|
||||
comp.same_device_classes(nl1.device_class_by_name("PMOSB"), nl2.device_class_by_name("PMOS"))
|
||||
good = comp.compare(nl1, nl2)
|
||||
|
||||
assert_equal(logger.text(), <<"END")
|
||||
begin_circuit INV INV
|
||||
match_nets VDD VDD
|
||||
match_nets OUT OUT
|
||||
match_nets VSS VSS
|
||||
match_nets IN IN
|
||||
match_pins $0 $1
|
||||
match_pins $1 $3
|
||||
match_pins $2 $0
|
||||
match_pins $3 $2
|
||||
match_devices $3 $1
|
||||
match_devices_with_different_parameters $2 $2
|
||||
device_mismatch (null) $3
|
||||
match_devices $1 $4
|
||||
end_circuit INV INV NOMATCH
|
||||
END
|
||||
|
||||
assert_equal(good, false)
|
||||
|
||||
comp.max_resistance = 900.0
|
||||
comp.min_capacitance = 1e-11
|
||||
|
||||
logger.clear
|
||||
good = comp.compare(nl1, nl2)
|
||||
|
||||
assert_equal(logger.text(), <<"END")
|
||||
begin_circuit INV INV
|
||||
match_nets VDD VDD
|
||||
match_nets OUT OUT
|
||||
match_nets IN IN
|
||||
match_nets VSS VSS
|
||||
match_pins $0 $1
|
||||
match_pins $1 $3
|
||||
match_pins $2 $0
|
||||
match_pins $3 $2
|
||||
match_devices $3 $1
|
||||
match_devices $1 $4
|
||||
end_circuit INV INV MATCH
|
||||
END
|
||||
|
||||
assert_equal(good, true)
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
load("test_epilogue.rb")
|
||||
|
||||
|
|
@ -56,17 +56,19 @@ class DBNetlistDeviceClasses_TestClass < TestBase
|
|||
circuit.connect_pin(pin_b, n3)
|
||||
|
||||
assert_equal(nl.to_s, <<END)
|
||||
Circuit (A=n1,B=n3):
|
||||
D r1 (A=n1,B=n2) [R=1]
|
||||
D r2 (A=n2,B=n3) [R=3]
|
||||
circuit '' (A=n1,B=n3);
|
||||
device '' r1 (A=n1,B=n2) (R=1);
|
||||
device '' r2 (A=n2,B=n3) (R=3);
|
||||
end;
|
||||
END
|
||||
|
||||
nl.combine_devices
|
||||
nl.purge
|
||||
|
||||
assert_equal(nl.to_s, <<END)
|
||||
Circuit (A=n1,B=n3):
|
||||
D r1 (A=n1,B=n3) [R=4]
|
||||
circuit '' (A=n1,B=n3);
|
||||
device '' r1 (A=n1,B=n3) (R=4);
|
||||
end;
|
||||
END
|
||||
|
||||
end
|
||||
|
|
@ -102,17 +104,19 @@ END
|
|||
circuit.connect_pin(pin_b, n3)
|
||||
|
||||
assert_equal(nl.to_s, <<END)
|
||||
Circuit (A=n1,B=n3):
|
||||
D c1 (A=n1,B=n2) [C=2]
|
||||
D c2 (A=n2,B=n3) [C=3]
|
||||
circuit '' (A=n1,B=n3);
|
||||
device '' c1 (A=n1,B=n2) (C=2);
|
||||
device '' c2 (A=n2,B=n3) (C=3);
|
||||
end;
|
||||
END
|
||||
|
||||
nl.combine_devices
|
||||
nl.purge
|
||||
|
||||
assert_equal(nl.to_s, <<END)
|
||||
Circuit (A=n1,B=n3):
|
||||
D c1 (A=n1,B=n3) [C=1.2]
|
||||
circuit '' (A=n1,B=n3);
|
||||
device '' c1 (A=n1,B=n3) (C=1.2);
|
||||
end;
|
||||
END
|
||||
|
||||
end
|
||||
|
|
@ -148,17 +152,19 @@ END
|
|||
circuit.connect_pin(pin_b, n3)
|
||||
|
||||
assert_equal(nl.to_s, <<END)
|
||||
Circuit (A=n1,B=n3):
|
||||
D l1 (A=n1,B=n2) [L=1]
|
||||
D l2 (A=n2,B=n3) [L=3]
|
||||
circuit '' (A=n1,B=n3);
|
||||
device '' l1 (A=n1,B=n2) (L=1);
|
||||
device '' l2 (A=n2,B=n3) (L=3);
|
||||
end;
|
||||
END
|
||||
|
||||
nl.combine_devices
|
||||
nl.purge
|
||||
|
||||
assert_equal(nl.to_s, <<END)
|
||||
Circuit (A=n1,B=n3):
|
||||
D l1 (A=n1,B=n3) [L=4]
|
||||
circuit '' (A=n1,B=n3);
|
||||
device '' l1 (A=n1,B=n3) (L=4);
|
||||
end;
|
||||
END
|
||||
|
||||
end
|
||||
|
|
@ -192,17 +198,19 @@ END
|
|||
circuit.connect_pin(pin_b, n2)
|
||||
|
||||
assert_equal(nl.to_s, <<END)
|
||||
Circuit (A=n1,B=n2):
|
||||
D d1 (A=n1,C=n2) [A=1]
|
||||
D d2 (A=n1,C=n2) [A=3]
|
||||
circuit '' (A=n1,B=n2);
|
||||
device '' d1 (A=n1,C=n2) (A=1);
|
||||
device '' d2 (A=n1,C=n2) (A=3);
|
||||
end;
|
||||
END
|
||||
|
||||
nl.combine_devices
|
||||
nl.purge
|
||||
|
||||
assert_equal(nl.to_s, <<END)
|
||||
Circuit (A=n1,B=n2):
|
||||
D d1 (A=n1,C=n2) [A=4]
|
||||
circuit '' (A=n1,B=n2);
|
||||
device '' d1 (A=n1,C=n2) (A=4);
|
||||
end;
|
||||
END
|
||||
|
||||
end
|
||||
|
|
@ -252,17 +260,19 @@ END
|
|||
d2.connect_terminal(RBA::DeviceClassMOS3Transistor::TERMINAL_G, n3)
|
||||
|
||||
assert_equal(nl.to_s, <<END)
|
||||
Circuit (A=n1,B=n2,C=n3):
|
||||
D d1 (S=n1,G=n3,D=n2) [L=1,W=2,AS=3,AD=4,PS=13,PD=14]
|
||||
D d2 (S=n1,G=n3,D=n2) [L=1,W=3,AS=4,AD=5,PS=14,PD=15]
|
||||
circuit '' (A=n1,B=n2,C=n3);
|
||||
device '' d1 (S=n1,G=n3,D=n2) (L=1,W=2,AS=3,AD=4,PS=13,PD=14);
|
||||
device '' d2 (S=n1,G=n3,D=n2) (L=1,W=3,AS=4,AD=5,PS=14,PD=15);
|
||||
end;
|
||||
END
|
||||
|
||||
nl.combine_devices
|
||||
nl.purge
|
||||
|
||||
assert_equal(nl.to_s, <<END)
|
||||
Circuit (A=n1,B=n2,C=n3):
|
||||
D d1 (S=n1,G=n3,D=n2) [L=1,W=5,AS=7,AD=9,PS=27,PD=29]
|
||||
circuit '' (A=n1,B=n2,C=n3);
|
||||
device '' d1 (S=n1,G=n3,D=n2) (L=1,W=5,AS=7,AD=9,PS=27,PD=29);
|
||||
end;
|
||||
END
|
||||
|
||||
end
|
||||
|
|
@ -318,17 +328,19 @@ END
|
|||
d2.connect_terminal(RBA::DeviceClassMOS4Transistor::TERMINAL_B, n4)
|
||||
|
||||
assert_equal(nl.to_s, <<END)
|
||||
Circuit (A=n1,B=n2,C=n3,D=n4):
|
||||
D d1 (S=n1,G=n3,D=n2,B=n4) [L=1,W=2,AS=3,AD=4,PS=13,PD=14]
|
||||
D d2 (S=n1,G=n3,D=n2,B=n4) [L=1,W=3,AS=4,AD=5,PS=14,PD=15]
|
||||
circuit '' (A=n1,B=n2,C=n3,D=n4);
|
||||
device '' d1 (S=n1,G=n3,D=n2,B=n4) (L=1,W=2,AS=3,AD=4,PS=13,PD=14);
|
||||
device '' d2 (S=n1,G=n3,D=n2,B=n4) (L=1,W=3,AS=4,AD=5,PS=14,PD=15);
|
||||
end;
|
||||
END
|
||||
|
||||
nl.combine_devices
|
||||
nl.purge
|
||||
|
||||
assert_equal(nl.to_s, <<END)
|
||||
Circuit (A=n1,B=n2,C=n3,D=n4):
|
||||
D d1 (S=n1,G=n3,D=n2,B=n4) [L=1,W=5,AS=7,AD=9,PS=27,PD=29]
|
||||
circuit '' (A=n1,B=n2,C=n3,D=n4);
|
||||
device '' d1 (S=n1,G=n3,D=n2,B=n4) (L=1,W=5,AS=7,AD=9,PS=27,PD=29);
|
||||
end;
|
||||
END
|
||||
|
||||
end
|
||||
|
|
|
|||
Loading…
Reference in New Issue