Provide strict mode for device classes, dmos3/dmos4 for LVS

This commit is contained in:
Matthias Koefferlein 2019-08-20 23:12:17 +02:00
parent 50a341232c
commit 45cdefcf9a
19 changed files with 1763 additions and 104 deletions

View File

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

View File

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

View File

@ -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;
};
// --------------------------------------------------------------------------------------------------------------------
@ -1070,14 +1088,17 @@ 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 ());
@ -2203,6 +2224,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 +2364,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));
@ -2872,7 +2903,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 +2937,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) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -161,6 +161,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

View File

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

View File

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

View File

@ -129,3 +129,8 @@ 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");
}

BIN
testdata/algo/device_extract_au9.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/device_extract_l9.gds vendored Normal file

Binary file not shown.

BIN
testdata/lvs/ringo.gds vendored

Binary file not shown.

83
testdata/lvs/ringo_simple_dmos.cir vendored Normal file
View File

@ -0,0 +1,83 @@
* Extracted by KLayout
* cell RINGO
* pin FB
* pin VDD
* pin OUT
* pin ENABLE
* pin VSS
.SUBCKT RINGO 11 12 13 14 15
* net 11 FB
* net 12 VDD
* net 13 OUT
* net 14 ENABLE
* net 15 VSS
* cell instance $1 r0 *1 1.8,0
X$1 12 1 15 12 11 14 15 ND2X1
* cell instance $2 r0 *1 4.2,0
X$2 12 2 15 12 1 15 INVX1
* cell instance $3 r0 *1 6,0
X$3 12 3 15 12 2 15 INVX1
* cell instance $4 r0 *1 7.8,0
X$4 12 4 15 12 3 15 INVX1
* cell instance $5 r0 *1 9.6,0
X$5 12 5 15 12 4 15 INVX1
* cell instance $6 r0 *1 11.4,0
X$6 12 6 15 12 5 15 INVX1
* cell instance $7 r0 *1 13.2,0
X$7 12 7 15 12 6 15 INVX1
* cell instance $8 r0 *1 15,0
X$8 12 8 15 12 7 15 INVX1
* cell instance $9 r0 *1 16.8,0
X$9 12 9 15 12 8 15 INVX1
* cell instance $10 r0 *1 18.6,0
X$10 12 10 15 12 9 15 INVX1
* cell instance $11 r0 *1 20.4,0
X$11 12 11 15 12 10 15 INVX1
* cell instance $12 r0 *1 22.2,0
X$12 12 13 15 12 11 15 INVX1
.ENDS RINGO
* cell INVX1
* pin VDD
* pin OUT
* pin VSS
* pin
* pin IN
* pin SUBSTRATE
.SUBCKT INVX1 1 2 3 4 5 6
* net 1 VDD
* net 2 OUT
* net 3 VSS
* net 5 IN
* net 6 SUBSTRATE
* device instance $1 r0 *1 0.85,5.8 PMOS
M$1 1 5 2 4 PMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U
* device instance $2 r0 *1 0.85,2.135 NMOS
M$2 3 5 2 6 NMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U PD=2.75U
.ENDS INVX1
* cell ND2X1
* pin VDD
* pin OUT
* pin VSS
* pin
* pin B
* pin A
* pin SUBSTRATE
.SUBCKT ND2X1 1 2 3 5 6 7 8
* net 1 VDD
* net 2 OUT
* net 3 VSS
* net 6 B
* net 7 A
* net 8 SUBSTRATE
* device instance $1 r0 *1 0.85,5.8 PMOS
M$1 1 7 2 5 PMOS L=0.25U W=1.5U AS=0.3375P AD=0.6375P PS=1.95U PD=3.85U
* device instance $2 r0 *1 1.55,5.8 PMOS
M$2 1 6 2 5 PMOS L=0.25U W=1.5U AS=0.3375P AD=0.6375P PS=1.95U PD=3.85U
* device instance $3 r0 *1 0.85,2.135 NMOS
M$3 4 7 3 8 NMOS L=0.25U W=0.95U AS=0.21375P AD=0.40375P PS=1.4U PD=2.75U
* device instance $4 r0 *1 1.55,2.135 NMOS
M$4 4 6 2 8 NMOS L=0.25U W=0.95U AS=0.21375P AD=0.40375P PS=1.4U PD=2.75U
.ENDS ND2X1

