Merge remote-tracking branch 'origin/dvb'

This commit is contained in:
Matthias Koefferlein 2019-04-16 18:55:37 +02:00
commit 3de4a8408e
61 changed files with 10046 additions and 816 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 &region, 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 {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 += "|";

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 &lt;&lt;"CODE"
def #{f}(*args)
_netter.#{f}(*args)

View File

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

View File

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

View File

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

View File

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

View File

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

17
testdata/algo/nreader1.cir vendored Normal file
View File

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

83
testdata/algo/nreader2.cir vendored Normal file
View File

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

27
testdata/algo/nreader3.cir vendored Normal file
View File

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

View File

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

View File

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

View File

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

66
testdata/drc/drcSimpleTests_12.drc vendored Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

68
testdata/drc/drcSimpleTests_au12a.cir vendored Normal file
View File

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

View File

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

View File

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

BIN
testdata/drc/implicit_nets.gds vendored Normal file

Binary file not shown.

View File

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

View File

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

992
testdata/ruby/dbNetlistCompare.rb vendored Normal file
View File

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

View File

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