mirror of https://github.com/KLayout/klayout.git
WIP: fixed bugs, added tests.
This commit is contained in:
parent
fccdee5186
commit
4035c804b7
|
|
@ -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 ®ion, 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 ®ion, 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 ®ion) 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);
|
||||
|
|
|
|||
|
|
@ -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 ®ion, 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 ®ion) 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;
|
||||
|
|
|
|||
|
|
@ -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 ®ion, 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 ®ion) const
|
||||
db::DeepLayer LayoutToNetlist::deep_layer_of (const db::Region ®ion) 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 ®ion) const
|
||||
{
|
||||
return deep_layer_of (region).layer ();
|
||||
}
|
||||
|
||||
db::CellMapping LayoutToNetlist::cell_mapping_into (db::Layout &layout, db::Cell &cell, bool with_device_cells)
|
||||
|
|
|
|||
|
|
@ -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 ®ion) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
) +
|
||||
|
|
|
|||
|
|
@ -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)");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue