WIP: fixed bugs, added tests.

This commit is contained in:
Matthias Koefferlein 2019-02-28 22:23:20 +01:00
parent fccdee5186
commit 4035c804b7
8 changed files with 526 additions and 35 deletions

View File

@ -227,11 +227,10 @@ struct DeepShapeStore::LayoutHolder
// .. nothing yet ..
}
unsigned int make_empty_layer ()
unsigned int empty_layer () const
{
if (m_empty_layer == std::numeric_limits<unsigned int>::max ()) {
m_empty_layer = layout.insert_layer ();
layer_refs [m_empty_layer] += 1; // the empty layer is not deleted
const_cast<LayoutHolder *> (this)->make_empty_layer ();
}
return m_empty_layer;
}
@ -256,6 +255,12 @@ struct DeepShapeStore::LayoutHolder
private:
unsigned int m_empty_layer;
void make_empty_layer ()
{
m_empty_layer = layout.insert_layer ();
layer_refs [m_empty_layer] += 1; // the empty layer is not deleted
}
};
// ----------------------------------------------------------------------------------
@ -282,6 +287,9 @@ DeepShapeStore::~DeepShapeStore ()
{
--s_instance_count;
// because of unregistration we must not do this in the destructor:
m_layers_for_flat.clear ();
for (std::vector<LayoutHolder *>::iterator h = m_layouts.begin (); h != m_layouts.end (); ++h) {
delete *h;
}
@ -290,6 +298,12 @@ DeepShapeStore::~DeepShapeStore ()
DeepLayer DeepShapeStore::create_from_flat (const db::Region &region, double max_area_ratio, size_t max_vertex_count, const db::ICplxTrans &trans)
{
// reuse existing layer
std::pair<bool, DeepLayer> lff = layer_for_flat (region);
if (lff.first) {
return lff.second;
}
require_singular ();
unsigned int layer = layout ().insert_layer ();
@ -308,11 +322,32 @@ DeepLayer DeepShapeStore::create_from_flat (const db::Region &region, double max
db::PolygonReferenceHierarchyBuilderShapeReceiver refs (&layout (), m_text_enlargement, m_text_property_name);
db::ReducingHierarchyBuilderShapeReceiver red (&refs, max_area_ratio, max_vertex_count);
for (db::Region::const_iterator p = region.begin (); ! p.at_end (); ++p) {
red.push (*p, trans, world, 0, shapes);
// try to maintain the texts - go through shape iterator
std::pair<db::RecursiveShapeIterator, db::ICplxTrans> ii = region.begin_iter ();
db::ICplxTrans ttop = trans * ii.second;
while (! ii.first.at_end ()) {
red.push (*ii.first, ttop * ii.first.trans (), world, 0, shapes);
++ii.first;
}
return DeepLayer (this, 0 /*singular layout index*/, layer);
DeepLayer dl (this, 0 /*singular layout index*/, layer);
m_layers_for_flat [tl::id_of (region.delegate ())] = dl;
return dl;
}
std::pair<bool, DeepLayer> DeepShapeStore::layer_for_flat (const db::Region &region) const
{
return layer_for_flat (tl::id_of (region.delegate ()));
}
std::pair<bool, DeepLayer> DeepShapeStore::layer_for_flat (size_t region_id) const
{
std::map<size_t, DeepLayer>::const_iterator lff = m_layers_for_flat.find (region_id);
if (lff == m_layers_for_flat.end ()) {
return std::make_pair (false, DeepLayer ());
} else {
return std::make_pair (true, lff->second);
}
}
bool DeepShapeStore::is_singular () const
@ -475,12 +510,12 @@ DeepLayer DeepShapeStore::create_polygon_layer (const db::RecursiveShapeIterator
return DeepLayer (this, layout_index, layer_index);
}
DeepLayer DeepShapeStore::empty_layer (unsigned int layout_index)
DeepLayer DeepShapeStore::empty_layer (unsigned int layout_index) const
{
return DeepLayer (this, layout_index, m_layouts[layout_index]->make_empty_layer ());
return DeepLayer (const_cast<DeepShapeStore *> (this), layout_index, m_layouts[layout_index]->empty_layer ());
}
DeepLayer DeepShapeStore::empty_layer ()
DeepLayer DeepShapeStore::empty_layer () const
{
require_singular ();
return empty_layer (0);

View File

@ -264,9 +264,25 @@ public:
*
* This method is intended for use with singular-created DSS objects (see
* singular constructor).
*
* After a flat layer has been created for a region, it can be retrieved
* from the region later with layer_for_flat (region).
*/
DeepLayer create_from_flat (const db::Region &region, double max_area_ratio = 0.0, size_t max_vertex_count = 0, const db::ICplxTrans &trans = db::ICplxTrans ());
/**
* @brief Gets the layer for a given flat region.
*
* If a layer has been created for a flat region with create_from_flat, it can be retrieved with this method.
* The first return value is true in this case.
*/
std::pair<bool, DeepLayer> layer_for_flat (const db::Region &region) const;
/**
* @brief Same as layer_for_flat, but takes a region Id
*/
std::pair<bool, DeepLayer> layer_for_flat (size_t region_id) const;
/**
* @brief Inserts a polygon layer into the deep shape store
*
@ -316,12 +332,12 @@ public:
* This method will deliver an empty layer for the given layout index. CAUTION: don't modify this layer as it may
* be reused.
*/
DeepLayer empty_layer (unsigned int layout_index);
DeepLayer empty_layer (unsigned int layout_index) const;
/**
* @brief Gets the empty working layer for the singular layout
*/
DeepLayer empty_layer ();
DeepLayer empty_layer () const;
/**
* @brief Inserts the deep layer's shapes into some target layout
@ -577,6 +593,7 @@ private:
DeepShapeStore &operator= (const DeepShapeStore &);
std::vector<LayoutHolder *> m_layouts;
std::map<size_t, DeepLayer> m_layers_for_flat;
layout_map_type m_layout_map;
int m_threads;
double m_max_area_ratio;

View File

@ -56,6 +56,12 @@ LayoutToNetlist::LayoutToNetlist (db::DeepShapeStore *dss, unsigned int layout_i
init ();
}
LayoutToNetlist::LayoutToNetlist (db::DeepShapeStore *dss)
: mp_dss (dss), m_netlist_extracted (false), m_is_flat (false)
{
init ();
}
LayoutToNetlist::LayoutToNetlist (const std::string &topcell_name, double dbu)
: m_iter (), m_netlist_extracted (false), m_is_flat (true)
{
@ -66,11 +72,21 @@ LayoutToNetlist::LayoutToNetlist (const std::string &topcell_name, double dbu)
}
LayoutToNetlist::LayoutToNetlist ()
: m_iter (), mp_internal_dss (new db::DeepShapeStore ()), mp_dss (mp_internal_dss.get ()), m_netlist_extracted (false), m_is_flat (true)
: m_iter (), mp_internal_dss (new db::DeepShapeStore ()), mp_dss (mp_internal_dss.get ()), m_netlist_extracted (false), m_is_flat (false)
{
init ();
}
LayoutToNetlist::~LayoutToNetlist ()
{
// NOTE: do this in this order because of unregistration of the layers
m_named_regions.clear ();
m_dlrefs.clear ();
mp_internal_dss.reset (0);
mp_netlist.reset (0);
m_net_clusters.clear ();
}
void LayoutToNetlist::init ()
{
if (! mp_dss.get ()) {
@ -179,15 +195,13 @@ void LayoutToNetlist::connect (const db::Region &l)
if (m_netlist_extracted) {
throw tl::Exception (tl::to_string (tr ("The netlist has already been extracted")));
}
if (! is_deep (l)) {
throw (tl::Exception (tl::to_string (tr ("Non-hierarchical layers cannot be used in intra-layer connectivity for netlist extraction"))));
}
if (! is_persisted (l)) {
throw (tl::Exception (tl::to_string (tr ("Only named layers can be used in intra-layer connectivity for netlist extraction"))));
}
// we need to keep a reference, so we can safely delete the region
db::DeepLayer dl (l);
db::DeepLayer dl = deep_layer_of (l);
m_dlrefs.insert (dl);
m_conn.connect (dl.layer ());
@ -198,12 +212,6 @@ void LayoutToNetlist::connect (const db::Region &a, const db::Region &b)
if (m_netlist_extracted) {
throw tl::Exception (tl::to_string (tr ("The netlist has already been extracted")));
}
if (! is_deep (a)) {
throw (tl::Exception (tl::to_string (tr ("Non-hierarchical layers cannot be used in inter-layer connectivity (first layer) for netlist extraction"))));
}
if (! is_deep (b)) {
throw (tl::Exception (tl::to_string (tr ("Non-hierarchical layers cannot be used in inter-layer connectivity (second layer) for netlist extraction"))));
}
if (! is_persisted (a)) {
throw (tl::Exception (tl::to_string (tr ("Only named layers can be used in inter-layer connectivity (first layer) for netlist extraction"))));
}
@ -212,7 +220,8 @@ void LayoutToNetlist::connect (const db::Region &a, const db::Region &b)
}
// we need to keep a reference, so we can safely delete the region
db::DeepLayer dla (a), dlb (b);
db::DeepLayer dla = deep_layer_of (a);
db::DeepLayer dlb = deep_layer_of (b);
m_dlrefs.insert (dla);
m_dlrefs.insert (dlb);
@ -224,15 +233,12 @@ size_t LayoutToNetlist::connect_global (const db::Region &l, const std::string &
if (m_netlist_extracted) {
throw tl::Exception (tl::to_string (tr ("The netlist has already been extracted")));
}
if (! is_deep (l)) {
throw (tl::Exception (tl::to_string (tr ("Non-hierarchical layers cannot be used in global connectivity for netlist extraction"))));
}
if (! is_persisted (l)) {
throw (tl::Exception (tl::to_string (tr ("Only named layers can be used in global connectivity for netlist extraction"))));
}
// we need to keep a reference, so we can safely delete the region
db::DeepLayer dl (l);
db::DeepLayer dl = deep_layer_of (l);
m_dlrefs.insert (dl);
return m_conn.connect_global (dl.layer (), gn);
@ -316,7 +322,7 @@ void LayoutToNetlist::register_layer (const db::Region &region, const std::strin
if (region.empty ()) {
dl = dss ().empty_layer ();
} else {
throw tl::Exception (tl::to_string (tr ("Layer is not a deep region")));
throw tl::Exception (tl::to_string (tr ("Layer is not a deep region and cannot be registered with name: ")) + n);
}
} else {
@ -381,13 +387,29 @@ db::Region *LayoutToNetlist::layer_by_index (unsigned int index)
}
}
unsigned int LayoutToNetlist::layer_of (const db::Region &region) const
db::DeepLayer LayoutToNetlist::deep_layer_of (const db::Region &region) const
{
const db::DeepRegion *dr = dynamic_cast<const db::DeepRegion *> (region.delegate ());
if (! dr) {
throw (tl::Exception (tl::to_string (tr ("Non-hierarchical layers cannot be used in netlist extraction"))));
std::pair<bool, db::DeepLayer> lff = dss ().layer_for_flat (region);
if (lff.first) {
return lff.second;
} else if (region.empty ()) {
// provide a substitute empty layer for empty
return dss ().empty_layer ();
} else {
throw (tl::Exception (tl::to_string (tr ("Non-hierarchical layers cannot be used in netlist extraction"))));
}
} else {
return dr->deep_layer ();
}
return dr->deep_layer ().layer ();
}
unsigned int LayoutToNetlist::layer_of (const db::Region &region) const
{
return deep_layer_of (region).layer ();
}
db::CellMapping LayoutToNetlist::cell_mapping_into (db::Layout &layout, db::Cell &cell, bool with_device_cells)

View File

@ -95,6 +95,19 @@ public:
*/
LayoutToNetlist (db::DeepShapeStore *dss, unsigned int layout_index);
/**
* @brief Alternative constructor using an external deep shape storage
*
* This constructor allows using an external DSS. It's intended to be used
* with existing DSS instances. Existing layers can be registered with
* "register_layer". The LayoutToNetlist object will hold a weak reference
* to the DSS but not own the DSS.
*
* NOTE: this version cannot create layers but just register layers
* which are present inside the DSS given as the argument.
*/
LayoutToNetlist (db::DeepShapeStore *dss);
/**
* @brief Alternative constructor for flat mode
*
@ -109,6 +122,11 @@ public:
*/
LayoutToNetlist ();
/**
* @brief The destructor
*/
~LayoutToNetlist ();
/**
* @brief Sets the number of threads to use for operations which support multiple threads
*/
@ -517,6 +535,7 @@ private:
size_t search_net (const db::ICplxTrans &trans, const db::Cell *cell, const db::local_cluster<db::PolygonRef> &test_cluster, std::vector<db::InstElement> &rev_inst_path);
void build_net_rec (const db::Net &net, db::Layout &target, db::Cell &target_cell, const std::map<unsigned int, const db::Region *> &lmap, const char *net_cell_name_prefix, const char *cell_name_prefix, const char *device_cell_name_prefix, std::map<std::pair<db::cell_index_type, size_t>, db::cell_index_type> &cmap, const ICplxTrans &tr) const;
void build_net_rec (db::cell_index_type ci, size_t cid, db::Layout &target, db::Cell &target_cell, const std::map<unsigned int, const db::Region *> &lmap, const Net *net, const char *net_cell_name_prefix, const char *cell_name_prefix, const char *device_cell_name_prefix, std::map<std::pair<db::cell_index_type, size_t>, db::cell_index_type> &cmap, const ICplxTrans &tr) const;
db::DeepLayer deep_layer_of (const db::Region &region) const;
};
}

View File

@ -141,7 +141,11 @@ void NetlistDeviceExtractor::extract (db::DeepShapeStore &dss, const NetlistDevi
db::DeepRegion *dr = dynamic_cast<db::DeepRegion *> (l->second->delegate ());
if (dr == 0) {
if (l->second->empty ()) {
std::pair<bool, db::DeepLayer> alias = dss.layer_for_flat (tl::id_of (l->second->delegate ()));
if (alias.first) {
// use deep layer alias for a given flat one (if found)
layers.push_back (alias.second.layer ());
} else if (l->second->empty ()) {
// provide a substitute empty layer
layers.push_back (dss.empty_layer ().layer ());
} else {

View File

@ -39,11 +39,16 @@ static db::LayoutToNetlist *make_l2n_default ()
return new db::LayoutToNetlist ();
}
static db::LayoutToNetlist *make_l2n_from_existing_dss (db::DeepShapeStore *dss, unsigned int layout_index)
static db::LayoutToNetlist *make_l2n_from_existing_dss_with_layout (db::DeepShapeStore *dss, unsigned int layout_index)
{
return new db::LayoutToNetlist (dss, layout_index);
}
static db::LayoutToNetlist *make_l2n_from_existing_dss (db::DeepShapeStore *dss)
{
return new db::LayoutToNetlist (dss);
}
static db::LayoutToNetlist *make_l2n_flat (const std::string &topcell_name, double dbu)
{
return new db::LayoutToNetlist (topcell_name, dbu);
@ -109,9 +114,18 @@ Class<db::LayoutToNetlist> decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
"@brief Creates a new and empty extractor object\n"
"The main objective for this constructor is to create an object suitable for reading an annotated netlist.\n"
) +
gsi::constructor ("new", &make_l2n_from_existing_dss, gsi::arg ("dss"), gsi::arg ("layout_index", 0),
gsi::constructor ("new", &make_l2n_from_existing_dss, gsi::arg ("dss"),
"@brief Creates a new extractor object reusing an existing \\DeepShapeStore object\n"
"This constrcutor can be used if there is a DSS object already from which the "
"This constructor can be used if there is a DSS object already from which the "
"shapes can be taken. This version can only be used with \\register to "
"add layers (regions) inside the 'dss' object.\n"
"\n"
"The make_... methods will not create new layers as there is no particular place "
"defined where to create the layers."
) +
gsi::constructor ("new", &make_l2n_from_existing_dss_with_layout, gsi::arg ("dss"), gsi::arg ("layout_index"),
"@brief Creates a new extractor object reusing an existing \\DeepShapeStore object\n"
"This constructor can be used if there is a DSS object already from which the "
"shapes can be taken. NOTE: in this case, the make_... functions will create "
"new layers inside this DSS. To register existing layers (regions) use \\register.\n"
) +

View File

@ -22,6 +22,8 @@
#include "dbDeepShapeStore.h"
#include "dbRegion.h"
#include "dbDeepRegion.h"
#include "tlUnitTest.h"
#include "tlStream.h"
@ -184,3 +186,25 @@ TEST(3_TextTreatment)
EXPECT_EQ (dss_layout->properties_repository ().prop_name (ps.begin ()->first).to_string (), "text");
EXPECT_EQ (ps.begin ()->second.to_string (), "TEXT");
}
TEST(4_FlatAndEmptyInput)
{
db::DeepShapeStore dss ("TOP", 0.01);
EXPECT_EQ (dss.layout ().dbu (), 0.01);
db::Region r1;
r1.insert (db::Box (0, 0, 1000, 1000));
db::Region r2;
r2.insert (db::Box (100, 100, 900, 900));
db::Region r3;
db::Region dr1 (new db::DeepRegion (dss.create_from_flat (r1)));
db::Region dr2 (new db::DeepRegion (dss.create_from_flat (r2)));
db::Region dr3 (new db::DeepRegion (dss.create_from_flat (r3)));
EXPECT_EQ ((dr1 - dr2).to_string (), "(0,0;0,900;100,900;100,100;900,100;900,900;0,900;0,1000;1000,1000;1000,0)");
EXPECT_EQ ((dr1 - dr3).to_string (), "(0,0;0,1000;1000,1000;1000,0)");
}

View File

@ -1897,3 +1897,359 @@ TEST(7_MoreByEmptyDeviceTypes)
" DLVNMOS $6 (S=VSS,G=A,D=$5,B=BULK) [L=1.5,W=5.25,AS=3.54375,AD=7.0875,PS=6.6,PD=13.2]\n"
);
}
TEST(8_FlatExtraction)
{
db::Layout ly;
db::LayerMap lmap;
unsigned int nwell = define_layer (ly, lmap, 1);
unsigned int active = define_layer (ly, lmap, 2);
unsigned int thickgox = define_layer (ly, lmap, 3);
unsigned int pplus = define_layer (ly, lmap, 4);
unsigned int nplus = define_layer (ly, lmap, 5);
unsigned int poly = define_layer (ly, lmap, 6);
unsigned int poly_lbl = define_layer (ly, lmap, 7);
unsigned int cont = define_layer (ly, lmap, 8);
unsigned int metal1 = define_layer (ly, lmap, 9);
unsigned int metal1_lbl = define_layer (ly, lmap, 10);
unsigned int via1 = define_layer (ly, lmap, 11);
unsigned int metal2 = define_layer (ly, lmap, 12);
unsigned int metal2_lbl = define_layer (ly, lmap, 13);
{
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_l6.gds");
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (ly, options);
}
db::Cell &tc = ly.cell (*ly.begin_top_down ());
db::LayoutToNetlist l2n (ly.cell_name (tc.cell_index ()), ly.dbu ());
std::auto_ptr<db::Region> rbulk (new db::Region ());
std::auto_ptr<db::Region> rnwell (new db::Region (db::RecursiveShapeIterator (ly, tc, nwell)));
std::auto_ptr<db::Region> rthickgox (new db::Region (db::RecursiveShapeIterator (ly, tc, thickgox)));
std::auto_ptr<db::Region> ractive (new db::Region (db::RecursiveShapeIterator (ly, tc, active)));
std::auto_ptr<db::Region> rpplus (new db::Region (db::RecursiveShapeIterator (ly, tc, pplus)));
std::auto_ptr<db::Region> rnplus (new db::Region (db::RecursiveShapeIterator (ly, tc, nplus)));
std::auto_ptr<db::Region> rpoly (new db::Region (db::RecursiveShapeIterator (ly, tc, poly)));
std::auto_ptr<db::Region> rpoly_lbl (new db::Region (db::RecursiveShapeIterator (ly, tc, poly_lbl)));
std::auto_ptr<db::Region> rcont (new db::Region (db::RecursiveShapeIterator (ly, tc, cont)));
std::auto_ptr<db::Region> rmetal1 (new db::Region (db::RecursiveShapeIterator (ly, tc, metal1)));
std::auto_ptr<db::Region> rmetal1_lbl (new db::Region (db::RecursiveShapeIterator (ly, tc, metal1_lbl)));
std::auto_ptr<db::Region> rvia1 (new db::Region (db::RecursiveShapeIterator (ly, tc, via1)));
std::auto_ptr<db::Region> rmetal2 (new db::Region (db::RecursiveShapeIterator (ly, tc, metal2)));
std::auto_ptr<db::Region> rmetal2_lbl (new db::Region (db::RecursiveShapeIterator (ly, tc, metal2_lbl)));
l2n.register_layer (*rbulk, "bulk");
l2n.register_layer (*rnwell, "nwell");
l2n.register_layer (*rthickgox, "thickgox");
l2n.register_layer (*ractive, "active");
l2n.register_layer (*rpplus, "pplus");
l2n.register_layer (*rnplus, "nplus");
l2n.register_layer (*rpoly, "poly");
l2n.register_layer (*rpoly_lbl, "poly_lbl");
l2n.register_layer (*rcont, "cont");
l2n.register_layer (*rmetal1, "metal1");
l2n.register_layer (*rmetal1_lbl, "metal1_lbl");
l2n.register_layer (*rvia1, "via1");
l2n.register_layer (*rmetal2, "metal2");
l2n.register_layer (*rmetal2_lbl, "metal2_lbl");
// derived regions
db::Region ractive_in_nwell = *ractive & *rnwell;
db::Region rpactive = ractive_in_nwell - *rnplus;
db::Region rntie = ractive_in_nwell & *rnplus;
db::Region rpgate = rpactive & *rpoly;
db::Region rpsd = rpactive - rpgate;
db::Region rhv_pgate = rpgate & *rthickgox;
db::Region rlv_pgate = rpgate - rhv_pgate;
db::Region rhv_psd = rpsd & *rthickgox;
db::Region rlv_psd = rpsd - *rthickgox;
l2n.register_layer (rntie, "ntie");
l2n.register_layer (rpsd, "psd");
// required to provide deep layers for flat ones for the extractor:
l2n.register_layer (rhv_pgate, "hv_pgate");
l2n.register_layer (rlv_pgate, "lv_pgate");
db::Region ractive_outside_nwell = *ractive - *rnwell;
db::Region rnactive = ractive_outside_nwell - *rpplus;
db::Region rptie = ractive_outside_nwell & *rpplus;
db::Region rngate = rnactive & *rpoly;
db::Region rnsd = rnactive - rngate;
db::Region rhv_ngate = rngate & *rthickgox;
db::Region rlv_ngate = rngate - rhv_ngate;
db::Region rhv_nsd = rnsd & *rthickgox;
db::Region rlv_nsd = rnsd - *rthickgox;
l2n.register_layer (rptie, "ptie");
l2n.register_layer (rnsd, "nsd");
// required to provide deep layers for flat ones for the extractor:
l2n.register_layer (rhv_ngate, "hv_ngate");
l2n.register_layer (rlv_ngate, "lv_ngate");
db::NetlistDeviceExtractorMOS4Transistor hvpmos_ex ("HVPMOS");
db::NetlistDeviceExtractorMOS4Transistor hvnmos_ex ("HVNMOS");
db::NetlistDeviceExtractorMOS4Transistor lvpmos_ex ("LVPMOS");
db::NetlistDeviceExtractorMOS4Transistor lvnmos_ex ("LVNMOS");
// device extraction
db::NetlistDeviceExtractor::input_layers dl;
dl["SD"] = &rpsd;
dl["G"] = &rhv_pgate;
dl["P"] = rpoly.get (); // not needed for extraction but to return terminal shapes
dl["W"] = rnwell.get ();
l2n.extract_devices (hvpmos_ex, dl);
dl["SD"] = &rpsd;
dl["G"] = &rlv_pgate;
dl["P"] = rpoly.get (); // not needed for extraction but to return terminal shapes
dl["W"] = rnwell.get ();
l2n.extract_devices (lvpmos_ex, dl);
dl["SD"] = &rnsd;
dl["G"] = &rhv_ngate;
dl["P"] = rpoly.get (); // not needed for extraction but to return terminal shapes
dl["W"] = rbulk.get ();
l2n.extract_devices (hvnmos_ex, dl);
dl["SD"] = &rnsd;
dl["G"] = &rlv_ngate;
dl["P"] = rpoly.get (); // not needed for extraction but to return terminal shapes
dl["W"] = rbulk.get ();
l2n.extract_devices (lvnmos_ex, dl);
// Intra-layer
l2n.connect (rpsd);
l2n.connect (rnsd);
l2n.connect (*rnwell);
l2n.connect (*rpoly);
l2n.connect (*rcont);
l2n.connect (*rmetal1);
l2n.connect (*rvia1);
l2n.connect (*rmetal2);
l2n.connect (rptie);
l2n.connect (rntie);
// Inter-layer
l2n.connect (*rcont, rntie);
l2n.connect (*rcont, rptie);
l2n.connect (*rnwell, rntie);
l2n.connect (rpsd, *rcont);
l2n.connect (rnsd, *rcont);
l2n.connect (*rpoly, *rcont);
l2n.connect (*rcont, *rmetal1);
l2n.connect (*rmetal1, *rvia1);
l2n.connect (*rvia1, *rmetal2);
l2n.connect (*rpoly, *rpoly_lbl); // attaches labels
l2n.connect (*rmetal1, *rmetal1_lbl); // attaches labels
l2n.connect (*rmetal2, *rmetal2_lbl); // attaches labels
// Global
l2n.connect_global (rptie, "BULK");
l2n.connect_global (*rbulk, "BULK");
l2n.extract_netlist ();
// compare netlist as string
EXPECT_EQ (l2n.netlist ()->to_string (),
"Circuit TOP ():\n"
" DHVPMOS $1 (S=Z,G=$5,D=VDD2,B=$8) [L=1.5,W=4.05,AS=5.4675,AD=2.73375,PS=10.8,PD=5.4]\n"
" DHVPMOS $2 (S=VDD2,G=Z,D=$5,B=$8) [L=1.5,W=4.05,AS=2.73375,AD=5.4675,PS=5.4,PD=10.8]\n"
" DLVPMOS $3 (S=$10,G=A,D=$6,B=$9) [L=1.5,W=2.475,AS=1.11375,AD=3.155625,PS=5.85,PD=7.5]\n"
" DHVNMOS $4 (S=Z,G=$6,D=VSS,B=BULK) [L=1.5,W=5.25,AS=7.0875,AD=3.54375,PS=13.2,PD=6.6]\n"
" DHVNMOS $5 (S=VSS,G=A,D=$5,B=BULK) [L=1.5,W=5.25,AS=3.54375,AD=7.0875,PS=6.6,PD=13.2]\n"
" DLVNMOS $6 (S=VSS,G=A,D=$6,B=BULK) [L=1.2,W=1.7,AS=2.346,AD=2.1165,PS=6.16,PD=5.89]\n"
);
}
TEST(9_FlatExtractionWithExternalDSS)
{
db::Layout ly;
db::LayerMap lmap;
unsigned int nwell = define_layer (ly, lmap, 1);
unsigned int active = define_layer (ly, lmap, 2);
unsigned int thickgox = define_layer (ly, lmap, 103); // does not exist
unsigned int pplus = define_layer (ly, lmap, 4);
unsigned int nplus = define_layer (ly, lmap, 5);
unsigned int poly = define_layer (ly, lmap, 6);
unsigned int poly_lbl = define_layer (ly, lmap, 7);
unsigned int cont = define_layer (ly, lmap, 8);
unsigned int metal1 = define_layer (ly, lmap, 9);
unsigned int metal1_lbl = define_layer (ly, lmap, 10);
unsigned int via1 = define_layer (ly, lmap, 11);
unsigned int metal2 = define_layer (ly, lmap, 12);
unsigned int metal2_lbl = define_layer (ly, lmap, 13);
{
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_l6.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;
db::LayoutToNetlist l2n (&dss);
std::auto_ptr<db::Region> rbulk (new db::Region ());
std::auto_ptr<db::Region> rnwell (new db::Region (db::RecursiveShapeIterator (ly, tc, nwell), dss));
std::auto_ptr<db::Region> rthickgox (new db::Region (db::RecursiveShapeIterator (ly, tc, thickgox), dss));
std::auto_ptr<db::Region> ractive (new db::Region (db::RecursiveShapeIterator (ly, tc, active), dss));
std::auto_ptr<db::Region> rpplus (new db::Region (db::RecursiveShapeIterator (ly, tc, pplus), dss));
std::auto_ptr<db::Region> rnplus (new db::Region (db::RecursiveShapeIterator (ly, tc, nplus), dss));
std::auto_ptr<db::Region> rpoly (new db::Region (db::RecursiveShapeIterator (ly, tc, poly), dss));
std::auto_ptr<db::Region> rpoly_lbl (new db::Region (db::RecursiveShapeIterator (ly, tc, poly_lbl), dss));
std::auto_ptr<db::Region> rcont (new db::Region (db::RecursiveShapeIterator (ly, tc, cont), dss));
std::auto_ptr<db::Region> rmetal1 (new db::Region (db::RecursiveShapeIterator (ly, tc, metal1), dss));
std::auto_ptr<db::Region> rmetal1_lbl (new db::Region (db::RecursiveShapeIterator (ly, tc, metal1_lbl), dss));
std::auto_ptr<db::Region> rvia1 (new db::Region (db::RecursiveShapeIterator (ly, tc, via1), dss));
std::auto_ptr<db::Region> rmetal2 (new db::Region (db::RecursiveShapeIterator (ly, tc, metal2), dss));
std::auto_ptr<db::Region> rmetal2_lbl (new db::Region (db::RecursiveShapeIterator (ly, tc, metal2_lbl), dss));
l2n.register_layer (*rbulk, "bulk");
l2n.register_layer (*rnwell, "nwell");
l2n.register_layer (*rthickgox, "thickgox");
l2n.register_layer (*ractive, "active");
l2n.register_layer (*rpplus, "pplus");
l2n.register_layer (*rnplus, "nplus");
l2n.register_layer (*rpoly, "poly");
l2n.register_layer (*rpoly_lbl, "poly_lbl");
l2n.register_layer (*rcont, "cont");
l2n.register_layer (*rmetal1, "metal1");
l2n.register_layer (*rmetal1_lbl, "metal1_lbl");
l2n.register_layer (*rvia1, "via1");
l2n.register_layer (*rmetal2, "metal2");
l2n.register_layer (*rmetal2_lbl, "metal2_lbl");
// derived regions
db::Region ractive_in_nwell = *ractive & *rnwell;
db::Region rpactive = ractive_in_nwell - *rnplus;
db::Region rntie = ractive_in_nwell & *rnplus;
db::Region rpgate = rpactive & *rpoly;
db::Region rpsd = rpactive - rpgate;
db::Region rhv_pgate = rpgate & *rthickgox;
db::Region rlv_pgate = rpgate - rhv_pgate;
db::Region rhv_psd = rpsd & *rthickgox;
db::Region rlv_psd = rpsd - *rthickgox;
l2n.register_layer (rntie, "ntie");
l2n.register_layer (rpsd, "psd");
// required to provide deep layers for flat ones for the extractor:
l2n.register_layer (rhv_pgate, "hv_pgate");
l2n.register_layer (rlv_pgate, "lv_pgate");
db::Region ractive_outside_nwell = *ractive - *rnwell;
db::Region rnactive = ractive_outside_nwell - *rpplus;
db::Region rptie = ractive_outside_nwell & *rpplus;
db::Region rngate = rnactive & *rpoly;
db::Region rnsd = rnactive - rngate;
db::Region rhv_ngate = rngate & *rthickgox;
db::Region rlv_ngate = rngate - rhv_ngate;
db::Region rhv_nsd = rnsd & *rthickgox;
db::Region rlv_nsd = rnsd - *rthickgox;
l2n.register_layer (rptie, "ptie");
l2n.register_layer (rnsd, "nsd");
// required to provide deep layers for flat ones for the extractor:
l2n.register_layer (rhv_ngate, "hv_ngate");
l2n.register_layer (rlv_ngate, "lv_ngate");
db::NetlistDeviceExtractorMOS4Transistor hvpmos_ex ("HVPMOS");
db::NetlistDeviceExtractorMOS4Transistor hvnmos_ex ("HVNMOS");
db::NetlistDeviceExtractorMOS4Transistor lvpmos_ex ("LVPMOS");
db::NetlistDeviceExtractorMOS4Transistor lvnmos_ex ("LVNMOS");
// device extraction
db::NetlistDeviceExtractor::input_layers dl;
dl["SD"] = &rpsd;
dl["G"] = &rhv_pgate;
dl["P"] = rpoly.get (); // not needed for extraction but to return terminal shapes
dl["W"] = rnwell.get ();
l2n.extract_devices (hvpmos_ex, dl);
dl["SD"] = &rpsd;
dl["G"] = &rlv_pgate;
dl["P"] = rpoly.get (); // not needed for extraction but to return terminal shapes
dl["W"] = rnwell.get ();
l2n.extract_devices (lvpmos_ex, dl);
dl["SD"] = &rnsd;
dl["G"] = &rhv_ngate;
dl["P"] = rpoly.get (); // not needed for extraction but to return terminal shapes
dl["W"] = rbulk.get ();
l2n.extract_devices (hvnmos_ex, dl);
dl["SD"] = &rnsd;
dl["G"] = &rlv_ngate;
dl["P"] = rpoly.get (); // not needed for extraction but to return terminal shapes
dl["W"] = rbulk.get ();
l2n.extract_devices (lvnmos_ex, dl);
// Intra-layer
l2n.connect (rpsd);
l2n.connect (rnsd);
l2n.connect (*rnwell);
l2n.connect (*rpoly);
l2n.connect (*rcont);
l2n.connect (*rmetal1);
l2n.connect (*rvia1);
l2n.connect (*rmetal2);
l2n.connect (rptie);
l2n.connect (rntie);
// Inter-layer
l2n.connect (*rcont, rntie);
l2n.connect (*rcont, rptie);
l2n.connect (*rnwell, rntie);
l2n.connect (rpsd, *rcont);
l2n.connect (rnsd, *rcont);
l2n.connect (*rpoly, *rcont);
l2n.connect (*rcont, *rmetal1);
l2n.connect (*rmetal1, *rvia1);
l2n.connect (*rvia1, *rmetal2);
l2n.connect (*rpoly, *rpoly_lbl); // attaches labels
l2n.connect (*rmetal1, *rmetal1_lbl); // attaches labels
l2n.connect (*rmetal2, *rmetal2_lbl); // attaches labels
// Global
l2n.connect_global (rptie, "BULK");
l2n.connect_global (*rbulk, "BULK");
l2n.extract_netlist ();
// compare netlist as string
EXPECT_EQ (l2n.netlist ()->to_string (),
"Circuit TOP ():\n"
" DLVPMOS $1 (S=Z,G=$5,D=VDD2,B=$8) [L=1.5,W=4.05,AS=5.4675,AD=2.73375,PS=10.8,PD=5.4]\n"
" DLVPMOS $2 (S=VDD2,G=Z,D=$5,B=$8) [L=1.5,W=4.05,AS=2.73375,AD=5.4675,PS=5.4,PD=10.8]\n"
" DLVPMOS $3 (S=$10,G=A,D=$6,B=$9) [L=1.5,W=2.475,AS=1.11375,AD=3.155625,PS=5.85,PD=7.5]\n"
" DLVNMOS $4 (S=VSS,G=A,D=$6,B=BULK) [L=1.2,W=1.7,AS=2.346,AD=2.1165,PS=6.16,PD=5.89]\n"
" DLVNMOS $5 (S=Z,G=$6,D=VSS,B=BULK) [L=1.5,W=5.25,AS=7.0875,AD=3.54375,PS=13.2,PD=6.6]\n"
" DLVNMOS $6 (S=VSS,G=A,D=$5,B=BULK) [L=1.5,W=5.25,AS=3.54375,AD=7.0875,PS=6.6,PD=13.2]\n"
);
}