Merge branch 'dvb'

This commit is contained in:
Matthias Koefferlein 2019-09-01 11:25:42 +02:00
commit 1106d3faac
147 changed files with 12834 additions and 1392 deletions

View File

@ -136,13 +136,13 @@ bool AllDeviceParametersAreEqual::equal (const db::Device &a, const db::Device &
// DeviceClass class implementation
DeviceClass::DeviceClass ()
: mp_netlist (0)
: mp_netlist (0), m_strict (false)
{
// .. nothing yet ..
}
DeviceClass::DeviceClass (const DeviceClass &other)
: gsi::ObjectBase (other), tl::Object (other), tl::UniqueId (other), mp_netlist (0)
: gsi::ObjectBase (other), tl::Object (other), tl::UniqueId (other), mp_netlist (0), m_strict (false)
{
operator= (other);
}
@ -154,6 +154,7 @@ DeviceClass &DeviceClass::operator= (const DeviceClass &other)
m_parameter_definitions = other.m_parameter_definitions;
m_name = other.m_name;
m_description = other.m_description;
m_strict = other.m_strict;
mp_pc_delegate.reset (const_cast<DeviceParameterCompareDelegate *> (other.mp_pc_delegate.get ()));
}
return *this;

View File

@ -350,6 +350,26 @@ public:
return mp_netlist;
}
/**
* @brief Sets a value indicating whether this class performs strict terminal mapping
*
* Classes with this flag set don't allow terminal swapping, independently of the
* "normalize_terminal_id" implementation. If two classes are involved in a compare,
* both classes are treated strict if one of them operates in strict mode.
*/
void set_strict (bool s)
{
m_strict = s;
}
/**
* @brief Gets a value indicating whether this class performs strict terminal mapping
*/
bool is_strict () const
{
return m_strict;
}
/**
* @brief Gets the name of the device class
*
@ -555,6 +575,7 @@ private:
std::string m_name, m_description;
std::vector<DeviceTerminalDefinition> m_terminal_definitions;
std::vector<DeviceParameterDefinition> m_parameter_definitions;
bool m_strict;
db::Netlist *mp_netlist;
tl::shared_ptr<db::DeviceParameterCompareDelegate> mp_pc_delegate;

View File

@ -1148,7 +1148,7 @@ db::Region LayoutToNetlist::antenna_check (const db::Region &gate, const db::Reg
}
void db::LayoutToNetlist::save (const std::string &path, bool short_format)
void LayoutToNetlist::save (const std::string &path, bool short_format)
{
tl::OutputStream stream (path);
db::LayoutToNetlistStandardWriter writer (stream, short_format);
@ -1156,7 +1156,7 @@ void db::LayoutToNetlist::save (const std::string &path, bool short_format)
writer.write (this);
}
void db::LayoutToNetlist::load (const std::string &path)
void LayoutToNetlist::load (const std::string &path)
{
tl::InputStream stream (path);
db::LayoutToNetlistStandardReader reader (stream);
@ -1165,7 +1165,7 @@ void db::LayoutToNetlist::load (const std::string &path)
reader.read (this);
}
db::LayoutToNetlist *db::LayoutToNetlist::create_from_file (const std::string &path)
db::LayoutToNetlist *LayoutToNetlist::create_from_file (const std::string &path)
{
std::auto_ptr<db::LayoutToNetlist> db;
@ -1189,4 +1189,9 @@ db::LayoutToNetlist *db::LayoutToNetlist::create_from_file (const std::string &p
return db.release ();
}
void LayoutToNetlist::set_generator (const std::string &g)
{
m_generator = g;
}
}

View File

@ -254,6 +254,19 @@ public:
*/
std::string name (unsigned int) const;
/**
* @brief Sets the generator string
*/
void set_generator (const std::string &g);
/**
* @brief Gets the generator string
*/
const std::string &generator () const
{
return m_generator;
}
/**
* @brief Returns true, if the region is a persisted region
* Persisted regions have a name and are kept inside the LayoutToNetlist
@ -730,6 +743,7 @@ private:
bool m_is_flat;
double m_device_scaling;
db::DeepLayer m_dummy_layer;
std::string m_generator;
struct CellReuseTableKey
{

View File

@ -86,7 +86,7 @@ db::NetlistCrossReference *LayoutVsSchematic::make_cross_ref ()
}
void db::LayoutVsSchematic::save (const std::string &path, bool short_format)
void LayoutVsSchematic::save (const std::string &path, bool short_format)
{
tl::OutputStream stream (path);
db::LayoutVsSchematicStandardWriter writer (stream, short_format);
@ -94,7 +94,7 @@ void db::LayoutVsSchematic::save (const std::string &path, bool short_format)
writer.write (this);
}
void db::LayoutVsSchematic::load (const std::string &path)
void LayoutVsSchematic::load (const std::string &path)
{
tl::InputStream stream (path);
db::LayoutVsSchematicStandardReader reader (stream);

View File

@ -603,11 +603,11 @@ public:
}
/**
* @brief Returns true, if the net is floating (has no or only a single connection)
* @brief Returns true, if the net is floating (there is no active element on the net)
*/
bool is_floating () const
{
return (m_pins.size () + m_subcircuit_pins.size () + m_terminals.size ()) < 2;
return (m_subcircuit_pins.size () + m_terminals.size ()) < 1;
}
/**

View File

@ -447,6 +447,24 @@ public:
{
return generic_categorizer<db::DeviceClass>::cat_for (cls);
}
void clear_strict_device_categories ()
{
m_strict_device_categories.clear ();
}
void set_strict_device_category (size_t cat)
{
m_strict_device_categories.insert (cat);
}
bool is_strict_device_category (size_t cat) const
{
return m_strict_device_categories.find (cat) != m_strict_device_categories.end ();
}
private:
std::set<size_t> m_strict_device_categories;
};
// --------------------------------------------------------------------------------------------------------------------
@ -505,12 +523,13 @@ class NetGraph;
struct CompareData
{
CompareData ()
: other (0), max_depth (0), max_n_branch (0), logger (0), circuit_pin_mapper (0)
: other (0), max_depth (0), max_n_branch (0), dont_consider_net_names (false), logger (0), circuit_pin_mapper (0)
{ }
NetGraph *other;
size_t max_depth;
size_t max_n_branch;
bool dont_consider_net_names;
NetlistCompareLogger *logger;
CircuitPinMapper *circuit_pin_mapper;
};
@ -714,7 +733,14 @@ public:
// .. nothing yet ..
}
/**
* @brief Builds a node for a net
*/
NetGraphNode (const db::Net *net, DeviceCategorizer &device_categorizer, CircuitCategorizer &circuit_categorizer, const DeviceFilter &device_filter, const std::map<const db::Circuit *, CircuitMapper> *circuit_map, const CircuitPinMapper *pin_map);
/**
* @brief Builds a virtual node for a subcircuit
*/
NetGraphNode (const db::SubCircuit *sc, CircuitCategorizer &circuit_categorizer, const std::map<const db::Circuit *, CircuitMapper> *circuit_map, const CircuitPinMapper *pin_map);
void expand_subcircuit_nodes (NetGraph *graph);
@ -984,7 +1010,7 @@ public:
* with a proposed identity. With "with_ambiguous", amiguities are resolved by trying
* different combinations in tentative mode and deciding for one combination if possible.
*/
size_t derive_node_identities_from_node_set (const std::vector<const NetGraphNode *> &nodes, const std::vector<const NetGraphNode *> &other_nodes, size_t depth, size_t n_branch, TentativeNodeMapping *tentative, bool with_ambiguous, CompareData *data);
size_t derive_node_identities_from_node_set (std::vector<const NetGraphNode *> &nodes, std::vector<const NetGraphNode *> &other_nodes, size_t depth, size_t n_branch, TentativeNodeMapping *tentative, bool with_ambiguous, CompareData *data);
private:
std::vector<NetGraphNode> m_nodes;
@ -1070,17 +1096,23 @@ NetGraphNode::NetGraphNode (const db::Net *net, DeviceCategorizer &device_catego
continue;
}
size_t terminal1_id = translate_terminal_id (i->terminal_id (), d);
bool is_strict = device_categorizer.is_strict_device_category (device_cat);
// strict device checking means no terminal swapping
size_t terminal1_id = is_strict ? i->terminal_id () : translate_terminal_id (i->terminal_id (), d);
const std::vector<db::DeviceTerminalDefinition> &td = d->device_class ()->terminal_definitions ();
for (std::vector<db::DeviceTerminalDefinition>::const_iterator it = td.begin (); it != td.end (); ++it) {
if (it->id () != i->terminal_id ()) {
size_t terminal2_id = translate_terminal_id (it->id (), d);
size_t terminal2_id = is_strict ? it->id () : translate_terminal_id (it->id (), d);
Transition ed2 (d, device_cat, terminal1_id, terminal2_id);
const db::Net *net2 = d->net_for_terminal (it->id ());
if (! net2) {
continue;
}
std::map<const void *, size_t>::const_iterator in = n2entry.find ((const void *) net2);
if (in == n2entry.end ()) {
@ -1117,6 +1149,9 @@ NetGraphNode::NetGraphNode (const db::SubCircuit *sc, CircuitCategorizer &circui
size_t pin_id = p->id ();
const db::Net *net_at_pin = sc->net_for_pin (pin_id);
if (! net_at_pin) {
continue;
}
// A pin assignment may be missing because there is no net for a pin -> skip this
@ -1348,7 +1383,7 @@ NetGraphNode::edge_equal (const db::Net *a, const db::Net *b)
*/
struct NodeRange
{
NodeRange (size_t _num, std::vector<const NetGraphNode *>::const_iterator _n1, std::vector<const NetGraphNode *>::const_iterator _nn1, std::vector<const NetGraphNode *>::const_iterator _n2, std::vector<const NetGraphNode *>::const_iterator _nn2)
NodeRange (size_t _num, std::vector<const NetGraphNode *>::iterator _n1, std::vector<const NetGraphNode *>::iterator _nn1, std::vector<const NetGraphNode *>::iterator _n2, std::vector<const NetGraphNode *>::iterator _nn2)
: num (_num), n1 (_n1), nn1 (_nn1), n2 (_n2), nn2 (_nn2)
{
// .. nothing yet ..
@ -1360,7 +1395,7 @@ struct NodeRange
}
size_t num;
std::vector<const NetGraphNode *>::const_iterator n1, nn1, n2, nn2;
std::vector<const NetGraphNode *>::iterator n1, nn1, n2, nn2;
};
// --------------------------------------------------------------------------------------------------------------------
@ -1646,8 +1681,81 @@ NetGraph::derive_node_identities (size_t net_index, size_t depth, size_t n_branc
return new_nodes;
}
namespace {
struct SortNodeByNet
{
public:
bool operator() (const NetGraphNode *a, const NetGraphNode *b) const
{
tl_assert (a->net () && b->net ());
return a->net ()->name () < b->net ()->name ();
}
};
}
static void sort_node_range_by_best_match (NodeRange &nr)
{
std::stable_sort (nr.n1, nr.nn1, SortNodeByNet ());
std::stable_sort (nr.n2, nr.nn2, SortNodeByNet ());
std::vector<const NetGraphNode *> nomatch1, nomatch2;
nomatch1.reserve (nr.nn1 - nr.n1);
nomatch2.reserve (nr.nn2 - nr.n2);
std::vector<const NetGraphNode *>::const_iterator i = nr.n1, j = nr.n2;
std::vector<const NetGraphNode *>::iterator iw = nr.n1, jw = nr.n2;
SortNodeByNet compare;
while (i != nr.nn1 || j != nr.nn2) {
if (j == nr.nn2) {
nomatch1.push_back (*i);
++i;
} else if (i == nr.nn1) {
nomatch2.push_back (*j);
++j;
} else if (compare (*i, *j)) {
nomatch1.push_back (*i);
++i;
} else if (compare (*j, *i)) {
nomatch2.push_back (*j);
++j;
} else {
if (iw != i) {
*iw = *i;
}
++iw, ++i;
if (jw != j) {
*jw = *j;
}
++jw, ++j;
}
}
tl_assert (iw + nomatch1.size () == nr.nn1);
tl_assert (jw + nomatch2.size () == nr.nn2);
for (i = nomatch1.begin (); i != nomatch1.end (); ++i) {
*iw++ = *i;
}
for (j = nomatch2.begin (); j != nomatch2.end (); ++j) {
*jw++ = *j;
}
}
static bool net_names_are_different (const db::Net *a, const db::Net *b)
{
if (! a || ! b || a->name ().empty () || b->name ().empty ()) {
return false;
} else {
return (a->name () != b->name ());
}
}
size_t
NetGraph::derive_node_identities_from_node_set (const std::vector<const NetGraphNode *> &nodes, const std::vector<const NetGraphNode *> &other_nodes, size_t depth, size_t n_branch, TentativeNodeMapping *tentative, bool with_ambiguous, CompareData *data)
NetGraph::derive_node_identities_from_node_set (std::vector<const NetGraphNode *> &nodes, std::vector<const NetGraphNode *> &other_nodes, size_t depth, size_t n_branch, TentativeNodeMapping *tentative, bool with_ambiguous, CompareData *data)
{
#if defined(PRINT_DEBUG_NETCOMPARE)
std::string indent;
@ -1723,8 +1831,8 @@ NetGraph::derive_node_identities_from_node_set (const std::vector<const NetGraph
std::vector<NodeRange> node_ranges;
std::vector<const NetGraphNode *>::const_iterator n1 = nodes.begin ();
std::vector<const NetGraphNode *>::const_iterator n2 = other_nodes.begin ();
std::vector<const NetGraphNode *>::iterator n1 = nodes.begin ();
std::vector<const NetGraphNode *>::iterator n2 = other_nodes.begin ();
while (n1 != nodes.end () && n2 != other_nodes.end ()) {
@ -1744,7 +1852,7 @@ NetGraph::derive_node_identities_from_node_set (const std::vector<const NetGraph
continue;
}
std::vector<const NetGraphNode *>::const_iterator nn1 = n1, nn2 = n2;
std::vector<const NetGraphNode *>::iterator nn1 = n1, nn2 = n2;
size_t num = 1;
++nn1;
@ -1819,6 +1927,16 @@ NetGraph::derive_node_identities_from_node_set (const std::vector<const NetGraph
if (! (*nr->n1)->has_other () && ! (*nr->n2)->has_other ()) {
// in tentative mode, reject this choice if both nets are named and
// their names differ -> this favors net matching by name
if (tentative && ! data->dont_consider_net_names && net_names_are_different ((*nr->n1)->net (), (*nr->n2)->net ())) {
#if defined(PRINT_DEBUG_NETCOMPARE)
tl::info << indent << "rejecting pair as names are not identical: " << (*nr->n1)->net ()->expanded_name () << " vs. " << (*nr->n2)->net ()->expanded_name ();
#endif
return std::numeric_limits<size_t>::max ();
}
// A single candiate: just take this one -> this may render
// inexact matches, but further propagates net pairing
@ -1875,10 +1993,17 @@ NetGraph::derive_node_identities_from_node_set (const std::vector<const NetGraph
#if defined(PRINT_DEBUG_NETCOMPARE)
tl::info << indent << "analyzing ambiguity group with " << nr->num << " members";
#endif
// sort the ambiguity group such that net names
std::vector<std::pair<const NetGraphNode *, const NetGraphNode *> > pairs;
tl::equivalence_clusters<const NetGraphNode *> equivalent_other_nodes;
std::set<const NetGraphNode *> seen;
if (! data->dont_consider_net_names) {
sort_node_range_by_best_match (*nr);
}
for (std::vector<const NetGraphNode *>::const_iterator i1 = nr->n1; i1 != nr->nn1; ++i1) {
if ((*i1)->has_other ()) {
@ -2027,6 +2152,8 @@ NetlistComparer::NetlistComparer (NetlistCompareLogger *logger)
m_max_depth = 8;
m_max_n_branch = 100;
m_dont_consider_net_names = false;
}
NetlistComparer::~NetlistComparer ()
@ -2104,14 +2231,14 @@ NetlistComparer::unmatched_circuits (db::Netlist *a, db::Netlist *b, std::vector
for (db::Netlist::circuit_iterator i = a->begin_circuits (); i != a->end_circuits (); ++i) {
size_t cat = circuit_categorizer.cat_for_circuit (i.operator-> ());
if (cat && i->begin_refs () != i->end_refs ()) {
if (cat) {
cat2circuits[cat].first = i.operator-> ();
}
}
for (db::Netlist::circuit_iterator i = b->begin_circuits (); i != b->end_circuits (); ++i) {
size_t cat = circuit_categorizer.cat_for_circuit (i.operator-> ());
if (cat && i->begin_refs () != i->end_refs ()) {
if (cat) {
cat2circuits[cat].second = i.operator-> ();
}
}
@ -2203,6 +2330,16 @@ NetlistComparer::compare (const db::Netlist *a, const db::Netlist *b) const
}
}
// device whether to use a device category in strict mode
device_categorizer.clear_strict_device_categories ();
for (std::map<size_t, std::pair<const db::DeviceClass *, const db::DeviceClass *> >::const_iterator i = cat2dc.begin (); i != cat2dc.end (); ++i) {
if (i->second.first && i->second.second && (i->second.first->is_strict () || i->second.second->is_strict ())) {
device_categorizer.set_strict_device_category (i->first);
}
}
// check for circuits that don't match
for (std::map<size_t, std::pair<const db::Circuit *, const db::Circuit *> >::const_iterator i = cat2circuits.begin (); i != cat2circuits.end (); ++i) {
@ -2333,13 +2470,13 @@ NetlistComparer::all_subcircuits_verified (const db::Circuit *c, const std::set<
}
static std::vector<std::pair<size_t, size_t> >
compute_device_key (const db::Device &device, const db::NetGraph &g)
compute_device_key (const db::Device &device, const db::NetGraph &g, bool strict)
{
std::vector<std::pair<size_t, size_t> > k;
const std::vector<db::DeviceTerminalDefinition> &td = device.device_class ()->terminal_definitions ();
for (std::vector<db::DeviceTerminalDefinition>::const_iterator t = td.begin (); t != td.end (); ++t) {
size_t terminal_id = translate_terminal_id (t->id (), &device);
size_t terminal_id = strict ? t->id () : translate_terminal_id (t->id (), &device);
const db::Net *net = device.net_for_terminal (t->id ());
size_t net_id = g.node_index_for_net (net);
k.push_back (std::make_pair (terminal_id, net_id));
@ -2573,6 +2710,7 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2,
data.other = &g2;
data.max_depth = m_max_depth;
data.max_n_branch = m_max_n_branch;
data.dont_consider_net_names = m_dont_consider_net_names;
data.circuit_pin_mapper = &circuit_pin_mapper;
data.logger = mp_logger;
@ -2625,6 +2763,7 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2,
data.other = &g2;
data.max_depth = m_max_depth;
data.max_n_branch = m_max_n_branch;
data.dont_consider_net_names = m_dont_consider_net_names;
data.circuit_pin_mapper = &circuit_pin_mapper;
data.logger = mp_logger;
@ -2666,186 +2805,170 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2,
return good;
}
void
NetlistComparer::handle_pin_mismatch (const db::Circuit *c1, const db::Pin *pin1, const db::Circuit *c2, const db::Pin *pin2, bool &good, bool &pin_mismatch) const
{
// Determine whether the pin in question is used - only in this case we will report an error.
// Otherwise, the report will be "match" against 0.
const db::Circuit *c = pin1 ? c1 : c2;
const db::Pin *pin = pin1 ? pin1 : pin2;
bool is_not_connected = true;
for (db::Circuit::const_refs_iterator r = c->begin_refs (); r != c->end_refs () && is_not_connected; ++r) {
const db::SubCircuit *sc = r.operator-> ();
const db::Net *net = sc->net_for_pin (pin->id ());
if (net && ((net->terminal_count () + net->pin_count ()) > 0 || net->subcircuit_pin_count () > 1)) {
is_not_connected = false;
}
}
if (is_not_connected) {
if (mp_logger) {
mp_logger->match_pins (pin1, pin2);
}
} else {
if (mp_logger) {
mp_logger->pin_mismatch (pin1, pin2);
}
good = false;
pin_mismatch = true;
}
}
void
NetlistComparer::do_pin_assignment (const db::Circuit *c1, const db::NetGraph &g1, const db::Circuit *c2, const db::NetGraph &g2, std::map<const db::Circuit *, CircuitMapper> &c12_circuit_and_pin_mapping, std::map<const db::Circuit *, CircuitMapper> &c22_circuit_and_pin_mapping, bool &pin_mismatch, bool &good) const
{
// Report pin assignment
// This step also does the pin identity mapping.
if (c1->pin_count () > 0 && c2->pin_count () > 0) {
// try to assign floating pins by name with higher prio
std::map<std::string, std::pair<const db::Pin *, const db::Pin *> > floating_pins_by_name;
// try to assign floating pins by name with higher prio
std::map<std::string, std::pair<const db::Pin *, const db::Pin *> > floating_pins_by_name;
for (db::Circuit::const_pin_iterator p = c2->begin_pins (); p != c2->end_pins (); ++p) {
const db::Net *net = c2->net_for_pin (p->id ());
if (!net && !p->name ().empty ()) {
floating_pins_by_name.insert (std::make_pair (normalize_name (p->name ()), std::make_pair ((const db::Pin *) 0, (const db::Pin *) 0))).first->second.second = p.operator-> ();
}
for (db::Circuit::const_pin_iterator p = c2->begin_pins (); p != c2->end_pins (); ++p) {
const db::Net *net = c2->net_for_pin (p->id ());
if (!net && !p->name ().empty ()) {
floating_pins_by_name.insert (std::make_pair (normalize_name (p->name ()), std::make_pair ((const db::Pin *) 0, (const db::Pin *) 0))).first->second.second = p.operator-> ();
}
}
for (db::Circuit::const_pin_iterator p = c1->begin_pins (); p != c1->end_pins (); ++p) {
const db::Net *net = c1->net_for_pin (p->id ());
if (!net && !p->name ().empty ()) {
floating_pins_by_name.insert (std::make_pair (normalize_name (p->name ()), std::make_pair ((const db::Pin *) 0, (const db::Pin *) 0))).first->second.first = p.operator-> ();
}
for (db::Circuit::const_pin_iterator p = c1->begin_pins (); p != c1->end_pins (); ++p) {
const db::Net *net = c1->net_for_pin (p->id ());
if (!net && !p->name ().empty ()) {
floating_pins_by_name.insert (std::make_pair (normalize_name (p->name ()), std::make_pair ((const db::Pin *) 0, (const db::Pin *) 0))).first->second.first = p.operator-> ();
}
}
std::map<const db::Pin *, const db::Pin *> floating_pin_name_mapping;
for (std::map<std::string, std::pair<const db::Pin *, const db::Pin *> >::const_iterator i = floating_pins_by_name.begin (); i != floating_pins_by_name.end (); ++i) {
if (i->second.first && i->second.second) {
floating_pin_name_mapping [i->second.first] = i->second.second;
floating_pin_name_mapping [i->second.second] = i->second.first;
}
std::map<const db::Pin *, const db::Pin *> floating_pin_name_mapping;
for (std::map<std::string, std::pair<const db::Pin *, const db::Pin *> >::const_iterator i = floating_pins_by_name.begin (); i != floating_pins_by_name.end (); ++i) {
if (i->second.first && i->second.second) {
floating_pin_name_mapping [i->second.first] = i->second.second;
floating_pin_name_mapping [i->second.second] = i->second.first;
}
}
std::vector<const db::Pin *> floating_pins;
std::multimap<size_t, const db::Pin *> net2pin;
for (db::Circuit::const_pin_iterator p = c2->begin_pins (); p != c2->end_pins (); ++p) {
const db::Net *net = c2->net_for_pin (p->id ());
if (net) {
net2pin.insert (std::make_pair (g2.node_index_for_net (net), p.operator-> ()));
} else if (floating_pin_name_mapping.find (p.operator-> ()) == floating_pin_name_mapping.end ()) {
floating_pins.push_back (p.operator-> ());
}
std::vector<const db::Pin *> floating_pins;
std::multimap<size_t, const db::Pin *> net2pin;
for (db::Circuit::const_pin_iterator p = c2->begin_pins (); p != c2->end_pins (); ++p) {
const db::Net *net = c2->net_for_pin (p->id ());
if (net) {
net2pin.insert (std::make_pair (g2.node_index_for_net (net), p.operator-> ()));
} else if (floating_pin_name_mapping.find (p.operator-> ()) == floating_pin_name_mapping.end ()) {
floating_pins.push_back (p.operator-> ());
}
}
std::vector<const db::Pin *>::iterator next_float = floating_pins.begin ();
std::vector<const db::Pin *>::iterator next_float = floating_pins.begin ();
CircuitMapper &c12_pin_mapping = c12_circuit_and_pin_mapping [c1];
c12_pin_mapping.set_other (c2);
CircuitMapper &c12_pin_mapping = c12_circuit_and_pin_mapping [c1];
c12_pin_mapping.set_other (c2);
// dummy mapping: we show this circuit is used.
CircuitMapper &c22_pin_mapping = c22_circuit_and_pin_mapping [c2];
c22_pin_mapping.set_other (c2);
// dummy mapping: we show this circuit is used.
CircuitMapper &c22_pin_mapping = c22_circuit_and_pin_mapping [c2];
c22_pin_mapping.set_other (c2);
for (db::Circuit::const_pin_iterator p = c1->begin_pins (); p != c1->end_pins (); ++p) {
for (db::Circuit::const_pin_iterator p = c1->begin_pins (); p != c1->end_pins (); ++p) {
const db::Net *net = c1->net_for_pin (p->id ());
if (! net) {
const db::Net *net = c1->net_for_pin (p->id ());
if (! net) {
std::map<const db::Pin *, const db::Pin *>::const_iterator fp = floating_pin_name_mapping.find (p.operator-> ());
if (fp != floating_pin_name_mapping.end ()) {
// assign a floating pin - this is a dummy assignment which is mitigated
// by declaring the pins equivalent in derive_pin_equivalence
if (mp_logger) {
mp_logger->match_pins (p.operator-> (), fp->second);
}
c12_pin_mapping.map_pin (p->id (), fp->second->id ());
c22_pin_mapping.map_pin (fp->second->id (), p->id ());
} else if (next_float != floating_pins.end ()) {
// assign a floating pin - this is a dummy assignment which is mitigated
// by declaring the pins equivalent in derive_pin_equivalence
if (mp_logger) {
mp_logger->match_pins (p.operator-> (), *next_float);
}
c12_pin_mapping.map_pin (p->id (), (*next_float)->id ());
c22_pin_mapping.map_pin ((*next_float)->id (), p->id ());
++next_float;
} else {
// otherwise this is an error
if (mp_logger) {
mp_logger->pin_mismatch (p.operator-> (), 0);
}
pin_mismatch = true;
good = false;
std::map<const db::Pin *, const db::Pin *>::const_iterator fp = floating_pin_name_mapping.find (p.operator-> ());
if (fp != floating_pin_name_mapping.end ()) {
// assign a floating pin - this is a dummy assignment which is mitigated
// by declaring the pins equivalent in derive_pin_equivalence
if (mp_logger) {
mp_logger->match_pins (p.operator-> (), fp->second);
}
c12_pin_mapping.map_pin (p->id (), fp->second->id ());
c22_pin_mapping.map_pin (fp->second->id (), p->id ());
continue;
} else if (next_float != floating_pins.end ()) {
// assign a floating pin - this is a dummy assignment which is mitigated
// by declaring the pins equivalent in derive_pin_equivalence
if (mp_logger) {
mp_logger->match_pins (p.operator-> (), *next_float);
}
c12_pin_mapping.map_pin (p->id (), (*next_float)->id ());
c22_pin_mapping.map_pin ((*next_float)->id (), p->id ());
++next_float;
} else {
// otherwise this is an error for subcircuits or worth a report for top-level circuits
handle_pin_mismatch (c1, p.operator-> (), c2, 0, good, pin_mismatch);
}
const db::NetGraphNode &n = *(g1.begin () + g1.node_index_for_net (net));
continue;
if (! n.has_other ()) {
}
const db::NetGraphNode &n = *(g1.begin () + g1.node_index_for_net (net));
if (! n.has_other ()) {
handle_pin_mismatch (c1, p.operator-> (), c2, 0, good, pin_mismatch);
continue;
}
std::multimap<size_t, const db::Pin *>::iterator np = net2pin.find (n.other_net_index ());
for (db::Net::const_pin_iterator pi = net->begin_pins (); pi != net->end_pins (); ++pi) {
if (np != net2pin.end () && np->first == n.other_net_index ()) {
if (mp_logger) {
mp_logger->pin_mismatch (p.operator-> (), 0);
mp_logger->match_pins (pi->pin (), np->second);
}
c12_pin_mapping.map_pin (pi->pin ()->id (), np->second->id ());
// dummy mapping: we show this pin is used.
c22_pin_mapping.map_pin (np->second->id (), np->second->id ());
pin_mismatch = true;
good = false;
std::multimap<size_t, const db::Pin *>::iterator np_delete = np;
++np;
net2pin.erase (np_delete);
continue;
} else {
}
std::multimap<size_t, const db::Pin *>::iterator np = net2pin.find (n.other_net_index ());
for (db::Net::const_pin_iterator pi = net->begin_pins (); pi != net->end_pins (); ++pi) {
if (np != net2pin.end () && np->first == n.other_net_index ()) {
if (mp_logger) {
mp_logger->match_pins (pi->pin (), np->second);
}
c12_pin_mapping.map_pin (pi->pin ()->id (), np->second->id ());
// dummy mapping: we show this pin is used.
c22_pin_mapping.map_pin (np->second->id (), np->second->id ());
std::multimap<size_t, const db::Pin *>::iterator np_delete = np;
++np;
net2pin.erase (np_delete);
} else {
if (mp_logger) {
mp_logger->pin_mismatch (pi->pin (), 0);
}
pin_mismatch = true;
good = false;
}
handle_pin_mismatch (c1, pi->pin (), c2, 0, good, pin_mismatch);
}
}
for (std::multimap<size_t, const db::Pin *>::iterator np = net2pin.begin (); np != net2pin.end (); ++np) {
if (mp_logger) {
mp_logger->pin_mismatch (0, np->second);
}
pin_mismatch = true;
good = false;
}
}
while (next_float != floating_pins.end ()) {
if (mp_logger) {
mp_logger->pin_mismatch (0, *next_float);
}
pin_mismatch = true;
good = false;
++next_float;
}
} else {
// skip pin mapping in case one circuit does not feature pins
// This is often the case for top-level circuits. We don't necessarily need pins for them.
// We still report those circuits with "pin mismatch" so they don't get considered within
// subcircuits. Plus we report the pins so they get listed in the cross-ref (but with a
// "match" - this is important to cover the cases which are found when analyzing the nets).
if (mp_logger) {
for (db::Circuit::const_pin_iterator p = c1->begin_pins (); p != c1->end_pins (); ++p) {
mp_logger->match_pins (p.operator-> (), 0);
}
for (db::Circuit::const_pin_iterator p = c2->begin_pins (); p != c2->end_pins (); ++p) {
mp_logger->match_pins (0, p.operator-> ());
}
}
if (c1->pin_count () != c2->pin_count ()) {
pin_mismatch = true;
}
for (std::multimap<size_t, const db::Pin *>::iterator np = net2pin.begin (); np != net2pin.end (); ++np) {
handle_pin_mismatch (c1, 0, c2, np->second, good, pin_mismatch);
}
while (next_float != floating_pins.end ()) {
handle_pin_mismatch (c1, 0, c2, *next_float, good, pin_mismatch);
++next_float;
}
}
@ -2872,7 +2995,7 @@ NetlistComparer::do_device_assignment (const db::Circuit *c1, const db::NetGraph
continue;
}
std::vector<std::pair<size_t, size_t> > k = compute_device_key (*d, g1);
std::vector<std::pair<size_t, size_t> > k = compute_device_key (*d, g1, device_categorizer.is_strict_device_category (device_cat));
bool mapped = true;
for (std::vector<std::pair<size_t, size_t> >::iterator i = k.begin (); i != k.end (); ++i) {
@ -2906,7 +3029,7 @@ NetlistComparer::do_device_assignment (const db::Circuit *c1, const db::NetGraph
continue;
}
std::vector<std::pair<size_t, size_t> > k = compute_device_key (*d, g2);
std::vector<std::pair<size_t, size_t> > k = compute_device_key (*d, g2, device_categorizer.is_strict_device_category (device_cat));
bool mapped = true;
for (std::vector<std::pair<size_t, size_t> >::iterator i = k.begin (); i != k.end (); ++i) {
@ -2999,14 +3122,12 @@ NetlistComparer::do_device_assignment (const db::Circuit *c1, const db::NetGraph
++i;
}
if (i == unmatched_a.end () && j == unmatched_b.end ()) {
if (i == unmatched_a.end () || j == unmatched_b.end ()) {
break;
}
unmatched_list::iterator ii = i, jj = j;
++i, ++j;
size_t n = ii->first.size ();
tl_assert (n == jj->first.size ());
while (i != unmatched_a.end () && cmp.equals (*i, *ii)) {
++i;
@ -3167,7 +3288,7 @@ NetlistComparer::do_subcircuit_assignment (const db::Circuit *c1, const db::NetG
++i;
}
if (i == unmatched_a.end () && j == unmatched_b.end ()) {
if (i == unmatched_a.end () || j == unmatched_b.end ()) {
break;
}

View File

@ -245,6 +245,23 @@ public:
return m_max_depth;
}
/**
* @brief Sets a value indicating whether not to consider net names
* This feature is mainly intended for testing.
*/
void set_dont_consider_net_names (bool f)
{
m_dont_consider_net_names = f;
}
/**
* @brief Gets a value indicating whether not to consider net names
*/
bool dont_consider_net_names () const
{
return m_dont_consider_net_names;
}
/**
* @brief Sets the maximum branch complexity
*
@ -297,6 +314,7 @@ protected:
void do_pin_assignment (const db::Circuit *c1, const db::NetGraph &g1, const db::Circuit *c2, const db::NetGraph &g2, std::map<const db::Circuit *, CircuitMapper> &c12_circuit_and_pin_mapping, std::map<const db::Circuit *, CircuitMapper> &c22_circuit_and_pin_mapping, bool &pin_mismatch, bool &good) const;
void do_device_assignment (const db::Circuit *c1, const db::NetGraph &g1, const db::Circuit *c2, const db::NetGraph &g2, const db::DeviceFilter &device_filter, DeviceCategorizer &device_categorizer, bool &good) const;
void do_subcircuit_assignment (const db::Circuit *c1, const db::NetGraph &g1, const db::Circuit *c2, const db::NetGraph &g2, CircuitCategorizer &circuit_categorizer, const db::CircuitPinMapper &circuit_pin_mapper, std::map<const db::Circuit *, CircuitMapper> &c12_circuit_and_pin_mapping, std::map<const db::Circuit *, CircuitMapper> &c22_circuit_and_pin_mapping, bool &good) const;
void handle_pin_mismatch (const db::Circuit *c1, const db::Pin *pin1, const db::Circuit *c2, const db::Pin *p2, bool &good, bool &pin_mismatch) const;
mutable NetlistCompareLogger *mp_logger;
std::map<std::pair<const db::Circuit *, const db::Circuit *>, std::vector<std::pair<const Net *, const Net *> > > m_same_nets;
@ -307,6 +325,7 @@ protected:
double m_res_threshold;
size_t m_max_n_branch;
size_t m_max_depth;
bool m_dont_consider_net_names;
};
}

View File

@ -30,114 +30,252 @@ namespace db
// ---------------------------------------------------------------------------------
// NetlistDeviceExtractorMOS3Transistor implementation
NetlistDeviceExtractorMOS3Transistor::NetlistDeviceExtractorMOS3Transistor (const std::string &name)
: db::NetlistDeviceExtractor (name)
NetlistDeviceExtractorMOS3Transistor::NetlistDeviceExtractorMOS3Transistor (const std::string &name, bool strict)
: db::NetlistDeviceExtractor (name),
m_strict (strict)
{
// .. nothing yet ..
}
void NetlistDeviceExtractorMOS3Transistor::setup ()
{
define_layer ("SD", "Source/drain diffusion"); // #0
define_layer ("G", "Gate input"); // #1
// for backward compatibility
define_layer ("P", 1, "Gate terminal output"); // #2 -> G
if (! is_strict ()) {
// terminal output
define_layer ("tG", 2, "Gate terminal output"); // #3 -> P -> G
define_layer ("tS", 0, "Source terminal output (default is SD)"); // #4
define_layer ("tD", 0, "Drain terminal output (default is SD)"); // #5
define_layer ("SD", "Source/drain diffusion"); // #0
define_layer ("G", "Gate input"); // #1
// for backward compatibility
define_layer ("P", 1, "Gate terminal output"); // #2 -> G
register_device_class (new db::DeviceClassMOS3Transistor ());
// terminal output
define_layer ("tG", 2, "Gate terminal output"); // #3 -> P -> G
define_layer ("tS", 0, "Source terminal output (default is SD)"); // #4
define_layer ("tD", 0, "Drain terminal output (default is SD)"); // #5
} else {
define_layer ("S", "Source diffusion"); // #0
define_layer ("D", "Drain diffusion"); // #1
define_layer ("G", "Gate input"); // #2
// for backward compatibility
define_layer ("P", 2, "Gate terminal output"); // #3 -> G
// terminal output
define_layer ("tG", 3, "Gate terminal output"); // #4 -> P -> G
define_layer ("tS", 0, "Source terminal output (default is S)"); // #5
define_layer ("tD", 1, "Drain terminal output (default is D)"); // #6
}
db::DeviceClass *cls = new db::DeviceClassMOS3Transistor ();
cls->set_strict (m_strict);
register_device_class (cls);
}
db::Connectivity NetlistDeviceExtractorMOS3Transistor::get_connectivity (const db::Layout & /*layout*/, const std::vector<unsigned int> &layers) const
{
tl_assert (layers.size () >= 3);
if (! is_strict ()) {
unsigned int diff = layers [0];
unsigned int gate = layers [1];
// not used for device recognition: poly (2), but used for producing the gate terminals
tl_assert (layers.size () >= 3);
// The layer definition is diff, gate
db::Connectivity conn;
// collect all connected diffusion shapes
conn.connect (diff, diff);
// collect all connected gate shapes
conn.connect (gate, gate);
// connect gate with diff to detect gate/diffusion boundary
conn.connect (diff, gate);
return conn;
unsigned int diff = layers [0];
unsigned int gate = layers [1];
// The layer definition is diff, gate
db::Connectivity conn;
// collect all connected diffusion shapes
conn.connect (diff, diff);
// collect all connected gate shapes
conn.connect (gate, gate);
// connect gate with diff to detect gate/diffusion boundary
conn.connect (diff, gate);
return conn;
} else {
tl_assert (layers.size () >= 4);
unsigned int sdiff = layers [0];
unsigned int ddiff = layers [1];
unsigned int gate = layers [2];
// The layer definition is diff, gate
db::Connectivity conn;
// collect all connected diffusion shapes
conn.connect (sdiff, sdiff);
conn.connect (ddiff, ddiff);
// collect all connected gate shapes
conn.connect (gate, gate);
// connect gate with diff to detect gate/diffusion boundary
conn.connect (sdiff, gate);
conn.connect (ddiff, gate);
return conn;
}
}
void NetlistDeviceExtractorMOS3Transistor::extract_devices (const std::vector<db::Region> &layer_geometry)
{
unsigned int diff_geometry_index = 0;
unsigned int gate_geometry_index = 1;
unsigned int gate_terminal_geometry_index = 3;
unsigned int source_terminal_geometry_index = 4;
unsigned int drain_terminal_geometry_index = 5;
if (! is_strict ()) {
const db::Region &rdiff = layer_geometry [diff_geometry_index];
const db::Region &rgates = layer_geometry [gate_geometry_index];
// See setup() for the geometry indexes
unsigned int diff_geometry_index = 0;
unsigned int gate_geometry_index = 1;
unsigned int gate_terminal_geometry_index = 3;
unsigned int source_terminal_geometry_index = 4;
unsigned int drain_terminal_geometry_index = 5;
for (db::Region::const_iterator p = rgates.begin_merged (); !p.at_end (); ++p) {
const db::Region &rdiff = layer_geometry [diff_geometry_index];
const db::Region &rgates = layer_geometry [gate_geometry_index];
db::Region rgate (*p);
rgate.set_base_verbosity (rgates.base_verbosity ());
for (db::Region::const_iterator p = rgates.begin_merged (); !p.at_end (); ++p) {
db::Region rdiff2gate = rdiff.selected_interacting (rgate);
rdiff2gate.set_base_verbosity (rdiff.base_verbosity ());
db::Region rgate (*p);
rgate.set_base_verbosity (rgates.base_verbosity ());
if (rdiff2gate.empty ()) {
error (tl::to_string (tr ("Gate shape touches no diffusion - ignored")), *p);
} else {
db::Region rdiff2gate = rdiff.selected_interacting (rgate);
rdiff2gate.set_base_verbosity (rdiff.base_verbosity ());
if (rdiff2gate.size () != 2) {
error (tl::sprintf (tl::to_string (tr ("Expected two polygons on diff interacting with one gate shape (found %d) - gate shape ignored")), int (rdiff2gate.size ())), *p);
continue;
}
if (rdiff2gate.empty ()) {
error (tl::to_string (tr ("Gate shape touches no diffusion - ignored")), *p);
} else {
db::Edges edges (rgate.edges () & rdiff2gate.edges ());
if (edges.size () != 2) {
error (tl::sprintf (tl::to_string (tr ("Expected two edges interacting gate/diff (found %d) - width and length may be incorrect")), int (edges.size ())), *p);
continue;
}
if (rdiff2gate.size () != 2) {
error (tl::sprintf (tl::to_string (tr ("Expected two polygons on diff interacting with one gate shape (found %d) - gate shape ignored")), int (rdiff2gate.size ())), *p);
continue;
}
if (! p->is_box ()) {
error (tl::to_string (tr ("Gate shape is not a box - width and length may be incorrect")), *p);
}
db::Edges edges (rgate.edges () & rdiff2gate.edges ());
if (edges.size () != 2) {
error (tl::sprintf (tl::to_string (tr ("Expected two edges interacting gate/diff (found %d) - width and length may be incorrect")), int (edges.size ())), *p);
continue;
}
db::Device *device = create_device ();
if (! p->is_box ()) {
error (tl::to_string (tr ("Gate shape is not a box - width and length may be incorrect")), *p);
}
device->set_trans (db::DCplxTrans ((p->box ().center () - db::Point ()) * dbu ()));
db::Device *device = create_device ();
device->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_W, sdbu () * edges.length () * 0.5);
device->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_L, sdbu () * (p->perimeter () - edges.length ()) * 0.5);
device->set_trans (db::DCplxTrans ((p->box ().center () - db::Point ()) * dbu ()));
int diff_index = 0;
for (db::Region::const_iterator d = rdiff2gate.begin (); !d.at_end () && diff_index < 2; ++d, ++diff_index) {
device->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_W, sdbu () * edges.length () * 0.5);
device->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_L, sdbu () * (p->perimeter () - edges.length ()) * 0.5);
// count the number of gate shapes attached to this shape and distribute the area of the
// diffusion region to the number of gates
size_t n = rgates.selected_interacting (db::Region (*d)).size ();
tl_assert (n > 0);
int diff_index = 0;
for (db::Region::const_iterator d = rdiff2gate.begin (); !d.at_end () && diff_index < 2; ++d, ++diff_index) {
device->set_parameter_value (diff_index == 0 ? db::DeviceClassMOS3Transistor::param_id_AS : db::DeviceClassMOS3Transistor::param_id_AD, sdbu () * sdbu () * d->area () / double (n));
device->set_parameter_value (diff_index == 0 ? db::DeviceClassMOS3Transistor::param_id_PS : db::DeviceClassMOS3Transistor::param_id_PD, sdbu () * d->perimeter () / double (n));
// count the number of gate shapes attached to this shape and distribute the area of the
// diffusion region to the number of gates
size_t n = rgates.selected_interacting (db::Region (*d)).size ();
tl_assert (n > 0);
unsigned int sd_index = diff_index == 0 ? source_terminal_geometry_index : drain_terminal_geometry_index;
define_terminal (device, diff_index == 0 ? db::DeviceClassMOS3Transistor::terminal_id_S : db::DeviceClassMOS3Transistor::terminal_id_D, sd_index, *d);
device->set_parameter_value (diff_index == 0 ? db::DeviceClassMOS3Transistor::param_id_AS : db::DeviceClassMOS3Transistor::param_id_AD, sdbu () * sdbu () * d->area () / double (n));
device->set_parameter_value (diff_index == 0 ? db::DeviceClassMOS3Transistor::param_id_PS : db::DeviceClassMOS3Transistor::param_id_PD, sdbu () * d->perimeter () / double (n));
unsigned int sd_index = diff_index == 0 ? source_terminal_geometry_index : drain_terminal_geometry_index;
define_terminal (device, diff_index == 0 ? db::DeviceClassMOS3Transistor::terminal_id_S : db::DeviceClassMOS3Transistor::terminal_id_D, sd_index, *d);
}
define_terminal (device, db::DeviceClassMOS3Transistor::terminal_id_G, gate_terminal_geometry_index, *p);
// allow derived classes to modify the device
modify_device (*p, layer_geometry, device);
// output the device for debugging
device_out (device, rdiff2gate, rgate);
}
define_terminal (device, db::DeviceClassMOS3Transistor::terminal_id_G, gate_terminal_geometry_index, *p);
}
// allow derived classes to modify the device
modify_device (*p, layer_geometry, device);
} else {
// output the device for debugging
device_out (device, rdiff2gate, rgate);
// See setup() for the geometry indexes
unsigned int source_geometry_index = 0;
unsigned int drain_geometry_index = 1;
unsigned int gate_geometry_index = 2;
unsigned int gate_terminal_geometry_index = 4;
unsigned int source_terminal_geometry_index = 5;
unsigned int drain_terminal_geometry_index = 6;
const db::Region &sdiff = layer_geometry [source_geometry_index];
const db::Region &ddiff = layer_geometry [drain_geometry_index];
const db::Region &rgates = layer_geometry [gate_geometry_index];
for (db::Region::const_iterator p = rgates.begin_merged (); !p.at_end (); ++p) {
db::Region rgate (*p);
rgate.set_base_verbosity (rgates.base_verbosity ());
db::Region sdiff2gate = sdiff.selected_interacting (rgate);
sdiff2gate.set_base_verbosity (sdiff.base_verbosity ());
db::Region ddiff2gate = ddiff.selected_interacting (rgate);
ddiff2gate.set_base_verbosity (ddiff.base_verbosity ());
if (sdiff2gate.empty () && ddiff2gate.empty ()) {
error (tl::to_string (tr ("Gate shape touches no diffusion - ignored")), *p);
} else if (sdiff2gate.empty () || ddiff2gate.empty ()) {
error (tl::to_string (tr ("Gate shape touches a single diffusion only - ignored")), *p);
} else {
if (sdiff2gate.size () != 1) {
error (tl::sprintf (tl::to_string (tr ("Expected one polygons on source diff interacting with one gate shape (found %d) - gate shape ignored")), int (sdiff2gate.size ())), *p);
continue;
}
if (ddiff2gate.size () != 1) {
error (tl::sprintf (tl::to_string (tr ("Expected one polygons on drain diff interacting with one gate shape (found %d) - gate shape ignored")), int (ddiff2gate.size ())), *p);
continue;
}
db::Region diff2gate = sdiff2gate + ddiff2gate;
db::Edges edges (rgate.edges () & diff2gate.edges ());
if (edges.size () != 2) {
error (tl::sprintf (tl::to_string (tr ("Expected two edges interacting gate/diff (found %d) - width and length may be incorrect")), int (edges.size ())), *p);
continue;
}
if (! p->is_box ()) {
error (tl::to_string (tr ("Gate shape is not a box - width and length may be incorrect")), *p);
}
db::Device *device = create_device ();
device->set_trans (db::DCplxTrans ((p->box ().center () - db::Point ()) * dbu ()));
device->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_W, sdbu () * edges.length () * 0.5);
device->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_L, sdbu () * (p->perimeter () - edges.length ()) * 0.5);
for (int diff_index = 0; diff_index < 2; ++diff_index) {
const db::Region *diff = diff_index == 0 ? &sdiff2gate : &ddiff2gate;
// count the number of gate shapes attached to this shape and distribute the area of the
// diffusion region to the number of gates
size_t n = rgates.selected_interacting (*diff).size ();
tl_assert (n > 0);
device->set_parameter_value (diff_index == 0 ? db::DeviceClassMOS3Transistor::param_id_AS : db::DeviceClassMOS3Transistor::param_id_AD, sdbu () * sdbu () * diff->area () / double (n));
device->set_parameter_value (diff_index == 0 ? db::DeviceClassMOS3Transistor::param_id_PS : db::DeviceClassMOS3Transistor::param_id_PD, sdbu () * diff->perimeter () / double (n));
unsigned int sd_index = diff_index == 0 ? source_terminal_geometry_index : drain_terminal_geometry_index;
define_terminal (device, diff_index == 0 ? db::DeviceClassMOS3Transistor::terminal_id_S : db::DeviceClassMOS3Transistor::terminal_id_D, sd_index, *diff);
}
define_terminal (device, db::DeviceClassMOS3Transistor::terminal_id_G, gate_terminal_geometry_index, *p);
// allow derived classes to modify the device
modify_device (*p, layer_geometry, device);
// output the device for debugging
device_out (device, diff2gate, rgate);
}
}
@ -147,35 +285,61 @@ void NetlistDeviceExtractorMOS3Transistor::extract_devices (const std::vector<db
// ---------------------------------------------------------------------------------
// NetlistDeviceExtractorMOS4Transistor implementation
NetlistDeviceExtractorMOS4Transistor::NetlistDeviceExtractorMOS4Transistor (const std::string &name)
: NetlistDeviceExtractorMOS3Transistor (name)
NetlistDeviceExtractorMOS4Transistor::NetlistDeviceExtractorMOS4Transistor (const std::string &name, bool strict)
: NetlistDeviceExtractorMOS3Transistor (name, strict)
{
// .. nothing yet ..
}
void NetlistDeviceExtractorMOS4Transistor::setup ()
{
define_layer ("SD", "Source/drain diffusion"); // #0
define_layer ("G", "Gate input"); // #1
// for backward compatibility
define_layer ("P", 1, "Gate terminal output"); // #2 -> G
if (! is_strict ()) {
// terminal output
define_layer ("tG", 2, "Gate terminal output"); // #3 -> P -> G
define_layer ("tS", 0, "Source terminal output (default is SD)"); // #4
define_layer ("tD", 0, "Drain terminal output (default is SD)"); // #5
define_layer ("SD", "Source/drain diffusion"); // #0
define_layer ("G", "Gate input"); // #1
// for backward compatibility
define_layer ("P", 1, "Gate terminal output"); // #2 -> G
// for backward compatibility
define_layer ("W", "Well (bulk) terminal output"); // #6
// terminal output
define_layer ("tG", 2, "Gate terminal output"); // #3 -> P -> G
define_layer ("tS", 0, "Source terminal output (default is SD)"); // #4
define_layer ("tD", 0, "Drain terminal output (default is SD)"); // #5
define_layer ("tB", 6, "Well (bulk) terminal output"); // #7 -> W
// for backward compatibility
define_layer ("W", "Well (bulk) terminal output"); // #6
register_device_class (new db::DeviceClassMOS4Transistor ());
define_layer ("tB", 6, "Well (bulk) terminal output"); // #7 -> W
} else {
define_layer ("S", "Source diffusion"); // #0
define_layer ("D", "Drain diffusion"); // #1
define_layer ("G", "Gate input"); // #2
// for backward compatibility
define_layer ("P", 2, "Gate terminal output"); // #3 -> G
// terminal output
define_layer ("tG", 3, "Gate terminal output"); // #4 -> P -> G
define_layer ("tS", 0, "Source terminal output (default is S)"); // #5
define_layer ("tD", 1, "Drain terminal output (default is D)"); // #6
// for backward compatibility
define_layer ("W", "Well (bulk) terminal output"); // #7
define_layer ("tB", 7, "Well (bulk) terminal output"); // #8 -> W
}
db::DeviceClass *cls = new db::DeviceClassMOS4Transistor ();
cls->set_strict (is_strict ());
register_device_class (cls);
}
void NetlistDeviceExtractorMOS4Transistor::modify_device (const db::Polygon &rgate, const std::vector<db::Region> & /*layer_geometry*/, db::Device *device)
{
unsigned int bulk_terminal_geometry_index = 7;
// see setup() for the layer indexes:
unsigned int bulk_terminal_geometry_index = is_strict () ? 8 : 7;
define_terminal (device, db::DeviceClassMOS4Transistor::terminal_id_B, bulk_terminal_geometry_index, rgate);
}

View File

@ -48,12 +48,17 @@ class DB_PUBLIC NetlistDeviceExtractorMOS3Transistor
: public db::NetlistDeviceExtractor
{
public:
NetlistDeviceExtractorMOS3Transistor (const std::string &name);
NetlistDeviceExtractorMOS3Transistor (const std::string &name, bool strict = false);
virtual void setup ();
virtual db::Connectivity get_connectivity (const db::Layout &layout, const std::vector<unsigned int> &layers) const;
virtual void extract_devices (const std::vector<db::Region> &layer_geometry);
bool is_strict () const
{
return m_strict;
}
protected:
/**
* @brief A callback when the device is produced
@ -72,6 +77,8 @@ protected:
// .. no specific implementation ..
}
private:
bool m_strict;
};
/**
@ -87,7 +94,7 @@ class DB_PUBLIC NetlistDeviceExtractorMOS4Transistor
: public NetlistDeviceExtractorMOS3Transistor
{
public:
NetlistDeviceExtractorMOS4Transistor (const std::string &name);
NetlistDeviceExtractorMOS4Transistor (const std::string &name, bool strict = false);
virtual void setup ();

View File

@ -27,6 +27,8 @@
#include "tlStream.h"
#include "tlLog.h"
#include "tlString.h"
#include "tlFileUtils.h"
#include "tlUri.h"
#include <sstream>
#include <cctype>
@ -83,34 +85,73 @@ static db::DeviceClass *make_device_class (db::Circuit *circuit, const std::stri
return cls;
}
bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::string &element, const std::string &name, const std::string &model, double value, const std::vector<db::Net *> &nets, const std::map<std::string, double> &params)
bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::string &element, const std::string &name, const std::string &model, double value, const std::vector<db::Net *> &nets, const std::map<std::string, double> &pv)
{
std::map<std::string, double> params = pv;
double mult = 1.0;
std::map<std::string, double>::const_iterator mp = params.find ("M");
if (mp != params.end ()) {
mult = mp->second;
}
if (mult < 1e-10) {
error (tl::sprintf (tl::to_string (tr ("Invalid multiplier value (M=%.12g) - must not be zero or negative")), mult));
}
std::string cn = model;
db::DeviceClass *cls = circuit->netlist ()->device_class_by_name (cn);
if (cls) {
// use given class
} else if (element == "R") {
if (cn.empty ()) {
cn = "RES";
}
cls = make_device_class<db::DeviceClassResistor> (circuit, cn);
// Apply multiplier
value /= mult;
} else if (element == "L") {
if (cn.empty ()) {
cn = "IND";
}
cls = make_device_class<db::DeviceClassInductor> (circuit, cn);
// Apply multiplier
value /= mult;
} else if (element == "C") {
if (cn.empty ()) {
cn = "CAP";
}
cls = make_device_class<db::DeviceClassCapacitor> (circuit, cn);
// Apply multiplier
value *= mult;
} else if (element == "D") {
if (cn.empty ()) {
cn = "DIODE";
}
cls = make_device_class<db::DeviceClassDiode> (circuit, cn);
// Apply multiplier to "A"
std::map<std::string, double>::iterator p;
p = params.find ("A");
if (p != params.end ()) {
p->second *= mult;
}
} else if (element == "Q") {
if (nets.size () == 3) {
if (cn.empty ()) {
cn = "BJT3";
@ -124,12 +165,29 @@ bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::strin
} else {
error (tl::to_string (tr ("'Q' element needs to have 3 or 4 terminals")));
}
// Apply multiplier to "AE"
std::map<std::string, double>::iterator p;
p = params.find ("AE");
if (p != params.end ()) {
p->second *= mult;
}
} else if (element == "M") {
if (nets.size () == 4) {
if (cn.empty ()) {
cn = "MOS4";
}
cls = make_device_class<db::DeviceClassMOS4Transistor> (circuit, cn);
// Apply multiplier to "W"
std::map<std::string, double>::iterator p;
p = params.find ("W");
if (p != params.end ()) {
p->second *= mult;
}
} else {
error (tl::to_string (tr ("'M' element needs to have 4 terminals")));
}
@ -243,7 +301,20 @@ void NetlistSpiceReader::finish ()
void NetlistSpiceReader::push_stream (const std::string &path)
{
tl::InputStream *istream = new tl::InputStream (path);
tl::URI current_uri (mp_stream->source ());
tl::URI new_uri (path);
tl::InputStream *istream;
if (current_uri.scheme ().empty () && new_uri.scheme ().empty ()) {
if (tl::is_absolute (path)) {
istream = new tl::InputStream (path);
} else {
istream = new tl::InputStream (tl::combine_path (tl::dirname (mp_stream->source ()), path));
}
} else {
istream = new tl::InputStream (current_uri.resolved (new_uri).to_string ());
}
m_streams.push_back (std::make_pair (istream, mp_stream.release ()));
mp_stream.reset (new tl::TextInputStream (*istream));
}
@ -291,7 +362,7 @@ std::string NetlistSpiceReader::get_line ()
}
tl::Extractor ex (l.c_str ());
if (ex.test_without_case (".include")) {
if (ex.test_without_case (".include") || ex.test_without_case (".inc")) {
std::string path = read_name_with_case (ex);
@ -346,8 +417,10 @@ bool NetlistSpiceReader::read_card ()
} else if (ex.test_without_case ("global")) {
std::string n = read_name (ex);
m_global_nets.push_back (n);
while (! ex.at_end ()) {
std::string n = read_name (ex);
m_global_nets.push_back (n);
}
} else if (ex.test_without_case ("subckt")) {
@ -405,7 +478,7 @@ void NetlistSpiceReader::error (const std::string &msg)
void NetlistSpiceReader::warn (const std::string &msg)
{
std::string fmt_msg = tl::sprintf ("%s in %s, line %d", msg, mp_stream->source (), mp_stream->line_number ());
std::string fmt_msg = tl::sprintf ("%s in %s, line %d", msg, mp_stream->source (), mp_stream->line_number () - 1);
tl::warn << fmt_msg;
}
@ -741,10 +814,6 @@ bool NetlistSpiceReader::read_element (tl::Extractor &ex, const std::string &ele
void NetlistSpiceReader::read_subcircuit (const std::string &sc_name, const std::string &nc_name, const std::vector<db::Net *> &nets)
{
if (nets.empty ()) {
error (tl::to_string (tr ("A circuit call needs at least one net")));
}
db::Circuit *cc = mp_netlist->circuit_by_name (nc_name);
if (! cc) {

View File

@ -3960,7 +3960,7 @@ Class<db::Instance> decl_Instance ("db", "Instance",
"\n"
"If the instance is a PCell instance, this method will convert the cell into a static cell and "
"remove the PCell variant if required. A new cell will be created containing the PCell content "
"but begin a static cell. If the instance is not a PCell instance, this method will not do anything.\n"
"but being a static cell. If the instance is not a PCell instance, this method won't do anything.\n"
"\n"
"This method has been introduced in version 0.24."
) +

View File

@ -169,6 +169,13 @@ Class<db::LayoutToNetlist> decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
"The database unit is mandatory because the physical parameter extraction "
"for devices requires this unit for translation of layout to physical dimensions.\n"
) +
gsi::method ("generator", &db::LayoutToNetlist::generator,
"@brief Gets the generator string.\n"
"The generator is the script that created this database.\n"
) +
gsi::method ("generator=", &db::LayoutToNetlist::set_generator, gsi::arg ("generator"),
"@brief Sets the generator string.\n"
) +
gsi::method ("dss", (db::DeepShapeStore &(db::LayoutToNetlist::*) ()) &db::LayoutToNetlist::dss,
"@brief Gets a reference to the internal DSS object.\n"
) +

View File

@ -809,6 +809,20 @@ Class<db::DeviceClass> decl_dbDeviceClass ("db", "DeviceClass",
gsi::method ("name=", &db::DeviceClass::set_name, gsi::arg ("name"),
"@brief Sets the name of the device class."
) +
gsi::method ("strict?", &db::DeviceClass::is_strict,
"@brief Gets a value indicating whether this class performs strict terminal mapping\n"
"See \\strict= for details about this attribute."
) +
gsi::method ("strict=", &db::DeviceClass::set_strict, gsi::arg ("s"),
"@brief Sets a value indicating whether this class performs strict terminal mapping\n"
"\n"
"Classes with this flag set never allow terminal swapping, even if the device symmetry supports that. "
"If two classes are involved in a netlist compare,\n"
"terminal swapping will be disabled if one of the classes is in strict mode.\n"
"\n"
"By default, device classes are not strict and terminal swapping is allowed as far as the "
"device symmetry supports that."
) +
gsi::method ("description", &db::DeviceClass::description,
"@brief Gets the description text of the device class."
) +
@ -1014,7 +1028,9 @@ Class<GenericDeviceClass> decl_GenericDeviceClass (decl_dbDeviceClass, "db", "Ge
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."
"call this method with S and D terminal IDs. In netlist matching, S will be translated to D and thus made equivalent to D.\n"
"\n"
"Note that terminal equivalence is not effective if the device class operates in strict mode (see \\DeviceClass#strict=)."
),
"@brief A generic device class\n"
"This class allows building generic device classes. Specificially, terminals can be defined "
@ -1090,7 +1106,7 @@ Class<db::Circuit> decl_dbCircuit ("db", "Circuit",
"@brief Iterates over the parent circuits of this circuit\n"
"Child circuits are the ones that are referencing this circuit via subcircuits."
) +
gsi::method ("has_refs", &db::Circuit::has_refs,
gsi::method ("has_refs?", &db::Circuit::has_refs,
"@brief Returns a value indicating whether the circuit has references\n"
"A circuit has references if there is at least one subcircuit referring to it."
) +
@ -1363,13 +1379,13 @@ Class<db::Netlist> decl_dbNetlist ("db", "Netlist",
gsi::method ("remove", &db::Netlist::remove_circuit, gsi::arg ("circuit"),
"@brief Removes the given circuit object from the netlist\n"
"After the circuit has been removed, the object becomes invalid and cannot be used further. "
"A circuit with references (see \\has_refs) should not be removed as the "
"A circuit with references (see \\has_refs?) should not be removed as the "
"subcircuits calling it would afterwards point to nothing."
) +
gsi::method ("purge_circuit", &db::Netlist::purge_circuit, gsi::arg ("circuit"),
"@brief Removes the given circuit object and all child circuits which are not used otherwise from the netlist\n"
"After the circuit has been removed, the object becomes invalid and cannot be used further. "
"A circuit with references (see \\has_refs) should not be removed as the "
"A circuit with references (see \\has_refs?) should not be removed as the "
"subcircuits calling it would afterwards point to nothing."
) +
gsi::method ("flatten_circuit", &db::Netlist::flatten_circuit, gsi::arg ("circuit"),

View File

@ -541,12 +541,10 @@ Class<db::NetlistComparer> decl_dbNetlistComparer ("db", "NetlistComparer",
gsi::method_ext ("unmatched_circuits_a", &unmatched_circuits_a, gsi::arg ("a"), gsi::arg ("b"),
"@brief Returns a list of circuits in A for which there is not corresponding circuit in B\n"
"This list can be used to flatten these circuits so they do not participate in the compare process.\n"
"Top level circuits are not included as they cannot be flattened.\n"
) +
gsi::method_ext ("unmatched_circuits_b", &unmatched_circuits_b, gsi::arg ("a"), gsi::arg ("b"),
"@brief Returns a list of circuits in B for which there is not corresponding circuit in A\n"
"This list can be used to flatten these circuits so they do not participate in the compare process.\n"
"Top level circuits are not included as they cannot be flattened.\n"
) +
gsi::method ("compare", (bool (db::NetlistComparer::*) (const db::Netlist *, const db::Netlist *) const) &db::NetlistComparer::compare, gsi::arg ("netlist_a"), gsi::arg ("netlist_b"),
"@brief Compares two netlists.\n"

View File

@ -397,14 +397,19 @@ Class<GenericDeviceExtractor> decl_GenericDeviceExtractor (decl_dbNetlistDeviceE
"This class has been introduced in version 0.26."
);
db::NetlistDeviceExtractorMOS3Transistor *make_mos3_extractor (const std::string &name)
static db::NetlistDeviceExtractorMOS3Transistor *make_mos3_extractor (const std::string &name, bool strict)
{
return new db::NetlistDeviceExtractorMOS3Transistor (name);
return new db::NetlistDeviceExtractorMOS3Transistor (name, strict);
}
Class<db::NetlistDeviceExtractorMOS3Transistor> decl_NetlistDeviceExtractorMOS3Transistor (decl_dbNetlistDeviceExtractor, "db", "DeviceExtractorMOS3Transistor",
gsi::constructor ("new", &make_mos3_extractor, gsi::arg ("name"),
"@brief Creates a new device extractor with the given name."
gsi::constructor ("new", &make_mos3_extractor, gsi::arg ("name"), gsi::arg ("strict", false),
"@brief Creates a new device extractor with the given name.\n"
"If \\strict is true, the MOS device extraction will happen in strict mode. That is, source and drain "
"are not interchangeable."
) +
gsi::method ("strict?", &db::NetlistDeviceExtractorMOS3Transistor::is_strict,
"@brief Returns a value indicating whether extraction happens in strict mode."
),
"@brief A device extractor for a three-terminal MOS transistor\n"
"\n"
@ -418,7 +423,8 @@ Class<db::NetlistDeviceExtractorMOS3Transistor> decl_NetlistDeviceExtractorMOS3T
"The device class produced by this extractor is \\DeviceClassMOS3Transistor.\n"
"The extractor extracts the six parameters of this class: L, W, AS, AD, PS and PD.\n"
"\n"
"The device recognition layer names are 'SD' (source/drain) and 'G' (gate).\n"
"In strict mode, the device recognition layer names are 'S' (source), 'D' (drain) and 'G' (gate).\n"
"Otherwise, they are 'SD' (source/drain) and 'G' (gate).\n"
"The terminal output layer names are 'tS' (source), 'tG' (gate) and 'tD' (drain).\n"
"\n"
"The diffusion area is distributed on the number of gates connecting to\n"
@ -430,13 +436,13 @@ Class<db::NetlistDeviceExtractorMOS3Transistor> decl_NetlistDeviceExtractorMOS3T
"This class has been introduced in version 0.26."
);
db::NetlistDeviceExtractorMOS4Transistor *make_mos4_extractor (const std::string &name)
static db::NetlistDeviceExtractorMOS4Transistor *make_mos4_extractor (const std::string &name, bool strict)
{
return new db::NetlistDeviceExtractorMOS4Transistor (name);
return new db::NetlistDeviceExtractorMOS4Transistor (name, strict);
}
Class<db::NetlistDeviceExtractorMOS4Transistor> decl_NetlistDeviceExtractorMOS4Transistor (decl_dbNetlistDeviceExtractor, "db", "DeviceExtractorMOS4Transistor",
gsi::constructor ("new", &make_mos4_extractor, gsi::arg ("name"),
gsi::constructor ("new", &make_mos4_extractor, gsi::arg ("name"), gsi::arg ("strict", false),
"@brief Creates a new device extractor with the given name."
),
"@brief A device extractor for a four-terminal MOS transistor\n"

View File

@ -270,7 +270,7 @@ TEST(2_ReaderWithGlobalNets)
{
db::LayoutToNetlist l2n;
std::string in_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "l2n_writer_au_2.txt");
std::string in_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "l2n_reader_au.txt");
tl::InputStream is_in (in_path);
db::LayoutToNetlistStandardReader reader (is_in);
@ -285,7 +285,7 @@ TEST(2_ReaderWithGlobalNets)
writer.write (&l2n);
}
std::string au_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "l2n_writer_au_2.txt");
std::string au_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "l2n_reader_au.txt");
compare_text_files (path, au_path);
@ -317,7 +317,7 @@ TEST(2_ReaderWithGlobalNets)
std::string au = tl::testsrc ();
au = tl::combine_path (au, "testdata");
au = tl::combine_path (au, "algo");
au = tl::combine_path (au, "l2n_reader_au_2.gds");
au = tl::combine_path (au, "l2n_reader_au_2r.gds");
db::compare_layouts (_this, ly2, au);
}
@ -327,7 +327,7 @@ TEST(3_ReaderAbsoluteCoordinates)
{
db::LayoutToNetlist l2n;
std::string in_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "l2n_writer_au_2_abs.txt");
std::string in_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "l2n_reader_au_abs.txt");
tl::InputStream is_in (in_path);
db::LayoutToNetlistStandardReader reader (is_in);
@ -342,7 +342,7 @@ TEST(3_ReaderAbsoluteCoordinates)
writer.write (&l2n);
}
std::string au_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "l2n_writer_au_2.txt");
std::string au_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "l2n_reader_au.txt");
compare_text_files (path, au_path);
@ -374,7 +374,7 @@ TEST(3_ReaderAbsoluteCoordinates)
std::string au = tl::testsrc ();
au = tl::combine_path (au, "testdata");
au = tl::combine_path (au, "algo");
au = tl::combine_path (au, "l2n_reader_au_2.gds");
au = tl::combine_path (au, "l2n_reader_au_2r.gds");
db::compare_layouts (_this, ly2, au);
}

View File

@ -554,15 +554,15 @@ TEST(1_BasicExtraction)
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"
" 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"
@ -583,7 +583,7 @@ TEST(1_BasicExtraction)
// the transistor which supplies this probe target has been optimized away by "purge".
EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (5.3, 0.0))), "(null)");
EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (2.6, 1.0))), "INV2:$2");
EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (2.6, 1.0))), "RINGO:$I39");
EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (6.4, 1.0))), "RINGO:$I2");
}
@ -806,14 +806,14 @@ TEST(2_Probing)
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"
" 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=(null),OUT=$I3,$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"
@ -834,7 +834,7 @@ TEST(2_Probing)
// the transistor which supplies this probe target has been optimized away by "purge".
EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (5.3, 0.0))), "(null)");
EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (2.6, 1.0))), "INV2PAIR:$I7");
EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (2.6, 1.0))), "RINGO:$I18");
EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (6.4, 1.0))), "INV2PAIR:$I3");
}
@ -1087,13 +1087,13 @@ TEST(3_GlobalNetConnections)
db::compare_netlist (_this, *l2n.netlist (),
"circuit RINGO (FB=FB,OSC=OSC,VDD=VDD,VSS=VSS);\n"
" subcircuit INV2PAIR $1 (BULK=VSS,$2=FB,$3=VDD,$4=VSS,$5=$I7,$6=OSC,$7=VDD);\n"
" subcircuit INV2PAIR $2 (BULK=VSS,$2=(null),$3=VDD,$4=VSS,$5=FB,$6=$I13,$7=VDD);\n"
" subcircuit INV2PAIR $3 (BULK=VSS,$2=(null),$3=VDD,$4=VSS,$5=$I13,$6=$I5,$7=VDD);\n"
" subcircuit INV2PAIR $4 (BULK=VSS,$2=(null),$3=VDD,$4=VSS,$5=$I5,$6=$I6,$7=VDD);\n"
" subcircuit INV2PAIR $5 (BULK=VSS,$2=(null),$3=VDD,$4=VSS,$5=$I6,$6=$I7,$7=VDD);\n"
" subcircuit INV2PAIR $2 (BULK=VSS,$2=$I22,$3=VDD,$4=VSS,$5=FB,$6=$I13,$7=VDD);\n"
" subcircuit INV2PAIR $3 (BULK=VSS,$2=$I23,$3=VDD,$4=VSS,$5=$I13,$6=$I5,$7=VDD);\n"
" subcircuit INV2PAIR $4 (BULK=VSS,$2=$I24,$3=VDD,$4=VSS,$5=$I5,$6=$I6,$7=VDD);\n"
" subcircuit INV2PAIR $5 (BULK=VSS,$2=$I25,$3=VDD,$4=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 $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=(null),IN=IN,$3=$3,OUT=OUT,VSS=VSS,VDD=VDD,BULK=(null));\n"
@ -1115,7 +1115,7 @@ TEST(3_GlobalNetConnections)
// the transistor which supplies this probe target has been optimized away by "purge".
EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (5.3, 0.0))), "(null)");
EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (2.6, 1.0))), "INV2PAIR:$I8");
EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (2.6, 1.0))), "RINGO:$I22");
EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (6.4, 1.0))), "INV2PAIR:$I4");
}
@ -1374,13 +1374,13 @@ TEST(4_GlobalNetDeviceExtraction)
db::compare_netlist (_this, *l2n.netlist (),
"circuit RINGO (FB=FB,OSC=OSC,VDD=VDD,VSS=VSS);\n"
" subcircuit INV2PAIR $1 (BULK=VSS,$2=FB,$3=VDD,$4=VSS,$5=$I7,$6=OSC,$7=VDD);\n"
" subcircuit INV2PAIR $2 (BULK=VSS,$2=(null),$3=VDD,$4=VSS,$5=FB,$6=$I13,$7=VDD);\n"
" subcircuit INV2PAIR $3 (BULK=VSS,$2=(null),$3=VDD,$4=VSS,$5=$I13,$6=$I5,$7=VDD);\n"
" subcircuit INV2PAIR $4 (BULK=VSS,$2=(null),$3=VDD,$4=VSS,$5=$I5,$6=$I6,$7=VDD);\n"
" subcircuit INV2PAIR $5 (BULK=VSS,$2=(null),$3=VDD,$4=VSS,$5=$I6,$6=$I7,$7=VDD);\n"
" subcircuit INV2PAIR $2 (BULK=VSS,$2=$I22,$3=VDD,$4=VSS,$5=FB,$6=$I13,$7=VDD);\n"
" subcircuit INV2PAIR $3 (BULK=VSS,$2=$I23,$3=VDD,$4=VSS,$5=$I13,$6=$I5,$7=VDD);\n"
" subcircuit INV2PAIR $4 (BULK=VSS,$2=$I24,$3=VDD,$4=VSS,$5=$I5,$6=$I6,$7=VDD);\n"
" subcircuit INV2PAIR $5 (BULK=VSS,$2=$I25,$3=VDD,$4=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 $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"
@ -1402,7 +1402,7 @@ TEST(4_GlobalNetDeviceExtraction)
// the transistor which supplies this probe target has been optimized away by "purge".
EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (5.3, 0.0))), "(null)");
EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (2.6, 1.0))), "INV2PAIR:$I8");
EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (2.6, 1.0))), "RINGO:$I22");
EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (6.4, 1.0))), "INV2PAIR:$I4");
}
@ -1658,10 +1658,10 @@ TEST(5_DeviceExtractionWithDeviceCombination)
db::compare_netlist (_this, *l2n.netlist (),
"circuit RINGO (FB=FB,OSC=OSC,VDD=VDD,VSS=VSS);\n"
" subcircuit INV2PAIR $1 (BULK=VSS,$2=VDD,$3=VSS,$4=FB,$5=$I7,$6=OSC,$7=VDD);\n"
" subcircuit INV2PAIR $2 (BULK=VSS,$2=VDD,$3=VSS,$4=(null),$5=FB,$6=$I13,$7=VDD);\n"
" subcircuit INV2PAIR $3 (BULK=VSS,$2=VDD,$3=VSS,$4=(null),$5=$I13,$6=$I5,$7=VDD);\n"
" subcircuit INV2PAIR $4 (BULK=VSS,$2=VDD,$3=VSS,$4=(null),$5=$I5,$6=$I6,$7=VDD);\n"
" subcircuit INV2PAIR $5 (BULK=VSS,$2=VDD,$3=VSS,$4=(null),$5=$I6,$6=$I7,$7=VDD);\n"
" subcircuit INV2PAIR $2 (BULK=VSS,$2=VDD,$3=VSS,$4=$I22,$5=FB,$6=$I13,$7=VDD);\n"
" subcircuit INV2PAIR $3 (BULK=VSS,$2=VDD,$3=VSS,$4=$I23,$5=$I13,$6=$I5,$7=VDD);\n"
" subcircuit INV2PAIR $4 (BULK=VSS,$2=VDD,$3=VSS,$4=$I24,$5=$I5,$6=$I6,$7=VDD);\n"
" subcircuit INV2PAIR $5 (BULK=VSS,$2=VDD,$3=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"

View File

@ -371,14 +371,14 @@ TEST(2_WriterWithGlobalNets)
l2n.netlist ()->make_top_level_pins ();
l2n.netlist ()->purge ();
std::string path = tmp_file ("tmp_l2nwriter_2.txt");
std::string path = tmp_file ("tmp_l2nwriter_2b.txt");
{
tl::OutputStream stream (path);
db::LayoutToNetlistStandardWriter writer (stream, false);
writer.write (&l2n);
}
std::string au_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "l2n_writer_au_2.txt");
std::string au_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "l2n_writer_au_2b.txt");
compare_text_files (path, au_path);

View File

@ -1661,6 +1661,7 @@ TEST(11_MismatchingSubcircuits)
NetlistCompareTestLogger logger;
db::NetlistComparer comp (&logger);
comp.set_dont_consider_net_names (true);
bool good = comp.compare (&nl1, &nl2);
@ -1696,6 +1697,7 @@ TEST(11_MismatchingSubcircuits)
db::NetlistCrossReference xref;
db::NetlistComparer comp_xref (&xref);
comp_xref.set_dont_consider_net_names (true);
good = comp_xref.compare (&nl1, &nl2);
@ -2053,12 +2055,12 @@ TEST(14_Subcircuit2NandMismatchNoSwap)
"net_mismatch INT IN1\n"
"net_mismatch IN1 INT\n"
"net_mismatch IN2 IN2\n"
"pin_mismatch $0 (null)\n"
"match_pins $0 (null)\n"
"match_pins $1 $1\n"
"match_pins $2 $2\n"
"match_pins $3 $3\n"
"match_pins $4 $4\n"
"pin_mismatch (null) $0\n"
"match_pins (null) $0\n"
"match_subcircuits $2 $1\n"
"subcircuit_mismatch $1 $2\n"
"end_circuit TOP TOP NOMATCH"
@ -2106,8 +2108,8 @@ TEST(14_Subcircuit2NandMismatchNoSwap)
" device $1:$1 [Match]\n"
" device $2:$2 [Match]\n"
"TOP:TOP [NoMatch]:\n"
" pin (null):$0 [Mismatch]\n"
" pin $0:(null) [Mismatch]\n"
" pin (null):$0 [Match]\n"
" pin $0:(null) [Match]\n"
" pin $1:$1 [Match]\n"
" pin $2:$2 [Match]\n"
" pin $3:$3 [Match]\n"
@ -2521,6 +2523,7 @@ TEST(17_InherentlyAmbiguousDecoder)
NetlistCompareTestLogger logger;
db::NetlistComparer comp (&logger);
comp.equivalent_pins (nl2.circuit_by_name ("NAND"), 0, 1);
comp.set_dont_consider_net_names (true);
bool good = comp.compare (&nl1, &nl2);
@ -2572,7 +2575,61 @@ TEST(17_InherentlyAmbiguousDecoder)
EXPECT_EQ (good, true);
comp.set_dont_consider_net_names (false);
logger.clear ();
good = comp.compare (&nl1, &nl2);
EXPECT_EQ (logger.text (),
"begin_circuit NAND NAND\n"
"match_nets VSS VSS\n"
"match_nets INT INT\n"
"match_nets OUT OUT\n"
"match_nets VDD VDD\n"
"match_nets B B\n"
"match_nets A A\n"
"match_pins $0 $0\n"
"match_pins $1 $1\n"
"match_pins $2 $2\n"
"match_pins $3 $3\n"
"match_pins $4 $4\n"
"match_devices $1 $1\n"
"match_devices $2 $2\n"
"match_devices $3 $3\n"
"match_devices $4 $4\n"
"end_circuit NAND NAND MATCH\n"
"begin_circuit DECODER DECODER\n"
"match_nets VSS VSS\n"
"match_nets VDD VDD\n"
"match_nets NQ0 NQ0\n"
"match_nets NQ1 NQ1\n"
"match_nets NQ2 NQ2\n"
"match_nets NQ3 NQ3\n"
"match_ambiguous_nets NA NA\n"
"match_ambiguous_nets NB NB\n"
"match_nets B B\n"
"match_nets A A\n"
"match_pins $0 $1\n"
"match_pins $1 $0\n"
"match_pins $2 $2\n"
"match_pins $3 $3\n"
"match_pins $4 $4\n"
"match_pins $5 $5\n"
"match_pins $6 $6\n"
"match_pins $7 $7\n"
"match_subcircuits $1 $1\n"
"match_subcircuits $2 $2\n"
"match_subcircuits $4 $3\n"
"match_subcircuits $6 $4\n"
"match_subcircuits $3 $5\n"
"match_subcircuits $5 $6\n"
"end_circuit DECODER DECODER MATCH"
);
EXPECT_EQ (good, true);
logger.clear ();
comp.set_dont_consider_net_names (true);
comp.same_nets (nl1.circuit_by_name ("DECODER")->net_by_name ("A"), nl2.circuit_by_name ("DECODER")->net_by_name ("A"));
good = comp.compare (&nl1, &nl2);

View File

@ -36,6 +36,7 @@
#include "dbTestSupport.h"
#include "dbCellMapping.h"
#include "dbTestSupport.h"
#include "dbNetlistCompare.h"
#include "tlUnitTest.h"
#include "tlString.h"
@ -353,15 +354,15 @@ TEST(1_DeviceAndNetExtraction)
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"
" 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"
@ -818,15 +819,15 @@ TEST(3_DeviceAndNetExtractionWithImplicitConnections)
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"
" 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"
@ -1864,3 +1865,246 @@ TEST(8_DiodeExtractionScaled)
db::compare_layouts (_this, ly, au);
}
TEST(9_StrictDeviceExtraction)
{
db::Layout ly;
db::LayerMap lmap;
unsigned int nwell = define_layer (ly, lmap, 1);
unsigned int active = define_layer (ly, lmap, 2);
unsigned int poly = define_layer (ly, lmap, 3);
unsigned int poly_lbl = define_layer (ly, lmap, 3, 1);
unsigned int diff_cont = define_layer (ly, lmap, 4);
unsigned int poly_cont = define_layer (ly, lmap, 5);
unsigned int metal1 = define_layer (ly, lmap, 6);
unsigned int metal1_lbl = define_layer (ly, lmap, 6, 1);
unsigned int via1 = define_layer (ly, lmap, 7);
unsigned int metal2 = define_layer (ly, lmap, 8);
unsigned int metal2_lbl = define_layer (ly, lmap, 8, 1);
unsigned int source = define_layer (ly, lmap, 10);
{
db::LoadLayoutOptions options;
options.get_options<db::CommonReaderOptions> ().layer_map = lmap;
options.get_options<db::CommonReaderOptions> ().create_other_layers = false;
std::string fn (tl::testsrc ());
fn = tl::combine_path (fn, "testdata");
fn = tl::combine_path (fn, "algo");
fn = tl::combine_path (fn, "device_extract_l9.gds");
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (ly, options);
}
db::Cell &tc = ly.cell (*ly.begin_top_down ());
db::DeepShapeStore dss;
dss.set_text_enlargement (1);
dss.set_text_property_name (tl::Variant ("LABEL"));
// original layers
db::Region rnwell (db::RecursiveShapeIterator (ly, tc, nwell), dss);
db::Region ractive (db::RecursiveShapeIterator (ly, tc, active), dss);
db::Region rpoly (db::RecursiveShapeIterator (ly, tc, poly), dss);
db::Region rpoly_lbl (db::RecursiveShapeIterator (ly, tc, poly_lbl), dss);
db::Region rdiff_cont (db::RecursiveShapeIterator (ly, tc, diff_cont), dss);
db::Region rpoly_cont (db::RecursiveShapeIterator (ly, tc, poly_cont), dss);
db::Region rmetal1 (db::RecursiveShapeIterator (ly, tc, metal1), dss);
db::Region rmetal1_lbl (db::RecursiveShapeIterator (ly, tc, metal1_lbl), dss);
db::Region rvia1 (db::RecursiveShapeIterator (ly, tc, via1), dss);
db::Region rmetal2 (db::RecursiveShapeIterator (ly, tc, metal2), dss);
db::Region rmetal2_lbl (db::RecursiveShapeIterator (ly, tc, metal2_lbl), dss);
db::Region rsource (db::RecursiveShapeIterator (ly, tc, source), dss);
// derived regions
db::Region rpactive = ractive & rnwell;
db::Region rpgate = rpactive & rpoly;
db::Region rpsd = rpactive - rpgate;
db::Region rps = rpsd & rsource;
db::Region rpd = rpsd - rsource;
db::Region rnactive = ractive - rnwell;
db::Region rngate = rnactive & rpoly;
db::Region rnsd = rnactive - rngate;
db::Region rns = rnsd & rsource;
db::Region rnd = rnsd - rsource;
// return the computed layers into the original layout and write it for debugging purposes
unsigned int lgate = ly.insert_layer (db::LayerProperties (20, 0)); // 10/0 -> Gate
unsigned int lsd = ly.insert_layer (db::LayerProperties (21, 0)); // 11/0 -> Source/Drain
unsigned int lpdiff = ly.insert_layer (db::LayerProperties (22, 0)); // 12/0 -> P Diffusion
unsigned int lndiff = ly.insert_layer (db::LayerProperties (23, 0)); // 13/0 -> N Diffusion
rpgate.insert_into (&ly, tc.cell_index (), lgate);
rngate.insert_into (&ly, tc.cell_index (), lgate);
rps.insert_into (&ly, tc.cell_index (), lsd);
rpd.insert_into (&ly, tc.cell_index (), lsd);
rns.insert_into (&ly, tc.cell_index (), lsd);
rnd.insert_into (&ly, tc.cell_index (), lsd);
rpsd.insert_into (&ly, tc.cell_index (), lpdiff);
rnsd.insert_into (&ly, tc.cell_index (), lndiff);
// perform the extraction
db::Netlist nl;
db::hier_clusters<db::PolygonRef> cl;
db::NetlistDeviceExtractorMOS3Transistor pmos_ex ("PMOS", true /*strict*/);
db::NetlistDeviceExtractorMOS3Transistor nmos_ex ("NMOS", true /*strict*/);
db::NetlistDeviceExtractor::input_layers dl;
dl["S"] = &rps;
dl["D"] = &rpd;
dl["G"] = &rpgate;
dl["P"] = &rpoly; // not needed for extraction but to return terminal shapes
pmos_ex.extract (dss, 0, dl, nl, cl);
dl["S"] = &rns;
dl["D"] = &rnd;
dl["G"] = &rngate;
dl["P"] = &rpoly; // not needed for extraction but to return terminal shapes
nmos_ex.extract (dss, 0, dl, nl, cl);
// perform the net extraction
db::NetlistExtractor net_ex;
db::Connectivity conn;
// Intra-layer
conn.connect (rps);
conn.connect (rpd);
conn.connect (rns);
conn.connect (rnd);
conn.connect (rpoly);
conn.connect (rdiff_cont);
conn.connect (rpoly_cont);
conn.connect (rmetal1);
conn.connect (rvia1);
conn.connect (rmetal2);
// Inter-layer
conn.connect (rps, rdiff_cont);
conn.connect (rpd, rdiff_cont);
conn.connect (rns, rdiff_cont);
conn.connect (rnd, rdiff_cont);
conn.connect (rpoly, rpoly_cont);
conn.connect (rpoly_cont, rmetal1);
conn.connect (rdiff_cont, rmetal1);
conn.connect (rmetal1, rvia1);
conn.connect (rvia1, rmetal2);
conn.connect (rpoly, rpoly_lbl); // attaches labels
conn.connect (rmetal1, rmetal1_lbl); // attaches labels
conn.connect (rmetal2, rmetal2_lbl); // attaches labels
// extract the nets
net_ex.extract_nets (dss, 0, conn, nl, cl);
// debug layers produced for nets
// 202/0 -> Active
// 203/0 -> Poly
// 204/0 -> Diffusion contacts
// 205/0 -> Poly contacts
// 206/0 -> Metal1
// 207/0 -> Via1
// 208/0 -> Metal2
// 210/0 -> N source/drain
// 211/0 -> P source/drain
std::map<unsigned int, unsigned int> dump_map;
dump_map [layer_of (rps) ] = ly.insert_layer (db::LayerProperties (210, 0));
dump_map [layer_of (rpd) ] = ly.insert_layer (db::LayerProperties (211, 0));
dump_map [layer_of (rns) ] = ly.insert_layer (db::LayerProperties (212, 0));
dump_map [layer_of (rnd) ] = ly.insert_layer (db::LayerProperties (213, 0));
dump_map [layer_of (rpoly) ] = ly.insert_layer (db::LayerProperties (203, 0));
dump_map [layer_of (rdiff_cont)] = ly.insert_layer (db::LayerProperties (204, 0));
dump_map [layer_of (rpoly_cont)] = ly.insert_layer (db::LayerProperties (205, 0));
dump_map [layer_of (rmetal1) ] = ly.insert_layer (db::LayerProperties (206, 0));
dump_map [layer_of (rvia1) ] = ly.insert_layer (db::LayerProperties (207, 0));
dump_map [layer_of (rmetal2) ] = ly.insert_layer (db::LayerProperties (208, 0));
// write nets to layout
db::CellMapping cm = dss.cell_mapping_to_original (0, &ly, tc.cell_index ());
dump_nets_to_layout (nl, cl, ly, dump_map, cm);
std::string nl_au_string =
"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=$5,G=IN,D=$2) (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=$4,G=IN,D=$2) (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 netlist as string
CHECKPOINT ();
db::compare_netlist (_this, nl, nl_au_string);
{
// compare vs. non-strict device classes
db::Netlist au_nl;
// non-strict
db::DeviceClass *dc;
dc = new db::DeviceClassMOS3Transistor ();
dc->set_name ("PMOS");
au_nl.add_device_class (dc);
dc = new db::DeviceClassMOS3Transistor ();
dc->set_name ("NMOS");
au_nl.add_device_class (dc);
au_nl.from_string (nl_au_string);
CHECKPOINT ();
db::compare_netlist (_this, nl, au_nl);
}
{
std::string nl_au_string_wrong_terminals = nl_au_string;
nl_au_string_wrong_terminals = tl::replaced (nl_au_string_wrong_terminals, "(S=$5,G=IN,D=$2)", "(S=$2,G=IN,D=$5)");
nl_au_string_wrong_terminals = tl::replaced (nl_au_string_wrong_terminals, "(S=$4,G=IN,D=$2)", "(S=$2,G=IN,D=$4)");
// compare vs. non-strict device classes with WRONG terminal assignment
db::Netlist au_nl;
// non-strict
db::DeviceClass *dc;
dc = new db::DeviceClassMOS3Transistor ();
dc->set_name ("PMOS");
au_nl.add_device_class (dc);
dc = new db::DeviceClassMOS3Transistor ();
dc->set_name ("NMOS");
au_nl.add_device_class (dc);
au_nl.from_string (nl_au_string_wrong_terminals);
db::NetlistComparer comp (0);
EXPECT_EQ (comp.compare (&nl, &au_nl), false);
}
// compare the collected test data
std::string au = tl::testsrc ();
au = tl::combine_path (au, "testdata");
au = tl::combine_path (au, "algo");
au = tl::combine_path (au, "device_extract_au9.gds");
db::compare_layouts (_this, ly, au);
}

View File

@ -137,10 +137,10 @@ TEST(4_ReaderWithUnconnectedPins)
EXPECT_EQ (nl.to_string (),
"circuit RINGO ('1'='1','2'='2','3'='3','4'='4');\n"
" subcircuit INV2PAIR $1 ('1'='4','2'='3','3'='4','4'='1','5'='6','6'='2','7'='3');\n"
" subcircuit INV2PAIR $2 ('1'='4','2'='3','3'='4','4'=(null),'5'='1','6'='5','7'='3');\n"
" subcircuit INV2PAIR $3 ('1'='4','2'='3','3'='4','4'=(null),'5'='5','6'='8','7'='3');\n"
" subcircuit INV2PAIR $4 ('1'='4','2'='3','3'='4','4'=(null),'5'='8','6'='7','7'='3');\n"
" subcircuit INV2PAIR $5 ('1'='4','2'='3','3'='4','4'=(null),'5'='7','6'='6','7'='3');\n"
" subcircuit INV2PAIR $2 ('1'='4','2'='3','3'='4','4'='100','5'='1','6'='5','7'='3');\n"
" subcircuit INV2PAIR $3 ('1'='4','2'='3','3'='4','4'='101','5'='5','6'='8','7'='3');\n"
" subcircuit INV2PAIR $4 ('1'='4','2'='3','3'='4','4'='102','5'='8','6'='7','7'='3');\n"
" subcircuit INV2PAIR $5 ('1'='4','2'='3','3'='4','4'='103','5'='7','6'='6','7'='3');\n"
"end;\n"
"circuit INV2PAIR ('1'='1','2'='2','3'='3','4'='4','5'='5','6'='6','7'='7');\n"
" subcircuit INV2 $1 ('1'='7','2'='5','3'='4','4'='3','5'='2','6'='1');\n"
@ -251,7 +251,7 @@ TEST(6_ReaderWithDelegate)
" device RES $1 (A=A,B=Z) (R=100000,L=0,W=0,A=0,P=0);\n"
"end;\n"
"circuit .TOP ();\n"
" subcircuit SUBCKT SUBCKT ($1=(null),A=(null),VDD=(null),Z=(null),GND=VSS,GND$1=VSS);\n"
" subcircuit SUBCKT SUBCKT ($1=IN,A=OUT,VDD=VDD,Z=Z,GND=VSS,GND$1=VSS);\n"
"end;\n"
);
}
@ -294,3 +294,93 @@ TEST(7_GlobalNets)
"end;\n"
);
}
TEST(8_Include)
{
db::Netlist nl;
std::string path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "nreader8.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 ('11'='11','12'='12','13'='13','14'='14','15'='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"
);
}
TEST(9_DeviceMultipliers)
{
db::Netlist nl;
std::string path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "nreader9.cir");
db::NetlistSpiceReader reader;
tl::InputStream is (path);
reader.read (is, nl);
std::string nl_string = nl.to_string ();
// normalization of exponential representation:
nl_string = tl::replaced (nl_string, "e-009", "e-09");
EXPECT_EQ (nl_string,
"circuit .TOP ();\n"
" device RES $1 (A='1',B='2') (R=850,L=0,W=0,A=0,P=0);\n"
" device RES $2 (A='3',B='4') (R=1700,L=0,W=0,A=0,P=0);\n"
" device NMOS $1 (S='1',G='2',D='3',B='4') (L=7,W=4,AS=0,AD=0,PS=0,PD=0);\n"
" device PMOS $2 (S='1',G='2',D='3',B='4') (L=7,W=2,AS=0,AD=0,PS=0,PD=0);\n"
" device CAP $1 (A='1',B='2') (C=2e-09,A=0,P=0);\n"
" device CAP $2 (A='3',B='4') (C=1e-09,A=0,P=0);\n"
" device DIODE $1 (A='1',C='2') (A=20,P=0);\n"
" device DIODE $2 (A='3',C='4') (A=10,P=0);\n"
" device BIP $1 (C='1',B='2',E='3',S='4') (AE=20,PE=0,AB=0,PB=0,AC=0,PC=0,NE=1);\n"
" device BIP $2 (C='1',B='2',E='3',S='4') (AE=10,PE=0,AB=0,PB=0,AC=0,PC=0,NE=1);\n"
"end;\n"
);
}
TEST(10_SubcircuitsNoPins)
{
db::Netlist nl;
std::string path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "nreader10.cir");
db::NetlistSpiceReader reader;
tl::InputStream is (path);
reader.read (is, nl);
EXPECT_EQ (nl.to_string (),
"circuit .TOP ();\n"
" device RES $1 (A=VDD,B=GND) (R=1000,L=0,W=0,A=0,P=0);\n"
" subcircuit FILLER_CAP '0' (VDD=VDD,GND=GND);\n"
"end;\n"
"circuit FILLER_CAP (VDD=VDD,GND=GND);\n"
" device NMOS '0' (S=GND,G=VDD,D=GND,B=GND) (L=10,W=10,AS=0,AD=0,PS=0,PD=0);\n"
"end;\n"
);
}

View File

@ -780,7 +780,7 @@ TEST(7_NetTerminalsEditing)
EXPECT_EQ (n1->terminal_count (), size_t (1));
EXPECT_EQ (n1->pin_count (), size_t (0));
EXPECT_EQ (n1->is_floating (), true);
EXPECT_EQ (n1->is_floating (), false);
EXPECT_EQ (n1->is_internal (), false);
d2->connect_terminal (1, n1);

View File

@ -20,6 +20,9 @@ module DRC
cv = RBA::CellView::active
@generator = ""
@rdb_index = nil
@l2ndb_index = nil
@def_layout = cv && cv.layout
@def_cell = cv && cv.cell
@def_path = cv && cv.filename
@ -161,6 +164,32 @@ module DRC
RBA::DeviceExtractorMOS4Transistor::new(name)
end
# %DRC%
# @brief Supplies the DMOS3 transistor extractor class
# @name dmos3
# @synopsis dmos3(name)
# Use this class with \extract_devices to specify extraction of a
# three-terminal DMOS transistor. A DMOS transistor is essentially
# the same than a MOS transistor, but source and drain are
# separated.
def dmos3(name)
RBA::DeviceExtractorMOS3Transistor::new(name, true)
end
# %DRC%
# @brief Supplies the MOS4 transistor extractor class
# @name dmos4
# @synopsis dmos4(name)
# Use this class with \extract_devices to specify extraction of a
# four-terminal DMOS transistor. A DMOS transistor is essentially
# the same than a MOS transistor, but source and drain are
# separated.
def dmos4(name)
RBA::DeviceExtractorMOS4Transistor::new(name, true)
end
# %DRC%
# @brief Supplies the BJT3 transistor extractor class
# @name bjt3
@ -734,10 +763,17 @@ module DRC
name = filename && File::basename(filename)
name ||= "DRC"
lv = RBA::LayoutView::current
if lv
@output_rdb_index = lv.create_rdb(name)
@output_rdb = lv.rdb(@output_rdb_index)
@output_rdb_index = nil
view = RBA::LayoutView::current
if view
if self._rdb_index
@output_rdb = RBA::ReportDatabase::new("") # reuse existing name
@output_rdb_index = view.replace_rdb(self._rdb_index, @output_rdb)
else
@output_rdb = RBA::ReportDatabase::new(name)
@output_rdb_index = view.add_rdb(@output_rdb)
end
else
@output_rdb = RBA::ReportDatabase::new(name)
end
@ -754,7 +790,7 @@ module DRC
cn || raise("No cell name specified - either the source was not specified before 'report' or there is no default source. In the latter case, specify a cell name as the third parameter of 'report'")
@output_rdb_cell = @output_rdb.create_cell(cn)
@output_rdb.generator = $0
@output_rdb.generator = self._generator
@output_rdb.top_cell_name = cn
@output_rdb.description = description
@ -1440,7 +1476,11 @@ CODE
# NOTE: to prevent the netter destroying the database, we need to take it
l2ndb = _take_data
l2ndb_index = view.add_l2ndb(l2ndb)
if self._l2ndb_index
l2ndb_index = view.replace_l2ndb(self._l2ndb_index, l2ndb)
else
l2ndb_index = view.add_l2ndb(l2ndb)
end
view.show_l2ndb(l2ndb_index, view.active_cellview_index)
end
@ -1525,6 +1565,30 @@ CODE
end
end
def _generator
@generator
end
def _generator=(g)
@generator = g
end
def _rdb_index
@rdb_index
end
def _rdb_index=(i)
@rdb_index = i
end
def _l2ndb_index
@l2ndb_index
end
def _l2ndb_index=(i)
@l2ndb_index = i
end
private
def _make_string(v)
@ -1691,7 +1755,7 @@ CODE
@layout_sources[name] = src
src
end
end
end

View File

@ -407,6 +407,9 @@ module DRC
@l2n = RBA::LayoutToNetlist::new(layout.top_cell.name, layout.dbu)
end
@l2n.name = "DRC"
@l2n.generator = @engine._generator
end
def register_layer(data)

View File

@ -17,37 +17,39 @@
<text>
module DRC
def DRC.execute_drc(_macro)
def DRC.execute_drc(macro, generator, rdb_index = nil)
_timer = RBA::Timer::new
_timer.start
_drc = DRCEngine::new
timer = RBA::Timer::new
timer.start
drc = DRCEngine::new
drc._rdb_index = rdb_index
drc._generator = generator
begin
# Set a debugger scope so that our errors end up with the debugger set to the DRC's line
RBA::MacroExecutionContext::set_debugger_scope(_macro.path)
RBA::MacroExecutionContext::set_debugger_scope(macro.path)
# No verbosity set in drc engine - we cannot use the engine's logger
RBA::Logger::verbosity &gt;= 10 &amp;&amp; RBA::Logger::info("Running #{_macro.path}")
_drc.instance_eval(_macro.text, _macro.path)
RBA::Logger::verbosity &gt;= 10 &amp;&amp; RBA::Logger::info("Running #{macro.path}")
drc.instance_eval(macro.text, macro.path)
# Remove the debugger scope
RBA::MacroExecutionContext::remove_debugger_scope
rescue =&gt; ex
_drc.error("In #{_macro.path}: #{ex.to_s}")
drc.error("In #{macro.path}: #{ex.to_s}")
RBA::MacroExecutionContext::ignore_next_exception
raise ex
ensure
# cleans up and creates layout and report views
_drc._finish
drc._finish
end
_timer.stop
_drc.info("Total run time: #{'%.3f'%(_timer.sys+_timer.user)}s")
timer.stop
drc.info("Total run time: #{'%.3f'%(timer.sys+timer.user)}s")
end
@ -55,7 +57,9 @@ module DRC
class DRCInterpreter &lt; RBA::MacroInterpreter
# Constructor
def initialize
def initialize(recipe)
@recipe = recipe
# Make the DSL use ruby syntax highlighting
self.syntax_scheme = "ruby"
@ -74,7 +78,7 @@ module DRC
# Implements the execute method
def execute(macro)
DRC::execute_drc(macro)
DRC::execute_drc(macro, @recipe.generator("script" => macro.path))
end
end
@ -83,7 +87,9 @@ module DRC
class DRCPlainTextInterpreter &lt; RBA::MacroInterpreter
# Constructor
def initialize
def initialize(recipe)
@recipe = recipe
# Make the DSL use ruby syntax highlighting
self.syntax_scheme = "ruby"
@ -99,14 +105,40 @@ module DRC
# Implements the execute method
def execute(macro)
DRC::execute_drc(macro)
DRC::execute_drc(macro, @recipe.generator("script" => macro.path))
end
end
# A recipe implementation allowing the LVS run to be redone
class DRCRecipe &lt; RBA::Recipe
def initialize
super("drc", "DRC recipe")
end
def execute(params)
script = params["script"]
if ! script
return
end
macro = RBA::Macro::macro_by_path(script)
macro || raise("Can't find DRC script #{script} - unable to re-run")
DRC::execute_drc(macro, self.generator("script" => script), params["rdb_index"])
end
end
# Register the recipe
drc_recipe = DRCRecipe::new
# Register the new interpreters
DRCInterpreter::new
DRCPlainTextInterpreter::new
DRCInterpreter::new(drc_recipe)
DRCPlainTextInterpreter::new(drc_recipe)
end
</text>

View File

@ -27,6 +27,7 @@
#include "tlProgress.h"
#include "tlExpression.h"
#include "tlGlobPattern.h"
#include "tlRecipe.h"
// ----------------------------------------------------------------
// Logger binding
@ -640,4 +641,87 @@ Class<tl::GlobPattern> decl_GlobPattern ("tl", "GlobPattern",
"This class has been introduced in version 0.26."
);
class Recipe_Impl
: public tl::Recipe, public gsi::ObjectBase
{
public:
Recipe_Impl (const std::string &name, const std::string &description)
: tl::Recipe (name, description)
{
// makes the object owned by the C++ side (registrar). This way we don't need to keep a
// singleton instance.
keep ();
}
virtual tl::Variant execute (const std::map<std::string, tl::Variant> &params) const
{
if (execute_cb.can_issue ()) {
return execute_cb.issue<tl::Recipe, tl::Variant, const std::map<std::string, tl::Variant> &> (&tl::Recipe::execute, params);
} else {
return tl::Variant ();
}
}
gsi::Callback execute_cb;
};
}
namespace tl
{
template <> struct type_traits<gsi::Recipe_Impl> : public type_traits<tl::Recipe> { };
}
namespace gsi
{
static Recipe_Impl *make_recipe (const std::string &name, const std::string &description)
{
return new Recipe_Impl (name, description);
}
Class<Recipe_Impl> decl_Recipe_Impl ("tl", "Recipe",
gsi::constructor ("new", &make_recipe, gsi::arg ("name"), gsi::arg ("description", std::string (), "\"\""),
"@brief Creates a new recipe object with the given name and (optional) description"
) +
gsi::method ("name", &Recipe_Impl::name,
"@brief Gets the name of the recipe."
) +
gsi::method ("description", &Recipe_Impl::description,
"@brief Gets the description of the recipe."
) +
gsi::method ("make", &Recipe_Impl::make, gsi::arg ("generator"), gsi::arg ("add_params", std::map<std::string, tl::Variant> (), "{}"),
"@brief Executes the recipe given by the generator string.\n"
"The generator string is the one delivered with \\generator.\n"
"Additional parameters can be passed in \"add_params\". They have lower priority than the parameters "
"kept inside the generator string."
) +
gsi::method ("generator", &Recipe_Impl::generator, gsi::arg ("params"),
"@brief Delivers the generator string from the given parameters.\n"
"The generator string can be used with \\make to re-run the recipe."
) +
gsi::callback ("execute", &Recipe_Impl::execute, &Recipe_Impl::execute_cb, gsi::arg ("params"),
"@brief Reimplement this method to provide the functionality of the recipe.\n"
"This method is supposed to re-run the recipe with the given parameters and deliver the "
"the intended output object."
),
"@brief A facility for providing reproducable recipes\n"
"The idea of this facility is to provide a service by which an object\n"
"can be reproduced in a parametrized way. The intended use case is a \n"
"DRC report for example, where the DRC script is the generator.\n"
"\n"
"In this use case, the DRC engine will register a recipe. It will \n"
"put the serialized version of the recipe into the DRC report. If the \n"
"user requests a re-run of the DRC, the recipe will be called and \n"
"the implementation is supposed to deliver a new database.\n"
"\n"
"To register a recipe, reimplement the Recipe class and create an\n"
"instance. To serialize a recipe, use \"generator\", to execute the\n"
"recipe, use \"make\".\n"
"\n"
"Parameters are kept as a generic key/value map.\n"
"\n"
"This class has been introduced in version 0.26."
);
}

View File

@ -89,12 +89,12 @@ plugins.depends += lib rdb db
plugins.depends += lay ant
laybasic.depends += rdb
lym.depends += gsi $$LANG_DEPENDS
laybasic.depends += rdb lym
ant.depends += laybasic
img.depends += laybasic
edt.depends += laybasic
lym.depends += gsi $$LANG_DEPENDS
lay.depends += laybasic ant img edt lym
lay.depends += laybasic ant img edt
klayout_main.depends += plugins $$MAIN_DEPENDS
}

View File

@ -204,6 +204,30 @@ See <a href="/about/drc_ref_netter.xml#device_scaling">Netter#device_scaling</a>
Use this class with <a href="#extract_devices">extract_devices</a> to specify extraction of a
planar diode
</p>
<h2>"dmos3" - Supplies the DMOS3 transistor extractor class</h2>
<keyword name="dmos3"/>
<a name="dmos3"/><p>Usage:</p>
<ul>
<li><tt>dmos3(name)</tt></li>
</ul>
<p>
Use this class with <a href="#extract_devices">extract_devices</a> to specify extraction of a
three-terminal DMOS transistor. A DMOS transistor is essentially
the same than a MOS transistor, but source and drain are
separated.
</p>
<h2>"dmos4" - Supplies the MOS4 transistor extractor class</h2>
<keyword name="dmos4"/>
<a name="dmos4"/><p>Usage:</p>
<ul>
<li><tt>dmos4(name)</tt></li>
</ul>
<p>
Use this class with <a href="#extract_devices">extract_devices</a> to specify extraction of a
four-terminal DMOS transistor. A DMOS transistor is essentially
the same than a MOS transistor, but source and drain are
separated.
</p>
<h2>"edge" - Creates an edge object</h2>
<keyword name="edge"/>
<a name="edge"/><p>Usage:</p>

View File

@ -7,7 +7,7 @@
<p>
KLayout implements a concept of "layer views". The layer list is made up of such layer views.
A "view" is bascically a specification of what is shown how.
A "view" is basically a specification of what is shown how.
The "how" part is given by the colors, stipples, styles etc.
The "what" part is given by the source specification.
</p>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View File

@ -119,11 +119,59 @@ same_device_classes("NMOS_IN_LAYOUT", "NMOS_IN_SCHEMATIC")</pre>
<p>
To eliminate all capacitors with a capacitance value below a certain threshold, use the
<a href="/about/lvs_ref_global.xml#max_caps">max_caps</a> function. This will
<a href="/about/lvs_ref_global.xml#min_caps">min_caps</a> function. This will
eliminate all capacitances with a value &lt;= 0.1fF:
</p>
<pre>max_caps(1e-16)</pre>
<pre>min_caps(1e-16)</pre>
<h2>Compare and netlist hierarchy</h2>
<p>
Good layouts are built hierarchically and the netlist compare can make use
of hierarchy. "Hierarchically" means that a circuit is built from cells
which itself map to subcircuits of the schematic netlist. The netlist
extractor tries hard to maintain the hierarchy and the netlist compare
will utilize the hierarchy to provide more meaningful reports and enable
a bottom-up design approach.
</p>
<p>
Given a hierarchical layout and schematic netlist, the compare algorithm
will work bottom-up: it will first compare the leaf circuits (circuits without
subcircuit calls) and if those match, it will continue with the calling
circuits. This approach is more efficient and fosters a clean relationship
between layout and schematic netlist.
</p>
<p>
To enable hierarchical extraction, you must use "deep" mode (<a href="/about/drc_ref_global.xml#deep">deep</a>).
If the deep mode statement is missing, the layout netlist will be flat (i.e. without
subcircuits).
</p>
<p>
The second useful feature is "align" (<a href="/about/lvs_ref_global.xml#align">align</a>).
This statement will remove circuits from the layout or schematic netlist which are
unknown in the other netlist. Often, layouts contain helper cells which are not
corresponding to a circuit (e.g. via cells). These are removed in this step. Eventually,
this step will also flatten the schematic netlist if the layout has been extracted
in a flat way.
</p>
<p>
In general, it's a good idea to include "align" before the "compare" step.
</p>
<p>
A very useful side effect of "align" is this: it will remove circuits above the
top level circuit of either side. So it will eventually render a sub-tree from
the circuit tree and use that for compare. This enables <b>subcell verification</b>:
by selecting a subcell in the layout hierarchy, an "align"-enabled LVS script will
compare this cell against the corresponding subcircuit in the schematic netlist.
It will ignore the parent hierarchy of this subcircuit. This way, you can work yourself
upwards in the hierarchy and fix LVS errors cell by cell with the same schematic netlist.
</p>
<h2>How the compare algorithm works</h2>

View File

@ -187,6 +187,27 @@ extract_devices(mos4(model_name), { "SD" => (active - poly) &amp; pplus, "G" =>
<img src="/manual/mos_ex_tb.png"/>
</p>
<h2>Diffusion MOS transistor extractor (<a href="/about/drc_ref_global.xml#dmos3">dmos3</a> and <a href="/about/drc_ref_global.xml#dmos4">dmos4</a>)</h2>
<p>
DMOS devices are basically identical to MOS devices, but for those source and drain are
separated. This is often the case for diffusion MOS transistory, hence this name.
</p>
<p>
DMOS and MOS devices share the same device class. DMOS devices are configured
such that source and drain cannot be swapped. The netlist compare will report
source/drain swapping as errors for such devices.
</p>
<p>
DMOS transistors are recognized by their gate ("G" input), source ("S" input) and drain ("D" input)
regions. Source and drain needs to be separated from the gate shape. The touching edges of gate and
source/drain regions define the width of the device, the perpendicular dimension the gate length.
The terminal output layers for DMOS devices are the same than for MOS devices: "tS" for source,
"tD" for drain, "tG" for gate, "tB" for bulk (4-terminal version).
</p>
<h2>Bipolar transistor extractor (<a href="/about/drc_ref_global.xml#bjt3">bjt3</a> and <a href="/about/drc_ref_global.xml#bjt4">bjt4</a>)</h2>
<p>

View File

@ -189,12 +189,14 @@ X$2 VSS IN OUT SUBSTRATE NMOS PARAMS: L=0.25 W=0.9 AS=0.405 AD=0.405 PS=2.7
class SubcircuitModelsReader &lt; RBA::NetlistSpiceReaderDelegate
# implements the delegate interface:
# says we want to catch these subcircuits as devices
def wants_subcircuit(name)
name == "NMOS" || name == "PMOS"
end
# translate the element
# implements the delegate interface:
# take and translate the element
def element(circuit, el, name, model, value, nets, params)
if el != "X"
@ -221,9 +223,13 @@ class SubcircuitModelsReader &lt; RBA::NetlistSpiceReaderDelegate
[ "S", "G", "D", "B" ].each_with_index do |t,index|
device.connect_terminal(t, nets[index])
end
params.each do |p,value|
device.set_parameter(p, value)
end
# parameters in the model are given in micrometer units, so
# we need to translate the parameter values from SI to um values:
device.set_parameter("W", (params["W"] || 0.0) * 1e6)
device.set_parameter("L", (params["L"] || 0.0) * 1e6)
return true
end

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

@ -1,7 +1,8 @@
<ui version="4.0" >
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MarkerBrowserDialog</class>
<widget class="QDialog" name="MarkerBrowserDialog" >
<property name="geometry" >
<widget class="QDialog" name="MarkerBrowserDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
@ -9,40 +10,75 @@
<height>553</height>
</rect>
</property>
<property name="windowTitle" >
<property name="windowTitle">
<string>Marker Database Browser</string>
</property>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<layout class="QVBoxLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="leftMargin">
<number>9</number>
</property>
<property name="topMargin">
<number>9</number>
</property>
<property name="rightMargin">
<number>9</number>
</property>
<property name="bottomMargin">
<number>9</number>
</property>
<item>
<widget class="QFrame" name="frame_3" >
<property name="frameShape" >
<widget class="QFrame" name="frame_3">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow" >
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QGridLayout" >
<property name="margin" >
<layout class="QGridLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="spacing" >
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<property name="spacing">
<number>6</number>
</property>
<item row="0" column="2" >
<item row="0" column="3">
<widget class="QToolButton" name="file_menu">
<property name="text">
<string>File ... </string>
</property>
<property name="popupMode">
<enum>QToolButton::InstantPopup</enum>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string> ... on layout </string>
</property>
</widget>
</item>
<item row="0" column="2">
<spacer>
<property name="orientation" >
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType" >
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" >
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
@ -50,152 +86,133 @@
</property>
</spacer>
</item>
<item row="0" column="1" >
<widget class="QComboBox" name="rdb_cb" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>7</hsizetype>
<vsizetype>0</vsizetype>
<item row="0" column="1">
<widget class="QComboBox" name="rdb_cb">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="sizeAdjustPolicy" >
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContentsOnFirstShow</enum>
</property>
</widget>
</item>
<item row="0" column="0" >
<widget class="QLabel" name="label_3" >
<property name="text" >
<item row="0" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Database </string>
</property>
</widget>
</item>
<item row="1" column="0" >
<widget class="QLabel" name="label" >
<property name="text" >
<string> ... on layout </string>
</property>
</widget>
</item>
<item row="1" column="1" >
<widget class="QComboBox" name="layout_cb" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>7</hsizetype>
<vsizetype>0</vsizetype>
<item row="1" column="1">
<widget class="QComboBox" name="layout_cb">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="sizeAdjustPolicy" >
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContentsOnFirstShow</enum>
</property>
</widget>
</item>
<item row="0" column="3" >
<widget class="QToolButton" name="file_menu" >
<property name="text" >
<string>File ... </string>
</property>
<property name="popupMode" >
<enum>QToolButton::InstantPopup</enum>
</property>
</widget>
</item>
<item row="2" column="0" colspan="4" >
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType" >
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" >
<size>
<width>20</width>
<height>10</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<widget class="Line" name="line" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QFrame" name="frame_4" >
<property name="frameShape" >
<widget class="QFrame" name="frame_4">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow" >
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<layout class="QHBoxLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QStackedWidget" name="central_stack" >
<property name="currentIndex" >
<widget class="QStackedWidget" name="central_stack">
<property name="currentIndex">
<number>1</number>
</property>
<widget class="QWidget" name="page" >
<layout class="QVBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<widget class="QWidget" name="page">
<layout class="QVBoxLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="rdb::MarkerBrowserPage" name="browser_frame" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>13</hsizetype>
<vsizetype>13</vsizetype>
<widget class="rdb::MarkerBrowserPage" name="browser_frame">
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Ignored">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape" >
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow" >
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="page_2" >
<layout class="QVBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<widget class="QWidget" name="page_2">
<layout class="QVBoxLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label_2" >
<property name="text" >
<string>Choose "Open" from the "File ..." menu
<widget class="QLabel" name="label_2">
<property name="text">
<string>Choose &quot;Open&quot; from the &quot;File ...&quot; menu
to load a marker database</string>
</property>
<property name="alignment" >
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="wordWrap" >
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
@ -208,40 +225,49 @@ to load a marker database</string>
</widget>
</item>
<item>
<widget class="Line" name="line_2" >
<property name="orientation" >
<widget class="Line" name="line_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QFrame" name="frame_2" >
<property name="frameShape" >
<widget class="QFrame" name="frame_2">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow" >
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<layout class="QHBoxLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QPushButton" name="configure_pb" >
<property name="text" >
<widget class="QPushButton" name="configure_pb">
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
@ -250,8 +276,8 @@ to load a marker database</string>
</spacer>
</item>
<item>
<widget class="QPushButton" name="pushButton_2" >
<property name="text" >
<widget class="QPushButton" name="pushButton_2">
<property name="text">
<string>Close</string>
</property>
</widget>
@ -266,6 +292,7 @@ to load a marker database</string>
<class>rdb::MarkerBrowserPage</class>
<extends>QFrame</extends>
<header>rdbMarkerBrowserPage.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<tabstops>
@ -282,11 +309,11 @@ to load a marker database</string>
<receiver>MarkerBrowserDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel" >
<hint type="sourcelabel">
<x>837</x>
<y>441</y>
</hint>
<hint type="destinationlabel" >
<hint type="destinationlabel">
<x>881</x>
<y>387</y>
</hint>

View File

@ -13,7 +13,7 @@
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QHBoxLayout">
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>6</number>
</property>
@ -29,6 +29,73 @@
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QFrame" name="frame_5">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="0" rowspan="3">
<widget class="QToolButton" name="rerun_button">
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../lay/lay/layResources.qrc">
<normaloff>:/run.png</normaloff>:/run.png</iconset>
</property>
<property name="shortcut">
<string>F5</string>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="1">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>11</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="1">
<widget class="Line" name="line_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QSplitter" name="splitter_2">
<property name="orientation">
@ -63,69 +130,6 @@
<property name="spacing">
<number>6</number>
</property>
<item row="2" column="1">
<widget class="QToolButton" name="dir_down_pb">
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../lay/lay/layResources.qrc">
<normaloff>:/down.png</normaloff>:/down.png</iconset>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QToolButton" name="dir_up_pb">
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../lay/lay/layResources.qrc">
<normaloff>:/up.png</normaloff>:/up.png</iconset>
</property>
</widget>
</item>
<item row="1" column="0" colspan="4">
<widget class="QTreeView" name="directory_tree">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="baseSize">
<size>
<width>0</width>
<height>4</height>
</size>
</property>
<property name="contextMenuPolicy">
<enum>Qt::ActionsContextMenu</enum>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::ExtendedSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="uniformRowHeights">
<bool>true</bool>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
<property name="allColumnsShowFocus">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="0" colspan="4">
<widget class="QLabel" name="label">
<property name="text">
<string>Directory</string>
</property>
</widget>
</item>
<item row="2" column="2" colspan="2">
<widget class="QFrame" name="frame_2">
<property name="sizePolicy">
@ -237,6 +241,69 @@
</layout>
</widget>
</item>
<item row="2" column="1">
<widget class="QToolButton" name="dir_down_pb">
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../lay/lay/layResources.qrc">
<normaloff>:/down.png</normaloff>:/down.png</iconset>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QToolButton" name="dir_up_pb">
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../lay/lay/layResources.qrc">
<normaloff>:/up.png</normaloff>:/up.png</iconset>
</property>
</widget>
</item>
<item row="1" column="0" colspan="4">
<widget class="QTreeView" name="directory_tree">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="baseSize">
<size>
<width>0</width>
<height>4</height>
</size>
</property>
<property name="contextMenuPolicy">
<enum>Qt::ActionsContextMenu</enum>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::ExtendedSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="uniformRowHeights">
<bool>true</bool>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
<property name="allColumnsShowFocus">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="0" colspan="4">
<widget class="QLabel" name="label">
<property name="text">
<string>Directory</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QSplitter" name="splitter">

View File

@ -132,6 +132,23 @@
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="rerun_button">
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../lay/lay/layResources.qrc">
<normaloff>:/run.png</normaloff>:/run.png</iconset>
</property>
<property name="shortcut">
<string>F5</string>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">

View File

@ -218,11 +218,17 @@ static db::LayoutVsSchematic *get_lvsdb (lay::LayoutView *view, unsigned int ind
return dynamic_cast<db::LayoutVsSchematic *> (db);
}
static void add_lvsdb (lay::LayoutView *view, db::LayoutVsSchematic *lvsdb)
static unsigned int add_lvsdb (lay::LayoutView *view, db::LayoutVsSchematic *lvsdb)
{
view->add_l2ndb (lvsdb);
return view->add_l2ndb (lvsdb);
}
static unsigned int replace_lvsdb (lay::LayoutView *view, unsigned int db_index, db::LayoutVsSchematic *lvsdb)
{
return view->replace_l2ndb (db_index, lvsdb);
}
// this binding returns a const pointer which is not converted into a copy by RBA
static lay::LayerPropertiesNodeRef insert_layer1 (lay::LayoutView *view, const lay::LayerPropertiesConstIterator &iter, const lay::LayerProperties &props)
{
@ -1442,7 +1448,7 @@ Class<lay::LayoutView> decl_LayoutView (QT_EXTERNAL_BASE (QWidget) "lay", "Layou
"@return The \\ReportDatabase object or nil if the index is not valid"
) +
gsi::method ("add_rdb", &lay::LayoutView::add_rdb, gsi::arg ("db"),
"@brief Adds the given database to the view\n"
"@brief Adds the given report database to the view\n"
"\n"
"This method will add an existing database to the view. It will then appear in the marker database browser.\n"
"A similar method is \\create_rdb which will create a new database within the view.\n"
@ -1451,6 +1457,15 @@ Class<lay::LayoutView> decl_LayoutView (QT_EXTERNAL_BASE (QWidget) "lay", "Layou
"\n"
"This method has been added in version 0.26."
) +
gsi::method ("replace_rdb", &lay::LayoutView::replace_rdb, gsi::arg ("db_index"), gsi::arg ("db"),
"@brief Replaces the report database with the given index\n"
"\n"
"If the index is not valid, the database will be added to the view (see \\add_rdb).\n"
"\n"
"@return The index of the database within the view (see \\rdb)\n"
"\n"
"This method has been added in version 0.26."
) +
gsi::method_ext ("create_rdb", &create_rdb, gsi::arg ("name"),
"@brief Creates a new report database and returns the index of the new database\n"
"@param name The name of the new report database\n"
@ -1490,7 +1505,7 @@ Class<lay::LayoutView> decl_LayoutView (QT_EXTERNAL_BASE (QWidget) "lay", "Layou
"This method has been added in version 0.26."
) +
gsi::method ("add_l2ndb", &lay::LayoutView::add_l2ndb, gsi::arg ("db"),
"@brief Adds the given database to the view\n"
"@brief Adds the given netlist database to the view\n"
"\n"
"This method will add an existing database to the view. It will then appear in the netlist database browser.\n"
"A similar method is \\create_l2ndb which will create a new database within the view.\n"
@ -1499,6 +1514,15 @@ Class<lay::LayoutView> decl_LayoutView (QT_EXTERNAL_BASE (QWidget) "lay", "Layou
"\n"
"This method has been added in version 0.26."
) +
gsi::method ("replace_l2ndb", &lay::LayoutView::replace_l2ndb, gsi::arg ("db_index"), gsi::arg ("db"),
"@brief Replaces the netlist database with the given index\n"
"\n"
"If the index is not valid, the database will be added to the view (see \\add_lvsdb).\n"
"\n"
"@return The index of the database within the view (see \\lvsdb)\n"
"\n"
"This method has been added in version 0.26."
) +
gsi::method_ext ("create_l2ndb", &create_l2ndb, gsi::arg ("name"),
"@brief Creates a new netlist database and returns the index of the new database\n"
"@param name The name of the new netlist database\n"
@ -1532,6 +1556,15 @@ Class<lay::LayoutView> decl_LayoutView (QT_EXTERNAL_BASE (QWidget) "lay", "Layou
"\n"
"This method has been added in version 0.26."
) +
gsi::method_ext ("replace_lvsdb", &replace_lvsdb, gsi::arg ("db_index"), gsi::arg ("db"),
"@brief Replaces the database with the given index\n"
"\n"
"If the index is not valid, the database will be added to the view (see \\add_lvsdb).\n"
"\n"
"@return The index of the database within the view (see \\lvsdb)\n"
"\n"
"This method has been added in version 0.26."
) +
gsi::method_ext ("create_lvsdb", &create_lvsdb, gsi::arg ("name"),
"@brief Creates a new netlist database and returns the index of the new database\n"
"@param name The name of the new netlist database\n"

View File

@ -7213,6 +7213,32 @@ LayoutView::add_l2ndb (db::LayoutToNetlist *l2ndb)
return (unsigned int)(m_l2ndbs.size () - 1);
}
unsigned int
LayoutView::replace_l2ndb (unsigned int db_index, db::LayoutToNetlist *l2ndb)
{
tl_assert (l2ndb != 0);
if (db_index < m_l2ndbs.size ()) {
// keep the name as it is used for reference in the browser for example
std::string n = m_l2ndbs [db_index]->name ();
l2ndb->set_name (n);
delete m_l2ndbs [db_index];
m_l2ndbs [db_index] = l2ndb;
// Mark this object as owned by us (for GSI)
l2ndb->keep ();
l2ndb_list_changed_event ();
return db_index;
} else {
return add_l2ndb (l2ndb);
}
}
db::LayoutToNetlist *
LayoutView::get_l2ndb (int index)
{
@ -7255,7 +7281,7 @@ LayoutView::remove_l2ndb (unsigned int index)
unsigned int
LayoutView::add_rdb (rdb::Database *rdb)
{
make_unique_name (rdb, m_l2ndbs.begin (), m_l2ndbs.end ());
make_unique_name (rdb, m_rdbs.begin (), m_rdbs.end ());
m_rdbs.push_back (rdb);
// Mark this object as owned by us (for GSI)
@ -7266,6 +7292,32 @@ LayoutView::add_rdb (rdb::Database *rdb)
return (unsigned int)(m_rdbs.size () - 1);
}
unsigned int
LayoutView::replace_rdb (unsigned int db_index, rdb::Database *rdb)
{
tl_assert (rdb != 0);
if (db_index < m_rdbs.size ()) {
// keep name because it's used for reference in the browser for example
std::string n = m_rdbs [db_index]->name ();
rdb->set_name (n);
delete m_rdbs [db_index];
m_rdbs [db_index] = rdb;
// Mark this object as owned by us (for GSI)
rdb->keep ();
rdb_list_changed_event ();
return db_index;
} else {
return add_rdb (rdb);
}
}
rdb::Database *
LayoutView::get_rdb (int index)
{

View File

@ -2285,6 +2285,17 @@ public:
*/
unsigned int add_rdb (rdb::Database *rdb);
/**
* @brief Replaces a marker database
*
* The layout view will become owner of the database.
* If the index is not valid, the database will be added and the new index will be returned.
*
* @param db_index The index of the database to replace
* @param rdb The database to add
*/
unsigned int replace_rdb (unsigned int db_index, rdb::Database *rdb);
/**
* @brief Get the marker database by index
*
@ -2340,6 +2351,17 @@ public:
*/
unsigned int add_l2ndb (db::LayoutToNetlist *l2ndb);
/**
* @brief Replaces a Netlist database
*
* The layout view will become owner of the database.
* If the index is not valid, the database will be added and the new index will be returned.
*
* @param db_index The index of the database to replace
* @param l2ndb The database to add
*/
unsigned int replace_l2ndb (unsigned int db_index, db::LayoutToNetlist *l2ndb);
/**
* @brief Get the netlist database by index
*

View File

@ -824,6 +824,9 @@ static
std::string device_parameter_string (const db::Device *device)
{
std::string s;
if (! device || ! device->device_class ()) {
return s;
}
bool first = true;
const std::vector<db::DeviceParameterDefinition> &pd = device->device_class ()->parameter_definitions ();

View File

@ -32,6 +32,7 @@
#include "layNetExportDialog.h"
#include "tlProgress.h"
#include "tlExceptions.h"
#include "tlRecipe.h"
#include "dbLayoutToNetlist.h"
#include "dbNetlistDeviceClasses.h"
#include "dbCellMapping.h"
@ -124,6 +125,7 @@ NetlistBrowserPage::NetlistBrowserPage (QWidget * /*parent*/)
m_update_needed (true),
mp_info_dialog (0),
dm_update_highlights (this, &NetlistBrowserPage::update_highlights),
dm_rerun_macro (this, &NetlistBrowserPage::rerun_macro),
m_cell_context_cache (0)
{
Ui::NetlistBrowserPage::setupUi (this);
@ -188,6 +190,7 @@ NetlistBrowserPage::NetlistBrowserPage (QWidget * /*parent*/)
connect (m_show_all_action, SIGNAL (triggered ()), this, SLOT (show_all_clicked ()));
connect (info_button, SIGNAL (pressed ()), this, SLOT (info_button_pressed ()));
connect (rerun_button, SIGNAL (pressed ()), this, SLOT (rerun_button_pressed ()));
connect (find_button, SIGNAL (pressed ()), this, SLOT (find_button_pressed ()));
connect (forward, SIGNAL (clicked ()), this, SLOT (navigate_forward ()));
connect (backward, SIGNAL (clicked ()), this, SLOT (navigate_back ()));
@ -585,6 +588,32 @@ NetlistBrowserPage::navigate_forward ()
}
}
void
NetlistBrowserPage::rerun_button_pressed ()
{
// NOTE: we use deferred execution, because otherwise the button won't get repainted properly
dm_rerun_macro ();
}
void
NetlistBrowserPage::rerun_macro ()
{
if (! mp_database->generator ().empty ()) {
std::map<std::string, tl::Variant> add_pars;
for (unsigned int i = 0; i < mp_view->num_l2ndbs (); ++i) {
if (mp_view->get_l2ndb (i) == mp_database.get ()) {
add_pars["l2ndb_index"] = tl::Variant (int (i));
break;
}
}
tl::Recipe::make (mp_database->generator (), add_pars);
}
}
void
NetlistBrowserPage::info_button_pressed ()
{
@ -741,6 +770,17 @@ NetlistBrowserPage::set_db (db::LayoutToNetlist *l2ndb)
db::LayoutVsSchematic *lvsdb = dynamic_cast<db::LayoutVsSchematic *> (l2ndb);
mp_database.reset (l2ndb);
rerun_button->setEnabled (mp_database.get () && ! mp_database->generator ().empty ());
if (rerun_button->isEnabled ()) {
QString shortcut;
if (! rerun_button->shortcut ().isEmpty ()) {
shortcut = QString::fromUtf8 (" (%1)").arg (rerun_button->shortcut ().toString ());
}
rerun_button->setToolTip (tl::to_qstring (tl::to_string (tr ("Run ")) + mp_database->generator ()) + shortcut);
} else {
rerun_button->setToolTip (QString ());
}
show_netlist->setVisible (lvsdb != 0);
show_xref->setVisible (lvsdb != 0);

View File

@ -169,6 +169,7 @@ public slots:
private slots:
void show_all_clicked ();
void info_button_pressed ();
void rerun_button_pressed ();
void find_button_pressed ();
void anchor_clicked (const QString &url);
void navigate_back ();
@ -212,6 +213,7 @@ private:
std::vector<const db::Circuit *> m_current_circuits;
lay::NetInfoDialog *mp_info_dialog;
tl::DeferredMethod<NetlistBrowserPage> dm_update_highlights;
tl::DeferredMethod<NetlistBrowserPage> dm_rerun_macro;
db::ContextCache m_cell_context_cache;
void set_db (db::LayoutToNetlist *l2ndb);
@ -233,6 +235,7 @@ private:
bool produce_highlights_for_subcircuit (const db::SubCircuit *subcircuit, size_t &n_markers, const std::vector<db::DCplxTrans> &tv);
bool produce_highlights_for_circuit (const db::Circuit *circuit, size_t &n_markers, const std::vector<db::DCplxTrans> &tv);
void configure_marker (lay::Marker *marker, bool with_fill);
void rerun_macro ();
void export_nets (const std::vector<const db::Net *> *nets);
};

View File

@ -275,9 +275,9 @@ HEADERS = \
layNetlistBrowserTreeModel.h \
layLibrariesView.h
INCLUDEPATH += $$TL_INC $$GSI_INC $$DB_INC $$RDB_INC
DEPENDPATH += $$TL_INC $$GSI_INC $$DB_INC $$RDB_INC
LIBS += -L$$DESTDIR -lklayout_tl -lklayout_gsi -lklayout_db -lklayout_rdb
INCLUDEPATH += $$TL_INC $$GSI_INC $$DB_INC $$RDB_INC $$LYM_INC
DEPENDPATH += $$TL_INC $$GSI_INC $$DB_INC $$RDB_INC $$LYM_INC
LIBS += -L$$DESTDIR -lklayout_tl -lklayout_gsi -lklayout_db -lklayout_rdb -lklayout_lym
INCLUDEPATH += $$QTBASIC_INC
DEPENDPATH += $$QTBASIC_INC

View File

@ -671,6 +671,7 @@ MarkerBrowserDialog::update_content ()
m_reload_action->setEnabled (rdb != 0);
browser_frame->enable_updates (false); // Avoid building the internal lists several times ...
browser_frame->set_rdb (0); // force update
browser_frame->set_rdb (rdb);
browser_frame->set_max_marker_count (m_max_marker_count);
browser_frame->set_marker_style (m_marker_color, m_marker_line_width, m_marker_vertex_size, m_marker_halo, m_marker_dither_pattern);

View File

@ -26,6 +26,7 @@
#include "dbLayoutUtils.h"
#include "tlRecipe.h"
#include "layLayoutView.h"
#include "layMarker.h"
@ -1463,7 +1464,8 @@ MarkerBrowserPage::MarkerBrowserPage (QWidget * /*parent*/)
m_marker_list_sort_order (Qt::DescendingOrder),
m_directory_tree_sorted_section (-1),
m_directory_tree_sort_order (Qt::DescendingOrder),
mp_plugin_root (0)
mp_plugin_root (0),
dm_rerun_macro (this, &MarkerBrowserPage::rerun_macro)
{
Ui::MarkerBrowserPage::setupUi (this);
@ -1514,6 +1516,7 @@ MarkerBrowserPage::MarkerBrowserPage (QWidget * /*parent*/)
connect (info_text, SIGNAL (anchorClicked (const QUrl &)), this, SLOT (info_anchor_clicked (const QUrl &)));
connect (cat_filter, SIGNAL (textEdited (const QString &)), this, SLOT (filter_changed ()));
connect (cell_filter, SIGNAL (textEdited (const QString &)), this, SLOT (filter_changed ()));
connect (rerun_button, SIGNAL (pressed ()), this, SLOT (rerun_button_pressed ()));
m_show_all_action = new QAction (QObject::tr ("Show All"), this);
m_show_all_action->setCheckable (true);
@ -1678,6 +1681,17 @@ MarkerBrowserPage::set_rdb (rdb::Database *database)
mp_database = database;
rerun_button->setEnabled (mp_database && ! mp_database->generator ().empty ());
if (rerun_button->isEnabled ()) {
QString shortcut;
if (! rerun_button->shortcut ().isEmpty ()) {
shortcut = QString::fromUtf8 (" (%1)").arg (rerun_button->shortcut ().toString ());
}
rerun_button->setToolTip (tl::to_qstring (tl::to_string (tr ("Run ")) + mp_database->generator ()) + shortcut);
} else {
rerun_button->setToolTip (QString ());
}
QAbstractItemModel *tree_model = directory_tree->model ();
MarkerBrowserTreeViewModel *new_model = new MarkerBrowserTreeViewModel ();
@ -2643,6 +2657,32 @@ MarkerBrowserPage::flag_button_clicked ()
list_model->mark_data_changed ();
}
void
MarkerBrowserPage::rerun_button_pressed ()
{
// NOTE: we use deferred execution, because otherwise the button won't get repainted properly
dm_rerun_macro ();
}
void
MarkerBrowserPage::rerun_macro ()
{
if (! mp_database->generator ().empty ()) {
std::map<std::string, tl::Variant> add_pars;
for (unsigned int i = 0; i < mp_view->num_rdbs (); ++i) {
if (mp_view->get_rdb (i) == mp_database) {
add_pars["rdb_index"] = tl::Variant (int (i));
break;
}
}
tl::Recipe::make (mp_database->generator (), add_pars);
}
}
void
MarkerBrowserPage::flag_menu_selected ()
{

View File

@ -26,6 +26,7 @@
#include "ui_MarkerBrowserPage.h"
#include "rdbMarkerBrowser.h"
#include "tlDeferredExecution.h"
#include "dbBox.h"
#include <QFrame>
@ -155,6 +156,7 @@ public slots:
void dir_down_clicked ();
void list_up_clicked ();
void list_down_clicked ();
void rerun_button_pressed ();
void flag_button_clicked ();
void flag_menu_selected ();
void important_button_clicked ();
@ -205,6 +207,7 @@ private:
int m_directory_tree_sorted_section;
Qt::SortOrder m_directory_tree_sort_order;
lay::PluginRoot *mp_plugin_root;
tl::DeferredMethod<MarkerBrowserPage> dm_rerun_macro;
void release_markers ();
void update_marker_list (int selection_mode);
@ -214,6 +217,7 @@ private:
void mark_visited (bool visited);
void do_update_markers ();
void update_info_text ();
void rerun_macro ();
};
} // namespace rdb

View File

@ -61,6 +61,9 @@ module LVS
@lvs = RBA::LayoutVsSchematic::new(cell.name, layout.dbu)
end
@lvs.name = "LVS"
@lvs.generator = @engine._generator
@l2n = @lvs
@comparer = RBA::NetlistComparer::new
@ -117,8 +120,16 @@ module LVS
nl = _ensure_two_netlists
unmatched_a = @comparer.unmatched_circuits_a(*nl)
# check whether we're about to flatten away the internal top cell - that's bad
top_cell = l2n_data.internal_top_cell.name
if unmatched_a.find { |c| c.name == top_cell }
raise("Can't find a schematic counterpart for the top cell #{top_cell} - use 'same_circuit' to establish a correspondence")
end
# flatten layout cells for which there is no corresponding schematic circuit
@comparer.unmatched_circuits_a(*nl).each do |c|
unmatched_a.each do |c|
@engine.info("Flatten layout cell (no schematic): #{c.name}")
nl[0].flatten_circuit(c)
end
@ -285,9 +296,13 @@ module LVS
( nl_a, nl_b ) = _ensure_two_netlists
dc_a = a && (nl_a.device_class_by_name(a) || raise("Not a valid device class in extracted netlist: #{a}"))
dc_b = b && (nl_b.device_class_by_name(b) || raise("Not a valid device class in reference netlist: #{b}"))
dc_b = b && nl_b.device_class_by_name(b)
@comparer.same_device_classes(dc_a, dc_b)
# NOTE: a device class is allowed to be missing in the reference netlist because the
# device may simply not be used there.
if dc_b
@comparer.same_device_classes(dc_a, dc_b)
end
end

View File

@ -17,37 +17,39 @@
<text>
module LVS
def LVS.execute_lvs(_macro)
def self.execute_lvs(macro, generator, l2ndb_index = nil)
_timer = RBA::Timer::new
_timer.start
_lvs = LVSEngine::new
timer = RBA::Timer::new
timer.start
lvs = LVSEngine::new
lvs._l2ndb_index = l2ndb_index
lvs._generator = generator
begin
# Set a debugger scope so that our errors end up with the debugger set to the LVS's line
RBA::MacroExecutionContext::set_debugger_scope(_macro.path)
RBA::MacroExecutionContext::set_debugger_scope(macro.path)
# No verbosity set in lvs engine - we cannot use the engine's logger
RBA::Logger::verbosity &gt;= 10 &amp;&amp; RBA::Logger::info("Running #{_macro.path}")
_lvs.instance_eval(_macro.text, _macro.path)
RBA::Logger::verbosity &gt;= 10 &amp;&amp; RBA::Logger::info("Running #{macro.path}")
lvs.instance_eval(macro.text, macro.path)
# Remove the debugger scope
RBA::MacroExecutionContext::remove_debugger_scope
rescue =&gt; ex
_lvs.error("In #{_macro.path}: #{ex.to_s}")
lvs.error("In #{macro.path}: #{ex.to_s}")
RBA::MacroExecutionContext::ignore_next_exception
raise ex
ensure
# cleans up and creates layout and report views
_lvs._finish
lvs._finish
end
_timer.stop
_lvs.info("Total run time: #{'%.3f'%(_timer.sys+_timer.user)}s")
timer.stop
lvs.info("Total run time: #{'%.3f'%(timer.sys+timer.user)}s")
end
@ -55,7 +57,9 @@ module LVS
class LVSInterpreter &lt; RBA::MacroInterpreter
# Constructor
def initialize
def initialize(recipe)
@recipe = recipe
# Make the DSL use ruby syntax highlighting
self.syntax_scheme = "ruby"
@ -80,7 +84,7 @@ module LVS
# Implements the execute method
def execute(macro)
LVS::execute_lvs(macro)
LVS::execute_lvs(macro, @recipe.generator("script" => macro.path))
end
end
@ -89,7 +93,9 @@ module LVS
class LVSPlainTextInterpreter &lt; RBA::MacroInterpreter
# Constructor
def initialize
def initialize(recipe)
@recipe = recipe
# Make the DSL use ruby syntax highlighting
self.syntax_scheme = "ruby"
@ -105,15 +111,41 @@ module LVS
# Implements the execute method
def execute(macro)
LVS::execute_lvs(macro)
LVS::execute_lvs(macro, @recipe.generator("script" => macro.path))
end
end
# A recipe implementation allowing the LVS run to be redone
class LVSRecipe &lt; RBA::Recipe
def initialize
super("lvs", "LVS recipe")
end
def execute(params)
script = params["script"]
if ! script
return
end
macro = RBA::Macro::macro_by_path(script)
macro || raise("Can't find LVS script #{script} - unable to re-run")
LVS::execute_lvs(macro, self.generator("script" => script), params["l2ndb_index"])
end
end
# Register the new interpreters
LVSInterpreter::new
LVSPlainTextInterpreter::new
# Register the recipe
lvs_recipe = LVSRecipe::new
# Register the new interpreters
LVSInterpreter::new(lvs_recipe)
LVSPlainTextInterpreter::new(lvs_recipe)
end
</text>
</klayout-macro>

View File

@ -28,7 +28,7 @@
#include "lymMacro.h"
#include "tlFileUtils.h"
void run_test (tl::TestBase *_this, const std::string &suffix, const std::string &layout, bool with_l2n = false)
void run_test (tl::TestBase *_this, const std::string &suffix, const std::string &layout, bool with_l2n = false, const std::string &top = std::string ())
{
std::string rs = tl::testsrc ();
rs += "/testdata/lvs/" + suffix + ".lvs";
@ -57,7 +57,8 @@ void run_test (tl::TestBase *_this, const std::string &suffix, const std::string
"$lvs_test_target_lvsdb = '%s'\n"
"$lvs_test_target_cir = '%s'\n"
"$lvs_test_target_l2n = '%s'\n"
, src, output_lvsdb, output_cir, output_l2n)
"$lvs_test_top = '%s'\n"
, src, output_lvsdb, output_cir, output_l2n, top)
);
config.set_interpreter (lym::Macro::Ruby);
EXPECT_EQ (config.run (), 0);
@ -129,3 +130,27 @@ TEST(11_device_scaling)
run_test (_this, "ringo_simple_device_scaling", "ringo.gds");
}
TEST(12_simple_dmos)
{
run_test (_this, "ringo_simple_dmos", "ringo.gds");
}
TEST(13_simple_ringo_device_subcircuits)
{
run_test (_this, "ringo_device_subcircuits", "ringo.gds");
}
TEST(14_simple_ringo_mixed_hierarchy)
{
run_test (_this, "ringo_mixed_hierarchy", "ringo_mixed_hierarchy.gds");
}
TEST(15_simple_dummy_device)
{
run_test (_this, "ringo_simple_dummy_device", "ringo_dummy_device.gds");
}
TEST(16_floating)
{
run_test (_this, "floating", "floating.gds", false, "TOP");
}

View File

@ -73,9 +73,8 @@ public:
};
Class<gsi::MacroExecutionContext> decl_MacroExecutionContext ("lay", "MacroExecutionContext",
gsi::method ("set_debugger_scope", &gsi::MacroExecutionContext::set_debugger_scope,
gsi::method ("set_debugger_scope", &gsi::MacroExecutionContext::set_debugger_scope, gsi::arg ("filename"),
"@brief Sets a debugger scope (file level which shall appear in the debugger)\n"
"@args filename\n"
"If a debugger scope is set, back traces will be produced starting from that scope. "
"Setting a scope is useful for implementing DSL interpreters and giving a proper hint about "
"the original location of an error."
@ -277,9 +276,8 @@ Class<gsi::MacroInterpreter> decl_MacroInterpreter ("lay", "MacroInterpreter",
gsi::method ("NoDebugger", &const_NoDebugger,
"@brief Indicates no debugging for \\debugger_scheme\n"
) +
gsi::method ("register", &MacroInterpreter::register_gsi,
gsi::method ("register", &MacroInterpreter::register_gsi, gsi::arg ("name"),
"@brief Registers the macro interpreter\n"
"@args name\n"
"@param name The interpreter name. This is an arbitrary string which should be unique.\n"
"\n"
"Registration of the interpreter makes the object known to the system. After registration, macros whose interpreter "
@ -351,9 +349,8 @@ Class<gsi::MacroInterpreter> decl_MacroInterpreter ("lay", "MacroInterpreter",
"Before version 0.25 this attribute was a reimplementable method. It has been turned into an attribute for "
"performance reasons in version 0.25.\n"
) +
gsi::callback ("execute", &gsi::MacroInterpreter::execute, &gsi::MacroInterpreter::f_execute,
gsi::callback ("execute", &gsi::MacroInterpreter::execute, &gsi::MacroInterpreter::f_execute, gsi::arg ("macro"),
"@brief Gets called to execute a macro\n"
"@args macro\n"
"This method must be reimplemented to execute the macro. "
"The system will call this script when a macro with interpreter type 'dsl' and the "
"name of this interpreter is run."
@ -424,6 +421,11 @@ Class<gsi::MacroInterpreter> decl_MacroInterpreter ("lay", "MacroInterpreter",
"This class has been introduced in version 0.23.\n"
);
static lym::Macro *macro_by_path (const std::string &path)
{
return lym::MacroCollection::root ().find_macro (path);
}
Class<lym::Macro> decl_Macro ("lay", "Macro",
gsi::method ("path", &lym::Macro::path,
"@brief Gets the path of the macro\n"
@ -431,6 +433,13 @@ Class<lym::Macro> decl_Macro ("lay", "Macro",
"The path is the path where the macro is stored, starting with an abstract group identifier. "
"The path is used to identify the macro in the debugger for example."
) +
gsi::method ("macro_by_path", &macro_by_path, gsi::arg ("path"),
"@brief Finds the macro by installation path\n"
"\n"
"Returns nil if no macro with this path can be found.\n"
"\n"
"This method has been added in version 0.26."
) +
gsi::method ("name", &lym::Macro::name,
"@brief Gets the name of the macro\n"
"\n"
@ -443,9 +452,8 @@ Class<lym::Macro> decl_Macro ("lay", "Macro",
"the description text can have the format \"Group;;Description\". In that case, the macro "
"will appear in a group with title \"Group\"."
) +
gsi::method ("description=", &lym::Macro::set_description,
gsi::method ("description=", &lym::Macro::set_description, gsi::arg ("description"),
"@brief Sets the description text\n"
"@args description\n"
"@param description The description text.\n"
"See \\description for details.\n"
) +
@ -455,9 +463,8 @@ Class<lym::Macro> decl_Macro ("lay", "Macro",
"The prolog is executed before the actual code is executed. Interpretation depends on the "
"implementation of the DSL interpreter for DSL macros."
) +
gsi::method ("prolog=", &lym::Macro::set_prolog,
gsi::method ("prolog=", &lym::Macro::set_prolog, gsi::arg ("string"),
"@brief Sets the prolog\n"
"@args string\n"
"See \\prolog for details.\n"
) +
gsi::method ("epilog", &lym::Macro::epilog,
@ -466,9 +473,8 @@ Class<lym::Macro> decl_Macro ("lay", "Macro",
"The epilog is executed after the actual code is executed. Interpretation depends on the "
"implementation of the DSL interpreter for DSL macros."
) +
gsi::method ("epilog=", &lym::Macro::set_epilog,
gsi::method ("epilog=", &lym::Macro::set_epilog, gsi::arg ("string"),
"@brief Sets the epilog\n"
"@args string\n"
"See \\epilog for details.\n"
) +
gsi::method ("category", &lym::Macro::category,
@ -477,9 +483,8 @@ Class<lym::Macro> decl_Macro ("lay", "Macro",
"The category tags string indicates to which categories a macro will belong to. This string "
"is only used for templates currently and is a comma-separated list of category names."
) +
gsi::method ("category=", &lym::Macro::set_category,
gsi::method ("category=", &lym::Macro::set_category, gsi::arg ("string"),
"@brief Sets the category tags string\n"
"@args string\n"
"See \\category for details.\n"
) +
gsi::method ("text", &lym::Macro::text,
@ -488,17 +493,15 @@ Class<lym::Macro> decl_Macro ("lay", "Macro",
"The text is the code executed by the macro interpreter. "
"Depending on the DSL interpreter, the text can be any kind of code."
) +
gsi::method ("text=", &lym::Macro::set_text,
gsi::method ("text=", &lym::Macro::set_text, gsi::arg ("string"),
"@brief Sets the macro text\n"
"@args string\n"
"See \\text for details.\n"
) +
gsi::method ("show_in_menu?", &lym::Macro::show_in_menu,
"@brief Gets a value indicating whether the macro shall be shown in the menu\n"
) +
gsi::method ("show_in_menu=", &lym::Macro::set_show_in_menu,
gsi::method ("show_in_menu=", &lym::Macro::set_show_in_menu, gsi::arg ("flag"),
"@brief Sets a value indicating whether the macro shall be shown in the menu\n"
"@args flag\n"
) +
gsi::method ("group_name", &lym::Macro::group_name,
"@brief Gets the menu group name\n"
@ -506,9 +509,8 @@ Class<lym::Macro> decl_Macro ("lay", "Macro",
"If a group name is specified and \\show_in_menu? is true, the macro will appear in "
"a separate group (separated by a separator) together with other macros sharing the same group."
) +
gsi::method ("group_name=", &lym::Macro::set_group_name,
gsi::method ("group_name=", &lym::Macro::set_group_name, gsi::arg ("string"),
"@brief Sets the menu group name\n"
"@args string\n"
"See \\group_name for details.\n"
) +
gsi::method ("menu_path", &lym::Macro::menu_path,
@ -517,9 +519,8 @@ Class<lym::Macro> decl_Macro ("lay", "Macro",
"If a menu path is specified and \\show_in_menu? is true, the macro will appear in "
"the menu at the specified position."
) +
gsi::method ("menu_path=", &lym::Macro::set_menu_path,
gsi::method ("menu_path=", &lym::Macro::set_menu_path, gsi::arg ("string"),
"@brief Sets the menu path\n"
"@args string\n"
"See \\menu_path for details.\n"
),
"@brief A macro class\n"

View File

@ -350,8 +350,14 @@ struct writer<gsi::VectorType>
aa->write<void *> ((void *)0);
}
} else {
if (TYPE (arg) != T_ARRAY) {
throw tl::Exception (tl::sprintf (tl::to_string (tr ("Unexpected object type (expected array, got %s)")), rba_class_name (arg).c_str ()));
}
tl_assert (atype.inner () != 0);
aa->write<void *> ((void *)new RubyBasedVectorAdaptor (arg, atype.inner ()));
}
}
};
@ -370,10 +376,17 @@ struct writer<gsi::MapType>
} else {
aa->write<void *> ((void *)0);
}
} else {
if (TYPE (arg) != T_HASH) {
throw tl::Exception (tl::sprintf (tl::to_string (tr ("Unexpected object type (expected hash, got %s)")), rba_class_name (arg).c_str ()));
}
tl_assert (atype.inner () != 0);
tl_assert (atype.inner_k () != 0);
aa->write<void *> ((void *)new RubyBasedMapAdaptor (arg, atype.inner (), atype.inner_k ()));
}
}
};

View File

@ -45,7 +45,8 @@ SOURCES = \
tlUniqueId.cc \
tlList.cc \
tlEquivalenceClusters.cc \
tlUniqueName.cc
tlUniqueName.cc \
tlRecipe.cc
HEADERS = \
tlAlgorithm.h \
@ -100,7 +101,8 @@ HEADERS = \
tlUniqueId.h \
tlList.h \
tlEquivalenceClusters.h \
tlUniqueName.h
tlUniqueName.h \
tlRecipe.h
equals(HAVE_CURL, "1") {

91
src/tl/tl/tlRecipe.cc Normal file
View File

@ -0,0 +1,91 @@
/*
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 "tlRecipe.h"
#include "tlString.h"
namespace tl
{
Recipe::Recipe (const std::string &name, const std::string &description)
: tl::RegisteredClass<tl::Recipe> (this, 0, name.c_str (), false)
{
m_name = name;
m_description = description;
}
std::string Recipe::generator (const std::map<std::string, tl::Variant> &params)
{
std::string g;
g += tl::to_word_or_quoted_string (name ());
g += ": ";
for (std::map<std::string, tl::Variant>::const_iterator p = params.begin (); p != params.end (); ++p) {
if (p != params.begin ()) {
g += ",";
}
g += tl::to_word_or_quoted_string (p->first);
g += "=";
g += p->second.to_parsable_string ();
}
return g;
}
tl::Variant Recipe::make (const std::string &generator, const std::map<std::string, tl::Variant> &padd)
{
tl::Extractor ex (generator.c_str ());
std::string recipe;
ex.read_word_or_quoted (recipe);
ex.test (":");
std::map<std::string, tl::Variant> params;
while (! ex.at_end ()) {
std::string key;
ex.read_word_or_quoted (key);
ex.test ("=");
tl::Variant v;
ex.read (v);
ex.test (",");
params.insert (std::make_pair (key, v));
}
for (std::map<std::string, tl::Variant>::const_iterator p = padd.begin (); p != padd.end (); ++p) {
params.insert (*p);
}
tl::Recipe *recipe_obj = 0;
for (tl::Registrar<tl::Recipe>::iterator r = tl::Registrar<tl::Recipe>::begin (); r != tl::Registrar<tl::Recipe>::end (); ++r) {
if (r->name () == recipe) {
recipe_obj = r.operator-> ();
}
}
if (! recipe_obj) {
return tl::Variant ();
} else {
return recipe_obj->execute (params);
}
}
} // namespace tl

134
src/tl/tl/tlRecipe.h Normal file
View File

@ -0,0 +1,134 @@
/*
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_tlRecipe
#define HDR_tlRecipe
#include "tlCommon.h"
#include "tlVariant.h"
#include "tlTypeTraits.h"
#include "tlClassRegistry.h"
namespace tl
{
/**
* @brief A facility for providing reproducable recipes
*
* The idea of this facility is to provide a service by which an object
* can be reproduced in a parametrized way. The intended use case is a
* DRC report for example, where the DRC script is the generator.
*
* In this use case, the DRC engine will register a recipe. It will
* put the serialized version of the recipe into the DRC report. If the
* user requests a re-run of the DRC, the recipe will be called and
* the implementation is supposed to deliver a new database.
*
* To register a recipe, reimplement tl::Recipe and create a singleton
* instance. To serialize a recipe, use "generator", to execute the
* recipe, use "make".
*
* Parameters are kept as a generic key/value map.
*/
class TL_PUBLIC Recipe
: public tl::RegisteredClass<Recipe>
{
public:
/**
* @brief @brief Creates a new recipe object
*/
Recipe (const std::string &name, const std::string &description = std::string ());
/**
* @brief Destructor
*/
virtual ~Recipe () { }
/**
* @brief Gets the recipes name (a unique identifier)
*/
const std::string &name () const
{
return m_name;
}
/**
* @brief Gets the description text
*/
const std::string &description () const
{
return m_description;
}
/**
* @brief An utility function to get a parameters
*/
template <class T>
static T get_value (const std::map<std::string, tl::Variant> &params, const std::string &pname, const T &def_value)
{
std::map<std::string, tl::Variant>::const_iterator p = params.find (pname);
if (p != params.end ()) {
const tl::Variant &v = p->second;
return v.to<T> ();
} else {
return def_value;
}
}
/**
* @brief Serializes the given recipe
*/
std::string generator (const std::map<std::string, tl::Variant> &params);
/**
* @brief Executes the recipe from the generator
*
* Returns nil if the recipe can't be executed, e.g. because the recipe isn't known.
* Additional parameters can be passed in the second argument.
* They have lower priority than the parameters kept in the generator argument.
*/
static tl::Variant make (const std::string &generator, const std::map<std::string, tl::Variant> &params = std::map<std::string, tl::Variant> ());
/**
* @brief Recipe interface: executes the recipe with the given parameters
*/
virtual tl::Variant execute (const std::map<std::string, tl::Variant> &params) const = 0;
private:
Recipe (const Recipe &) : tl::RegisteredClass<tl::Recipe> (this) { }
Recipe &operator= (const Recipe &) { return *this; }
std::string m_name;
std::string m_description;
};
template<> struct type_traits<tl::Recipe> : public type_traits<void>
{
typedef tl::false_tag has_copy_constructor;
typedef tl::false_tag has_default_constructor;
};
} // namespace tl
#endif

View File

@ -0,0 +1,64 @@
/*
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 "tlRecipe.h"
#include "tlUnitTest.h"
#include <memory>
namespace {
class MyRecipe : public tl::Recipe
{
public:
MyRecipe () : tl::Recipe ("test_recipe", "description") { }
tl::Variant execute (const std::map<std::string, tl::Variant> &params) const
{
int a = get_value (params, "A", 0);
double b = get_value (params, "B", 0.0);
double c = get_value (params, "C", 1.0);
return tl::Variant (b * a * c);
}
};
static MyRecipe my_recipe;
}
// basic abilities
TEST(1)
{
std::map<std::string, tl::Variant> params;
params["A"] = tl::Variant (7);
params["B"] = tl::Variant (6.0);
std::string g = my_recipe.generator (params);
EXPECT_EQ (g, "test_recipe: A=#7,B=##6");
tl::Variant res = tl::Recipe::make (g);
EXPECT_EQ (res.to_double (), 42.0);
std::map<std::string, tl::Variant> padd;
padd["C"] = tl::Variant(1.5);
res = tl::Recipe::make (g, padd);
EXPECT_EQ (res.to_double (), 63.0);
}

View File

@ -38,7 +38,8 @@ SOURCES = \
tlListTests.cc \
tlEquivalenceClustersTests.cc \
tlUniqueNameTests.cc \
tlGlobPatternTests.cc
tlGlobPatternTests.cc \
tlRecipeTests.cc
!equals(HAVE_QT, "0") {

BIN
testdata/algo/device_extract_au9.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/device_extract_l9.gds vendored Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
testdata/algo/l2n_reader_au_2r.gds vendored Normal file

Binary file not shown.

View File

@ -363,54 +363,108 @@ circuit(RINGO
rect(metal2_lbl (-23941 -381) (2 2))
)
net(5
rect(diff_cont (20210 2490) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 -3420) (220 220))
rect(diff_cont (-220 180) (220 220))
)
net(6
rect(diff_cont (17570 2490) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 -3420) (220 220))
rect(diff_cont (-220 180) (220 220))
)
net(7
rect(diff_cont (14930 2490) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 -3420) (220 220))
rect(diff_cont (-220 180) (220 220))
)
net(8
rect(diff_cont (12290 2490) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 -3420) (220 220))
rect(diff_cont (-220 180) (220 220))
)
net(9
rect(diff_cont (9650 2490) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 -3420) (220 220))
rect(diff_cont (-220 180) (220 220))
)
net(10
rect(diff_cont (7010 2490) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 -3420) (220 220))
rect(diff_cont (-220 180) (220 220))
)
net(11
rect(diff_cont (4370 2490) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 -3420) (220 220))
rect(diff_cont (-220 180) (220 220))
)
net(12
rect(diff_cont (1730 2490) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 -3420) (220 220))
rect(diff_cont (-220 180) (220 220))
)
net(13
rect(diff_cont (-910 2490) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 -3420) (220 220))
rect(diff_cont (-220 180) (220 220))
)
net(14
rect(diff_cont (690 2890) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -2620) (220 220))
rect(diff_cont (-220 -620) (220 220))
)
net(6
net(15
rect(diff_cont (21810 2890) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -2620) (220 220))
rect(diff_cont (-220 -620) (220 220))
)
net(7
net(16
rect(diff_cont (19170 2890) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -2620) (220 220))
rect(diff_cont (-220 -620) (220 220))
)
net(8
net(17
rect(diff_cont (16530 2890) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -2620) (220 220))
rect(diff_cont (-220 -620) (220 220))
)
net(9
net(18
rect(diff_cont (13890 2890) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -2620) (220 220))
rect(diff_cont (-220 -620) (220 220))
)
net(10
net(19
rect(diff_cont (11250 2890) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -2620) (220 220))
rect(diff_cont (-220 -620) (220 220))
)
net(11
net(20
rect(diff_cont (8610 2890) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -2620) (220 220))
rect(diff_cont (-220 -620) (220 220))
)
net(12
net(21
rect(diff_cont (5970 2890) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -2620) (220 220))
rect(diff_cont (-220 -620) (220 220))
)
net(13
net(22
rect(diff_cont (3330 2890) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -2620) (220 220))
@ -425,7 +479,7 @@ circuit(RINGO
# Subcircuits and their connections
circuit(1 INV2 location(23760 0)
pin(0 6)
pin(0 15)
pin(1 1)
pin(2 2)
pin(3 3)
@ -433,55 +487,64 @@ circuit(RINGO
)
circuit(2 INV2 location(0 0)
pin(0 1)
pin(2 5)
pin(1 13)
pin(2 14)
pin(3 3)
pin(4 4)
)
circuit(3 INV2 location(2640 0)
pin(0 5)
pin(2 13)
pin(0 14)
pin(1 12)
pin(2 22)
pin(3 3)
pin(4 4)
)
circuit(4 INV2 location(5280 0)
pin(0 13)
pin(2 12)
pin(0 22)
pin(1 11)
pin(2 21)
pin(3 3)
pin(4 4)
)
circuit(5 INV2 location(7920 0)
pin(0 12)
pin(2 11)
pin(0 21)
pin(1 10)
pin(2 20)
pin(3 3)
pin(4 4)
)
circuit(6 INV2 location(10560 0)
pin(0 11)
pin(2 10)
pin(0 20)
pin(1 9)
pin(2 19)
pin(3 3)
pin(4 4)
)
circuit(7 INV2 location(13200 0)
pin(0 10)
pin(2 9)
pin(0 19)
pin(1 8)
pin(2 18)
pin(3 3)
pin(4 4)
)
circuit(8 INV2 location(15840 0)
pin(0 9)
pin(2 8)
pin(0 18)
pin(1 7)
pin(2 17)
pin(3 3)
pin(4 4)
)
circuit(9 INV2 location(18480 0)
pin(0 8)
pin(2 7)
pin(0 17)
pin(1 6)
pin(2 16)
pin(3 3)
pin(4 4)
)
circuit(10 INV2 location(21120 0)
pin(0 7)
pin(2 6)
pin(0 16)
pin(1 5)
pin(2 15)
pin(3 3)
pin(4 4)
)

Binary file not shown.

619
testdata/algo/l2n_writer_au_2b.txt vendored Normal file
View File

@ -0,0 +1,619 @@
#%l2n-klayout
top(RINGO)
unit(0.001)
# Layer section
# This section lists the mask layers (drawing or derived) and their connections.
# Mask layers
layer(rbulk)
layer(nwell '1/0')
layer(poly '3/0')
layer(poly_lbl '3/1')
layer(diff_cont '4/0')
layer(poly_cont '5/0')
layer(metal1 '6/0')
layer(metal1_lbl '6/1')
layer(via1 '7/0')
layer(metal2 '8/0')
layer(metal2_lbl '8/1')
layer(ntie)
layer(psd)
layer(ptie)
layer(nsd)
# Mask layer connectivity
connect(nwell nwell ntie)
connect(poly poly poly_lbl poly_cont)
connect(poly_lbl poly)
connect(diff_cont diff_cont metal1 ntie psd ptie nsd)
connect(poly_cont poly poly_cont metal1)
connect(metal1 diff_cont poly_cont metal1 metal1_lbl via1)
connect(metal1_lbl metal1)
connect(via1 metal1 via1 metal2)
connect(metal2 via1 metal2 metal2_lbl)
connect(metal2_lbl metal2)
connect(ntie nwell diff_cont ntie)
connect(psd diff_cont psd)
connect(ptie diff_cont ptie)
connect(nsd diff_cont nsd)
# Global nets and connectivity
global(rbulk BULK)
global(ptie BULK)
# Device class section
class(PMOS MOS4)
class(NMOS MOS4)
# Device abstracts section
# Device abstracts list the pin shapes of the devices.
device(D$PMOS PMOS
terminal(S
rect(psd (-650 -475) (525 950))
)
terminal(G
rect(poly (-125 -475) (250 950))
)
terminal(D
rect(psd (125 -475) (550 950))
)
terminal(B
rect(nwell (-125 -475) (250 950))
)
)
device(D$PMOS$1 PMOS
terminal(S
rect(psd (-675 -475) (550 950))
)
terminal(G
rect(poly (-125 -475) (250 950))
)
terminal(D
rect(psd (125 -475) (525 950))
)
terminal(B
rect(nwell (-125 -475) (250 950))
)
)
device(D$NMOS NMOS
terminal(S
rect(nsd (-650 -475) (525 950))
)
terminal(G
rect(poly (-125 -475) (250 950))
)
terminal(D
rect(nsd (125 -475) (550 950))
)
terminal(B
rect(rbulk (-125 -475) (250 950))
)
)
device(D$NMOS$1 NMOS
terminal(S
rect(nsd (-675 -475) (550 950))
)
terminal(G
rect(poly (-125 -475) (250 950))
)
terminal(D
rect(nsd (125 -475) (525 950))
)
terminal(B
rect(rbulk (-125 -475) (250 950))
)
)
# Circuit section
# Circuits are the hierarchical building blocks of the netlist.
circuit(INV2
# Circuit boundary
rect((-1700 -1640) (3100 6220))
# Nets with their geometries
net(1
rect(nwell (-1400 1800) (2800 2780))
rect(diff_cont (-1510 -650) (220 220))
rect(ntie (-510 -450) (800 680))
)
net(2 name(IN)
rect(poly (-525 -250) (250 2500))
rect(poly (-1425 -630) (1300 360))
rect(poly (-125 -2780) (250 1600))
rect(poly (-250 1200) (250 1600))
rect(poly_lbl (-526 -1801) (2 2))
rect(poly_cont (-831 -111) (220 220))
)
net(3
rect(poly (275 -250) (250 2500))
rect(poly (-305 -1430) (360 360))
rect(poly (-305 820) (250 1600))
rect(poly (-250 -4400) (250 1600))
rect(diff_cont (-1435 1690) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 -3420) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(poly_cont (980 580) (220 220))
rect(metal1 (-1310 -290) (1380 360))
rect(metal1 (-1560 -1600) (360 2840))
rect(metal1 (-360 0) (360 760))
rect(metal1 (-360 -3560) (360 760))
rect(psd (-430 1945) (525 950))
rect(nsd (-525 -3750) (525 950))
)
net(4 name(OUT)
rect(diff_cont (690 2890) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -2620) (220 220))
rect(diff_cont (-220 -620) (220 220))
polygon(metal1 (-110 110) (0 360) (140 0) (0 1240) (-320 0) (0 800) (360 0) (0 -440) (320 0) (0 -1960))
rect(metal1 (-680 2400) (360 760))
rect(metal1 (-360 -3560) (360 760))
rect(metal1_lbl (-181 1419) (2 2))
rect(psd (-276 524) (525 950))
rect(nsd (-525 -3750) (525 950))
)
net(5 name(VSS)
rect(diff_cont (-110 -310) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 -220) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(metal1 (-290 -290) (360 760))
rect(metal1 (-360 -760) (360 760))
rect(via1 (-305 -705) (250 250))
rect(via1 (-250 150) (250 250))
rect(metal2 (-1525 -775) (2800 900))
rect(metal2_lbl (-161 -541) (2 2))
rect(nsd (-1516 -386) (550 950))
)
net(6 name(VDD)
rect(diff_cont (-110 2490) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 -220) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(metal1 (-290 -290) (360 760))
rect(metal1 (-360 -760) (360 760))
rect(via1 (-305 -705) (250 250))
rect(via1 (-250 150) (250 250))
rect(metal2 (-1525 -775) (2800 900))
rect(metal2_lbl (-151 -451) (2 2))
rect(psd (-1526 -476) (550 950))
)
net(7 name(BULK)
rect(diff_cont (-110 -1360) (220 220))
rect(ptie (-510 -450) (800 680))
)
# Outgoing pins and their connections to nets
pin(1)
pin(2 name(IN))
pin(3)
pin(4 name(OUT))
pin(5 name(VSS))
pin(6 name(VDD))
pin(7 name(BULK))
# Devices and their connections
device(1 D$PMOS
location(-400 2800)
param(L 0.25)
param(W 0.95)
param(AS 0.49875)
param(AD 0.26125)
param(PS 2.95)
param(PD 1.5)
terminal(S 3)
terminal(G 2)
terminal(D 6)
terminal(B 1)
)
device(2 D$PMOS$1
location(400 2800)
param(L 0.25)
param(W 0.95)
param(AS 0.26125)
param(AD 0.49875)
param(PS 1.5)
param(PD 2.95)
terminal(S 6)
terminal(G 3)
terminal(D 4)
terminal(B 1)
)
device(3 D$NMOS
location(-400 0)
param(L 0.25)
param(W 0.95)
param(AS 0.49875)
param(AD 0.26125)
param(PS 2.95)
param(PD 1.5)
terminal(S 3)
terminal(G 2)
terminal(D 5)
terminal(B 7)
)
device(4 D$NMOS$1
location(400 0)
param(L 0.25)
param(W 0.95)
param(AS 0.26125)
param(AD 0.49875)
param(PS 1.5)
param(PD 2.95)
terminal(S 5)
terminal(G 3)
terminal(D 4)
terminal(B 7)
)
)
circuit(INV2PAIR
# Circuit boundary
rect((0 -840) (5740 6220))
# Nets with their geometries
net(1 name(BULK))
net(2
rect(diff_cont (3430 3290) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 -3420) (220 220))
rect(diff_cont (-220 180) (220 220))
)
net(3
rect(diff_cont (790 3290) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 -3420) (220 220))
rect(diff_cont (-220 180) (220 220))
)
net(4
rect(diff_cont (4230 3290) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 -220) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-2860 -220) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 -220) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(metal1 (2350 -290) (360 760))
rect(metal1 (-360 -760) (360 760))
rect(metal1 (-3000 -760) (360 760))
rect(metal1 (-360 -760) (360 760))
)
net(5
rect(diff_cont (4230 490) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 -220) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-2860 -220) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 -220) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(metal1 (2350 -290) (360 760))
rect(metal1 (-360 -760) (360 760))
rect(metal1 (-3000 -760) (360 760))
rect(metal1 (-360 -760) (360 760))
)
net(6
rect(diff_cont (2390 3690) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -2620) (220 220))
rect(diff_cont (-220 -620) (220 220))
)
net(7)
net(8
rect(diff_cont (5030 3690) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -2620) (220 220))
rect(diff_cont (-220 -620) (220 220))
)
net(9)
# Outgoing pins and their connections to nets
pin(1 name(BULK))
pin(2)
pin(4)
pin(5)
pin(7)
pin(8)
pin(9)
# Subcircuits and their connections
circuit(1 INV2 location(1700 800)
pin(0 9)
pin(1 7)
pin(2 3)
pin(3 6)
pin(4 5)
pin(5 4)
pin(6 1)
)
circuit(2 INV2 location(4340 800)
pin(0 9)
pin(1 6)
pin(2 2)
pin(3 8)
pin(4 5)
pin(5 4)
pin(6 1)
)
)
circuit(RINGO
# Circuit boundary
rect((-1720 -1640) (26880 6220))
# Nets with their geometries
net(1 name(FB)
rect(diff_cont (22850 2490) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 -3420) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(metal1 (-24770 1310) (360 360))
rect(via1 (-305 -305) (250 250))
rect(via1 (24230 -250) (250 250))
rect(metal2 (-24805 -325) (24880 400))
rect(metal2_lbl (-23161 -201) (2 2))
)
net(2 name(OSC)
rect(diff_cont (24450 2890) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -2620) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(via1 (-235 1765) (250 250))
rect(metal2 (-325 -325) (400 400))
rect(metal2_lbl (-201 -201) (2 2))
)
net(3 name(VDD)
rect(diff_cont (7810 2490) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 -220) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-2860 -220) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 -220) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-2860 -220) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 -220) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-2860 -220) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 -220) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (12980 -220) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 -220) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-2860 -220) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 -220) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (7700 -220) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 -220) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-2860 -220) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 -220) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (7700 -220) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 -220) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-2860 -220) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 -220) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(metal1 (-21410 390) (360 1120))
rect(metal1 (2280 -1120) (360 1120))
rect(metal1 (2280 -1120) (360 1120))
rect(metal1 (2280 -1120) (360 1120))
rect(metal1 (2280 -1120) (360 1120))
rect(metal1 (2280 -1120) (360 1120))
rect(metal1 (2280 -1120) (360 1120))
rect(metal1 (2280 -1120) (360 1120))
rect(metal1 (2280 -1120) (360 1120))
rect(metal1 (2280 -1120) (360 1120))
rect(metal1 (-16200 -1800) (360 760))
rect(metal1 (-360 -760) (360 760))
rect(metal1 (-3000 -760) (360 760))
rect(metal1 (-360 -760) (360 760))
rect(metal1 (-3000 -760) (360 760))
rect(metal1 (-360 -760) (360 760))
rect(metal1 (-3000 -760) (360 760))
rect(metal1 (-360 -760) (360 760))
rect(metal1 (12840 -760) (360 760))
rect(metal1 (-360 -760) (360 760))
rect(metal1 (-3000 -760) (360 760))
rect(metal1 (-360 -760) (360 760))
rect(metal1 (7560 -760) (360 760))
rect(metal1 (-360 -760) (360 760))
rect(metal1 (-3000 -760) (360 760))
rect(metal1 (-360 -760) (360 760))
rect(metal1 (7560 -760) (360 760))
rect(metal1 (-360 -760) (360 760))
rect(metal1 (-3000 -760) (360 760))
rect(metal1 (-360 -760) (360 760))
rect(metal2_lbl (-21301 -381) (2 2))
)
net(4 name(VSS)
rect(diff_cont (7810 -310) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 -220) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-2860 -220) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 -220) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-2860 -220) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 -220) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-2860 -220) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 -220) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (12980 -220) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 -220) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-2860 -220) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 -220) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (7700 -220) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 -220) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-2860 -220) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 -220) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (7700 -220) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 -220) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-2860 -220) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 -220) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(metal1 (-21410 -1330) (360 1120))
rect(metal1 (2280 -1120) (360 1120))
rect(metal1 (2280 -1120) (360 1120))
rect(metal1 (2280 -1120) (360 1120))
rect(metal1 (2280 -1120) (360 1120))
rect(metal1 (2280 -1120) (360 1120))
rect(metal1 (2280 -1120) (360 1120))
rect(metal1 (2280 -1120) (360 1120))
rect(metal1 (2280 -1120) (360 1120))
rect(metal1 (2280 -1120) (360 1120))
rect(metal1 (-16200 -80) (360 760))
rect(metal1 (-360 -760) (360 760))
rect(metal1 (-3000 -760) (360 760))
rect(metal1 (-360 -760) (360 760))
rect(metal1 (-3000 -760) (360 760))
rect(metal1 (-360 -760) (360 760))
rect(metal1 (-3000 -760) (360 760))
rect(metal1 (-360 -760) (360 760))
rect(metal1 (12840 -760) (360 760))
rect(metal1 (-360 -760) (360 760))
rect(metal1 (-3000 -760) (360 760))
rect(metal1 (-360 -760) (360 760))
rect(metal1 (7560 -760) (360 760))
rect(metal1 (-360 -760) (360 760))
rect(metal1 (-3000 -760) (360 760))
rect(metal1 (-360 -760) (360 760))
rect(metal1 (7560 -760) (360 760))
rect(metal1 (-360 -760) (360 760))
rect(metal1 (-3000 -760) (360 760))
rect(metal1 (-360 -760) (360 760))
rect(metal2_lbl (-21301 -381) (2 2))
)
net(5
rect(diff_cont (17570 2490) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 -3420) (220 220))
rect(diff_cont (-220 180) (220 220))
)
net(6
rect(diff_cont (12290 2490) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 -3420) (220 220))
rect(diff_cont (-220 180) (220 220))
)
net(7
rect(diff_cont (7010 2490) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 -3420) (220 220))
rect(diff_cont (-220 180) (220 220))
)
net(8
rect(diff_cont (1730 2490) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 -3420) (220 220))
rect(diff_cont (-220 180) (220 220))
)
net(9
rect(diff_cont (3330 2890) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -2620) (220 220))
rect(diff_cont (-220 -620) (220 220))
)
net(10
rect(diff_cont (19170 2890) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -2620) (220 220))
rect(diff_cont (-220 -620) (220 220))
)
net(11
rect(diff_cont (13890 2890) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -2620) (220 220))
rect(diff_cont (-220 -620) (220 220))
)
net(12
rect(diff_cont (8610 2890) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -2620) (220 220))
rect(diff_cont (-220 -620) (220 220))
)
# Outgoing pins and their connections to nets
pin(1 name(FB))
pin(2 name(OSC))
pin(3 name(VDD))
pin(4 name(VSS))
# Subcircuits and their connections
circuit(1 INV2PAIR location(19420 -800)
pin(0 4)
pin(1 1)
pin(2 3)
pin(3 4)
pin(4 10)
pin(5 2)
pin(6 3)
)
circuit(2 INV2PAIR location(-1700 -800)
pin(0 4)
pin(1 8)
pin(2 3)
pin(3 4)
pin(4 1)
pin(5 9)
pin(6 3)
)
circuit(3 INV2PAIR location(3580 -800)
pin(0 4)
pin(1 7)
pin(2 3)
pin(3 4)
pin(4 9)
pin(5 12)
pin(6 3)
)
circuit(4 INV2PAIR location(8860 -800)
pin(0 4)
pin(1 6)
pin(2 3)
pin(3 4)
pin(4 12)
pin(5 11)
pin(6 3)
)
circuit(5 INV2PAIR location(14140 -800)
pin(0 4)
pin(1 5)
pin(2 3)
pin(3 4)
pin(4 11)
pin(5 10)
pin(6 3)
)
)

View File

@ -232,6 +232,12 @@ X(INV2PAIR
R(diff_cont (-220 180) (220 220))
)
N(3
R(diff_cont (790 3290) (220 220))
R(diff_cont (-220 180) (220 220))
R(diff_cont (-220 -3420) (220 220))
R(diff_cont (-220 180) (220 220))
)
N(4
R(diff_cont (4230 3290) (220 220))
R(diff_cont (-220 180) (220 220))
R(diff_cont (-220 -220) (220 220))
@ -245,7 +251,7 @@ X(INV2PAIR
R(metal1 (-3000 -760) (360 760))
R(metal1 (-360 -760) (360 760))
)
N(4
N(5
R(diff_cont (4230 490) (220 220))
R(diff_cont (-220 180) (220 220))
R(diff_cont (-220 -220) (220 220))
@ -259,42 +265,43 @@ X(INV2PAIR
R(metal1 (-3000 -760) (360 760))
R(metal1 (-360 -760) (360 760))
)
N(5
N(6
R(diff_cont (2390 3690) (220 220))
R(diff_cont (-220 -620) (220 220))
R(diff_cont (-220 -2620) (220 220))
R(diff_cont (-220 -620) (220 220))
)
N(6)
N(7
N(7)
N(8
R(diff_cont (5030 3690) (220 220))
R(diff_cont (-220 -620) (220 220))
R(diff_cont (-220 -2620) (220 220))
R(diff_cont (-220 -620) (220 220))
)
N(8)
N(9)
P(1 I(BULK))
P(2)
P(3)
P(4)
P(6)
P(5)
P(7)
P(8)
P(9)
X(1 INV2 Y(1700 800)
P(0 8)
P(1 6)
P(3 5)
P(4 4)
P(5 3)
P(0 9)
P(1 7)
P(2 3)
P(3 6)
P(4 5)
P(5 4)
P(6 1)
)
X(2 INV2 Y(4340 800)
P(0 8)
P(1 5)
P(0 9)
P(1 6)
P(2 2)
P(3 7)
P(4 4)
P(5 3)
P(3 8)
P(4 5)
P(5 4)
P(6 1)
)
)
@ -467,24 +474,48 @@ X(RINGO
R(metal2_lbl (-21301 -381) (2 2))
)
N(5
R(diff_cont (17570 2490) (220 220))
R(diff_cont (-220 180) (220 220))
R(diff_cont (-220 -3420) (220 220))
R(diff_cont (-220 180) (220 220))
)
N(6
R(diff_cont (12290 2490) (220 220))
R(diff_cont (-220 180) (220 220))
R(diff_cont (-220 -3420) (220 220))
R(diff_cont (-220 180) (220 220))
)
N(7
R(diff_cont (7010 2490) (220 220))
R(diff_cont (-220 180) (220 220))
R(diff_cont (-220 -3420) (220 220))
R(diff_cont (-220 180) (220 220))
)
N(8
R(diff_cont (1730 2490) (220 220))
R(diff_cont (-220 180) (220 220))
R(diff_cont (-220 -3420) (220 220))
R(diff_cont (-220 180) (220 220))
)
N(9
R(diff_cont (3330 2890) (220 220))
R(diff_cont (-220 -620) (220 220))
R(diff_cont (-220 -2620) (220 220))
R(diff_cont (-220 -620) (220 220))
)
N(6
N(10
R(diff_cont (19170 2890) (220 220))
R(diff_cont (-220 -620) (220 220))
R(diff_cont (-220 -2620) (220 220))
R(diff_cont (-220 -620) (220 220))
)
N(7
N(11
R(diff_cont (13890 2890) (220 220))
R(diff_cont (-220 -620) (220 220))
R(diff_cont (-220 -2620) (220 220))
R(diff_cont (-220 -620) (220 220))
)
N(8
N(12
R(diff_cont (8610 2890) (220 220))
R(diff_cont (-220 -620) (220 220))
R(diff_cont (-220 -2620) (220 220))
@ -499,40 +530,44 @@ X(RINGO
P(1 1)
P(2 3)
P(3 4)
P(4 6)
P(4 10)
P(5 2)
P(6 3)
)
X(2 INV2PAIR Y(-1700 -800)
P(0 4)
P(1 8)
P(2 3)
P(3 4)
P(4 1)
P(5 5)
P(5 9)
P(6 3)
)
X(3 INV2PAIR Y(3580 -800)
P(0 4)
P(1 7)
P(2 3)
P(3 4)
P(4 5)
P(5 8)
P(4 9)
P(5 12)
P(6 3)
)
X(4 INV2PAIR Y(8860 -800)
P(0 4)
P(1 6)
P(2 3)
P(3 4)
P(4 8)
P(5 7)
P(4 12)
P(5 11)
P(6 3)
)
X(5 INV2PAIR Y(14140 -800)
P(0 4)
P(1 5)
P(2 3)
P(3 4)
P(4 7)
P(5 6)
P(4 11)
P(5 10)
P(6 3)
)
)

View File

@ -333,54 +333,108 @@ X(RINGO
R(metal2_lbl (-23941 -381) (2 2))
)
N(5
R(diff_cont (20210 2490) (220 220))
R(diff_cont (-220 180) (220 220))
R(diff_cont (-220 -3420) (220 220))
R(diff_cont (-220 180) (220 220))
)
N(6
R(diff_cont (17570 2490) (220 220))
R(diff_cont (-220 180) (220 220))
R(diff_cont (-220 -3420) (220 220))
R(diff_cont (-220 180) (220 220))
)
N(7
R(diff_cont (14930 2490) (220 220))
R(diff_cont (-220 180) (220 220))
R(diff_cont (-220 -3420) (220 220))
R(diff_cont (-220 180) (220 220))
)
N(8
R(diff_cont (12290 2490) (220 220))
R(diff_cont (-220 180) (220 220))
R(diff_cont (-220 -3420) (220 220))
R(diff_cont (-220 180) (220 220))
)
N(9
R(diff_cont (9650 2490) (220 220))
R(diff_cont (-220 180) (220 220))
R(diff_cont (-220 -3420) (220 220))
R(diff_cont (-220 180) (220 220))
)
N(10
R(diff_cont (7010 2490) (220 220))
R(diff_cont (-220 180) (220 220))
R(diff_cont (-220 -3420) (220 220))
R(diff_cont (-220 180) (220 220))
)
N(11
R(diff_cont (4370 2490) (220 220))
R(diff_cont (-220 180) (220 220))
R(diff_cont (-220 -3420) (220 220))
R(diff_cont (-220 180) (220 220))
)
N(12
R(diff_cont (1730 2490) (220 220))
R(diff_cont (-220 180) (220 220))
R(diff_cont (-220 -3420) (220 220))
R(diff_cont (-220 180) (220 220))
)
N(13
R(diff_cont (-910 2490) (220 220))
R(diff_cont (-220 180) (220 220))
R(diff_cont (-220 -3420) (220 220))
R(diff_cont (-220 180) (220 220))
)
N(14
R(diff_cont (690 2890) (220 220))
R(diff_cont (-220 -620) (220 220))
R(diff_cont (-220 -2620) (220 220))
R(diff_cont (-220 -620) (220 220))
)
N(6
N(15
R(diff_cont (21810 2890) (220 220))
R(diff_cont (-220 -620) (220 220))
R(diff_cont (-220 -2620) (220 220))
R(diff_cont (-220 -620) (220 220))
)
N(7
N(16
R(diff_cont (19170 2890) (220 220))
R(diff_cont (-220 -620) (220 220))
R(diff_cont (-220 -2620) (220 220))
R(diff_cont (-220 -620) (220 220))
)
N(8
N(17
R(diff_cont (16530 2890) (220 220))
R(diff_cont (-220 -620) (220 220))
R(diff_cont (-220 -2620) (220 220))
R(diff_cont (-220 -620) (220 220))
)
N(9
N(18
R(diff_cont (13890 2890) (220 220))
R(diff_cont (-220 -620) (220 220))
R(diff_cont (-220 -2620) (220 220))
R(diff_cont (-220 -620) (220 220))
)
N(10
N(19
R(diff_cont (11250 2890) (220 220))
R(diff_cont (-220 -620) (220 220))
R(diff_cont (-220 -2620) (220 220))
R(diff_cont (-220 -620) (220 220))
)
N(11
N(20
R(diff_cont (8610 2890) (220 220))
R(diff_cont (-220 -620) (220 220))
R(diff_cont (-220 -2620) (220 220))
R(diff_cont (-220 -620) (220 220))
)
N(12
N(21
R(diff_cont (5970 2890) (220 220))
R(diff_cont (-220 -620) (220 220))
R(diff_cont (-220 -2620) (220 220))
R(diff_cont (-220 -620) (220 220))
)
N(13
N(22
R(diff_cont (3330 2890) (220 220))
R(diff_cont (-220 -620) (220 220))
R(diff_cont (-220 -2620) (220 220))
@ -391,7 +445,7 @@ X(RINGO
P(3 I(VSS))
P(4 I(VDD))
X(1 INV2 Y(23760 0)
P(0 6)
P(0 15)
P(1 1)
P(2 2)
P(3 3)
@ -399,55 +453,64 @@ X(RINGO
)
X(2 INV2 Y(0 0)
P(0 1)
P(2 5)
P(1 13)
P(2 14)
P(3 3)
P(4 4)
)
X(3 INV2 Y(2640 0)
P(0 5)
P(2 13)
P(0 14)
P(1 12)
P(2 22)
P(3 3)
P(4 4)
)
X(4 INV2 Y(5280 0)
P(0 13)
P(2 12)
P(0 22)
P(1 11)
P(2 21)
P(3 3)
P(4 4)
)
X(5 INV2 Y(7920 0)
P(0 12)
P(2 11)
P(0 21)
P(1 10)
P(2 20)
P(3 3)
P(4 4)
)
X(6 INV2 Y(10560 0)
P(0 11)
P(2 10)
P(0 20)
P(1 9)
P(2 19)
P(3 3)
P(4 4)
)
X(7 INV2 Y(13200 0)
P(0 10)
P(2 9)
P(0 19)
P(1 8)
P(2 18)
P(3 3)
P(4 4)
)
X(8 INV2 Y(15840 0)
P(0 9)
P(2 8)
P(0 18)
P(1 7)
P(2 17)
P(3 3)
P(4 4)
)
X(9 INV2 Y(18480 0)
P(0 8)
P(2 7)
P(0 17)
P(1 6)
P(2 16)
P(3 3)
P(4 4)
)
X(10 INV2 Y(21120 0)
P(0 7)
P(2 6)
P(0 16)
P(1 5)
P(2 15)
P(3 3)
P(4 4)
)

View File

@ -655,7 +655,7 @@ layout(
rect(metal2_lbl (-21301 -381) (2 2))
)
net(5
rect(diff_cont (1730 90) (220 220))
rect(diff_cont (14930 90) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -620) (220 220))
@ -673,7 +673,7 @@ layout(
rect(diff_cont (-220 180) (220 220))
)
net(6
rect(diff_cont (17570 90) (220 220))
rect(diff_cont (9650 90) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -620) (220 220))
@ -691,7 +691,7 @@ layout(
rect(diff_cont (-220 180) (220 220))
)
net(7
rect(diff_cont (12290 90) (220 220))
rect(diff_cont (4370 90) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -620) (220 220))
@ -709,6 +709,78 @@ layout(
rect(diff_cont (-220 180) (220 220))
)
net(8
rect(diff_cont (-910 90) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (1380 3380) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 -3820) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-1820 3380) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 180) (220 220))
)
net(9
rect(diff_cont (1730 90) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (1380 3380) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 -3820) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-1820 3380) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 180) (220 220))
)
net(10
rect(diff_cont (17570 90) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (1380 3380) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 -3820) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-1820 3380) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 180) (220 220))
)
net(11
rect(diff_cont (12290 90) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (1380 3380) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 -3820) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-1820 3380) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 180) (220 220))
)
net(12
rect(diff_cont (7010 90) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -620) (220 220))
@ -739,7 +811,7 @@ layout(
pin(1 3)
pin(2 4)
pin(3 1)
pin(4 6)
pin(4 10)
pin(5 2)
pin(6 3)
)
@ -747,32 +819,36 @@ layout(
pin(0 4)
pin(1 3)
pin(2 4)
pin(3 8)
pin(4 1)
pin(5 5)
pin(5 9)
pin(6 3)
)
circuit(3 INV2PAIR location(3580 -800)
pin(0 4)
pin(1 3)
pin(2 4)
pin(4 5)
pin(5 8)
pin(3 7)
pin(4 9)
pin(5 12)
pin(6 3)
)
circuit(4 INV2PAIR location(8860 -800)
pin(0 4)
pin(1 3)
pin(2 4)
pin(4 8)
pin(5 7)
pin(3 6)
pin(4 12)
pin(5 11)
pin(6 3)
)
circuit(5 INV2PAIR location(14140 -800)
pin(0 4)
pin(1 3)
pin(2 4)
pin(4 7)
pin(5 6)
pin(3 5)
pin(4 11)
pin(5 10)
pin(6 3)
)
@ -882,9 +958,13 @@ reference(
net(3 name('3'))
net(4 name('4'))
net(5 name('6'))
net(6 name('5'))
net(7 name('8'))
net(8 name('7'))
net(6 name('100'))
net(7 name('5'))
net(8 name('101'))
net(9 name('8'))
net(10 name('102'))
net(11 name('7'))
net(12 name('103'))
# Outgoing pins and their connections to nets
pin(1 name('1'))
@ -906,31 +986,35 @@ reference(
pin(0 4)
pin(1 3)
pin(2 4)
pin(3 6)
pin(4 1)
pin(5 6)
pin(5 7)
pin(6 3)
)
circuit(3 INV2PAIR name($3)
pin(0 4)
pin(1 3)
pin(2 4)
pin(4 6)
pin(5 7)
pin(3 8)
pin(4 7)
pin(5 9)
pin(6 3)
)
circuit(4 INV2PAIR name($4)
pin(0 4)
pin(1 3)
pin(2 4)
pin(4 7)
pin(5 8)
pin(3 10)
pin(4 9)
pin(5 11)
pin(6 3)
)
circuit(5 INV2PAIR name($5)
pin(0 4)
pin(1 3)
pin(2 4)
pin(4 8)
pin(3 12)
pin(4 11)
pin(5 5)
pin(6 3)
)
@ -980,10 +1064,14 @@ xref(
)
circuit(RINGO RINGO match
xref(
net(5 6 match)
net(6 5 match)
net(8 6 match)
net(7 8 match)
net(8 7 match)
net(6 10 match)
net(5 12 match)
net(9 7 match)
net(10 5 match)
net(11 11 match)
net(12 9 match)
net(1 1 match)
net(2 2 match)
net(3 3 match)

View File

@ -655,7 +655,7 @@ layout(
rect(metal2_lbl (-21301 -381) (2 2))
)
net(5
rect(diff_cont (1730 90) (220 220))
rect(diff_cont (14930 90) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -620) (220 220))
@ -673,7 +673,7 @@ layout(
rect(diff_cont (-220 180) (220 220))
)
net(6
rect(diff_cont (17570 90) (220 220))
rect(diff_cont (9650 90) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -620) (220 220))
@ -691,7 +691,7 @@ layout(
rect(diff_cont (-220 180) (220 220))
)
net(7
rect(diff_cont (12290 90) (220 220))
rect(diff_cont (4370 90) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -620) (220 220))
@ -709,6 +709,78 @@ layout(
rect(diff_cont (-220 180) (220 220))
)
net(8
rect(diff_cont (-910 90) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (1380 3380) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 -3820) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-1820 3380) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 180) (220 220))
)
net(9
rect(diff_cont (1730 90) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (1380 3380) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 -3820) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-1820 3380) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 180) (220 220))
)
net(10
rect(diff_cont (17570 90) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (1380 3380) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 -3820) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-1820 3380) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 180) (220 220))
)
net(11
rect(diff_cont (12290 90) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (1380 3380) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 -3820) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-1820 3380) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 180) (220 220))
rect(diff_cont (-220 180) (220 220))
)
net(12
rect(diff_cont (7010 90) (220 220))
rect(diff_cont (-220 -620) (220 220))
rect(diff_cont (-220 -620) (220 220))
@ -739,7 +811,7 @@ layout(
pin(1 3)
pin(2 4)
pin(3 1)
pin(4 6)
pin(4 10)
pin(5 2)
pin(6 3)
)
@ -747,32 +819,36 @@ layout(
pin(0 4)
pin(1 3)
pin(2 4)
pin(3 8)
pin(4 1)
pin(5 5)
pin(5 9)
pin(6 3)
)
circuit(3 INV2PAIR location(3580 -800)
pin(0 4)
pin(1 3)
pin(2 4)
pin(4 5)
pin(5 8)
pin(3 7)
pin(4 9)
pin(5 12)
pin(6 3)
)
circuit(4 INV2PAIR location(8860 -800)
pin(0 4)
pin(1 3)
pin(2 4)
pin(4 8)
pin(5 7)
pin(3 6)
pin(4 12)
pin(5 11)
pin(6 3)
)
circuit(5 INV2PAIR location(14140 -800)
pin(0 4)
pin(1 3)
pin(2 4)
pin(4 7)
pin(5 6)
pin(3 5)
pin(4 11)
pin(5 10)
pin(6 3)
)
@ -882,9 +958,13 @@ reference(
net(3 name('3'))
net(4 name('4'))
net(5 name('6'))
net(6 name('5'))
net(7 name('8'))
net(8 name('7'))
net(6 name('100'))
net(7 name('5'))
net(8 name('101'))
net(9 name('8'))
net(10 name('102'))
net(11 name('7'))
net(12 name('103'))
# Outgoing pins and their connections to nets
pin(1 name('1'))
@ -906,31 +986,35 @@ reference(
pin(0 4)
pin(1 3)
pin(2 4)
pin(3 6)
pin(4 1)
pin(5 6)
pin(5 7)
pin(6 3)
)
circuit(3 INV2PAIR name($3)
pin(0 4)
pin(1 3)
pin(2 4)
pin(4 6)
pin(5 7)
pin(3 8)
pin(4 7)
pin(5 9)
pin(6 3)
)
circuit(4 INV2PAIR name($4)
pin(0 4)
pin(1 3)
pin(2 4)
pin(4 7)
pin(5 8)
pin(3 10)
pin(4 9)
pin(5 11)
pin(6 3)
)
circuit(5 INV2PAIR name($5)
pin(0 4)
pin(1 3)
pin(2 4)
pin(4 8)
pin(3 12)
pin(4 11)
pin(5 5)
pin(6 3)
)
@ -980,10 +1064,14 @@ xref(
)
circuit(RINGO RINGO match
xref(
net(5 6 match)
net(6 5 match)
net(8 6 match)
net(7 8 match)
net(8 7 match)
net(6 10 match)
net(5 12 match)
net(9 7 match)
net(10 5 match)
net(11 11 match)
net(12 9 match)
net(1 1 match)
net(2 2 match)
net(3 3 match)

Some files were not shown because too many files have changed in this diff Show More