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
+3 -2
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;
+21
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;
+37 -6
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) {
+249 -85
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);
}
+9 -2
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 ();
+17 -1
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 "
+14 -8
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"
@@ -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);
}
@@ -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
+24
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>
@@ -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>
+5
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");
}