Merge branch 'dvb'
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
|
||||
|
|
|
|||
|
|
@ -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> ¶ms)
|
||||
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) {
|
||||
|
||||
|
|
|
|||
|
|
@ -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."
|
||||
) +
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
) +
|
||||
|
|
|
|||
|
|
@ -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"),
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 >= 10 && RBA::Logger::info("Running #{_macro.path}")
|
||||
_drc.instance_eval(_macro.text, _macro.path)
|
||||
RBA::Logger::verbosity >= 10 && RBA::Logger::info("Running #{macro.path}")
|
||||
drc.instance_eval(macro.text, macro.path)
|
||||
# Remove the debugger scope
|
||||
RBA::MacroExecutionContext::remove_debugger_scope
|
||||
|
||||
rescue => 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 < 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 < 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 < 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>
|
||||
|
|
|
|||
|
|
@ -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> ¶ms) 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."
|
||||
);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 5.9 KiB |
|
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 5.8 KiB |
|
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 5.9 KiB |
|
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 6.0 KiB |
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 5.8 KiB |
|
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.6 KiB |
|
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 5.8 KiB |
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
|
|
@ -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 <= 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>
|
||||
|
||||
|
|
|
|||
|
|
@ -187,6 +187,27 @@ extract_devices(mos4(model_name), { "SD" => (active - poly) & 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>
|
||||
|
|
|
|||
|
|
@ -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 < 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 < 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
|
||||
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 5.0 KiB |
|
|
@ -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 "Open" from the "File ..." 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>
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 ()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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 >= 10 && RBA::Logger::info("Running #{_macro.path}")
|
||||
_lvs.instance_eval(_macro.text, _macro.path)
|
||||
RBA::Logger::verbosity >= 10 && RBA::Logger::info("Running #{macro.path}")
|
||||
lvs.instance_eval(macro.text, macro.path)
|
||||
# Remove the debugger scope
|
||||
RBA::MacroExecutionContext::remove_debugger_scope
|
||||
|
||||
rescue => 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 < 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 < 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 < 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>
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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", ¯o_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"
|
||||
|
|
|
|||
|
|
@ -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 ()));
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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") {
|
||||
|
||||
|
|
|
|||
|
|
@ -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> ¶ms)
|
||||
{
|
||||
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
|
||||
|
|
@ -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> ¶ms, 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> ¶ms);
|
||||
|
||||
/**
|
||||
* @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> ¶ms = 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> ¶ms) 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
|
||||
|
||||
|
|
@ -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> ¶ms) 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);
|
||||
}
|
||||
|
|
@ -38,7 +38,8 @@ SOURCES = \
|
|||
tlListTests.cc \
|
||||
tlEquivalenceClustersTests.cc \
|
||||
tlUniqueNameTests.cc \
|
||||
tlGlobPatternTests.cc
|
||||
tlGlobPatternTests.cc \
|
||||
tlRecipeTests.cc
|
||||
|
||||
!equals(HAVE_QT, "0") {
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
)
|
||||
|
||||
)
|
||||
|
|
@ -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)
|
||||
)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||