Merge pull request #454 from KLayout/dvb

Dvb
This commit is contained in:
Matthias Köfferlein 2019-12-18 18:09:39 +01:00 committed by GitHub
commit a4e87e5b4a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 147 additions and 99 deletions

View File

@ -415,11 +415,15 @@ private:
} while (f != future && bc (*f->first).left () == xx); } while (f != future && bc (*f->first).left () == xx);
} while (f != future && f - c < min_box_size); } while (f != future && f - c < min_box_size);
if (m_report_progress) {
// Note: there is no better estimation of the progress than "current" ...
progress->set (current - m_pp.begin ());
}
for (iterator_type i = f0; i != f; ++i) { for (iterator_type i = f0; i != f; ++i) {
for (iterator_type j = c; j < i; ++j) { for (iterator_type j = c; j < i; ++j) {
if (bs_boxes_overlap (bc (*i->first), bc (*j->first), enl)) { if (bs_boxes_overlap (bc (*i->first), bc (*j->first), enl)) {
if (seen.insert (std::make_pair (i->first, j->first)).second) { if (seen.insert (std::make_pair (i->first, j->first)).second) {
seen.insert (std::make_pair (j->first, i->first));
rec.add (i->first, i->second, j->first, j->second); rec.add (i->first, i->second, j->first, j->second);
if (rec.stop ()) { if (rec.stop ()) {
return false; return false;
@ -431,10 +435,6 @@ private:
x = xx; x = xx;
if (m_report_progress) {
progress->set (f - m_pp.begin ());
}
} }
y = yy; y = yy;

View File

@ -1023,15 +1023,21 @@ connected_clusters<T>::join_cluster_with (typename local_cluster<T>::id_type id,
// handle the connections by translating // handle the connections by translating
const connections_type &to_join = connections_for_cluster (with_id); typename std::map<typename local_cluster<T>::id_type, connections_type>::iterator tc = m_connections.find (with_id);
connections_type &target = m_connections [id]; if (tc != m_connections.end ()) {
target.insert (target.end (), to_join.begin (), to_join.end ());
connections_type &to_join = tc->second;
for (connections_type::const_iterator c = to_join.begin (); c != to_join.end (); ++c) { for (connections_type::const_iterator c = to_join.begin (); c != to_join.end (); ++c) {
m_rev_connections [*c] = id; m_rev_connections [*c] = id;
} }
m_connections.erase (with_id); connections_type &target = m_connections [id];
target.splice (target.end (), to_join, to_join.begin (), to_join.end ());
m_connections.erase (tc);
}
} }
template <class T> template <class T>
@ -1161,6 +1167,11 @@ public:
: cluster_id (_cluster_id), other_ci (_other_ci) : cluster_id (_cluster_id), other_ci (_other_ci)
{ } { }
bool operator== (const ClusterInstanceInteraction &other) const
{
return cluster_id == other.cluster_id && other_ci == other.other_ci;
}
size_t cluster_id; size_t cluster_id;
ClusterInstance other_ci; ClusterInstance other_ci;
}; };
@ -1205,6 +1216,7 @@ public:
db::ICplxTrans t; db::ICplxTrans t;
consider_cluster_instance_pair (*c1, *i2, t, ic); consider_cluster_instance_pair (*c1, *i2, t, ic);
ic.unique ();
m_ci_interactions.splice (m_ci_interactions.end (), ic, ic.begin (), ic.end ()); m_ci_interactions.splice (m_ci_interactions.end (), ic, ic.begin (), ic.end ());
} }
@ -1405,6 +1417,8 @@ private:
for (std::list<std::pair<ClusterInstance, ClusterInstance> >::iterator i = ii_interactions.begin (); i != ii_interactions.end (); ++i) { for (std::list<std::pair<ClusterInstance, ClusterInstance> >::iterator i = ii_interactions.begin (); i != ii_interactions.end (); ++i) {
propagate_cluster_inst (i->second, i2.cell_index (), i2t, i2.prop_id ()); propagate_cluster_inst (i->second, i2.cell_index (), i2t, i2.prop_id ());
} }
ii_interactions.unique ();
interacting_clusters.splice (interacting_clusters.end (), ii_interactions, ii_interactions.begin (), ii_interactions.end ()); interacting_clusters.splice (interacting_clusters.end (), ii_interactions, ii_interactions.begin (), ii_interactions.end ());
} }
@ -1430,6 +1444,8 @@ private:
for (std::list<std::pair<ClusterInstance, ClusterInstance> >::iterator i = ii_interactions.begin (); i != ii_interactions.end (); ++i) { for (std::list<std::pair<ClusterInstance, ClusterInstance> >::iterator i = ii_interactions.begin (); i != ii_interactions.end (); ++i) {
propagate_cluster_inst (i->first, i1.cell_index (), i1t, i1.prop_id ()); propagate_cluster_inst (i->first, i1.cell_index (), i1t, i1.prop_id ());
} }
ii_interactions.unique ();
interacting_clusters.splice (interacting_clusters.end (), ii_interactions, ii_interactions.begin (), ii_interactions.end ()); interacting_clusters.splice (interacting_clusters.end (), ii_interactions, ii_interactions.begin (), ii_interactions.end ());
} }
@ -1442,15 +1458,28 @@ private:
} }
cluster_instance_pair_list_type &cached = (*mp_instance_interaction_cache) [ii_key]; // remove duplicates (after doing a quick unique before)
cached = interacting_clusters; // NOTE: duplicates may happen due to manifold child/child interactions which boil down to
// identical parent cluster interactions.
std::vector<std::pair<ClusterInstance, ClusterInstance> > sorted_interactions;
sorted_interactions.reserve (interacting_clusters.size ());
sorted_interactions.insert (sorted_interactions.end (), interacting_clusters.begin (), interacting_clusters.end ());
interacting_clusters.clear ();
std::sort (sorted_interactions.begin (), sorted_interactions.end ());
sorted_interactions.erase (std::unique (sorted_interactions.begin (), sorted_interactions.end ()), sorted_interactions.end ());
// return the list of unique interactions
interacting_clusters.insert (interacting_clusters.end (), sorted_interactions.begin (), sorted_interactions.end ());
// normalize transformations in cache // normalize transformations in cache
db::ICplxTrans i1ti = i1t.inverted (), i2ti = i2t.inverted (); db::ICplxTrans i1ti = i1t.inverted (), i2ti = i2t.inverted ();
for (std::list<std::pair<ClusterInstance, ClusterInstance> >::iterator i = cached.begin (); i != cached.end (); ++i) { for (std::vector<std::pair<ClusterInstance, ClusterInstance> >::iterator i = sorted_interactions.begin (); i != sorted_interactions.end (); ++i) {
i->first.transform (i1ti); i->first.transform (i1ti);
i->second.transform (i2ti); i->second.transform (i2ti);
} }
cluster_instance_pair_list_type &cached = (*mp_instance_interaction_cache) [ii_key];
cached.insert (cached.end (), sorted_interactions.begin (), sorted_interactions.end ());
} }
/** /**
@ -1773,11 +1802,8 @@ private:
const ClusterInstance &k2 = ic->second; const ClusterInstance &k2 = ic->second;
// Note: "with_self" is false as we're going to create a connected cluster anyway // Note: "with_self" is false as we're going to create a connected cluster anyway
mp_tree->propagate_cluster_inst (*mp_layout, *mp_cell, k1, mp_cell->cell_index (), false); id_type x1 = mp_tree->propagate_cluster_inst (*mp_layout, *mp_cell, k1, mp_cell->cell_index (), false);
mp_tree->propagate_cluster_inst (*mp_layout, *mp_cell, k2, mp_cell->cell_index (), false); id_type x2 = mp_tree->propagate_cluster_inst (*mp_layout, *mp_cell, k2, mp_cell->cell_index (), false);
id_type x1 = mp_cell_clusters->find_cluster_with_connection (k1);
id_type x2 = mp_cell_clusters->find_cluster_with_connection (k2);
if (x1 == 0) { if (x1 == 0) {
@ -2228,9 +2254,8 @@ hier_clusters<T>::build_hier_connections (cell_clusters_box_converter<T> &cbc, c
} else { } else {
// ensures the cluster is propagated so we can connect it with another // ensures the cluster is propagated so we can connect it with another
propagate_cluster_inst (layout, cell, *i, cell.cell_index (), false); size_t other_id = propagate_cluster_inst (layout, cell, *i, cell.cell_index (), false);
size_t other_id = local.find_cluster_with_connection (*i);
if (other_id == gcid) { if (other_id == gcid) {
// shouldn't happen, but duplicate instances may trigger this // shouldn't happen, but duplicate instances may trigger this
} else if (other_id) { } else if (other_id) {

View File

@ -136,19 +136,9 @@ public:
} }
} }
void set_can_cancel (bool f) void set_progress (tl::Progress *progress)
{ {
mp_progress_widget->set_can_cancel (f); mp_progress_widget->set_progress (progress);
}
void set_text (const std::string &text)
{
mp_progress_widget->set_text (text);
}
void set_value (double v, const std::string &value)
{
mp_progress_widget->set_value (v, value);
} }
void add_widget (QWidget *widget) void add_widget (QWidget *widget)
@ -4732,23 +4722,14 @@ MainWindow::progress_get_widget () const
bool bool
MainWindow::update_progress (tl::Progress *progress) MainWindow::update_progress (tl::Progress *progress)
{ {
bool can_cancel = progress->can_cancel ();
std::string text = progress->desc ();
std::string value = progress->formatted_value ();
double v = progress->value ();
if (mp_progress_dialog) { if (mp_progress_dialog) {
mp_progress_dialog->set_can_cancel (can_cancel); mp_progress_dialog->set_progress (progress);
mp_progress_dialog->set_text (text);
mp_progress_dialog->set_value (v, value);
return true; return true;
} else if (isVisible () && mp_progress_widget) { } else if (isVisible () && mp_progress_widget) {
mp_progress_widget->set_can_cancel (can_cancel); mp_progress_widget->set_progress (progress);
mp_progress_widget->set_text (text);
mp_progress_widget->set_value (v, value);
return true; return true;
} else { } else {

View File

@ -25,6 +25,7 @@
#include <QFrame> #include <QFrame>
#include <QGridLayout> #include <QGridLayout>
#include <QLabel>
#include <math.h> #include <math.h>
@ -41,15 +42,8 @@ public:
void set_value (double v, const std::string &value); void set_value (double v, const std::string &value);
QSize sizeHint () const QSize sizeHint () const;
{ QSize minimumSizeHint () const;
return QSize (m_width, 1);
}
QSize minimumSizeHint () const
{
return QSize (m_width, 1);
}
private: private:
double m_value; double m_value;
@ -69,6 +63,7 @@ ProgressBarWidget::ProgressBarWidget (QWidget *parent, const char *name)
{ {
setObjectName (QString::fromUtf8 (name)); setObjectName (QString::fromUtf8 (name));
setMinimumSize (64, 10); setMinimumSize (64, 10);
setSizePolicy (QSizePolicy::Expanding, QSizePolicy::Expanding);
} }
void void
@ -90,6 +85,19 @@ ProgressBarWidget::set_value (double v, const std::string &value)
} }
} }
QSize
ProgressBarWidget::sizeHint () const
{
QFontMetrics fm (font ());
return QSize (m_width, fm.height () + 2);
}
QSize
ProgressBarWidget::minimumSizeHint () const
{
return QSize (m_width, 1);
}
void void
ProgressBarWidget::paintEvent (QPaintEvent *) ProgressBarWidget::paintEvent (QPaintEvent *)
{ {
@ -161,16 +169,21 @@ ProgressWidget::ProgressWidget (ProgressReporter *pr, QWidget *parent, bool full
QFrame *progress_bar_frame = new QFrame (bar_frame); QFrame *progress_bar_frame = new QFrame (bar_frame);
progress_bar_frame->setFrameStyle (QFrame::Box | QFrame::Plain); progress_bar_frame->setFrameStyle (QFrame::Box | QFrame::Plain);
progress_bar_frame->setSizePolicy (QSizePolicy::Expanding, QSizePolicy::Preferred); progress_bar_frame->setSizePolicy (QSizePolicy::Expanding, QSizePolicy::Expanding);
layout->addWidget (progress_bar_frame, 0, col, 1, 1); layout->addWidget (progress_bar_frame, 0, col, 1, 1);
layout->setColumnStretch(col++, 2); layout->setColumnStretch(col++, 2);
QHBoxLayout *pbf_layout = new QHBoxLayout (progress_bar_frame); QGridLayout *pbf_layout = new QGridLayout (progress_bar_frame);
progress_bar_frame->setLayout (pbf_layout); progress_bar_frame->setLayout (pbf_layout);
pbf_layout->setMargin (0); pbf_layout->setMargin (0);
pbf_layout->setSpacing (0);
mp_progress_bar = new ProgressBarWidget (progress_bar_frame); mp_progress_bar1 = new ProgressBarWidget (progress_bar_frame);
pbf_layout->addWidget (mp_progress_bar); pbf_layout->addWidget (mp_progress_bar1, 0, 0, 1, 1);
mp_progress_bar2 = new ProgressBarWidget (progress_bar_frame);
pbf_layout->addWidget (mp_progress_bar2, 1, 0, 1, 1);
mp_progress_bar3 = new ProgressBarWidget (progress_bar_frame);
pbf_layout->addWidget (mp_progress_bar3, 2, 0, 1, 1);
layout->addItem (new QSpacerItem (8, 8, QSizePolicy::Fixed, QSizePolicy::Fixed), 0, col++, 1, 1); layout->addItem (new QSpacerItem (8, 8, QSizePolicy::Fixed, QSizePolicy::Fixed), 0, col++, 1, 1);
@ -218,21 +231,43 @@ ProgressWidget::remove_widget ()
} }
void void
ProgressWidget::set_can_cancel (bool f) ProgressWidget::set_progress (tl::Progress *progress)
{ {
mp_cancel_button->setEnabled (f); bool can_cancel = false;
} std::string text;
void if (progress) {
ProgressWidget::set_text (const std::string &text) can_cancel = progress->can_cancel ();
{ text = progress->desc ();
}
mp_cancel_button->setEnabled (can_cancel);
mp_label->setText (tl::to_qstring (text)); mp_label->setText (tl::to_qstring (text));
}
void lay::ProgressBarWidget *progress_bars[] = { mp_progress_bar1, mp_progress_bar2, mp_progress_bar3 };
ProgressWidget::set_value (double v, const std::string &value)
{ for (size_t i = 0; i < sizeof (progress_bars) / sizeof (progress_bars[0]); ++i) {
mp_progress_bar->set_value (v, value);
lay::ProgressBarWidget *pb = progress_bars[i];
if (progress) {
pb->show ();
std::string value = progress->formatted_value ();
double v = progress->value ();
pb->set_value (v, value);
progress = progress->next ();
} else {
pb->hide ();
}
}
// according to the doc this should not be required, but without, the progress bar does not resize
mp_progress_bar1->parentWidget ()->updateGeometry ();
} }
void void

View File

@ -37,6 +37,11 @@ class QLabel;
class QToolButton; class QToolButton;
class QGridLayout; class QGridLayout;
namespace tl
{
class Progress;
}
namespace lay namespace lay
{ {
@ -50,9 +55,7 @@ Q_OBJECT
public: public:
ProgressWidget (ProgressReporter *pr, QWidget *parent, bool full_width = false); ProgressWidget (ProgressReporter *pr, QWidget *parent, bool full_width = false);
void set_text (const std::string &text); void set_progress (tl::Progress *progress);
void set_value (double v, const std::string &value);
void set_can_cancel (bool f);
void add_widget (QWidget *widget); void add_widget (QWidget *widget);
void remove_widget (); void remove_widget ();
QWidget *get_widget () const; QWidget *get_widget () const;
@ -64,7 +67,7 @@ public slots:
private: private:
QLabel *mp_label; QLabel *mp_label;
ProgressBarWidget *mp_progress_bar; ProgressBarWidget *mp_progress_bar1, *mp_progress_bar2, *mp_progress_bar3;
QWidget *mp_widget; QWidget *mp_widget;
int m_widget_col; int m_widget_col;
QGridLayout *mp_layout; QGridLayout *mp_layout;

View File

@ -148,8 +148,7 @@ Progress::set_desc (const std::string &d)
} }
} }
void bool Progress::test(bool force_yield)
Progress::test (bool force_yield)
{ {
if (++m_interval_count >= m_yield_interval || force_yield) { if (++m_interval_count >= m_yield_interval || force_yield) {
@ -180,6 +179,10 @@ Progress::test (bool force_yield)
throw tl::BreakException (); throw tl::BreakException ();
} }
return true;
} else {
return false;
} }
} }
@ -222,8 +225,9 @@ RelativeProgress &
RelativeProgress::set (size_t count, bool force_yield) RelativeProgress::set (size_t count, bool force_yield)
{ {
m_count = count; m_count = count;
test (force_yield || m_count - m_last_count >= m_unit); if (test (force_yield || m_count - m_last_count >= m_unit)) {
m_last_count = m_count; m_last_count = m_count;
}
return *this; return *this;
} }

View File

@ -203,7 +203,7 @@ protected:
* This method must be called by the derived class. * This method must be called by the derived class.
* If "force_yield" is true, the events are always processed. * If "force_yield" is true, the events are always processed.
*/ */
void test (bool force_yield = false); bool test (bool force_yield = false);
/** /**
* @brief This method needs to be called by all derived classes after initialization has happened * @brief This method needs to be called by all derived classes after initialization has happened

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -386,11 +386,11 @@ end;
l2n.extract_netlist() l2n.extract_netlist()
self.assertEqual(str(l2n.netlist()), """circuit RINGO (); self.assertEqual(str(l2n.netlist()), """circuit RINGO ();
subcircuit INV2PAIR $1 (BULK=VSS,$2=FB,$3=VDD,$4=VSS,$5=$I7,$6=OSC,$7=VDD); subcircuit INV2PAIR $1 (BULK=VSS,$2=FB,$3=VDD,$4=VSS,$5=$I11,$6=OSC,$7=VDD);
subcircuit INV2PAIR $2 (BULK=VSS,$2=$I22,$3=VDD,$4=VSS,$5=FB,$6=$I13,$7=VDD); subcircuit INV2PAIR $2 (BULK=VSS,$2=$I22,$3=VDD,$4=VSS,$5=FB,$6=$I17,$7=VDD);
subcircuit INV2PAIR $3 (BULK=VSS,$2=$I23,$3=VDD,$4=VSS,$5=$I13,$6=$I5,$7=VDD); subcircuit INV2PAIR $3 (BULK=VSS,$2=$I23,$3=VDD,$4=VSS,$5=$I17,$6=$I9,$7=VDD);
subcircuit INV2PAIR $4 (BULK=VSS,$2=$I24,$3=VDD,$4=VSS,$5=$I5,$6=$I6,$7=VDD); subcircuit INV2PAIR $4 (BULK=VSS,$2=$I24,$3=VDD,$4=VSS,$5=$I9,$6=$I10,$7=VDD);
subcircuit INV2PAIR $5 (BULK=VSS,$2=$I25,$3=VDD,$4=VSS,$5=$I6,$6=$I7,$7=VDD); subcircuit INV2PAIR $5 (BULK=VSS,$2=$I25,$3=VDD,$4=VSS,$5=$I10,$6=$I11,$7=VDD);
end; end;
circuit INV2PAIR (BULK=BULK,$2=$I8,$3=$I6,$4=$I5,$5=$I3,$6=$I2,$7=$I1); 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 $1 ($1=$I1,IN=$I3,$3=$I7,OUT=$I4,VSS=$I5,VDD=$I6,BULK=BULK);
@ -415,11 +415,11 @@ end;
l2n.netlist().purge() l2n.netlist().purge()
self.assertEqual(str(l2n.netlist()), """circuit RINGO (FB=FB,OSC=OSC,VDD=VDD,VSS=VSS); self.assertEqual(str(l2n.netlist()), """circuit RINGO (FB=FB,OSC=OSC,VDD=VDD,VSS=VSS);
subcircuit INV2PAIR $1 (BULK=VSS,$2=FB,$3=VDD,$4=VSS,$5=$I7,$6=OSC,$7=VDD); subcircuit INV2PAIR $1 (BULK=VSS,$2=FB,$3=VDD,$4=VSS,$5=$I11,$6=OSC,$7=VDD);
subcircuit INV2PAIR $2 (BULK=VSS,$2=$I22,$3=VDD,$4=VSS,$5=FB,$6=$I13,$7=VDD); subcircuit INV2PAIR $2 (BULK=VSS,$2=$I22,$3=VDD,$4=VSS,$5=FB,$6=$I17,$7=VDD);
subcircuit INV2PAIR $3 (BULK=VSS,$2=$I23,$3=VDD,$4=VSS,$5=$I13,$6=$I5,$7=VDD); subcircuit INV2PAIR $3 (BULK=VSS,$2=$I23,$3=VDD,$4=VSS,$5=$I17,$6=$I9,$7=VDD);
subcircuit INV2PAIR $4 (BULK=VSS,$2=$I24,$3=VDD,$4=VSS,$5=$I5,$6=$I6,$7=VDD); subcircuit INV2PAIR $4 (BULK=VSS,$2=$I24,$3=VDD,$4=VSS,$5=$I9,$6=$I10,$7=VDD);
subcircuit INV2PAIR $5 (BULK=VSS,$2=$I25,$3=VDD,$4=VSS,$5=$I6,$6=$I7,$7=VDD); subcircuit INV2PAIR $5 (BULK=VSS,$2=$I25,$3=VDD,$4=VSS,$5=$I10,$6=$I11,$7=VDD);
end; end;
circuit INV2PAIR (BULK=BULK,$2=$I8,$3=$I6,$4=$I5,$5=$I3,$6=$I2,$7=$I1); 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 $1 ($1=$I1,IN=$I3,$3=$I7,OUT=$I4,VSS=$I5,VDD=$I6,BULK=BULK);

View File

@ -424,11 +424,11 @@ END
assert_equal(l2n.netlist.to_s, <<END) assert_equal(l2n.netlist.to_s, <<END)
circuit RINGO (); circuit RINGO ();
subcircuit INV2PAIR $1 (BULK=VSS,$2=FB,$3=VDD,$4=VSS,$5=$I7,$6=OSC,$7=VDD); subcircuit INV2PAIR $1 (BULK=VSS,$2=FB,$3=VDD,$4=VSS,$5=$I11,$6=OSC,$7=VDD);
subcircuit INV2PAIR $2 (BULK=VSS,$2=$I22,$3=VDD,$4=VSS,$5=FB,$6=$I13,$7=VDD); subcircuit INV2PAIR $2 (BULK=VSS,$2=$I22,$3=VDD,$4=VSS,$5=FB,$6=$I17,$7=VDD);
subcircuit INV2PAIR $3 (BULK=VSS,$2=$I23,$3=VDD,$4=VSS,$5=$I13,$6=$I5,$7=VDD); subcircuit INV2PAIR $3 (BULK=VSS,$2=$I23,$3=VDD,$4=VSS,$5=$I17,$6=$I9,$7=VDD);
subcircuit INV2PAIR $4 (BULK=VSS,$2=$I24,$3=VDD,$4=VSS,$5=$I5,$6=$I6,$7=VDD); subcircuit INV2PAIR $4 (BULK=VSS,$2=$I24,$3=VDD,$4=VSS,$5=$I9,$6=$I10,$7=VDD);
subcircuit INV2PAIR $5 (BULK=VSS,$2=$I25,$3=VDD,$4=VSS,$5=$I6,$6=$I7,$7=VDD); subcircuit INV2PAIR $5 (BULK=VSS,$2=$I25,$3=VDD,$4=VSS,$5=$I10,$6=$I11,$7=VDD);
end; end;
circuit INV2PAIR (BULK=BULK,$2=$I8,$3=$I6,$4=$I5,$5=$I3,$6=$I2,$7=$I1); 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 $1 ($1=$I1,IN=$I3,$3=$I7,OUT=$I4,VSS=$I5,VDD=$I6,BULK=BULK);
@ -454,11 +454,11 @@ END
assert_equal(l2n.netlist.to_s, <<END) assert_equal(l2n.netlist.to_s, <<END)
circuit RINGO (FB=FB,OSC=OSC,VDD=VDD,VSS=VSS); circuit RINGO (FB=FB,OSC=OSC,VDD=VDD,VSS=VSS);
subcircuit INV2PAIR $1 (BULK=VSS,$2=FB,$3=VDD,$4=VSS,$5=$I7,$6=OSC,$7=VDD); subcircuit INV2PAIR $1 (BULK=VSS,$2=FB,$3=VDD,$4=VSS,$5=$I11,$6=OSC,$7=VDD);
subcircuit INV2PAIR $2 (BULK=VSS,$2=$I22,$3=VDD,$4=VSS,$5=FB,$6=$I13,$7=VDD); subcircuit INV2PAIR $2 (BULK=VSS,$2=$I22,$3=VDD,$4=VSS,$5=FB,$6=$I17,$7=VDD);
subcircuit INV2PAIR $3 (BULK=VSS,$2=$I23,$3=VDD,$4=VSS,$5=$I13,$6=$I5,$7=VDD); subcircuit INV2PAIR $3 (BULK=VSS,$2=$I23,$3=VDD,$4=VSS,$5=$I17,$6=$I9,$7=VDD);
subcircuit INV2PAIR $4 (BULK=VSS,$2=$I24,$3=VDD,$4=VSS,$5=$I5,$6=$I6,$7=VDD); subcircuit INV2PAIR $4 (BULK=VSS,$2=$I24,$3=VDD,$4=VSS,$5=$I9,$6=$I10,$7=VDD);
subcircuit INV2PAIR $5 (BULK=VSS,$2=$I25,$3=VDD,$4=VSS,$5=$I6,$6=$I7,$7=VDD); subcircuit INV2PAIR $5 (BULK=VSS,$2=$I25,$3=VDD,$4=VSS,$5=$I10,$6=$I11,$7=VDD);
end; end;
circuit INV2PAIR (BULK=BULK,$2=$I8,$3=$I6,$4=$I5,$5=$I3,$6=$I2,$7=$I1); 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 $1 ($1=$I1,IN=$I3,$3=$I7,OUT=$I4,VSS=$I5,VDD=$I6,BULK=BULK);