81
testdata/lvs/ringo_simple_dmos.lvs vendored Normal file
View File

@ -0,0 +1,81 @@
source($lvs_test_source, "RINGO")
report_lvs($lvs_test_target_lvsdb, true)
target_netlist($lvs_test_target_cir, write_spice, "Extracted by KLayout")
schematic("ringo.cir")
deep
# Drawing layers
nwell = input(1, 0)
active = input(2, 0)
pplus = input(3, 0)
nplus = input(4, 0)
poly = input(5, 0)
contact = input(8, 0)
metal1 = input(9, 0)
via1 = input(10, 0)
metal2 = input(11, 0)
source = input(14, 0)
# Bulk layer for terminal provisioning
bulk = polygon_layer
# Computed layers
active_in_nwell = active & nwell
pactive = active_in_nwell & pplus
pgate = pactive & poly
psd = pactive - pgate
ps = psd & source
pd = psd - source
ntie = active_in_nwell & nplus
active_outside_nwell = active - nwell
nactive = active_outside_nwell & nplus
ngate = nactive & poly
nsd = nactive - ngate
ns = nsd & source
nd = nsd - source
ptie = active_outside_nwell & pplus
# Device extraction
# PMOS transistor device extraction
extract_devices(dmos4("PMOS"), { "S" => ps, "D" => pd, "G" => pgate, "W" => nwell,
"tS" => ps, "tD" => pd, "tG" => poly, "tW" => nwell })
# NMOS transistor device extraction
extract_devices(dmos4("NMOS"), { "S" => ns, "D" => nd, "G" => ngate, "W" => bulk,
"tS" => ns, "tD" => nd, "tG" => poly, "tW" => bulk })
# Define connectivity for netlist extraction
# Inter-layer
connect(ps, contact)
connect(pd, contact)
connect(ns, contact)
connect(nd, contact)
connect(poly, contact)
connect(ntie, contact)
connect(nwell, ntie)
connect(ptie, contact)
connect(contact, metal1)
connect(metal1, via1)
connect(via1, metal2)
# Global
connect_global(bulk, "SUBSTRATE")
connect_global(ptie, "SUBSTRATE")
# Compare section
netlist.simplify
compare

925
testdata/lvs/ringo_simple_dmos.lvsdb vendored Normal file
View File

@ -0,0 +1,925 @@
#%lvsdb-klayout
# Layout
layout(
top(RINGO)
unit(0.001)
# Layer section
# This section lists the mask layers (drawing or derived) and their connections.
# Mask layers
layer(l4 '1/0')
layer(l5 '5/0')
layer(l10 '8/0')
layer(l13 '9/0')
layer(l14 '10/0')
layer(l15 '11/0')
layer(l9)
layer(l3)
layer(l1)
layer(l11)
layer(l8)
layer(l6)
layer(l12)
# Mask layer connectivity
connect(l4 l4 l11)
connect(l5 l5 l10)
connect(l10 l5 l10 l13 l3 l1 l11 l8 l6 l12)
connect(l13 l10 l13 l14)
connect(l14 l13 l14 l15)
connect(l15 l14 l15)
connect(l9 l9)
connect(l3 l10 l3)
connect(l1 l10 l1)
connect(l11 l4 l10 l11)
connect(l8 l10 l8)
connect(l6 l10 l6)
connect(l12 l10 l12)
# Global nets and connectivity
global(l9 SUBSTRATE)
global(l12 SUBSTRATE)
# 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(l3 (125 -750) (450 1500))
)
terminal(G
rect(l5 (-125 -750) (250 1500))
)
terminal(D
rect(l1 (-550 -750) (425 1500))
)
terminal(B
rect(l4 (-125 -750) (250 1500))
)
)
device(D$PMOS$1 PMOS
terminal(S
rect(l3 (-575 -750) (450 1500))
)
terminal(G
rect(l5 (-125 -750) (250 1500))
)
terminal(D
rect(l1 (125 -750) (425 1500))
)
terminal(B
rect(l4 (-125 -750) (250 1500))
)
)
device(D$PMOS$2 PMOS
terminal(S
rect(l3 (-550 -750) (425 1500))
)
terminal(G
rect(l5 (-125 -750) (250 1500))
)
terminal(D
rect(l1 (125 -750) (425 1500))
)
terminal(B
rect(l4 (-125 -750) (250 1500))
)
)
device(D$NMOS NMOS
terminal(S
rect(l8 (125 -475) (450 950))
)
terminal(G
rect(l5 (-125 -475) (250 950))
)
terminal(D
rect(l6 (-550 -475) (425 950))
)
terminal(B
rect(l9 (-125 -475) (250 950))
)
)
device(D$NMOS$1 NMOS
terminal(S
rect(l8 (-575 -475) (450 950))
)
terminal(G
rect(l5 (-125 -475) (250 950))
)
terminal(D
rect(l6 (125 -475) (425 950))
)
terminal(B
rect(l9 (-125 -475) (250 950))
)
)
device(D$NMOS$2 NMOS
terminal(S
rect(l8 (-550 -475) (425 950))
)
terminal(G
rect(l5 (-125 -475) (250 950))
)
terminal(D
rect(l6 (125 -475) (425 950))
)
terminal(B
rect(l9 (-125 -475) (250 950))
)
)
# Circuit section
# Circuits are the hierarchical building blocks of the netlist.
circuit(ND2X1
# Circuit boundary
rect((-100 400) (2600 7600))
# Nets with their geometries
net(1 name(VDD)
rect(l10 (1110 5160) (180 180))
rect(l10 (-180 920) (180 180))
rect(l10 (-180 -730) (180 180))
rect(l13 (-240 -790) (300 1700))
rect(l13 (-1350 0) (2400 800))
rect(l13 (-1151 -401) (2 2))
rect(l3 (-276 -2151) (425 1500))
rect(l3 (-400 -1500) (425 1500))
)
net(2 name(OUT)
rect(l10 (1810 1770) (180 180))
rect(l10 (-180 370) (180 180))
rect(l10 (-1580 3760) (180 180))
rect(l10 (-180 -730) (180 180))
rect(l10 (-180 -730) (180 180))
rect(l10 (1220 920) (180 180))
rect(l10 (-180 -1280) (180 180))
rect(l10 (-180 370) (180 180))
polygon(l13 (-240 -4180) (0 1390) (490 0) (0 -300) (-190 0) (0 -1090))
rect(l13 (-110 1390) (300 1400))
polygon(l13 (-1890 0) (0 600) (300 0) (0 -300) (1590 0) (0 -300))
rect(l13 (-141 -501) (2 2))
rect(l13 (-1751 1099) (300 1400))
rect(l13 (1100 -1700) (300 300))
rect(l13 (-300 0) (300 1400))
rect(l1 (-1750 -1450) (425 1500))
rect(l1 (950 -1500) (425 1500))
rect(l6 (-425 -4890) (425 950))
)
net(3 name(VSS)
rect(l10 (410 1770) (180 180))
rect(l10 (-180 370) (180 180))
rect(l13 (-240 -1300) (300 1360))
rect(l13 (-650 -2160) (2400 800))
rect(l13 (-1151 -401) (2 2))
rect(l6 (-951 859) (425 950))
)
net(4
rect(l8 (975 1660) (425 950))
rect(l8 (-400 -950) (425 950))
)
net(5
rect(l4 (-100 4500) (2600 3500))
)
net(6 name(B)
rect(l5 (1425 2860) (250 1940))
rect(l5 (-345 -950) (300 300))
rect(l5 (-205 650) (250 2000))
rect(l5 (-250 -2000) (250 2000))
rect(l5 (-250 -5390) (250 1450))
rect(l10 (-285 1050) (180 180))
rect(l13 (-71 -91) (2 2))
rect(l13 (-171 -151) (300 300))
)
net(7 name(A)
rect(l5 (725 2860) (250 1940))
rect(l5 (-325 -1850) (300 300))
rect(l5 (-225 1550) (250 2000))
rect(l5 (-250 -2000) (250 2000))
rect(l5 (-250 -5390) (250 1450))
rect(l10 (-265 150) (180 180))
rect(l13 (-91 -91) (2 2))
rect(l13 (-151 -151) (300 300))
)
net(8 name(SUBSTRATE))
# Outgoing pins and their connections to nets
pin(1 name(VDD))
pin(2 name(OUT))
pin(3 name(VSS))
pin(5)
pin(6 name(B))
pin(7 name(A))
pin(8 name(SUBSTRATE))
# Devices and their connections
device(1 D$PMOS
location(850 5800)
param(L 0.25)
param(W 1.5)
param(AS 0.3375)
param(AD 0.6375)
param(PS 1.95)
param(PD 3.85)
terminal(S 1)
terminal(G 7)
terminal(D 2)
terminal(B 5)
)
device(2 D$PMOS$1
location(1550 5800)
param(L 0.25)
param(W 1.5)
param(AS 0.3375)
param(AD 0.6375)
param(PS 1.95)
param(PD 3.85)
terminal(S 1)
terminal(G 6)
terminal(D 2)
terminal(B 5)
)
device(3 D$NMOS
location(850 2135)
param(L 0.25)
param(W 0.95)
param(AS 0.21375)
param(AD 0.40375)
param(PS 1.4)
param(PD 2.75)
terminal(S 4)
terminal(G 7)
terminal(D 3)
terminal(B 8)
)
device(4 D$NMOS$1
location(1550 2135)
param(L 0.25)
param(W 0.95)
param(AS 0.21375)
param(AD 0.40375)
param(PS 1.4)
param(PD 2.75)
terminal(S 4)
terminal(G 6)
terminal(D 2)
terminal(B 8)
)
)
circuit(INVX1
# Circuit boundary
rect((-100 400) (2000 7600))
# Nets with their geometries
net(1 name(VDD)
rect(l10 (410 6260) (180 180))
rect(l10 (-180 -730) (180 180))
rect(l10 (-180 -730) (180 180))
rect(l13 (-240 -240) (300 1400))
rect(l13 (-650 300) (1800 800))
rect(l13 (-1450 -1100) (300 300))
rect(l13 (299 399) (2 2))
rect(l3 (-651 -2151) (425 1500))
)
net(2 name(OUT)
rect(l10 (1110 5160) (180 180))
rect(l10 (-180 920) (180 180))
rect(l10 (-180 -730) (180 180))
rect(l10 (-180 -4120) (180 180))
rect(l10 (-180 370) (180 180))
rect(l13 (-240 -790) (300 4790))
rect(l13 (-151 -2501) (2 2))
rect(l1 (-226 1049) (425 1500))
rect(l6 (-425 -4890) (425 950))
)
net(3 name(VSS)
rect(l10 (410 1770) (180 180))
rect(l10 (-180 370) (180 180))
rect(l13 (-240 -1300) (300 1360))
rect(l13 (-650 -2160) (1800 800))
rect(l13 (-851 -401) (2 2))
rect(l8 (-651 859) (425 950))
)
net(4
rect(l4 (-100 4500) (2000 3500))
)
net(5 name(IN)
rect(l5 (725 2860) (250 1940))
rect(l5 (-525 -1850) (300 300))
rect(l5 (-25 1550) (250 2000))
rect(l5 (-250 -2000) (250 2000))
rect(l5 (-250 -5390) (250 1450))
rect(l10 (-465 150) (180 180))
rect(l13 (-91 -91) (2 2))
rect(l13 (-151 -151) (300 300))
)
net(6 name(SUBSTRATE))
# Outgoing pins and their connections to nets
pin(1 name(VDD))
pin(2 name(OUT))
pin(3 name(VSS))
pin(4)
pin(5 name(IN))
pin(6 name(SUBSTRATE))
# Devices and their connections
device(1 D$PMOS$2
location(850 5800)
param(L 0.25)
param(W 1.5)
param(AS 0.6375)
param(AD 0.6375)
param(PS 3.85)
param(PD 3.85)
terminal(S 1)
terminal(G 5)
terminal(D 2)
terminal(B 4)
)
device(2 D$NMOS$2
location(850 2135)
param(L 0.25)
param(W 0.95)
param(AS 0.40375)
param(AD 0.40375)
param(PS 2.75)
param(PD 2.75)
terminal(S 3)
terminal(G 5)
terminal(D 2)
terminal(B 6)
)
)
circuit(RINGO
# Circuit boundary
rect((0 350) (25800 7650))
# Nets with their geometries
net(1
rect(l10 (4710 3010) (180 180))
rect(l13 (-850 -240) (610 300))
)
net(2
rect(l10 (6510 3010) (180 180))
rect(l13 (-1140 -240) (900 300))
)
net(3
rect(l10 (8310 3010) (180 180))
rect(l13 (-1140 -240) (900 300))
)
net(4
rect(l10 (10110 3010) (180 180))
rect(l13 (-1140 -240) (900 300))
)
net(5
rect(l10 (11910 3010) (180 180))
rect(l13 (-1140 -240) (900 300))
)
net(6
rect(l10 (13710 3010) (180 180))
rect(l13 (-1140 -240) (900 300))
)
net(7
rect(l10 (15510 3010) (180 180))
rect(l13 (-1140 -240) (900 300))
)
net(8
rect(l10 (17310 3010) (180 180))
rect(l13 (-1140 -240) (900 300))
)
net(9
rect(l10 (19110 3010) (180 180))
rect(l13 (-1140 -240) (900 300))
)
net(10
rect(l10 (20910 3010) (180 180))
rect(l13 (-1140 -240) (900 300))
)
net(11 name(FB)
rect(l10 (22710 3010) (180 180))
rect(l10 (-19700 720) (180 180))
rect(l13 (18380 -1140) (900 300))
rect(l13 (-19530 590) (320 320))
rect(l13 (17820 -320) (320 320))
rect(l14 (-18400 -260) (200 200))
rect(l14 (17940 -200) (200 200))
rect(l15 (-18040 -300) (17740 400))
rect(l15 (-17921 -201) (2 2))
rect(l15 (-221 -201) (400 400))
rect(l15 (17740 -400) (400 400))
)
net(12 name(VDD)
rect(l4 (500 4500) (1400 3500))
rect(l4 (-1900 -3500) (600 3500))
rect(l4 (23300 -3500) (1400 3500))
rect(l4 (-100 -3500) (600 3500))
rect(l10 (-24690 -1240) (180 180))
rect(l10 (-180 370) (180 180))
rect(l10 (-180 -1280) (180 180))
rect(l10 (23220 370) (180 180))
rect(l10 (-180 370) (180 180))
rect(l10 (-180 -1280) (180 180))
rect(l13 (-21741 859) (2 2))
rect(l13 (-2351 -451) (1200 800))
rect(l13 (-750 -1450) (300 1400))
rect(l13 (-101 -351) (2 2))
rect(l13 (-1251 -401) (600 800))
rect(l13 (23400 -800) (1200 800))
rect(l13 (-750 -1450) (300 1400))
rect(l13 (-101 -351) (2 2))
rect(l13 (549 -401) (600 800))
rect(l11 (-24850 -1500) (500 1500))
rect(l11 (22900 -1500) (500 1500))
)
net(13 name(OUT)
rect(l13 (23440 3840) (320 320))
rect(l14 (-260 -260) (200 200))
rect(l15 (-101 -101) (2 2))
rect(l15 (-201 -201) (400 400))
)
net(14 name(ENABLE)
rect(l10 (2510 3010) (180 180))
rect(l13 (-250 -250) (320 320))
rect(l14 (-260 -260) (200 200))
rect(l15 (-101 -101) (2 2))
rect(l15 (-201 -201) (400 400))
)
net(15 name(VSS)
rect(l10 (1110 1610) (180 180))
rect(l10 (-180 -1280) (180 180))
rect(l10 (-180 370) (180 180))
rect(l10 (23220 370) (180 180))
rect(l10 (-180 -1280) (180 180))
rect(l10 (-180 370) (180 180))
rect(l13 (-21741 -391) (2 2))
rect(l13 (-1901 -401) (300 1400))
rect(l13 (-750 -1450) (1200 800))
rect(l13 (-551 -401) (2 2))
rect(l13 (-1251 -401) (600 800))
rect(l13 (23850 -750) (300 1400))
rect(l13 (-750 -1450) (1200 800))
rect(l13 (-551 -401) (2 2))
rect(l13 (549 -401) (600 800))
rect(l12 (-24850 -800) (500 1500))
rect(l12 (22900 -1500) (500 1500))
)
# Outgoing pins and their connections to nets
pin(11 name(FB))
pin(12 name(VDD))
pin(13 name(OUT))
pin(14 name(ENABLE))
pin(15 name(VSS))
# Subcircuits and their connections
circuit(1 ND2X1 location(1800 0)
pin(0 12)
pin(1 1)
pin(2 15)
pin(3 12)
pin(4 11)
pin(5 14)
pin(6 15)
)
circuit(2 INVX1 location(4200 0)
pin(0 12)
pin(1 2)
pin(2 15)
pin(3 12)
pin(4 1)
pin(5 15)
)
circuit(3 INVX1 location(6000 0)
pin(0 12)
pin(1 3)
pin(2 15)
pin(3 12)
pin(4 2)
pin(5 15)
)
circuit(4 INVX1 location(7800 0)
pin(0 12)
pin(1 4)
pin(2 15)
pin(3 12)
pin(4 3)
pin(5 15)
)
circuit(5 INVX1 location(9600 0)
pin(0 12)
pin(1 5)
pin(2 15)
pin(3 12)
pin(4 4)
pin(5 15)
)
circuit(6 INVX1 location(11400 0)
pin(0 12)
pin(1 6)
pin(2 15)
pin(3 12)
pin(4 5)
pin(5 15)
)
circuit(7 INVX1 location(13200 0)
pin(0 12)
pin(1 7)
pin(2 15)
pin(3 12)
pin(4 6)
pin(5 15)
)
circuit(8 INVX1 location(15000 0)
pin(0 12)
pin(1 8)
pin(2 15)
pin(3 12)
pin(4 7)
pin(5 15)
)
circuit(9 INVX1 location(16800 0)
pin(0 12)
pin(1 9)
pin(2 15)
pin(3 12)
pin(4 8)
pin(5 15)
)
circuit(10 INVX1 location(18600 0)
pin(0 12)
pin(1 10)
pin(2 15)
pin(3 12)
pin(4 9)
pin(5 15)
)
circuit(11 INVX1 location(20400 0)
pin(0 12)
pin(1 11)
pin(2 15)
pin(3 12)
pin(4 10)
pin(5 15)
)
circuit(12 INVX1 location(22200 0)
pin(0 12)
pin(1 13)
pin(2 15)
pin(3 12)
pin(4 11)
pin(5 15)
)
)
)
# Reference netlist
reference(
# Device class section
class(PMOS MOS4)
class(NMOS MOS4)
# Circuit section
# Circuits are the hierarchical building blocks of the netlist.
circuit(ND2X1
# Nets
net(1 name(VDD))
net(2 name(OUT))
net(3 name(VSS))
net(4 name(NWELL))
net(5 name(B))
net(6 name(A))
net(7 name(BULK))
net(8 name('1'))
# Outgoing pins and their connections to nets
pin(1 name(VDD))
pin(2 name(OUT))
pin(3 name(VSS))
pin(4 name(NWELL))
pin(5 name(B))
pin(6 name(A))
pin(7 name(BULK))
# Devices and their connections
device(1 PMOS
name($1)
param(L 0.25)
param(W 1.5)
param(AS 0)
param(AD 0)
param(PS 0)
param(PD 0)
terminal(S 2)
terminal(G 6)
terminal(D 1)
terminal(B 4)
)
device(2 PMOS
name($2)
param(L 0.25)
param(W 1.5)
param(AS 0)
param(AD 0)
param(PS 0)
param(PD 0)
terminal(S 1)
terminal(G 5)
terminal(D 2)
terminal(B 4)
)
device(3 NMOS
name($3)
param(L 0.25)
param(W 0.95)
param(AS 0)
param(AD 0)
param(PS 0)
param(PD 0)
terminal(S 3)
terminal(G 6)
terminal(D 8)
terminal(B 7)
)
device(4 NMOS
name($4)
param(L 0.25)
param(W 0.95)
param(AS 0)
param(AD 0)
param(PS 0)
param(PD 0)
terminal(S 8)
terminal(G 5)
terminal(D 2)
terminal(B 7)
)
)
circuit(INVX1
# Nets
net(1 name(VDD))
net(2 name(OUT))
net(3 name(VSS))
net(4 name(NWELL))
net(5 name(IN))
net(6 name(BULK))
# Outgoing pins and their connections to nets
pin(1 name(VDD))
pin(2 name(OUT))
pin(3 name(VSS))
pin(4 name(NWELL))
pin(5 name(IN))
pin(6 name(BULK))
# Devices and their connections
device(1 PMOS
name($1)
param(L 0.25)
param(W 1.5)
param(AS 0)
param(AD 0)
param(PS 0)
param(PD 0)
terminal(S 1)
terminal(G 5)
terminal(D 2)
terminal(B 4)
)
device(2 NMOS
name($2)
param(L 0.25)
param(W 0.95)
param(AS 0)
param(AD 0)
param(PS 0)
param(PD 0)
terminal(S 3)
terminal(G 5)
terminal(D 2)
terminal(B 6)
)
)
circuit(RINGO
# Nets
net(1 name(VSS))
net(2 name(VDD))
net(3 name(FB))
net(4 name(ENABLE))
net(5 name(OUT))
net(6 name('1'))
net(7 name('2'))
net(8 name('3'))
net(9 name('4'))
net(10 name('5'))
net(11 name('6'))
net(12 name('7'))
net(13 name('8'))
net(14 name('9'))
net(15 name('10'))
# Outgoing pins and their connections to nets
pin(1 name(VSS))
pin(2 name(VDD))
pin(3 name(FB))
pin(4 name(ENABLE))
pin(5 name(OUT))
# Subcircuits and their connections
circuit(1 ND2X1 name($1)
pin(0 2)
pin(1 6)
pin(2 1)
pin(3 2)
pin(4 3)
pin(5 4)
pin(6 1)
)
circuit(2 INVX1 name($2)
pin(0 2)
pin(1 7)
pin(2 1)
pin(3 2)
pin(4 6)
pin(5 1)
)
circuit(3 INVX1 name($3)
pin(0 2)
pin(1 8)
pin(2 1)
pin(3 2)
pin(4 7)
pin(5 1)
)
circuit(4 INVX1 name($4)
pin(0 2)
pin(1 9)
pin(2 1)
pin(3 2)
pin(4 8)
pin(5 1)
)
circuit(5 INVX1 name($5)
pin(0 2)
pin(1 10)
pin(2 1)
pin(3 2)
pin(4 9)
pin(5 1)
)
circuit(6 INVX1 name($6)
pin(0 2)
pin(1 11)
pin(2 1)
pin(3 2)
pin(4 10)
pin(5 1)
)
circuit(7 INVX1 name($7)
pin(0 2)
pin(1 12)
pin(2 1)
pin(3 2)
pin(4 11)
pin(5 1)
)
circuit(8 INVX1 name($8)
pin(0 2)
pin(1 13)
pin(2 1)
pin(3 2)
pin(4 12)
pin(5 1)
)
circuit(9 INVX1 name($9)
pin(0 2)
pin(1 14)
pin(2 1)
pin(3 2)
pin(4 13)
pin(5 1)
)
circuit(10 INVX1 name($10)
pin(0 2)
pin(1 15)
pin(2 1)
pin(3 2)
pin(4 14)
pin(5 1)
)
circuit(11 INVX1 name($11)
pin(0 2)
pin(1 3)
pin(2 1)
pin(3 2)
pin(4 15)
pin(5 1)
)
circuit(12 INVX1 name($12)
pin(0 2)
pin(1 5)
pin(2 1)
pin(3 2)
pin(4 3)
pin(5 1)
)
)
)
# Cross reference
xref(
circuit(INVX1 INVX1 match
xref(
net(4 4 match)
net(5 5 match)
net(2 2 match)
net(6 6 match)
net(1 1 match)
net(3 3 match)
pin(3 3 match)
pin(4 4 match)
pin(1 1 match)
pin(5 5 match)
pin(0 0 match)
pin(2 2 match)
device(2 2 match)
device(1 1 match)
)
)
circuit(ND2X1 ND2X1 nomatch
xref(
net(4 8 mismatch)
net(5 4 mismatch)
net(7 6 match)
net(6 5 match)
net(2 2 mismatch)
net(8 7 mismatch)
net(1 1 mismatch)
net(3 3 mismatch)
pin(3 3 match)
pin(5 5 match)
pin(4 4 match)
pin(1 1 match)
pin(6 6 match)
pin(0 0 match)
pin(2 2 match)
device(4 4 match)
device(3 3 mismatch)
device(2 2 match)
device(1 1 mismatch)
)
)
circuit(RINGO RINGO match
xref(
net(1 6 match)
net(10 15 match)
net(2 7 match)
net(3 8 match)
net(4 9 match)
net(5 10 match)
net(6 11 match)
net(7 12 match)
net(8 13 match)
net(9 14 match)
net(14 4 match)
net(11 3 match)
net(13 5 match)
net(12 2 match)
net(15 1 match)
pin(3 3 match)
pin(0 2 match)
pin(2 4 match)
pin(1 1 match)
pin(4 0 match)
circuit(2 2 match)
circuit(3 3 match)
circuit(4 4 match)
circuit(5 5 match)
circuit(6 6 match)
circuit(7 7 match)
circuit(8 8 match)
circuit(9 9 match)
circuit(10 10 match)
circuit(11 11 match)
circuit(12 12 match)
circuit(1 1 match)
)
)
)

View File

@ -115,6 +115,10 @@ class DBNetlist_TestClass < TestBase
assert_equal(nl.device_class_by_name("UVW") == cc, true)
assert_equal(nl.device_class_by_name("doesntexist") == nil, true)
assert_equal(cc.strict?, false)
cc.strict = true
assert_equal(cc.strict?, true)
names = []
nl.each_device_class { |i| names << i.name }
assert_equal(names, [ c.name, cc.name ])